【问题标题】:C++ Winapi - wrapping up a callback of subclass in a classC ++ Winapi - 在类中包装子类的回调
【发布时间】:2021-03-24 15:13:42
【问题描述】:

我想创建一个用于创建静态控件的类。问题是当子类化控件时,回调应该是静态的,这意味着我将无法访问回调中的非静态变量和函数。

我一直在努力使我的代码正常工作,但仍然没有成功。

MyClass.cpp

#include "MyClass.h"

MyClass::MyClass(){
    non_static_variable = 0; //default is zero.
}

LRESULT CALLBACK MyClass::SubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {

    MyClass* pThis = reinterpret_cast<MyClass*>(dwRefData);
    
    char buffer[5];
    sprintf_s(buffer, "The value of non_static_variable is: %d \n", pThis->non_static_variable);
    OutputDebugStringA(buffer);    
        
    switch (uMsg) {
        case WM_PAINT: {
            // do nothing for now
            return 0;
        }

        case WM_NCDESTROY: {
            RemoveWindowSubclass(hwnd, SubClassProc, uIdSubclass);
            break;
        }
    }        
    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}

void MyClass::CreateStaticControl(HWND WindowHandle) {
    
    StaticControl = CreateWindowEx(0, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, x, y, width, height, WindowHandle, NULL, NULL, this); 
    SetWindowSubclass(StaticControl, &SubClassProc, ID, reinterpret_cast<DWORD_PTR>(this));
}

void MyClass::SetValue(int value){
    non_static_variable = value; //test if I can access this in callback
}

MyClass.h

#include "header.h"

public:
    MyClass();

    void CreateStaticControl(HWND window);
    void SetValue(int value);
    static LRESULT CALLBACK SubClassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

private:
    int non_static_variable;
    HWND StaticControl;

};

然后从我的主窗口过程中调用我的WM_CREATE 中的类,我是这样使用它的。

...
case WM_CREATE:{
   MyClass myClass;
   myClass.CreateStaticControl(hwnd);
   myClass.SetValue(888);
   break;
}

您可能认为这是其他人的重复,我发现了很多,但由于这是关于子类化的,我无权访问 WM_NCCREATE 我无法正确设置我的类的指针。谁能帮帮我?

编辑:我输入了我拥有的确切代码。

【问题讨论】:

  • @RemyLebeau -我试过MyClass* pThis = reinterpret_cast&lt;MyClass*&gt;(dwRefData);,它给了我read access violation, pThis was nullptr的错误。
  • 那是因为你在调用SetWindowSubclass 时传递了0 作为dwRefData。你可能打算通过(DWORD_PTR)this。
  • @RaymondChen - 我尝试SetWindowSubclass(StaticControl, &amp;SubClassProc, ID, (DWORD_PTR)this); 然后转换MyClass* pThis = reinterpret_cast&lt;MyClass*&gt;(dwRefData);,代码运行,但是,我无法获得非静态变量的值。
  • 将MyClass myClass; 的声明移到WM_CREATE 之外将解决问题。尝试使其成为全球性的。 MyClass myClass; CALLBACK YouMainWndProc(...){...case WM_CREATE:{...myClass.SetValue(888);}}

标签: c++ winapi visual-studio-2019 subclassing


【解决方案1】:

您可以使用SetWindowSubclass() 的dwRefData 参数将this 指针传递给回调的dwRefData 参数。然后,您可以对该参数进行类型转换以访问非静态成员。根本不需要使用GWLP_USERDATA(尤其是在设置GWLP_USERDATA 时没有正确使用回调的lParam)。

试试这个:

MyClass.h

class MyClass {

public:
    MyClass();

    void CreateStaticControl(HWND window);
    static LRESULT CALLBACK SubClassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);

private:
    int non_static_variable;
    HWND StaticControl;

};

MyClass.cpp:

void MyClass::CreateStaticControl(HWND WindowHandle) {
    StaticControl = CreateWindowEx(0, L"STATIC", NULL, WS_CHILD | WS_VISIBLE | SS_OWNERDRAW, x, y, width, height, WindowHandle, NULL, NULL, this); 
    SetWindowSubclass(StaticControl, &SubClassProc, ID, reinterpret_cast<DWORD_PTR>(this));
}

LRESULT CALLBACK MyClass::SubClassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {

    MyClass* pThis = reinterpret_cast<MyClass*>(dwRefData);
        
    switch (uMsg) {
        case WM_PAINT: {
                
            // use pThis->non_static_variable as needed...
                
            return 0;
        }

        case WM_NCDESTROY: {
            RemoveWindowSubclass(hwnd, SubClassProc, uIdSubclass);
            break;
        }
    }        

    return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}

【讨论】:

  • 这使得代码运行,但是int non_static_variable;的值不正确。我尝试在void MyClass::CreateStaticControl(HWND WindowHandle) { non_static_variable = 888;} 中初始化它,并在我的子类回调中得到0。
  • @Bolomeo 然后你做错了其他事情,比如可能在无效的MyClass 对象上调用CreateStaticControl()。我们看不到你所做的一切。请使用minimal reproducible example 更新您的问题,显示您如何创建MyClass 对象并在其上调用CreateStaticControl(),以及如何访问non_static_variable。
  • 我把我的确切代码和你的建议,包括我如何使用这个类,请看一下。
  • @Bolomeo 你的MyClass 对象是WM_CREATE 处理程序中的一个局部变量。当处理程序退出时,它将被销毁。但是MyClass 没有破坏 STATIC 控件并移除子类的析构函数。因此 STATIC 控件继续存在,子类回调将访问无效的 MyClass 对象。 MyClass 对象需要比子类寿命更长,而不是相反。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-08
  • 1970-01-01
相关资源
最近更新 更多