为什么单击子窗口并不总是将应用程序带到前台?

Dav*_*ron 5 windows winapi

当应用程序位于其他应用程序后面并且我单击我的应用程序的任务栏图标时,即使打开了app-modal,WS_POPUP对话框,我也希望整个应用程序位于z-order的顶部.

但是,有些时候,对于我的一些(和其他人)对话框,只有对话框出现在前面; 应用程序的其余部分留在后面.

我看过Spy ++,对于那些工作正常的,我可以看到WM_WINDOWPOSCHANGING被发送到对话框的父级.对于留下应用程序其余部分的那些,WM_WINDOWPOSCHANGING不会被发送到对话框的父级.

我有一个例子,其中一个对话框通常带有整个应用程序,而另一个没有.工作对话框和非工作对话框都具有相同的窗口样式,子样式,父级,所有者,个体发生.

简而言之,两者都是使用DialogBoxParam()创建的WS_POPUPWINDOW窗口,它们传入了与第三个参数相同的HWND.

有没有人注意到Windows程序中的这种行为奇怪?单击按钮时,TaskBar会向应用程序发送什么消息?谁负责确保所有应用程序的窗口都出现在前台?

在我的情况下,基础父母是一个MDI框架...以某种方式影响这个因素?

P D*_*ddy 5

我知道现在这已经很老了,但是我偶然发现了它,并且知道答案。

在您看到(并编写)的应用程序中,将对话框置于前台并没有将主窗口置于其中,开发人员只是忽略了指定对话框的所有者。

这既适用于模态窗口,如对话框和消息框,也适用于无模态窗口。设置无模式弹出窗口的所有者还会使弹出窗口始终保持在其所有者之上。

在Win32 API中,用于弹出对话框或消息框的函数将所有者窗口作为参数:

INT_PTR DialogBox(
    HINSTANCE hInstance,
    LPCTSTR lpTemplate,
    HWND hWndParent,      /* this is the owner */
    DLGPROC lpDialogFunc
);

int MessageBox(
    HWND hWnd,            /* this is the owner */
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);
Run Code Online (Sandbox Code Playgroud)

类似地,在.NET WinForms中,可以指定所有者:

public DialogResult ShowDialog(
    IWin32Window owner
)

public static DialogResult Show(
    IWin32Window owner,
    string text
) /* ...and other overloads that include this first parameter */
Run Code Online (Sandbox Code Playgroud)

此外,在WinForms中,很容易设置无模式窗口的所有者:

public void Show(
    IWin32Window owner,
)
Run Code Online (Sandbox Code Playgroud)

或等效地:

form.Owner = this;
form.Show();
Run Code Online (Sandbox Code Playgroud)

在直接的WinAPI代码中,可以在创建窗口时设置无模式窗口的所有者:

HWND CreateWindow(
    LPCTSTR lpClassName,
    LPCTSTR lpWindowName,
    DWORD dwStyle,
    int x,
    int y,
    int nWidth,
    int nHeight,
    HWND hWndParent, /* this is the owner if dwStyle does not contain WS_CHILD */
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam
);
Run Code Online (Sandbox Code Playgroud)

或之后:

SetWindowLong(hWndPopup, GWL_HWNDPARENT, (LONG)hWndOwner);
Run Code Online (Sandbox Code Playgroud)

或(64位兼容)

SetWindowLongPtr(hWndPopup, GWLP_HWNDPARENT, (LONG_PTR)hWndOwner);
Run Code Online (Sandbox Code Playgroud)

请注意,MSDN关于SetWindowLong [Ptr]的说法如下:

不要使用GWLP_HWNDPARENT索引调用SetWindowLongPtr来更改子窗口的父窗口。而是,使用SetParent函数。

这有点令人误解,因为这似乎暗示上面的最后两个片段是错误的。不是这样 调用SetParent将转向预期弹出到孩子的父窗口(设置其WS_CHILD位),而不是使其成为一个拥有窗口。上面的代码是使现有弹出窗口成为拥有的窗口的正确方法。


jma*_*ias 0

对话框的父窗口设置是否正确?

发布此内容后,我启动了自己的 Windows 窗体应用程序并重现了您所描述的问题。我有两个对话框,一个可以正常工作,另一个则不能,我看不出任何直接原因可以解释为什么它们的行为不同。如果我发现的话我会更新这篇文章。

陈雷蒙你在哪里!