C++ 将LPRAM作为指向类的指针发送,并在WndProc()中使用它

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

我有一个抽象代码: 我想在CreateWindowEx()中使用lParam(最后一个参数)保存指向main-SaveArr开头声明的类的指针。然后,我想在函数WndProc中使用它。 在开始的时候,我做了一个全局数组,然后我可以在任何地方使用它,但是它并不像C++所关心的那么“聪明”,所以我试图对它进行一点升级。p>
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
的成本永远不会显示为一个亮点。)