拦截WM_NCCALCSIZE时reinterpret_castLPNCCALCSIZE_PARAMS转LPRECT安全吗?
Is it safe to reinterpret_cast LPNCCALCSIZE_PARAMS to LPRECT when intercepting WM_NCCALCSIZE?
虽然对我有用,但我担心将来有一天它会在我脸上爆炸,
LPRECT pRect = reinterpret_cast<LPRECT>(lParam);
我需要知道拦截WM_NCCALCSIZE
时reinterpret_castLPNCCALCSIZE_PARAMS
到LPRECT
是否安全,如果只需要处理(LPNCCALCSIZE_PARAMS)lParam->rgrc[0]
or (LPARAM)lParam
不管剩下的 NCCALCSIZE_PARAMS
都会!
参考文献:
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
对象的内存地址与其第一个数据成员的内存地址相同。并且数组的内存地址与其第一个元素的内存地址相同。
根据 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.
由于 NCCALCSIZE_PARAMS
的第一个数据成员是一个 RECT[3]
数组:
typedef struct tagNCCALCSIZE_PARAMS {
RECT rgrc[3];
PWINDOWPOS lppos;
} NCCALCSIZE_PARAMS, *LPNCCALCSIZE_PARAMS;
那么逻辑上,总会有一个RECT
位于lParam
指向的内存地址,是的。
但是 技术上,在 C++ 下,当 wParam
是 TRUE
时,您提出的是严格别名冲突,因为 lParam
将指向 NCCALCSIZE_PARAMS
,而不是 RECT
。每 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).
您提出的将 NCCALCSIZE_PARAMS
当作 RECT
访问的提议不满足这些要求。
但是,由于 Win32 API 主要是为 C 而不是 C++ 设计的,您的提议 可能 在大多数 C++ 编译器中“有效”。
但是,为了安全起见,您确实应该根据 wParam
的值将 lParam
转换为正确的类型,例如:
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);
}
虽然对我有用,但我担心将来有一天它会在我脸上爆炸,
LPRECT pRect = reinterpret_cast<LPRECT>(lParam);
我需要知道拦截WM_NCCALCSIZE
时reinterpret_castLPNCCALCSIZE_PARAMS
到LPRECT
是否安全,如果只需要处理(LPNCCALCSIZE_PARAMS)lParam->rgrc[0]
or (LPARAM)lParam
不管剩下的 NCCALCSIZE_PARAMS
都会!
参考文献:
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
对象的内存地址与其第一个数据成员的内存地址相同。并且数组的内存地址与其第一个元素的内存地址相同。
根据 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.
由于 NCCALCSIZE_PARAMS
的第一个数据成员是一个 RECT[3]
数组:
typedef struct tagNCCALCSIZE_PARAMS {
RECT rgrc[3];
PWINDOWPOS lppos;
} NCCALCSIZE_PARAMS, *LPNCCALCSIZE_PARAMS;
那么逻辑上,总会有一个RECT
位于lParam
指向的内存地址,是的。
但是 技术上,在 C++ 下,当 wParam
是 TRUE
时,您提出的是严格别名冲突,因为 lParam
将指向 NCCALCSIZE_PARAMS
,而不是 RECT
。每 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).
您提出的将 NCCALCSIZE_PARAMS
当作 RECT
访问的提议不满足这些要求。
但是,由于 Win32 API 主要是为 C 而不是 C++ 设计的,您的提议 可能 在大多数 C++ 编译器中“有效”。
但是,为了安全起见,您确实应该根据 wParam
的值将 lParam
转换为正确的类型,例如:
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);
}