6

When an application is behind another applications and I click on my application's taskbar icon, I expect the entire application to come to the top of the z-order, even if an app-modal, WS_POPUP dialog box is open.

However, some of the time, for some of my (and others') dialog boxes, only the dialog box comes to the front; the rest of the application stays behind.

I've looked at Spy++ and for the ones that work correctly, I can see WM_WINDOWPOSCHANGING being sent to the dialog's parent. For the ones that leave the rest of the application behind, WM_WINDOWPOSCHANGING is not being sent to the dialog's parent.

I have an example where one dialog usually brings the whole app with it and the other does not. Both the working dialog box and the non-working dialog box have the same window style, substyle, parent, owner, ontogeny.

In short, both are WS_POPUPWINDOW windows created with DialogBoxParam(), having passed in identical HWNDs as the third argument.

Has anyone else noticed this behavioral oddity in Windows programs? What messages does the TaskBar send to the application when I click its button? Who's responsibility is it to ensure that all of the application's windows come to the foreground?

In my case the base parentage is an MDI frame...does that factor in somehow?

4

3 回答 3

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

同样,在 .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),而不是使其成为拥有的窗口。上面的代码是使现有弹出窗口成为拥有窗口的正确方法。

于 2009-11-22T05:14:03.430 回答
1

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

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

于 2008-09-19T04:08:19.307 回答
0

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

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

雷蒙德陈你在哪里!

于 2008-09-09T03:16:05.490 回答