What is the difference between WM_DESTROY and WM_NCDESTROY?

Date:July 26, 2005 / year-entry #203
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20050726-00/?p=34803
Comments:    16
Summary: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....

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.

*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