When will the window manager destroy a menu automatically, and when do I need to do it manually?

Our old friend Norman Diamond wonders when you are supposed to destroy a menu and when you are supposed to let Windows destroy it.

The rules for when the window manager implicitly destroys menus are actually not that complicated.

  • If a window is destroyed, the menus attached to the window are also destroyed:

    • Attached as the menu bar (Get­Menu/Set­Menu)
    • Attached as the system menu (Get­System­Menu)
  • If a menu is destroyed, its submenus are also destroyed.
  • If you replace a MIIM_SUBMENU submenu, the old menu is destroyed.
  • If you pass bRevert = TRUE to Get­System­Menu, then the old system menu is destroyed and a clean system menu is created in its place.

Outside of the above situations, you are on your own.

Of course, when I write that "you are on your own" I do not mean that "every code which sees a menu is responsible for destroying it." If that were the case, you would have a disaster as the slightest passing breeze would cause people to call Destroy­Menu all over the place. Rather, I mean that in all other cases, you need to "work it out amongst yourselves" who is responsible for destroying the menu. Typically, the person who creates the menu takes responsibility for destroying it, although that responsibility can be handed off based on mutual agreement between the creator and another component.

The original question did include a misunderstanding:

If the old object belonged to a window class, and we destroy the old object, how do we know that other windows of the same class aren't going to get in trouble?

The mistaken belief here is that each window of a class shares the same menu. If that were true, then if a program created two windows of the same class, modifications to one window's menu would affect the other. You can see that this is not true by inspection, or at least it was easier back in 1995. On Windows 95, open two Explorer windows, and set them into different views. The two windows now have different menus: One of them has a bullet next to the Large Icons menu item, whereas the other has a bullet next to Details.

When you register a window class, you pass in the menu you want, but only in the form of a template:

    WNDCLASS wc;
    wc.lpszMenuName = MAKEINTRESOURCE(...);

