What’s so special about the desktop window?


The window returned by GetDesktopWindow() is very special, and I see people abusing it all over the place.

For example, many functions in the shell accept a window handle parameter to be used in case UI is needed. IShellFolder::EnumObjects, for example.

What happens if you pass GetDesktopWindow()?

If UI does indeed need to be displayed, you hang the system.

Why?

  • A modal dialog disables its owner.
  • Every window is a descendant of the desktop.
  • When a window is disabled, all its descendants are also disabled.

Put this together: If the owner of a modal dialog is the desktop, then the desktop becomes disabled, which disables all of its descendants. In other words, it disables every window in the system. Even the one you're trying to display!

You also don't want to pass GetDesktopWindow() as your hwndParent. If you create a child window whose parent is GetDesktopWindow(), your window is now glued to the desktop window. If your window then calls something like MessageBox(), well that's a modal dialog, and then the rules above kick in and the desktop gets disabled and the machine is toast.

So what window do you pass if you don't have a window?

Pass NULL. To the window manager, a parent of NULL means "Create this window without an owner." To the shell, a UI window of NULL typically means "Do not display UI," which is likely what you wanted anyway.

Be careful, though: If your thread does have a top-level unowned window, then creating a second such window modally will create much havoc if the user switches to and interacts with the first window. If you have a window, then use it.

