【问题标题】:Using wndproc as a member function of a class使用 wndproc 作为类的成员函数
【发布时间】:2018-12-24 01:23:16
【问题描述】:

我一直在关注this 线程,了解如何将 wndproc 函数用作成员函数,但我不断收到读取访问冲突(虽然它不会告诉我程序中的确切行,但它在第 120 行xmemory0 const uintptr_t _Ptr_container = _Ptr_user[-1]; 上面写着 Unhandled exception thrown: read access violation. _Ptr_user was 0x7. 我可能正在做一些我不应该做的时髦的事情。有没有人看到任何明显的东西?

代码:

LRESULT CALLBACK wndproc::WndProc(HWND hwnd, UINT msg,
    WPARAM wParam, LPARAM lParam) {
    wndproc* pThis; //wndproc is the class name
    bool checked = true;

    HWND text, button, selection1, selection2;
    //hwnd is parent window

    switch (msg) {

    case WM_CREATE: {
        pThis = static_cast<wndproc*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
        SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<::LONG_PTR>(pThis));
        text = CreateWindow("STATIC", "Please select options from below:", WS_VISIBLE | WS_CHILD, 20, 20, 300, 25, hwnd, NULL, NULL, NULL);
        button = CreateWindow("BUTTON", "Submit", WS_VISIBLE | WS_CHILD | WS_BORDER, 500, 500, 80, 25, hwnd, (HMENU)0, NULL, NULL);
        selection1 = CreateWindow("button", "Scan?", WS_VISIBLE | WS_CHILD | BS_CHECKBOX | WS_OVERLAPPED, 500, 460, 350, 20, hwnd, (HMENU)1001, NULL, NULL);
        CheckDlgButton(hwnd, 1001, BST_CHECKED);
        LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
        vector<string> *strings = reinterpret_cast<vector<string>*>(lpcs->lpCreateParams);
        int j = 40;

        pThis->checkVectorSize = strings->size();
        for (int i = 1; i != strings->size() + 1; i++)
        {
            CreateWindowA("button", (*strings)[i - 1].c_str(),
                WS_VISIBLE | WS_CHILD | BS_CHECKBOX | WS_OVERLAPPED,
                20, j, 185, 35, hwnd, (HMENU)i,
                NULL, NULL);
            CheckDlgButton(hwnd, 0, BST_UNCHECKED);

            j = j + 30;
        }
        //SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<::LONG_PTR>(strings));

        break;
    }
    case WM_COMMAND: {
        pThis = reinterpret_cast<wndproc*>(GetWindowLongPtrW(hwnd, GWLP_USERDATA));
        int i = wParam;
        if (i == 0) //LOWORD(wParam)
        {
            for (int j = 0; j != pThis->checkVectorSize; j++)
            {
                if (IsDlgButtonChecked(hwnd, j + 1) == true)
                {
                    pThis->check.push_back(j);
                }
            }
            if (IsDlgButtonChecked(hwnd, 1001) == true)
            {
                pThis->scan = true;
            }
            else
            {
                pThis->scan = false;
            }
            PostMessage(hwnd, WM_CLOSE, 0, 0);
            break;
        }
        checked = IsDlgButtonChecked(hwnd, i);
        if (checked) {

            CheckDlgButton(hwnd, i, BST_UNCHECKED);
        }
        else {
            CheckDlgButton(hwnd, i, BST_CHECKED);
        }
        break;
    }
    case WM_DESTROY: {

        PostQuitMessage(0);
        break;
    }
    }
    return DefWindowProcW(hwnd, msg, wParam, lParam);
}

编辑:包装函数:

void wndproc::select(vector<string>& return)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    WNDCLASSW wc = { 0 };
    MSG  msg;

    wc.lpszClassName = L"Selection1";
    wc.hInstance = hInstance;
    wc.hbrBackground = CreateSolidBrush(RGB(0, 0, 255));
    wc.lpfnWndProc = WndProc;
    wc.hCursor = LoadCursor(0, IDC_ARROW);
    wc.style = CS_DBLCLKS;

    RegisterClassW(&wc);
    CreateWindowW(wc.lpszClassName, L"Selection",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE | WS_SYSMENU,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hInstance, &return);

    while (GetMessage(&msg, NULL, 0, 0)) {

        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

【问题讨论】:

  • lpcs-&gt;lpCreateParams 指向什么?到pThis,正如您在WM_CREATE 或vector&lt;string&gt; *strings 中使用的那样?
  • 请显示 WndProc 的声明(在头文件/类声明中给出)。它是static 函数吗?请提供minimal reproducible example。
  • @WernerHenze 是一个静态函数:static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  • @RbMm 两者都有?我不太确定,我认为这可能是我使用了两次的问题
  • 请注意 raymond chen 和 i - 首先使用 lpcs-&gt;lpCreateParams 作为指向 wndproc* pThis; 的指针,然后将相同的指针解释为 vector&lt;string&gt; *strings。最少一个演员是如何错误的

标签: c++ visual-studio winapi member wndproc


【解决方案1】:

非静态成员函数不与非成员函数相同。非静态成员函数需要调用对象,非成员函数不需要。

如果您不使用任何其他(非静态)成员函数或成员变量,您可以创建函数static,它应该可以工作。


考虑到您以其他方式将“this”传递给函数,另一种可能的解决方案与上述解决方案部分相同,以及第二个非静态成员函数。

类似

class wndproc
{
    ...

    static LRESULT WndProcWrapper(...)
    {
        wndproc *pThis;

        // Set pThis...

        // Call *real* window procedure
        return pThis->WndProc(...);
    }

private:
    LRESULT WndProc(...)
    {
        ...
    }
};

然后将wndproc::WndProcWrapper设为窗口过程。

【讨论】:

  • 那么解决方案是什么?摆脱 pThis?但是,WndProc 被声明为静态:static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  • 当我将我的其他函数设置为静态(不是 WndProc 函数)时,这里出现编译器错误wc.lpfnWndProc = WndProc;,说 LRESULT 类型不能分配给 WNDPROC。
  • 检查我的编辑顶部,它显示了我正在使用的包装函数。我不确定如何使 WndProcWrapper 成为“窗口过程”。如果我不应该将上述函数用作包装器,请告诉我
  • @Colebacha2 首先,您添加的函数是您的创建和消息循环,而不是包装函数。至于你的问题,你把wndproc::WndProc变成了static成员函数了吗?
  • @Colebacha2 请尝试创建一个Minimal, Complete, and Verifiable Example 向我们展示(但不要只是复制粘贴整个代码,确保不要忘记Minimal 部分以及)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-16
  • 2015-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
相关资源
最近更新 更多