The correct order for disabling and enabling windows

Date:February 27, 2004 / year-entry #77
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20040227-00/?p=40463
Comments:    42
Summary:If you want to display modal UI, you need to disable the owner and enable the modal child, and then reverse the procedure when the modal child is finished. And if you do it wrong, focus will get all messed up. If you are finished with a modal dialog, your temptation would be to clean...

If you want to display modal UI, you need to disable the owner and enable the modal child, and then reverse the procedure when the modal child is finished.

And if you do it wrong, focus will get all messed up.

If you are finished with a modal dialog, your temptation would be to clean up in the following order:

  • Destroy the modal dialog.
  • Re-enable the owner.

But if you do that, you'll find that foreground activation doesn't go back to your owner. Instead, it goes to some random other window. Explicitly setting activation to the intended owner "fixes" the problem, but you still have all the flicker, and the Z-order of the interloper window gets all messed up.

What's going on?

When you destroy the modal dialog, you are destroying the window with foreground activation. The window manager now needs to find somebody else to give activation to. It tries to give it to the dialog's owner, but the owner is still disabled, so the window manager skips it and looks for some other window, somebody who is not disabled.

That's why you get the weird interloper window.

The correct order for destroying a modal dialog is

  • Re-enable the owner.
  • Destroy the modal dialog.

This time, when the modal dialog is destroyed, the window manager looks to the owner and hey this time it's enabled, so it inherits activation.

No flicker. No interloper.


