windows proc/callback 函数可以是 class 的成员函数吗?

Can windows proc/callback function be a member function of a class?

例如,当您在 windows 的屏幕上创建一个 window 时,您创建了一个回调函数来接收来自 windows

的消息
 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)

你能把这个函数做成class的成员函数吗?如果是这样,我该怎么做?我希望回调函数成为 class 成员的原因是可以访问某些变量,同时仍然封装变量。例如,我保存了 window 的宽度和高度,因此如果它们需要更改,我可以直接在回调函数中更改它们。

如果没有,你对我如何解决这个问题有什么建议吗?让回调函数访问封装变量?

就像评论建议的 static 成员函数和 SetWindowLongPtr 的组合可以用来实现你想要做的事情。

这里是一个示例 class 声明,它将静态 WindowProc 定义为成员函数。

class MyClass
{
public:
    void MainThreadProc ();

private:
    static LRESULT CALLBACK WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    LRESULT _WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};

MainThreadProc 方法将创建 window。确保将 this 传递给 CreateWindowEx,因为这是您访问 class 成员的方式。

void MyClass::MainThreadProc()
{
    MSG msg;    
    HINSTANCE hinstance = GetModuleHandle (NULL);    
    WNDCLASSEX wcx = {0};
    HWND hwnd = NULL;

    wcx.cbSize = sizeof wcx;
    wcx.hInstance = hinstance;
    wcx.hCursor = LoadCursor (NULL, IDC_NO);
    wcx.style = CS_HREDRAW | CS_VREDRAW;
    wcx.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    wcx.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wcx.lpfnWndProc = WindowProc;
    wcx.lpszClassName = L"MyWindowClass";

    RegisterClassEx (&wcx);

    hwnd = CreateWindowEx ( WS_EX_APPWINDOW,
                            L"MyWindowClass",
                            L"MyWindow",
                            WS_OVERLAPPEDWINDOW,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            NULL,
                            NULL,
                            hinstance,
                            this);

    ShowWindow (hwnd, SW_SHOWDEFAULT);    

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

WindowProc 中,您将使用 SetWindowLongPtr 存储 this 对象以备将来使用。

LRESULT MyClass::WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (WM_NCCREATE == uMsg)
    {
        SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) ((CREATESTRUCT*) lParam)->lpCreateParams);
        return TRUE;
    }

    return ((MyClass*) GetWindowLongPtr (hwnd, GWLP_USERDATA))->_WindowProc (hwnd, uMsg, wParam, lParam);
}

为了完整起见,这是处理 window 消息的最终成员函数,此时您将可以访问所有 class 成员。

LRESULT MyClass::_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {   
    case WM_DESTROY:
        PostQuitMessage (S_OK);
        break;
    default:
        return DefWindowProc (hwnd, uMsg, wParam, lParam);
    }

    return 0;
}