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

时间:2008-09-09 02:58:15

标签: windows winapi

当应用程序落后于其他应用程序时 我点击我的应用程序的任务栏图标,我希望整个应用程序 即使是app-modal,WS_POPUP对话框,也会出现在z顺序的顶部 开。

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

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

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

简而言之,两者都是使用DialogBoxParam()创建的WS_POPUPWINDOW窗口, 传入相同的HWND作为第三个参数。

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

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

3 个答案:

答案 0 :(得分:4)

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

在您看到(和写入)将对话框置于前台的应用程序将主窗口与其一起启动时,开发人员只是忽略指定所有者对话框。

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

在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
);

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

public DialogResult ShowDialog(
    IWin32Window owner
)

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

此外,在WinForms中,可以轻松设置无模式窗口的所有者:

public void Show(
    IWin32Window owner,
)

或等同于:

form.Owner = this;
form.Show();

在直接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
);

或之后:

SetWindowLong(hWndPopup, GWL_HWNDPARENT, (LONG)hWndOwner);

或(64位兼容)

SetWindowLongPtr(hWndPopup, GWLP_HWNDPARENT, (LONG_PTR)hWndOwner);

请注意,MSDN对SetWindowLong[Ptr]

有以下说法
  

不要使用GWLP_HWNDPARENT索引调用 SetWindowLongPtr 来更改子窗口的父级。而是使用SetParent功能。

这有点误导,因为它似乎暗示上面的最后两个片段是错误的。事实并非如此。调用SetParent会将预期的弹出窗口转换为父窗口的(设置其WS_CHILD位),而不是将其设置为拥有窗口。上面的代码是使现有弹出窗口成为拥有窗口的正确方法。

答案 1 :(得分:1)

当您单击任务栏图标时,Windows将向您的应用程序发送 WM_ACTIVATE 消息。

您确定您的代码是否将 WM_ACTIVATE 消息传递给 DefWindowProc 窗口过程进行处理?

答案 2 :(得分:0)

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

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

Raymond Chen你在哪里!