12

I've been used to thinking that WM_CREATE is the first message a window receives. However, when testing this assumption on a top-level window, it turns out to be false. In my test, WM_MINMAXINFO turned up as the first message.

So, what is the first message a window is guaranteed to receive?

Agnel Kurian
  • 57,975
  • 43
  • 146
  • 217
  • 1
    This question makes no sense. As you noted, the first messages is not always the same. Depending on whether the window is created visible or not a whole slew of messages may come to the WindowPRoc before CreateWindow ever returns. which messages, and their order has changed between versions of windows. All you are guaranteed is that WM_CREATE - and now WM_NCREATE - will be sent before CreateWindow returns (Assuming a successfull window creation). – Chris Becke Nov 16 '09 at 12:47
  • 5
    Chris, why a comment instead of an answer? Also, doesn't it make any sense? I bet 90% of Win32 developers would swear WM_CREATE is the first msg received (and I was one of them until 30 seconds ago). After all, that's what we all read in our textbooks. – Serge Wautier Dec 07 '09 at 22:09
  • Agreed Serge Wautier, I thought this too until I did a little test. This is the order of all my WM messages up to WM_CREATE: WM_GETMINMAXINFO, WM_NCCREATE, WM_NCCALCSIZE, WM_CREATE. – Kit10 Mar 03 '17 at 16:47
  • @SergeWautier I have no clue why this question makes no sense. It mattered not whether the behaviour is undefined. That was what the question was trying find out. – user13947194 Oct 12 '21 at 08:35

4 Answers4

14

WM_NCCREATE is actually the very first message your window will receive, which will arrive before WM_CREATE. It is related to creating the non-client area (eg. title bar, system menu, etc), hence the NC prefix.

WM_GETMINMAXINFO is sent before the window size/position is changed, and may arrive before WM_CREATE (see below for more).

The WM_CREATE message is sent before CreateWindow() returns, so you can guarantee that per-window initialisation has been performed by that point. Your window proc will receive WM_CREATE after the window is created, but before the window becomes visible (WM_SHOWWINDOW).

Actually, there is an interesting inconsistency in the MSDN documentation - the creation messages seem to depend on whether you call CreateWindow() or CreateWindowEx(), however it does not specify that the messages are necessarily listed in order of dispatching.

  • CreateWindow(): WM_CREATE, WM_GETMINMAXINFO and WM_NCCREATE
  • CreateWindowEx(): WM_NCCREATE, WM_NCCALCSIZE, and WM_CREATE

I strongly suspect that the message order described in CreateWindow() should have WM_NCCREATE first, and the regular WM_CREATE last, which is consistent with the notification documentation and the CreateWindowEx() reference (and also consistent with what you describe).

Raymond Chen also has some interesting information on window creation/destruction.

It just goes to show, even seemingly simple things can get complex the more you look at them.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
gavinb
  • 19,278
  • 3
  • 45
  • 60
  • Interesting that WM_NCCREATE was introduced in Win95, which explains why it wasn't documented in Petzold's "Programming Windows" when I first read it in 1997. – PP. Nov 16 '09 at 10:41
  • 2
    WM_NCCREATE has been around since Windows 1.0. There's a lot that Petzold has never attempted to cover. – Jerry Coffin Nov 16 '09 at 15:54
  • 1
    Lots of useful information here and I am sorry to downvote. However, WM_NCCREATE is the very first message only for top-level windows. – Agnel Kurian Aug 12 '10 at 11:10
  • 1
    Correction to my previous comment. WM_NCCREATE is the very first message only for non-top-level windows. Sorry for the delay in correcting this. :) – Agnel Kurian Feb 16 '12 at 18:45
  • 3
    @gavinb, that's wrong! After several test I've found out that the first message is (why ever) WM_GETMINMAXINFO. So the correct chain is: `WM_GETMINMAXINFO -> WM_NCCREATE -> WM_CREATE` – Sebi2020 Jun 02 '15 at 15:35
  • @Sebi2020 How exactly did you test this? Presumably you were testing `CreateWindow()`? I've linked to the official docs above for these APIs, and quoted the messages under the "Remarks" section. Do you have another reference? – gavinb Jun 16 '15 at 12:05
  • 2
    @gavinb No I have no reference for that. I've logged the messages, that were posted to the message loop. And the first one which occured was WM_GETMINMAXINFO. I tried this more than once and every time the first message I get is WM_GETMINMAXINFO (0x36). – Sebi2020 Jul 11 '15 at 15:55
  • @seb Neither `WM_NCCREATE` not `WM_GETMINMAXINFO` are ever posted. Those are non-queue messages. As such they are never observed by your message loop (even when they are sent across threads). – IInspectable Jun 30 '20 at 18:32
  • 1
    @gav I've followed the documentation all the way back to the version that was published in December 2008. With the exception of the supported platforms, the documentation hasn't changed at all. There is no mention in the documentation, that `WM_NCCREATE` were indeed the first message sent to a window procedure, as this answer suggests. What sources do you have for that? – IInspectable Jun 30 '20 at 18:42
  • 1
    @IInspectable Regarding "non-queue messages", the docs all say of these messages: "A window receives this message through its WindowProc function." As for the sources to the answer (from many years ago!) they are all linked in the answer and as specified are under "Remarks". For example: "The CreateWindowEx function sends WM_NCCREATE, WM_NCCALCSIZE, and WM_CREATE messages to the window being created." I had assumed the events were listed in order. Given comments by others about events they have logged, the order doesn't seem to match. I guess the docs don't match reality! – gavinb Jul 02 '20 at 12:20
  • 1
    The docs match reality. Your interpretation is, what's at fault. The documentation provides a **non-exhaustive** set of messages, that are sent to a window's procedure before the window creation function returns. It doesn't make any promises about the order, nor the completeness. The only guarantee you get is that `WM_NCCREATE` is sent prior to `WM_CREATE`. I'm not sure what you were trying to communicate in the comment starting with *"Regarding 'non-queued message'"*. – IInspectable Jul 02 '20 at 12:47
