Window message parameters do not come with metaphysical certitude


The MSDN documentation for window messages describes what each of the parameters means, but just because it means something doesn't mean that it is that something; it merely means it.

But you knew this already. If you have a window handle, you can send it whatever message you like, with whatever parameters you like, even if those parameters contradict reality. For example, you could write some code that seeks out a target window and sends it a WM_COMMAND with parameters that claim that the message was generated from a keyboard accelerator, when in fact it was generated by code contained within your custom control. But you send the message with the accelerator parameters because your goal is to fool the target program into thinking that it came from a keyboard accelerator. Similarly, if your control wants to simulate a menu click, you should package the parameters in the same way a menu delivers them.

There are some people, however, who have difficulty wrapping their brains around this concept, that if you are trying to simulate something, then you have to behave as the thing you are trying to simulate and not as your actual self. If the documentation says that "A control sends the message with these parameters" and you're a control but you want to pretend that you're a menu, then you need to send the message the way a menu would. That's why it's called pretending.

Message parameter documentation is written on the assumption that nobody is pretending anything. What other choice is there? There's no point discussing the possibility that the sender of the message is playing tricks and lying to you because (1) your program should just go along with the ruse and respond to fake menu messages as if they were real menu messages, because (2) there's no way to tell that you're being lied to anyway. To detect lying, you'd have to be able to read into the mindset of the programmer who sent you the message. "Gosh, this code is generating a message and claiming that it was triggered by a menu selection. Is the code is implementing a menu-like window, or is it just trying to trick me?"

Comments (12)
  1. Adam Rosenfield says:

    Clearly a program should look into its stack to see who's calling SendMessage to see if it's being lied to.</sarcasm> (blogs.msdn.com/…/704232.aspx)

  2. I was shocked to see how LPARAM's are blindly casted when I was first learning win32.  I could also see an expectation that the compiler would somehow enforce some type-contract or use reflection to detect behavior from people learning .net and java before they learn C.

  3. H. Dumpty says:

    When I use a WM_COMMAND with parameters it means just what I choose it to mean — neither more nor less.

  4. int says:

    Along those same lines, is there a way to determine if a string is actually a sequence of binary integers? The documentation doesn't say.

  5. Pierre B. says:

    To paraphrase you: When pretending to interpret documentation like a normal user / programmer, you need to pretend you are a normal user / programmer and have no internal knowledge of how Win32 works internally. :)

    The general source of confusion for such question stems from not knowing /why/ the documentation says what it says. For someone intimate with the actual implementation, it may be obvious that when the documentation says that WM_COMMAND requires a certain value for parameters when coming from a certain type of control, that it is merely stating the convention of the API. For an ordinary user though, it may implies that the requirements is absolute. For example, maybe Win32 keeps internal state that are specific to each control type, so lying or pretending is not even an option.

    For example, no matter how much a normal program would wish to, it cannot pretend to be a driver and call driver-level API. For someone knowledgeable in the differences between an ordinary application and a driver, the reason is obvious. Some programmer may think that there is such a "magic" barrier between application and win32 messaging.

    (There may be line of reasoning that would invalidate such a supposition, but it probably requires knowledge of the real Win32 API. Most programmer, at least for the UI-related stuff, are usually programming at a higher level of abstraction though some kind of framework (MFC, ATL, .NET…) which hides detail and introduce its own kind of magic. (Think: magic message dispatching in MFC.) As is often the case, the problem often lies in knowing that you don't know.)

    [I would hope that people familiar with Win32 UI programming know that you can send any message to anybody (usual disclaimers apply). (Though doing so might not be a good idea.) It's not like SendMessage is a driver-only API. -Raymond]
  6. Joshua says:

    Since nobody else mentioned this:

    This is also the basis of the infamous shatter attack. I think this was finally fixed in Vista by preventing processes from sending messages to processes with higher privileges.

  7. AsmGuru62 says:

    My favourite WM_CREATE cast:

    TWindow* pWnd = ((TWindow**) lParam) [0];

    Sweet!

    Just one cast instead of two!

  8. Miral says:

    "[I would hope that people familiar with Win32 UI programming know that you can send any message to anybody (usual disclaimers apply). (Though doing so might not be a good idea.) It's not like SendMessage is a driver-only API. -Raymond]"

    I think the fear that Pierre was trying to hint at is that while the MSDN docs might say "and this bit is set to 1 if it comes from a menu", there might be an undocumented extra clause that goes something like "and when this is set the window manager will look up something in an internal table it populated with other data before sending the message, and will either behave incorrectly or crash if it wasn't the source of the message and didn't get to populate the table beforehand".

    I'm not aware of any such condition in this case, of course, but that doesn't dismiss some people's fears that it might happen somewhere in the API.  (Whether there's any real examples of that, I don't know.  But it wouldn't surprise me if this sort of thing happened when superclassing certain controls, for example.)

  9. Alex Grigoriev says:

    @AsmGuru:

    That's simple. You can't pass to lParam what haven't been initialized yet. TWindow may not be allocated yet when CreateWindow is called (it will only be allocated in WM_NCCREATE). WM_NCCREATE handler puts TWindow* to *lParam.

  10. Pierre B. says:

    " [UI programmers should]… know that you can send any message to anybody (usual disclaimers apply). (Though doing so might not be a good idea.)"

    I like the progression, or rather regression, from enthusiastic "you can do anything" down to "that wouldn't be a good idea". :)

    Still, knowing the underpinning of why people ask certain type of questions can be interesting in itself, and help improve how to best answer them and how to write effective documentation.

  11. Paul M. Parks says:

    @Pierre B.: It's the difference between descriptive and prescriptive. You're allowed to do anything (descriptive), but it's not in your best interest to do everything you are allowed to do (prescriptive). Raymond has pointed out in the past that MSDN docs are generally descriptive.

  12. Pierre B. says:

    Paul: that's a nice a concise vocabulary.

    I don't think it's due to any choice on the part of MSDN authors, though. By definition, description is easy and prescription is hard; listing what you can do is easy, while the list of things that you can't or shouldn't do is infinite.

    "While Calling SendMessage(), one should avoid driving a heavy hatchet through the motherboard, …" :)

Comments are closed.

Skip to main content