What is the difference between WM_DESTROY and WM_NCDESTROY?

There are two window messages closely-associated with window destruction, the WM_DESTROY message and the WM_NCDESTROY message. What's the difference?

The difference is that the WM_DESTROY message is sent at the start of the window destruction sequence, whereas the WM_NCDESTROY message is sent at the end. This is an important distinction when you have child windows. If you have a parent window with a child window, then the message traffic (in the absence of weirdness) will go like this:

hwnd = parent, uMsg = WM_DESTROY
hwnd = child, uMsg = WM_DESTROY
hwnd = child, uMsg = WM_NCDESTROY
hwnd = parent, uMsg = WM_NCDESTROY

Notice that the parent receives the WM_DESTROY before the child windows are destroyed, and it receives the WM_NCDESTROY message after they have been destroyed.

Having two destruction messages, one sent top-down and the other bottom-up, means that you can perform clean-up appropriate to a particular model when handling the corresponding message. If there is something that must be cleaned up top-down, then you can use the WM_DESTROY message, for example.

The WM_NCDESTROY is the last message your window will receive (in the absence of weirdness), and it is therefore the best place to do "final cleanup". This is why our new scratch program waits until WM_NCDESTROY to destroy its instance variables.

These two destruction messages are paired with the analogous WM_CREATE and WM_NCCREATE messages. Just as WM_NCDESTROY is the last message your window receives, the WM_NCCREATE message is the first message, so that's a good place to create your instance variables. Note also that if you cause the WM_NCCREATE message to return failure, then all you will get is WM_NCDESTROY; there will be no WM_DESTROY since you never got the corresponding WM_CREATE.

What's this "absence of weirdness" I keep alluding to? We'll look at that next time.

[Typos corrected, 9:30am]

Comments (16)
  1. Christian says:


    Does anybody (not the autor of the blog, this is not a .NET-blog), know how this is best mapped to .NET? What is the OnLoad-event, and how can I get the other three?

  2. Al says:

    Just a couple of clean-up points:

    "and it receives the WM_NCDESTROY come after they have been destroyed." could do with making sense. Maybe "and it receives the WM_NCDESTROY [message] after they have been destroyed."

    Also your link to the scratch program has an additional quote at the end of the href, thus making the link fail without some editing.

  3. mschaef says:

    How far do the WM_NCDESTROY and WM_NCCREATE messages date back? Windows 1.0?

  4. Yes, obviously WM_NCCREATE is the first message sent to a window. Nothing else would make sense, would it?

    Try setting a breakpoint on an window function and see what is really the first message sent to a window. It may surprise you…

  5. Adrian says:

    I had a home-brew framework that would get an assertion-failure if a window proc received any message before the WM_NCCREATE. Turns out that top-level windows often receive a WM_GETMINMAXSIZE first. It’s annoying since you can’t respond rationally to the message before you’re initialized. I wonder if this is one of the weirdnesses Raymond will talk about.

  6. Slaven says:

    NC is probably non-client…

  7. Mike says:

    I also find the mention of NC_CREATE misleading, since AFAIK getminmaxinfo is always the first message ever sent to any ("frame"/non-child) window. For a (C++) framework I have worked on, testing has proved (to me) that it’s the only realiable message to depend on to create a C++ object and attach it to the frame window HWND being created (at least if you, like in my case, from then on use that C++ object to handle all messages to that window).

    This under-documentation (to put it mildly) of the order of messages during creation I consider a quite serious flaw. Either you (as a developer) have to know about many of these undocumented behaviours by experience or just trial-and-error, or be prepared to create backing objects for windows no matter what message is recieved.

  8. Bryan says:

    NC == non-client for the WM_NCPAINT message, so I would assume that NC == non-client here also.

    Could be wrong, though.

    Christian — you might be able to disassemble the System.Windows.Forms.dll assembly and find out which functions the various messages correspond to (though this may not be allowed by the framework’s license, I’m not sure). I’d think that System.Windows.Forms.Form.WndProc would be the logical place to start, if you want to do this.

    I’d look at the MSIL opcodes using ildasm.exe (part of vs.net), not the raw x86 assembly. Or maybe Rotor would be helpful (I’m not entirely sure what Rotor even is, but I’ve heard mention of it relative to decompiling / disassembling before).

  9. asdf says:

    I remember there was some windows spy program that would send WM_GETICON (or maybe WM_SETICON) before the WM_NCCREATE message got to your wndproc and it would cause problems on certain programs.

  10. Neil says:

    The MSDN docs for MFC CWnd::CreateEx say:

    "When CreateEx executes, Windows sends the WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALCSIZE, and WM_CREATE messages to the window."

    and for the Win32 CreateWindowEx (which is called by the CWnd version):

    "The CreateWindowEx function sends WM_NCCREATE, WM_NCCALCSIZE, and WM_CREATE messages to the window being created."

  11. josh says:

    Another oddity is that MSDN says WM_SIZE and WM_MOVE aren’t sent if you don’t pass WM_WINDOWPOSCHANGED on to DefWindowProc, but you’ll still get one of each during creation. (at least on Windows 2000…)

  12. Ulric says:

    One thing I learned the hard way while creating a menu-like widget was that while in WM_DESTROY all the children still exist, owned windows have already been destroyed. In order words, all the WM_POPUP that look like "children" (but actually, owned) by a window are destroyed before WM_DESTROY gets sent to that window.

  13. Remember the order in which windows are destroyed.

  14. fengzi_shen says:

    WM_DESTROY 和 WM_NCDESTROY 消息之间有什么区别?

Comments are closed.

Skip to main content