Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does clicking a child window not always bring the application to the foreground?

Tags:

windows

winapi

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?

like image 828
David Citron Avatar asked Sep 09 '08 02:09

David Citron


2 Answers

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.

like image 166
P Daddy Avatar answered Oct 11 '22 22:10

P Daddy


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?

like image 39
jussij Avatar answered Oct 11 '22 23:10

jussij