Though it worked for me without problems, but I am afraid that it will explode in my face some day in the future,
LPRECT pRect = reinterpret_cast<LPRECT>(lParam);
I need to know if it is safe to reinterpret_cast LPNCCALCSIZE_PARAMS
to LPRECT
when intercepting WM_NCCALCSIZE
, if I need to deal with only (LPNCCALCSIZE_PARAMS)lParam->rgrc[0]
or (LPARAM)lParam
no matter of the rest of NCCALCSIZE_PARAMS
will be!
Refs:
https://docs.microsoft.com/en-us/windows/win32/winmsg/wm-nccalcsize https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-nccalcsize_params
CodePudding user response:
The memory address of an object is the same as the memory address of its 1st data member. And the memory address of an array is the same as the memory address of its 1st element.
Per the WM_NCCALCSIZE
documentation:
lParam
If wParam is TRUE, lParam points to an NCCALCSIZE_PARAMS structure that contains information an application can use to calculate the new size and position of the client rectangle.
If wParam is FALSE, lParam points to a RECT structure. On entry, the structure contains the proposed window rectangle for the window. On exit, the structure should contain the screen coordinates of the corresponding window client area.
Since the 1st data member of NCCALCSIZE_PARAMS
is a RECT[3]
array:
typedef struct tagNCCALCSIZE_PARAMS {
RECT rgrc[3];
PWINDOWPOS lppos;
} NCCALCSIZE_PARAMS, *LPNCCALCSIZE_PARAMS;
Then logically, there will always be a RECT
located at the memory address pointed at by the lParam
, yes.
But technically, under C , what you are proposing is a Strict Alias Violation when wParam
is TRUE
, since the lParam
will be pointing at a NCCALCSIZE_PARAMS
, not a RECT
. Per cppreference.com:
Strict aliasing
Given an object with effective type T1, using an lvalue expression (typically, dereferencing a pointer) of a different type T2 is undefined behavior, unless:
- T2 and T1 are compatible types.
- T2 is cvr-qualified version of a type that is compatible with T1.
- T2 is a signed or unsigned version of a type that is compatible with T1.
- T2 is an aggregate type or union type type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union).
- T2 is a character type (char, signed char, or unsigned char).
Your proposal to access a NCCALCSIZE_PARAMS
as if it were a RECT
does not satisfy those requirements.
But, since the Win32 API is primarily designed for C not C , your proposal will likely "work" in most C compilers.
But, to be on the safe side, you really should cast lParam
to the correct type based on the value of wParam
, eg:
LPRECT pRect;
if (wParam) {
pRect = &(reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam)->rgrc[0]);
// or:
// pRect = reinterpret_cast<NCCALCSIZE_PARAMS*>(lParam)->rgrc;
}
else {
pRect = reinterpret_cast<LPRECT>(lParam);
}