11

You answered your own question. I too see WM_GETMINMAXINFO, on Windows XP SP3, followed by WM_NCCREATE, WM_NCCALCSIZE, and finally WM_CREATE before CreateWindowEx() has even returned the handle to the window being created. What garabage'

The general answer is that Microsoft is incompetent when it comes to orderly creation and destruction of objects. They get it wrong with windows, with COM, and with device drivers. There's always some catch-22 where an object is half-created or half-destroyed that requires some roundabout convoluted solution to produce a reliable product.

Steel
  • 174
  • 2
4

Results by experimentation are better than just trusting the source, especially since the source is composed by a legion of programmers, and none know all the code. That said:

The fist message I receive is 0x24 (WM_GETMINMAXINFO).

Can I assume that it will always be the first message? No, since code change between versions of windows, and Microsoft has not documented a message guaranteed to be the first one received.

Bottom line: Do not assume that WM_CREATE was called before another message.

rxantos
  • 1,724
  • 1
  • 13
  • 14
  • 5
    No, experimentation is never a good idea. These things are undocumented for a reason. There's no guarantee that `WM_GETMINMAXINFO` will *always* be the first message sent, no matter which version of Windows and the configuration of the user's machine. Any application that relies on receiving messages in a certain order like this is fundamentally broken. The documentation tells you to assume that `WM_NCCREATE` is the first message received. You should do all of your initialization there: it will work every time, no matter what system your app runs on. Don't reverse engineer Windows. – Cody Gray - on strike Dec 10 '11 at 12:21
  • @CodyGray I have always been doing my initialization in WM_CREATE and thats what the documentation for CreateWindowEx showed. But I get uninitialized error for messages that occur before WM_CREATE. What is the purpose of having two create messages? – user13947194 Oct 12 '21 at 08:43
  • 1
    @user13947194 Are you asking why there are both the WM_CREATE and WM_NCCREATE messages? One (NC) is for the creation of the non-client area, while the other is for the creation of the client area. Use the one that best matches what you are doing. See [this Q&A](https://stackoverflow.com/q/6289196) for a complete explanation of the difference. I cannot help you to debug "uninitialized error messages" without seeing any sample code. Ask a new question about that; be sure to include a [mcve]. – Cody Gray - on strike Oct 12 '21 at 08:44
  • @CodyGray 1. I am sorry I misled you but I wasn't actually asking you to help me debug anything. I already know why my GWL_USERDATA has not been initialized on handling messages that occur before WM_CREATE. Do GWL_USERDATA initialization in WM_NCCREATE solved my problem. Thanks for helping. 2. Asking questions in StackOverflow is dangerous to ones reputation. 3. uhm! WM_CREATE is not for creating the client area. and WM_NCCREATE is not for creating non client area. They are messages for you to initialize your variables. But I found out that at the time of WM_NCCREATE the hwnd is still invalid. – user13947194 Oct 12 '21 at 10:40
2

You can use spy++ which comes with visual studio to see what messages are generated when the application or window is started.

K Singh
  • 1,710
  • 1
  • 17
  • 32