C++ 将LPRAM作为指向类的指针发送,并在WndProc()中使用它
我有一个抽象代码: 我想在CreateWindowEx()中使用lParam(最后一个参数)保存指向main-SaveArr开头声明的类的指针。然后,我想在函数WndProc中使用它。 在开始的时候,我做了一个全局数组,然后我可以在任何地方使用它,但是它并不像C++所关心的那么“聪明”,所以我试图对它进行一点升级。p>C++ 将LPRAM作为指向类的指针发送,并在WndProc()中使用它,c++,winapi,wndproc,C++,Winapi,Wndproc,我有一个抽象代码: 我想在CreateWindowEx()中使用lParam(最后一个参数)保存指向main-SaveArr开头声明的类的指针。然后,我想在函数WndProc中使用它。 在开始的时候,我做了一个全局数组,然后我可以在任何地方使用它,但是它并不像C++所关心的那么“聪明”,所以我试图对它进行一点升级。p> class Samples { int arr[ITERATIONS+1]; int index; ... } INT WINA
class Samples
{
int arr[ITERATIONS+1];
int index;
...
}
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
Samples * SaveArr;
...
hWnd = CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
ClsName,
WindowCaption,
WS_OVERLAPPEDWINDOW,
INITIAL_WIN_LOCAT_X,
INITIAL_WIN_LOCAT_Y,
WIN_WIDTH,
WIN_HIGHT,
NULL,
NULL,
hInstance,
NULL); //here i want to pass SaveArr, so that i can use it in the WndProc(...) function
...
return 0;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
... //here i would like to use lParam as the class pointer, meaning using the
SaveArr declared in the main function.
}
}
从:
lpParam[输入,可选]
Type: LPVOID
Pointer to a value to be passed to the window through the
所指向的CREATESTRUCT结构(lpCreateParams成员)
WM_CREATE消息的lParam参数。此消息将发送到
此函数在返回前创建的窗口
If an application calls CreateWindow to create a MDI client
窗口中,lpParam应指向CLIENTCREATESTRUCT结构。如果
MDI客户端窗口调用CreateWindow来创建MDI子窗口,
lpParam应指向MDICREATESTRUCT结构。lpParam可能是
如果不需要其他数据,则为NULL
您希望lParam总是传递给WndProc,但它只通过WM_CREATE传递
请注意,即使这样,它也不会直接传递,而是通过一个结构传递,该结构是WM_CREATE的实际LPRAM。读取LPRAM的唯一机会是在WM_CREATE期间。如果以后要继续使用该值,则必须将其存储在某个位置。可能作为WndProc的静态,或者将其分配给将要确定作用域的其他对象。最好的方法是
LRESULT CALLBACK WndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
Samples *savearr = (Samples*)GetWindowLong(hWnd,GWL_USERDATA)
switch(Msg)
{
case WM_CREATE:
SetWindowLong(hWnd, GWL_USERDATA, (LONG)lParam);
break;
}
}
下次调用WndProc时,该值将在savearr中,并且可以使用。为什么要坚持使用最后一个lpParam值设置为X,然后在WM_CREATE上捕获它(通过所有间接结构的东西,不少于!),然后设置GWL_USERDATA 为什么不直截了当地这样做: HWND H=CreateWindow(…) SetWindowLong(H,GWL_用户数据,X) 换句话说,直接把X放在那里,你自己,就在windowcreation语句之后
在我的测试中,它是有效的,只要您根据一些已知句柄列表测试窗口句柄,就可以防止程序接收到一些错误消息,并防止不适当地使用其他用户数据。将调用方信息添加到窗口中:
m_window = CreateWindow(..., this);
template< typename CallerT >
[[nodiscard]] inline CallerT *GetWindowCaller(HWND window,
UINT message,
[[maybe_unused]] WPARAM wParam,
LPARAM lParam) noexcept {
if (WM_NCCREATE != message) {
// Retrieves information about the specified window.
// 1. A handle to the window and, indirectly, the class to which
// the window belongs.
// 2. Retrieves the user data associated with the window.
return reinterpret_cast< CallerT * >(GetWindowLongPtr(window, GWLP_USERDATA));
}
const auto caller = reinterpret_cast< CallerT * >(
reinterpret_cast< CREATESTRUCT * >(lParam)->lpCreateParams);
// Changes an attribute of the specified window.
// 1. A handle to the window and, indirectly, the class to which the
// window belongs.
// 2. Sets the user data associated with the window.
// 3. The replacement value.
SetWindowLongPtr(window,
GWLP_USERDATA,
reinterpret_cast< LONG_PTR >(caller));
return caller;
}
类似于扩展的CreateWindowEx
获取指向调用者的指针:
m_window = CreateWindow(..., this);
template< typename CallerT >
[[nodiscard]] inline CallerT *GetWindowCaller(HWND window,
UINT message,
[[maybe_unused]] WPARAM wParam,
LPARAM lParam) noexcept {
if (WM_NCCREATE != message) {
// Retrieves information about the specified window.
// 1. A handle to the window and, indirectly, the class to which
// the window belongs.
// 2. Retrieves the user data associated with the window.
return reinterpret_cast< CallerT * >(GetWindowLongPtr(window, GWLP_USERDATA));
}
const auto caller = reinterpret_cast< CallerT * >(
reinterpret_cast< CREATESTRUCT * >(lParam)->lpCreateParams);
// Changes an attribute of the specified window.
// 1. A handle to the window and, indirectly, the class to which the
// window belongs.
// 2. Sets the user data associated with the window.
// 3. The replacement value.
SetWindowLongPtr(window,
GWLP_USERDATA,
reinterpret_cast< LONG_PTR >(caller));
return caller;
}
模板
[[nodiscard]]内联调用程序*GetWindowCaller(HWND窗口,
UINT消息,
[可能没有用过]WPARAM WPARAM,
LPARAM(LPARAM)无例外{
if(WM_NCCREATE!=消息){
//检索有关指定窗口的信息。
//1.窗口的句柄,以及间接指向的类
//这扇窗户属于我。
//2.检索与窗口关联的用户数据。
返回reinterpret_cast(GetWindowLongPtr(window,GWLP_USERDATA));
}
const auto caller=reinterpret\u cast(
重新解释\u cast(lParam)->lpCreateParams;
//更改指定窗口的属性。
//1.窗口的句柄,以及
//窗户属于我。
//2.设置与窗口关联的用户数据。
//3.重置价值。
设置窗口长PTR(窗口,
GWLP_用户数据,
重新解释演员(调用者);
回叫;
}
此方法需要在您的消息回调中调用。
lParam
代表长参数
,如下MSVC++和Windows SDK命名。我不明白,我有lParam值,已发送到WndProc,因此有人正在发送它。是否有可能每次调用WndProc时,lparam值中都会出现一个指向我创建的类的指针?lparam是消息的参数,因此发送消息的人都会设置其值。在WM_CREATE的情况下,CreateWindow将其设置为指向包含创建窗口所需数据的特定结构。该结构的一个成员是传递给CreateWindow的LPRAM。事实上,这些变量有相同的名字意味着什么——它们不是相同的变量。啊……好吧,我明白我的错误了。那么我想我最好的选择就是把它保存为程序中的全局值,尽管它看起来不太好。不,不要使用全局值。使用SetWindowLong()将其保存在WM_CREATE消息中,并在需要检索时使用GetWindowLong()。这效率极低。考虑到消息泵被命中的频率,您不必要地重新分配了很多次。@Mike Kwan Samples savearr=(Samples)GetWindowLong(hWnd,GWL_USERDATA)可用于任何需要的消息情况。由于没有指定消息,我只是在开头添加了它。您需要从CREATESTRUCT
保存lpCreateParams
,因为CREATESTRUCT
本身仅在WM_CREATE
消息的生命周期内有效。例如,SetWindowLong(hWnd,GWL_USERDATA,(LONG)((CREATESTRUCT*)lParam)->lpCreateParams)
。(至于效率:首先分析一下你的程序。我敢打赌GetWindowLong
的成本永远不会显示为一个亮点。)