2

I'm looking for confirmation on this windows programming idiom, am I correct in thinking that many different types of "handles" are passed around as not only LRESULT objects but also lParam and wParam objects?

I'm guessing that as long as we know "what" type of handle is in LRESULT or lParam/wParam we can cast back into it.

For example

case WM_CREATE:
   ...
   //create a window
   //lParam is the CREATESTRUCT for new window created here
   ....
   return lParam;
...
...
CREATESTRUCT cStruct = (CREATESTRUCT)SendMessage(hwnd, msg /*WM_CREATE*/);
cStrcut.cx;//this is the width of the new window?

correct?

Is this is "correct"? Can anyone provide me and the StaticOverflow community a short thesis on this technique/idiom?

Questions: Should we only return lParam (or only wParam) values? Are there any pitfalls one should know about? Both LRESULT and LPARAM are LONG_PTR types, which are 32 or 64 bit integers. I'm not a seasoned C programmer, but it appears these integers are just being used as "buffers" which the programmer later casts into their "real" type before using... sound accurate?

  • 1
    For starters, the going-in assumption is wrong. WM_CREATE *receives* an **LPCREATESTRUCT** cast as the LPARAM parameter to the WndProc; it does not *return* a CREATESTRUCT form SendMessage, which brings us to the second invalid assumption: You never *send* a WM_CREATE, the window manager does. You *process* it. The style of programming is essentially abstraction with refinement via documentation. Things like LPARAM takes on *many* roles in various different window messages, including custom ones that you can define, but you can't "know" them by reading code. You need the docs. – WhozCraig Apr 21 '13 at 07:59
  • I give up. I can't reply without a code block and nothing works. [code][/code] nor nor 'code' '/code' so I can't be precise. But SendMessage places the WindowProcedure on the stack and returns w/e the WindowProc does as an LRESULT. – Trae Barlow Apr 21 '13 at 08:37
  • Also, you very well can use SendMessage to fire off a WM_CREATE message, or any other message. You probably "shouldn't" but you can. Also, WM_CREATE very well can return a CREATESRUCT to SendMessage (which will return it to you), you're correct that you do have to catch messages and process them, but you can make them return w/e you want as long as the compiler can cast to LRESULT. Nobody would probably ever use WM_CREATE in this manner, which is probably why you're doubting it's correctness. I only chose it for this example because it was a message every windows programmer is familiar with. – Trae Barlow Apr 21 '13 at 08:58
  • Of course you're also bound by documentation. Parts of the API "expect" certain return values from certain messages. Returning the LPARAM of a WM_CREATE message very well might break parts of the API that could expect WM_CREATE to return something else, which would cause a segfault. I don't know, but in the future I'll refrain from using bad code in communicating valid ideas. – Trae Barlow Apr 21 '13 at 09:03
  • The [edit] link works, though. And you get code blocks there the same way you did when you originally posted the question. Comments are not designed for posting extended code. They're designed for clarification questions. – Cody Gray - on strike Apr 21 '13 at 12:06
  • And just because you *can* do something in Windows does not mean that you *should*. You'll end up with undefined behavior and a program that is subtly or massively broken. You should *never* send the `WM_CREATE` message yourself. It is reserved exclusively for the window manager. And you should only return values the documentation tells you make sense. Returning a `CREATESTRUCT` makes no sense. Nor does it make sense to invent your own usage—the value gets returned to the window manager for processing, not your own code. – Cody Gray - on strike Apr 21 '13 at 12:13
  • The problem here is precisely the fact that you *did* pick something all Windows programmers are familiar with as an example, but your example was wildly incorrect. That sets all kinds of warning bells off in our heads. – Cody Gray - on strike Apr 21 '13 at 12:14
  • @TraeBarlow Look at that comment again You can't return a **[`CREATESTRUCT`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms632603(v=vs.85).aspx)** from a valid WndProc which, by the definition of valid, must return an `LRESULT`, a type considerably smaller than the minimum Win32 `CREATESTRUCT` size of 48 bytes. A **`LPCREATESTRUCT`** , however, fits. Of course, if you step into the *invalid* world, like the rest of the sample, you're certainly capable of returning anything you want (including nothing). Once you enter undefined behavior, the world is (or is not) your oyster. – WhozCraig Apr 21 '13 at 14:00
  • 1
    @TraeBarlow: [read the documentation](http://stackoverflow.com/editing-help#comment-formatting), it explains how to format code in comments. – Remy Lebeau Apr 21 '13 at 16:34

1 Answers1

2

This style of programming is "bad" as there is no way to know what something really is at compile-time. That said, as the WIN32 API is a C API (instead of say, C++), there's not much else that can be done when one wants to pass around any type of struct using the same method signature.

So, the API design team decided to have two parameters to handle this. A 32-bit LPARAM and a 16-bit WPARAM.

When working with the Win32 C API, you're just going to have to make sure you read the documentation correctly and ensure you're casting to the right thing that the documentation says it is.

So to answer your question, you are correct - but only because you have no other choice. In an attempt to be complete here, MFC came along (for C++ programmers), but that isn't considered a good object-orientated library - it's more of a wrapper. There are others out there that do a much better job (e.g. wxWidgets).

Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
  • I wonder why thy just didn't make LRESULT and LPARAM void pointers? It's exactly what I've used them for in the past. I'm guessing they wanted a larger "buffer" than w/e a void pointer allocates. I'm also guessing int32/64 is a bit more standardized. – Trae Barlow Apr 21 '13 at 08:10
  • Oh btw. These days both LPARAM and WPARAM are both typedefs of 32 or 64 bit integers, however WPARAMs are unsigned. – Trae Barlow Apr 21 '13 at 08:40
  • 1
    @Trae Because of the difference between far pointers and near pointers, which had to be distinguished between when 16-bit Windows was being written. Yes, LPARAM, WPARAM, LRESULT, and other data types have changed over time. That's the reason you use the #defines. Like Moo says, it's not considered good style anymore, but it was pretty damn spry in the early 1980s and still works pretty well. Only disadvantage is that you absolutely must read the documentation. But back in the 1980s, you could also expect programmers to read docs. They didn't have Stack Overflow back then, so it was hard work. – Cody Gray - on strike Apr 21 '13 at 12:11
  • @CodyGray, +1 for "didn't have Stack Overflow back then" ;) – Moo-Juice Apr 21 '13 at 12:16