Which message numbers belong to whom?


Valid window messages break down into four categories.

0 .. 0x3FF (WM_USER-1): System-defined messages.

The meanings of these messages are defined by the operating system and cannot be changed. Do not invent new messages here. Since the meanings are defined by Windows, the operating system understands how to parse the WPARAM and LPARAM parameters and can marshal the messages between processes (or knows to refuse to do so).

0x400 .. 0x7FFF (WM_USER .. WM_APP-1): Class-defined messages.

The meanings of these messages is determined by the implementor of the window class. (Informally: By the person who calls RegisterClass for that window class.) For example, the WM_USER+1 message means TB_ENABLEBUTTON if the window is a toolbar control, but it means TTM_ACTIVATE if it is a tooltip control, and it means DM_SETDEFID if it is a dialog box. If you created your own control, it would mean something else completely different. Since anybody can create a message in this range, the operating system does not know what the parameters mean and cannot perform automatic marshalling.

0x8000 .. 0xBFFF (WM_APP ... MAXINTATOM-1): Application-defined messages.

The meanings of these messages is determined by the application that created the window. (Informally: By the person who calls CreateWindow.) This message region was created in Windows 95 to ensure that applications which subclass a window and generate custom messages will not interfere with new messages created by the window class in future versions. Again, since anybody can create a message in this range, the operating system does not know what the parameters mean and cannot perform automatic marshalling.

0xC000 .. 0xFFFF (MAXINTATOM .. MAXWORD): Registered messages.

The meanings of these messages is determined by the caller of RegisterWindowMessage. Note that the numerical value of registered messages can change from run to run, so you must use RegisterWindowMessage to obtain the message number. Once again, since anybody can create a message in this range, the operating system does not know what the parameters mean and cannot perform automatic marshalling.

Comments (18)
  1. Anonymous says:

    I remember reading somewhere that for backward compatibility reasons Windows will actually marshall cross-process messages above WM_USER for classes like listbox etc. Can you comment on that?

  2. Anonymous says:

    If you look closely at winuser.h, you’ll see that all those messages got renumbered to be below WM_USER.

    #define LB_ADDSTRING 0x0180
    #define LB_INSERTSTRING 0x0181

    etc.

  3. Anonymous says:

    You’re right. The funny thing is that LB_ADDSTRING is also #defined in winres.h as (WM_USER + 1), at least in SDK which ships with VC6.

  4. Anonymous says:

    There isn’t any way to free a registered message, is there?

  5. Anonymous says:

    Oh, something else I’ve always wondered: What is *supposed* to happen when the registered message pool is exhausted? It seems that (on Windows 2000) RegisterWindowMessage() will loop back to 0xC000 and start returning identifiers that were already registered under different names. Is this intentional?

  6. Anonymous says:

    Speaking of Atoms..how about a posting about their uses/merits/etc. I rarely think to use one..when should I?

    Thanks for a great blog!

  7. Anonymous says:

    You can’t explicitly free the message, it’s handled automagically when your app quits (and no you can’t even free it with GlobalDeleteAtom). And I’m sure there is some refcounting goodness in the object manager to account for multiple processes registering the message. As for what is the merits of atoms… It’s just a hash table so I’m sure you mean the global one since that is more interesting. Basically that is mostly good for keeping track of wndclasses, easy way to check if multiple processes are open, or for easy communication between processes. But there are much, much better ways for the latter two.

  8. Anonymous says:

    In my tests, registered messages don’t appear to be (completely?) freed when a process terminates. If I register two messages in application, then swap the order in which the messages are registered and run it again, each message gets the same ID as before.

  9. Anonymous says:

    Eh? That’s probably because the string gets hashed to the same numeric value again.

  10. Anonymous says:

    I don’t think that’s the case. On Windows 2000 and XP, the IDs seem to be assigned sequentially; the content of the string doesn’t matter.

  11. Anonymous says:

    Registered window messages cannot be freed; once they’ve been created they will hang around until you log off.

    In Windows 3,1/95/98/etc,, the numerical value of a registered window message was based on the address of the hash table entry for the name, so they looked pseudorandom. In Windows NT/2000/XP/etc., the numerical values are sequentially assigned in order of request.

  12. Anonymous says:

    Thanks for the clarification. :)

  13. Anonymous says:

    A predefined place to hide a pointer-sized value.

  14. Anonymous says:

    Most messages are not safe to broadcast.

  15. Anonymous says:

    Most messages are not safe to broadcast.

  16. Anonymous says:

    Answer to previous exercise.

  17. Anonymous says:

    And when something is reserved, who’s it reserved for?

Comments are closed.