CustomDialogProc 必须是静态的吗? WinAPI

Do CustomDialogProc have to be static. WinAPI

我一直在考虑使用 WinApi 为我的应用程序创建自定义控件,并且我制作了一个 class,其中包含 CustomDialogProcCreateWindowEx 以及 RegisterClass() 职能。

我可以在 CustomDialogProc 中设置一个断点并且它命中,因此 class 被正确注册。

但是,我必须将 class

的 CustomDialogProc 函数声明为 static int header
static LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam);

如果我不将其设置为静态,则会出现错误

Error   C3867   'CustomControl::CustomDialogProc': non-standard syntax; use '&' to create a pointer to member   

这是必要的吗,这要求我在此控件中创建的所有控件也都是静态的。如果我想要此控件的多个实例怎么办? 我该如何解决这个问题?主要的 MsgProc 似乎不是静态函数。下面显示的第一个 link 中的 UpDownDialogProc 也不是

下面是我的 CustomControl.h 代码,以备不时之需。 从以下位置找到的代码放在一起: https://msdn.microsoft.com/en-us/library/windows/desktop/hh298353(v=vs.85).aspx https://www.codeproject.com/Articles/485767/True-Windows-control-subclassing

谢谢,

#pragma once
#include <windows.h>

#include <commctrl.h>

#pragma comment(lib, "comctl32.lib")

class CustomControl
{
public:
    CustomControl();
    ~CustomControl();

    LRESULT CALLBACK CustomDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
    {
        switch (message)
        {
            case WM_CREATE:
            //DO STUFF HERE
            break;
        }
    }

    bool CreateControl(HWND hwnd, HINSTANCE* m_hApp_instance)
    {
        g_hInst = m_hApp_instance;

        RegisterSubClass(*g_hInst, WC_LISTBOX, TEXT("CustomControl"), CustomDialogProc);

        HWND hwndCustom = CreateWindow(TEXT("CustomControl"), NULL, WS_CHILD | WS_VISIBLE,
        0, 0, 0, 0, hwnd, (HMENU)100, *g_hInst, NULL);

        return true;
    }

private:

    HINSTANCE* g_hInst;

    WNDPROC RegisterSubClass(HINSTANCE hInstance, LPCTSTR ParentClass, LPCTSTR ChildClassName, WNDPROC ChildProc) {
        WNDCLASSEX  twoWayStruct;
        WNDPROC     parentWndProc;

        if (GetClassInfoEx(NULL, ParentClass, &twoWayStruct)) {
            parentWndProc = twoWayStruct.lpfnWndProc; // save the original message handler 

            twoWayStruct.cbSize = sizeof(WNDCLASSEX); // does not always get filled properly
            twoWayStruct.hInstance = hInstance;
            twoWayStruct.lpszClassName = ChildClassName;
            twoWayStruct.lpfnWndProc = ChildProc;

            /* Register the window class, and if it fails return 0 */
            if (RegisterClassEx(&twoWayStruct))
                return parentWndProc; // returns the parent class WndProc pointer;
                                      // subclass MUST call it instead of DefWindowProc();
                                      // if you do not save it, this function is wasted
        }
        return 0;
    }
};

最常见的方法是使用 SetWindowLongPtr 存储指向与 window 句柄关联的对象的指针。

HWND hWnd = CreateWindow(...);
SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) this);

然后在您的对话过程中,获取该指针并调用您的 class:

// this static method is registered with your window class
static LRESULT CALLBACK CustomDialogProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam,LPARAM lParam)
{
    auto pThis = (CustomControl*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
    if (pThis != NULL)
        return pThis->CustomDialogProcInstance(hWnd, uMsg, wParam, lParam);
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

// this instance method is called by the static method
LRESULT CustomDialogProcInstance(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    ...
}

确保适当地管理 window 和 class 生命周期,以防止 window 过程调用已删除的对象实例。在许多情况下,这就像确保在 class 被破坏时调用 DestroyWindow 一样简单。

Windows API 基于 C 语言。它对 C++、non-static 成员函数、对象等一无所知

所以是的,所有将与 Windows API 直接 通信的功能必须 static class 成员函数,或 non-class / global / "free" 函数。

这并不妨碍您为 C API 编写 C++ 包装器。这就是 Microsoft 的 MFC 或旧的 Borland OWL 库完成的任务。其他独立小组也为 Windows API 编写了包装器。

请注意,这些不同的库以不同的方式实现了将基于 C 的 API 挂接到 C++ 的目标。一种是使用@MichaelGunter给出的答案中提到的SetWindowLongPtr方法。另一种方法是使用映射来关联 window 句柄和静态 Window 过程。

我建议您在自己尝试此操作(创建包装器)之前,调查一下其他人是如何完成此操作的,然后选择最适合的方法。另一个建议是,在创建包装器之前,您应该了解基于 C 的 API,而不仅仅是粗略的了解。如果您希望包装器在不同场景下相对完美地工作,您需要对任何 C API 计划创建一个包装器的 C++ 包装器有高级到专业的知识。