tags:

views:

654

answers:

3

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?

A: 

Is the dialog's parent window set correctly?

After I posted this, I started my own Windows Forms application and reproduced the problem you describe. I have two dialogs, one works correctly the other does not and I can't see any immediate reason is to why they behave differently. I'll update this post if I find out.

Raymond Chen where are you!

jmatthias
+1  A: 

When you click on the taskbar icon Windows will send a WM_ACTIVATE message to your application.

Are you sure your code is passing the WM_ACTIVATE message to the DefWindowProc window procedure for processing?

jussij
A: 

I know this is very old now, but I just stumbled across it, and I know the answer.

In the applications you've seen (and written) where bringing the dialog box to the foreground did not bring the main window up along with it, the developer has simply neglected to specify the owner of the dialog box.

This applies to both modal windows, like dialog boxes and message boxes, as well as to modeless windows. Setting the owner of a modeless popup also keeps the popup above its owner at all times.

In the Win32 API, the functions to bring up a dialog box or a message box take the owner window as a parameter:

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

Similary, in .NET WinForms, the owner can be specified:

public DialogResult ShowDialog(
    IWin32Window owner
)

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

Additionally, in WinForms, it's easy to set the owner of a modeless window:

public void Show(
    IWin32Window owner,
)

or, equivalently:

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

In straight WinAPI code, the owner of a modeless window can be set when the window is created:

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

or afterwards:

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

or (64-bit compatible)

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

Note that MSDN has the following to say about SetWindowLong[Ptr]:

Do not call SetWindowLongPtr with the GWLP_HWNDPARENT index to change the parent of a child window. Instead, use the SetParent function.

This is somewhat misleading, as it seems to imply that the last two snippets above are wrong. This isn't so. Calling SetParent will turn the intended popup into a child of the parent window (setting its WS_CHILD bit), rather than making it an owned window. The code above is the correct way to make an existing popup an owned window.

P Daddy
Thanks for your answer! However, this is not the cause of the problem with my application. As I said in my question, I am passing the owner in all cases. Any other ideas?
David Citron
Do you have a reproducible sample, by chance?
P Daddy