Modality, part 5: Setting the correct owner for modal UI

Date:February 24, 2005 / year-entry #46
Tags:code;modality
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20050224-00/?p=36373
Comments:    10
Summary:Here is the very simple fix for the buggy program we presented last time. void OnChar(HWND hwnd, TCHAR ch, int cRepeat) { switch (ch) { case ' ': MessageBox(hwnd, TEXT("Message"), TEXT("Title"), MB_OK); if (!IsWindow(hwnd)) MessageBeep(-1); break; } } We have fixed the problem by passing the correct owner window for the modal UI. Since MessageBox...

Here is the very simple fix for the buggy program we presented last time.

void OnChar(HWND hwnd, TCHAR ch, int cRepeat)
{
  switch (ch) {
  case ' ':
    MessageBox(hwnd, TEXT("Message"), TEXT("Title"), MB_OK);
    if (!IsWindow(hwnd)) MessageBeep(-1);
    break;
  }
}

We have fixed the problem by passing the correct owner window for the modal UI. Since MessageBox is modal, it disables the owner while the modal UI is being displayed, thereby preventing the user from destroying or changing the owner window's state when it is not expecting it.

This is why all the shell functions that can potentially display UI accept a window handle as one of its parameters. They need to know which window to use as the owner for any necessary UI dialogs. If you call such functions from a thread that is hosting UI, you must pass the handle to the window you want the shell to use as the UI owner. If you pass NULL (or worse, GetDesktopWindow), you may find yourself in the same bad state that our buggy sample program demonstrated.

If you are displaying a modal dialog from another modal dialog, it is important to pass the correct window as the owner for the second dialog. Specifically, you need to pass the modal dialog initiating the sub-dialog and not the original frame window. Here's a stack diagram illustrating:

 MainWindow
  DialogBox(hwndOwner = main window) [dialog 1]
   ... dialog manager ...
    DlgProc
     DialogBox(hwndOwner = dialog 1) [dialog 2]

If you mess up and pass the main window handle when creating the second modal dialog, you will find yourself back in a situation analogous to what we had last time: The user can dismiss the first dialog while the second dialog is up, leaving its stack frames orphaned.


Comments (10)
  1. Dave says:

    I have a windowless ActiveX control and it sometimes needs to pop a dialog box. If the container is IE or WebBrowser, IObjectWithSite gives me the container’s IUnknown and from there I can get the IWebBrowser2.HWND property. Otherwise I punt back to NULL, for example if called from a WScript.exe script. Is there a generic way to get any container’s HWND?

  2. Ivo says:

    WTL is using GetActiveWindow as parent by default. Will that work in all cases? What will happen for example if a tooltip pops up – will that be the active window?

  3. Tooltips never get activation. The Active Window is the one which is … erm… active – not the one on the top of the Z-order.

  4. Jonathan says:

    Dave: ActiveX controls can use their host’s IOleWindow interface to get its HWND.

  5. A says:

    WTL is using GetActiveWindow as parent by default. Will that work in all cases?

    Nope, I would call that a bug. GetActiveWindow will return NULL if your application isn’t in the foreground. Thus, if your application were to throw up a dialog in response to, say, a timer tick, it would have no owner if your application wasn’t in the foreground at that precise moment.

  6. Scott says:

    I’m sure these series are great for those that can understand them, but how about a little lighter fare to break this one up? Something simple even I can understand like "Why does Windows do such and such?" And then tell us about the good old days and how they transitioned to the even better later days.

  7. Anthony Wieser says:

    Funny, just yesterday, I came across a problem with HtmlHelp in a debug MFC build of my project.

    If I clicked on the dialog, sometimes, the program would assert in _AfxHandleActivate, after the WM_ACTIVATE was called.

    It seems that despite setting the parent window correctly, because HTML help is on another thread, the window pointed to as being deactivated will not necessarily exist, as it was on another thread.

    And we all know how much MFC likes windows from multiple threads ;)

    Apparently the solution is to initialize HTML Help as single threaded, and pass it messages (yuck).

  8. Mike Dunn says:

    Ivo> Yeah, the default of GetActiveWindow() has bitten me a couple times in the past. Now I’m in the paranoid habit of passing an HWND to every DoModal(), luckily most of the time "*this" is sufficient so it’s not a hassle.

  9. Respect the modality of a window.

  10. Otherwise you end up creating the impossible.

Comments are closed.


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index