Comments (26)
  1. Joel Spolsky says:

    Didn’t GetDesktopWindow() used to return NULL?

  2. Joel Spolsky says:

    Oh, wait, now I remember why I abuse this all over the place.

    Here’s some sample code from MSDN that advocates this exact abusage:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/WinUI/WindowsUserInterface/Windowing/DialogBoxes/UsingDialogBoxes.asp#init_box

    At some point, I don’t remember where, I was taught not to just throw around NULL willy-nilly to functions that want HWNDs, but to always use a real HWND, GetDesktopWindow being a last resort.

  3. Reuben Harris says:

    Here’s a question – on XP/2000, is the desktop HWND always 0x10014? If so, why? It’s presumably the first window object Win32 creates, so you’d expect 0x10000 or something like that (making sweeping assumptions about how HWNDs are generated of course).

  4. Raymond Chen says:

    Thanks, Joel, for digging up all the bad sample code – people who find errors can send them directly to me via the Contact link and I’ll submit doc bugs to the MSDN team.

    Real HWNDs are preferred of course. And if a function really wants a window then you had better give it a window. But GetDesktopWindow() is nearly always the wrong choice, since you don’t control that window.

    The numerical value of the desktop window is just whatever value happens to be assigned next. I am not myself familiar with XP’s algorithm for assigning window handles, but I suspect that the handle table is used for other things too (menus, icons, etc.) and it’s not out of the question that USER32 creates some menus and stuff before it gets around to creating the desktop.

  5. Raymond Chen says:

    Okay I took a look at that sample code, and it’s not using the desktop window for parenting. It’s just calling GetWindowRect() on it. That’s fine; it gets you the size of the desktop.

  6. Gregor Brandt says:

    Does that mean that this is bad?

    DirectSound->SetCooperativeLevel( ::GetDesktopWindow(), DSSCL_PRIORITY )

    ?

  7. Raymond Chen says:

    That’s definitely bad, since it associates your program with the desktop window’s thread, which is not a thread your program is actually running on. Even worse: If two programs do this, they end up stepping all over each other.

  8. I’m only reading your blog since a few weeks, but the more I read about mistakes people can make and actually even do, the less am I getting surprised by funky behaviour some applications may expose on themselves or the system. Strange, huh? :)

    I hope WinFX will be free of possibilities to create such sort of quirks.

  9. Kim Gräsman says:

    So, what are good uses for GetDesktopWindow?

    The kind of measuring you mentioned (GetWindowRect) looks OK, but is that primarily why GetDesktopWindow was exported and documented?

  10. Mario: You can have flexibility or you can have robustness in the face of uninformed engineers. Pick either one; you can’t have both.

    Gregor:

    Just create a hidden top-level window, and attach your DirectSound code to it. If you use ATL’s Windowing classes, you can do it with very little impact to your code, and it’ll solve all of your problems.

  11. Eva Douzinas says:

    Not sure I’m clear why you wouldn’t want to pass GetDesktopWindow() as your hwndParent. I thought that when you show a modal dialog, the parent gets disabled, not the grandparent. What am I missing?

  12. Steve Sheppard says:

    Didn’t you just answer your own question? If the act of invoking a modal dialog is to disable the parent and ALL OF IT’S CHILDREN. Then doesn’t invoking a modal dialog and declaring the desktop to be it’s parent (GetDesktopWindow() returns a handle to the desktop) cause the desktop and all of it’s children (including your new dialog) to be disabled as well? Yes it does, because you have created a deadlock.

  13. 4nd3r$ says:

    i think this is what he means: DesktopWindow->app_mainwnd->modal_dlg

  14. Raymond Chen says:

    Remember that owner and parent are two different things.

    Modal dialogs disable their OWNERs. All top-level windows have the desktop as their PARENT.

  15. Jordan Russell says:

    In the current SPs for Windows 2000 and XP, it looks like they fixed it so that disabling the desktop window is no longer possible.

    (i.e. EnableWindow(GetDesktopWindow(), FALSE) has no effect)

  16. ramkoth says:

    Raymond – You said owner and parent window are different. At the same time, you also state that "To the window manager, a parent of NULL means "Create this window without an owner."

    I am confused here. By the above statement you probably mean owner window and parent window are one and the same. Or may be you should explain why CreateWindow API doesn’t differentiate between owner and parent.

  17. Raymond Chen says:

    Sigh. The parent/owner confusion is on my list of topics to cover.

    The problem is that the ninth parameter to CreateWindowEx and the third parameter to the DialogBox functions are called "hwndParent" – when in fact it really should be called "hwndParentOrOwner". In casual talk, people often say "parent" when they really mean "parent or owner".

    To be more precise, I should have written "an owner of NULL means "Create this window without an owner"."

  18. Norman Diamond says:

    I’m also confused by two of these three:

    > A modal dialog disables its owner.

    > [Irrelevant to my confusion: Every window

    > is a descendant of the desktop.]

    > When a window is disabled, all its

    > descendants are also disabled.

    This seems to imply that a modal dialog would always disable itself (among others). No need to involve the desktop window in this mess. I assume your upcoming discussion of parent vs. owner will explain this too.

    By the way, the MSDN Library said that GetAncestor() could be used in Windows 98 but the header files said that it couldn’t, last time I looked. And at the same time, a Knowledge Base article said that some Windows 98 crashes were caused by programs somehow getting handles to their ancestor window even though there was no known way to do so. Perhaps the author of that Knowledge Base article should be given a pointer to the MSDN Library?

  19. This seems to imply that a modal dialog would

    > always disable itself (among others). No

    > need to involve the desktop window in this

    > mess. I assume your upcoming discussion of

    > parent vs. owner will explain this too.

    My guess (and note, I’m just guessing – I’m not Raymond) would be that as a belt-and-braces measure, the last step in the DialogBox function would be a call to EnableWindow for the Dialog itself. Then, even if it is created with the disabled style set, or you set the Desktop as its owner, it’ll still be valid and won’t lock up the application which spawned it.

    There are other possibilities; DialogBox might be spawning a modal message loop and eating messages instead of actually calling EnableWindow on all of the other messages.

  20. Raymond Chen says:

    An owned window is not a child window. Disabling a parent also disables children, but it does NOT disable owned windows.

    The desktop is the parent of all top-level windows, so disabling the desktop disables everybody. The desktop is special that way.

  21. Norman Diamond says:

    Hmm. Suppose an attempt to disable a desktop window would result in an error message and close the application (or yield an exception if the application is still running at its developer’s site instead of a hapless customer). Would this cause any new bugs? Does anyone really have a legitimate reason to disable a desktop window?

  22. Actually, Norman, if anything’s going to change, it makes much more sense to just silently ignore the request to disable the desktop window. According to others in this thread, this may actually be the current behavior for Win2k and XP.

  23. Walk the template header and do what it says.

  24. It gets worse and worse until it works in the worst way possible.

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

Comments are closed.