Comments (42)
  1. Jerry Pisk says:

    Since I’ve never coded a WinForms app (just Asp.Net) I’m curious – why do I have to disable the owner of a modal dialog? Doesn’t modal dialog imply that user cannot interact with the owner until the dialog is dismissed?

  2. Steve Sheppard says:

    Where does the term "Modal" come from?

  3. theCoach says:

    I am going to make some guesses here. Jerry, he is referring to Win32 apps. You are thinking in terms of the end user, he is describing the coding that is required to respond to a user command to destroy the modal dialog.

    This seems like a good candidate for some "Pit of Success" treatment. Sure it makes sense; but it is an invitation for buggy code. Perhaps an api call that did something like DestroyModalDialog( bFocusToParent ) bFocusToParent being a boolean for whether or not to make sure the parent dialog box is enabled.

  4. Raymond Chen says:

    Jerry: I’m talking about the case where a program is manually managing modality. If you use built-in functions like DialogBox() then the OS manages the enabling/disabling for you.

    Steve: Conceptually, a modal dialog is one that forces you to complete a task before you can continue. The program has been put into a "mode" that you have to complete before you can continue. I don’t know if that’s the actual history of the term but that’s how I think of it.

  5. Steve: Modal comes from the idea of programming "modes", where instead of working on a given task (eg. using a wordprocessor or a webbrowser), you switch the application into a different mode of operation (eg. changing configuration parameters, or creating mailing labels).

    Modeless dialogs do not involve this conceptual switchover, as they act within the context of the current task. Modeless dialogs, however, require that you focus entirely on another task, which can completely change the behavior of the previous task – and so you have to wait until the new task is finished before you go back. Which is why modal things prevent you from messing with the main application.

    As a user interface design principle, modality is to be avoided if at all possible, because it forces the user down a given path and prevents them from having full control over the application. There are cases where it makes sense, but it has been abused really badly in the past.

  6. Raymond: Yep, that’s it. I can’t remember where I first came across the term… it might have been in an Apple Lisa version of the Apple Human Interface Guidelines, but it dates back to the days of text console displays on mainframes, where each display screen was a different mode.

  7. sd says:

    This isn’t applicable to MFC is it?

    Cdialog1Dlg dlg;

    m_pMainWnd = &dlg;

    INT_PTR nResponse = dlg.DoModal();

    if (nResponse == IDOK)

    {

    // TODO: Place code here to handle when the dialog is

    // dismissed with OK

    }

    else if (nResponse == IDCANCEL)

    {

    // TODO: Place code here to handle when the dialog is

    // dismissed with Cancel

    }

  8. Mike Dimmick says:

    MFC uses modeless dialogs behind the scenes. The DialogBox API does its own modal message loop internally, which MFC can’t hook into. This would mean that things like PreTranslateMessage and idle processing would fail to work.

    I believe there are other reasons too.

    Thankfully, MFC appears to get this right.

    See the code in DLGCORE.CPP (if you don’t have MFC source installed and you’re writing MFC code, go and install it right now, you’ll find debugging much easier, IMO).

  9. Jerry Pisk says:

    I see, this is about using modeless dialogs and making them act as modal. Then it makes sense even though I still don’t understand why not just use a modal dialog if I want to show the user a modal dialog. Any processing can (and imo should) run on a worker thread…

  10. Raymond Chen says:

    If you are using a framework that handles for you, then great! Use the framework and then you don’t need to worry about this.

    But if you want to do it manually, now you know how. (For example, if you’re writing your own framework.)

  11. Let me just make sure I’m clear on this:

    Referring back to your previous discussion on modal dialogs…

    When you create a dialog, you specify its owner.

    DialogBox then – if this owner is not NULL – disables the owner window, which then disables all of its child windows.

    If you specify the desktop window as your owner, this causes problems – because every top level window is a child of the desktop, and disabling the desktop then disables the dialog.

    Disabling / Enabling a window only affect its children, and not windows that are owned by the window being enabled/disabled.

    Owned and child windows always appear above their owners in the Z-order.

    The question being this:

    If you create a window, and give it a modeless dialog (eg. a find window), and then the user does something to show a modal dialog (eg. decides to change app. config), what happens to the modeless find window? Do you have to disable this separately and manually? Or am I missing a piece of the relationship here?

    Thanks!

  12. Raymond Chen says:

    You can run this experiment and answer the question yourself.

    Run Notepad, hit Ctrl+F to open the Find dialog, which is modeless.

    Now click File, Save As. This creates a modal dialog.

    Now play around.

  13. Yipes. That’s fascinating, not the behavior I expected, and slightly scary all in one.

    Even with a modal dialog present, I can still do an instance-by-instance replace of text in the control.

    Now, that leaves us with another question: what would the *right* way to handle this be?

    Personally, if I were implementing notepad, I’d probably come up with some way of disabling all of my owned windows except the one I’m using as a modal dialog. So you wouldn’t be able to activate the find/replace window while you were trying to save.

    Ouch – thanks Raymond – that’s weird.

  14. Mike Dunn says:

    Using modeless dlgs and faking modality is also useful in WTL, if you’re like me and need PreTranslateMessage() to work when the dialog is up. You have to do that to get proper keyboard handling when there are ActiveX controls in the dialog.

  15. Mark says:

    Someone at the eMbedded Visual C++ group should look at this article… it has the flicker bug in the "send file to device" dialog.

  16. Joku says:

    Sometimes i’ve found it that while filling in a modal dialog, i need to write some text in it that i forgot to copy / find from the now disabled parent/owner. Currently it sometimes works and sometimes maybe not, can’t remember.

    Point is i find useful it that you can scroll/copy from a textbox while the same app has a modal dialog open. Most of the time the modal dialog will have OK/Apply button that does the changes, why should the rest of the app be ‘stuck’ while i’m thinking whether to do the thing in the modal dialog or not? It’s not like your desktop gets disabled while you are at display properties! And it shouldn’t!

    Or maybe i’ve just misunderstood the whole thing you are talking here :-)

  17. Joku says:

    Trying to answer my own question.. Maybe apps should use Modal Dialogs only when it is really necessary to disable the owner.

    For example, when i press the About box in help menu, what is there in the regular About box that has to disable rest of the UI while viewing it? Maybe it keeps the UI a bit simpler when you can’t open a ton of dialogs, but as a power user i like control.

  18. Norman Diamond says:

    Someone in the Outlook Express group should read Mr. Chen’s blog. In another note someone mentioned that Outlook Express leaks GDIs every time the user changes folders. Here we can mention the FOUR flickers every time the OE main window recovers focus from a dialog box. This beats the one flicker that Mark mentioned for Pocket Explorer.

  19. Joku wrote:

    > Trying to answer my own question.. Maybe

    > apps should use Modal Dialogs only when it

    > is really necessary to disable the owner.

    Yep :) If you don’t need to disable the owner, you shouldn’t; it removes control from the user, and makes the app less intuitive and fun to use.

    > For example, when i press the About box in

    > help menu, what is there in the regular

    > About box that has to disable rest of the UI

    > while viewing it? Maybe it keeps the UI a

    > bit simpler when you can’t open a ton of

    > dialogs, but as a power user i like control.

    Good question… I guess it’s because it’s not something you generally want to see, so it’s probably not a good idea to have the window hanging around, but that is indeed an interesting edge case.

  20. When I use the find and replace while saving feature in Notepad, the replace dialog seems to ignore the tab key while the save dialog is shown. Odd.

  21. Tim Robinson says:

    That’s because Tab and Alt+? for a dialog are handled by calling IsDialogMessage on the HWND of that dialog.

    Normally Notepad calls IsDialogMessage(hwndFindOrReplaceDialog) in its main message loop. But while a modal dialog is open, the main message loop isn’t running; it’s replaced by one inside the Save dialog.

    The Save dialog doesn’t know about Notepad’s Replace dialog, so the Save dialog grabs the Tab and Alt+? keys.

  22. Eva Douzinas says:

    If you would like to show another application (exe) as a modal dialog, what is the signal that it is time to re-enable your window? My guess is that you would have to write some sort of hook to get the WM_CLOSE message for the apps main window, but I was wondering if there is a standard recommended approach.

  23. Seth McCarus says:

    Eva, you normally wait for a process to end by starting it with CreateProcess and using one of the wait functions (e.g. WaitForSingleObject) to wait until the process handle is signalled.

  24. Raymond Chen says:

    Jonathan/Tim: That’s correct. Which is why making "all" UI modeless is very difficult to code. It’s a very different programming model, since you have to turn everything into a state machine.

  25. Eva Douzinas says:

    Seth– if you wait for the process handle to be signaled, it is too late; the app window is already destroyed and the behavior Raymond describes happens (flicker, interloper) since the owner dialog has not been re-enabled in time.

  26. Raymond Chen says:

    You have to have the cooperation of the program you are launching. Anything else is just a hack.

  27. Eva Douzinas says:

    Raymond– can you recommend a design pattern for this (high level)? We have control over the applications we are launching. Thanks.

  28. Raymond Chen says:

    Very simple. Pass the window handle to the launched process. Then the launched process passes that window handle as the owner window for its UI. If you use a system function like DialogBox(), then the proper enabling/disabling happens automatically. If you do some custom UI then you’ll have to do it manually as described above.

  29. B.Y. says:

    Maybe you can explain something I noticed when I first started windows programming, but never felt I understood it 100%: Is there any difference between a parent window and a owner window, other than a child window must be inside its parent, but owned window is not inside the owner window ? Why there’re Get/SetParent() but no Get/SetOwner() ? But in GetWindow() call, there’s GW_OWNER, but no GW_PARENT.

  30. Raymond Chen says:

    Owner and parent are very different. I have a note to explain the difference in a future entry, thanks for asking.

  31. BY: Maybe I can answer this… probably not as well as Raymond could, but here you go:

    Parent/Child relationships are part of the window tree, and strongly determine Z-ordering. Changing the parent/child relationship immediately forces changes to the window hierarchy, and requires a re-layout of the window information (thus it’s a separate function).

    Owner/Owned relationships aren’t part of the Window tree; they only weakly determine Z-ordering. Changing the owner of a window has no immediate effect on the layout of the windows, and as such can be left to GetWindowLong/ SetWindowLong as it doesn’t need to interface to the Window Manager.

    At least, that’s my rather lame understanding of it.

  32. Centaur says:

    Regarding parent/child relationships…

    I have once had an attempt to build an appbar stuck at the screen edge. That’s nothing really special. But I had it contain other applications’ top-level windows, those that never were designed to be, so to say, /adopted/.

    For the most part, it worked. But it introduced all kinds of system instability.

    I’m just curious… what evil things may happen when you take a window that was born to live free on a desktop, and SetParent it into a cage? (Not that I would want to try it again…)

  33. The biggest problem is that activation goes all weird for that one stack of windows.

    Heck, check out MDI; that’s pretty much the same thing you’re describing :-)

  34. Jtk says:

    Raymond: I have always wondered what happened to modal dialogs in Windows 2000 (or NT 4, can’t remember for sure). When most apps show a modal dialog, clicking the owner window causes the title bar of the modal dialog to flash a few times. In some applications (like VS.NET 2003) modal dialogs still work like they always have been (no flashing). Was this change in Windows a deliberate one or is the flashing just a bug?

  35. Raymond Chen says:

    The flashing was a feature added to DefWindowProc, as I recall.

  36. Jtk says:

    Any idea what’s the reason for adding this feature (flashing)?

  37. Raymond Chen says:

    I thought it was obvious. If you click on a window that is disabled because it has a modal dialog up, it used to be that nothing happens Then you get frustrated and say, "I hate Windows; it always hangs," and reboot your computer.

    The blinking is there to say, "Look over here. This is the window you want."

  38. Raymond Chen says:

    Commenting on this article has been closed.

  39. Exploiting the rules for handling of the WM_QUIT message.

  40. Disable the owner window, but make sure it’s really the owner.

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