There is no menu yet, just a description of how to create a menu when the time comes. When you create a window from this class, the window manager initializes the menu by doing the equivalent of

    SetMenu(hwnd, LoadMenu(pWndClass->hInstance,

Each window gets a fresh menu from the specified menu template. Once that's done, you can change it all you want; it won't affect any the menus associated with any other windows.

The system menu works the same way: Every window starts out with a default system menu, and when you call Get­System­Menu with bRevert = FALSE, you get a handle to that system menu, which you can modify to your heart's content without affecting any other menus. System menus have this additional wrinkle where you can pass with bRevert = TRUE to ask the window manager to destroy the current system menu and replace it with a fresh new default system menu.

Exercise: How would you accomplish the logical equivalent of Get­System­Menu(TRUE) for the menu bar menu?

Bonus chatter: While the system menu certainly behaves as I described it above, there's actually a little bit of optimization going on under the hood. We'll look at that next time.

Comments (17)
  1. Damien says:

    Presumably, using the second code snippet you just posted i.e.

       SetMenu(hwnd, LoadMenu(pWndClass->hInstance,


  2. TB says:


    I would assume (assumptions are bad, but I'm lazy atm) that the old menu needs to be destroyed manually, as per the rules Raymond laid out at the beginning of the post.

  3. Damien says:

    @TB – Doh.



    and then what I posted?

  4. Re: Bonus Chatter

    I'm guessing that the system keeps around one copy of a pristine, unmodified system menu, which it shares between all windows by default.  Then, when someone calls GetSystemMenu(hwnd, FALSE), it copies that system menu, sets the window's system menu to that copy, and then returns the handle of that copy.

    This way, in the common case (where the window doesn't touch its system menu), you don't have to bother copying a menu, but in the uncommon case, you do the same amount of work of copying a menu, except this time the copying happens when you call GetSystemMenu() instead of when the window is created.  There's also a marginal amount of extra bookkeeping, but I don't think that's relevant.

  5. mariete says:

    SetMenu(hwnd, LoadMenu(pWndClass->hInstance,pWndClass->lpszMenuName));

    and restore it:

    SetMenu(hwnd, TRUE);

  6. Owen S says:

    Re: Adam Rosenfield

    I'd guess that the system doesn't do that; the app may call GetSystemMenu(TRUE) and then modify it.

    What I would expect is that the menu has a dirty bit, which is set when its modified. GetSystemMenu(TRUE) only replaces  a dirty menu.

  7. Henke37 says:

    Kinda obvious, but I do think there is one more case where the menu will be destroyed for you, if you somehow manage to have one at process termination even when the windows have been destroyed.

  8. @Owen S: That's not possible.  If you look at the documentation for GetSystemMenu(), it says that it returns NULL if bRevert is TRUE.

  9. Mark says:

    Henke37: probably not, it will just get lost as the process terminates.

  10. Henning Makholm says:



    destroys the menu while it is still assigned to a window. That sounds like a no-no — if not by documented rule, then certainly as a matter of sane coding practice in general.

  11. Nick says:

    Interesting timing on this article since I spent most of today working with the system menu and reading the related documentation.  I haven't worked with the *Menu functions before so I've been doing a lot of learning.

    One question I ran across if anyone has any ideas: Is there a way to determine the number of items in a menu which is modified before being displayed?  I have a program that adds several items to the system menu of all windows (via a global hook DLL I believe).  When I call GetMenuItemCount I'm given the number of items before this other program modifies the menu.

    I assume this other program must be modifying the system menu when it's displayed (hence the discrepancy) so I can see the difficulty of determining the item count, but does anyone know of a way?  Thanks.

    [It sounds like you're asking for a time machine. "I want to know how many items will be in a menu at some point in the future." You're also violating the rule If it's not yours, then don't mess with it without permission from the owner as well as the principle What if two programs did this?. This is definitely not the way to learn how to work with the *Menu functions. -Raymond]
  12. Wilczek says:

    — OFF —

    Hi all,

    I'm sorry to post this question, or rather observation here, but I could not add a comment to the article "If you can detect the difference between an emulator and the real thing, then the emulator has failed". Recently I have migrated my very old stuff (including some 16 bit apps/programs) on a new computer into a virtual machine. The main OS is Win7 Pro 64 bit and I use Windows Virtual PC. In the virtual machine I've installed Win2003 Server Standard (32 bit). Now, if I start for example turbo.exe (TP6.0 :)) in the VM, NTVDM says that "NTVDM has encountered a hard error". If I run the same app. on the old computer where Win2003 Server Standard (32 bit) is not inside a VM, it starts fine. My question is if Virtual PC is on a 64 bit OS and it's creating a virtual 32 bit environment for the guest OS and it tries to start a 16 bit app then there is a limitation of the VPC? Also, if I run a 16 bit app. in a VM hosted by a 32 bit OS using Virtual PC and the guest OS is e.g. XP 32 bit, the 16 bit app. starts just fine.

    PS: this is not an issue for me, it was just interesting…

    Thanks and regards,


  13. Josh says:

    According to several support engineers, 16 bit installers should work in XP mode (which is a 32 bit virtualized OS) on 64-bit Windows 7 ( social.answers.microsoft.com/…/64b42c08-dd90-424f-8dfc-adf8fc474351 ). So if they're correct, the problem shouldn't be caused by the inability to run in 16 bit mode when the processor and host OS are 64 bit, though that would imply that the VM software would need to emulate 16 bit mode when the guest OS requests it.

    Of course, most of the 16 bit apps I've wanted to run are old DOS games; DOSBox works well enough for that, and doesn't depend on the 16 bit processor mode at all (it runs fine on my Vista x64 box). You need to exempt it from DEP checks to run it with full performance (because the fastest method of execution basically involves rewriting the DOS executable code to a buffer, then executing the buffer), but given how little CPU DOS programs depended on, you can usually run them at least as well as they ran on their original hardware. In many case they run better; old games like Master of Magic demanded your conventional memory be nearly unused, while also demanding lots of XMS and EMS memory, which required drivers that occupied the precious conventional memory. When I used to play it on actual machines, I had to manually install it from the CD onto the hard disk, then load up a custom autoexec.bat and config.sys that disabled the CD drive or I wouldn't have enough memory to load the sound driver and play the game at the same time. DOSBox just pretends to have completely empty conventional memory, and an arbitrary amount of XMS and EMS. Much simpler. :-)

  14. Nick says:

    [It sounds like you're asking for a time machine. … ]

    Thanks for the feedback, Raymond.  As I said, I didn't expect it would be easy (or even possible).  My only thought was that maybe there was a way to ask the window manager to "pretend" to show the menu (do everything but actually display it), and then get the item count from that.  Of course, this may not even be possible (my ignorance is showing by this point I'm sure).

    For what it's worth, the program that manipulates every window's system menu is out of my control and I'm just trying to work around it.  As you suggest, hacking around a poorly implemented system is probably a bad way to try and learn something new, but all too often that seems to be how it goes :/

    Thanks again.

    [Imagine if there were a "pretend to do it" method. You "pretend to do it" and then do your extra thing. Hey, you now broke the assumption of some other guy who also used the "pretend to do it" technique, because he didn't get to see your extra thing! (Hence my reference to the "What if two programs did this?" principle.) You are saying "I always want to be the last guy to modify this menu." And then when two people ask to always be the last guy? -Raymond]
  15. Nick says:

    [And then when two people ask to always be the last guy? -Raymond]

    Clearly a match of wits must ensue.  Perhaps a game of riddles or a quick round of Go between the two programs with the winner getting to be the last guy. That seems fair.

    Seriously though, I see your point and appreciate the input.

  16. Worf says:

    @Wilczek: The problem 8is you're runnimg 16 bit code on a 64-bit OS. That cannot be done due to the way x64 works. In 32-bit mode, an x64 CPU acts and behaves like a normal IA-32 system. But when a 64-bit OS puts the x64 chip into 64-bit mode, it's x64 with a 32-bit compatibility layer. 16-bit code is illegal and cannot run.

    AMD got rid of all the 16-bit legacy stuff (16-bit, real mode, etc) when designing x64, but they kept the 32-bit protected mode. It's really two processors in one since an x64 program has a different programming model (more registers!).

    DOSBox works because it emulates an x86 CPU (which is why your GHz class machine ends up being barely more than a 500MHz one), which enables it to work on non-x86 as well.

    Your options are either to dual-boot with a 32-bit OS version, or hope your really old stuff works with DOSBox, QEMU or bochs. Or other emulator.

  17. Wilczek says:

    — OFF —



    Please read my comment again, I am not trying to run 16 bit code on a 64 bit OS. There is a virtual machine running on the 64 bit OS and in the virtual machine there is a 32 bit OS installed. I tried to run the 16 bit app on the 32 bit OS inside the virtual machine.


    Thanks for the comment. First I thought that it would work in the virtual machine :), the 2nd option was/is DOSBox.

Comments are closed.