0

So I've started learning Windows C++ programming from the tutorial found on MSDN and got a bit confused by application state management. I'm rather new to coding so this might be a dumb question.

The page says:

"When you receive the WM_NCCREATE and WM_CREATE messages, the lParam parameter of each message is a pointer to a CREATESTRUCT structure."

Then:

"Here is how you extract the pointer to your data structure. First, get the CREATESTRUCT structure by casting the lParam parameter."

And proceeds to

CREATESTRUCT *pCreate = reinterpret_cast<CREATESTRUCT*>(lParam);

What I don't get is if the lParam was already a pointer to a Createstruct,why do I have to cast it?

zett42
  • 25,437
  • 3
  • 35
  • 72
Phobia00
  • 19
  • 3
  • Sounds like you don't understand C++' type system. Start with [The Definitive C++ Book Guide and List](https://stackoverflow.com/q/388242/1889329). – IInspectable Jan 04 '18 at 13:50
  • Focus on how SendMessage() works. All the extra info that is sent along with the message needs to be crammed in two parameters. And has to be uncrammed in the window procedure. – Hans Passant Jan 04 '18 at 13:56

3 Answers3

1

First, have a look at how casting pointers works in C:

What are the rules for casting pointers in C?

The reason for your confusion is that while lParam is already a pointer to a CREATESTRUCT in the case of your WM_CREATE message, the value stored in it varies depends on the message. It doesn't even have to be a pointer (for example, in the case of the WM_SIZE message). It's just an integral type, and its value is determined at runtime. This is the whole point of the cast.

Nasser Al-Shawwa
  • 3,573
  • 17
  • 27
  • Thanks, that link was useful. :) I was focused on WM_CREATE and forgot that lParam can be anything,not necessarily a pointer. – Phobia00 Jan 04 '18 at 13:53
1

Keep in mind that when msdn says lParam is already a pointer to a CREATESTRUCT it means that its contents are a address to a valid CREATESTRUCT somewhere in memory. But lParam for the type system (and your compiler) is just LONG_PTR that stores the address.

So, when you cast, you are telling the compiler: "I know this guy points to a CREATESTRUCT, so let me handle it like a CREATESTRUCT pointer".

Otherwise, if you do not cast, the compiler will flag errors if you try to access any member of CREATESTRUCT, because for it, until you cast, lParam is just a void pointer.

Pointer casting, beside some special situations, is just a way to tell the compiler that "this address points to something else and I know what I am doing, so shut up".

bcsanches
  • 2,362
  • 21
  • 32
  • 2
    `LPARAM` is not a `void*`, it is an alias for `LONG_PTR`, which itself is an alias for a **pointer-sized signed integer** (`long` in 32bit and `__int64` in 64bit), not an actual pointer (like `PLONG`, aka `long*`). Refer to [Windows Data Types](https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751.aspx) on MSDN. – Remy Lebeau Jan 05 '18 at 00:11
1

LPARAM is a numeric data type (specifically, long in 32bit, and __int64 in 64bit). It is not a pointer type. However, in the case of WM_(NC)CREATE messages, the value of the LPARAM contains a memory address to a CREATESTRUCT that is located somewhere in memory. C and C++ are type-safe languages, so in order to actually access the CREATESTRUCT, you have to type-cast the value of the LPARAM to an actual CREATESTRUCT* pointer type, and then you can dereference the pointer (using the -> operator, which is just shorthand for using * and . operators) to access the CREATESTRUCT's individual fields.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770