如何将WndProc用作类函数
How to use WndProc as a class function
我正试图创建一个包含WndProc的类,但我遇到了一个错误:
Error 2 error C2440: '=' : cannot convert from 'LRESULT (__stdcall Client::* )(HWND,UINT,WPARAM,LPARAM)' to 'WNDPROC'
我在网上搜索了一下,发现你需要使WndProc静态,但后来,它编译了,一切都很好,尽管如果我想更改什么,它不允许我:
Error 3 error C2352: 'Client::CreateMen' : illegal call of non-static member function
(CreateMen是使用HMENU等创建菜单的类中的一个函数)。
这是我的功能标题:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
我能做什么?我真的很困惑。。。
谢谢!
非静态类方法有一个隐藏的this
参数。这就是阻止该方法用作WndProc(或任何其他API回调)的原因。必须将类方法声明为static
才能删除该this
参数。但是,正如您已经注意到的,您无法从静态方法访问非静态成员。您需要一个指向对象的指针才能访问它们。
在WndProc回调的特定情况下,您可以将对象指针存储在HWND本身中(使用SetWindowLongPtr(GWLP_USERDATA)
或SetProp()
),然后您的静态方法可以从hWnd
参数中检索该对象指针(使用GetWindowLongPtr(GWLP_USERDATA)
或GetProp()
),并根据需要使用该对象指针访问非静态成员。
例如:
private:
HWND m_Wnd;
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK Client::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
Client *pThis;
if (msg == WM_NCCREATE)
{
pThis = static_cast<Client*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
SetLastError(0);
if (!SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis)))
{
if (GetLastError() != 0)
return FALSE;
}
}
else
{
pThis = reinterpret_cast<Client*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
if (pThis)
{
// use pThis->member as needed...
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
m_Wnd = CreateWindowEx(..., this);
不幸的是,您不能将类函数用作wndproc,因为当编译器试图告诉您调用约定不同时,即使两个函数具有相同的签名,类函数也希望this指针传递给它。在64位构建中,它希望它在RCX/ECX注册表中,而在32位构建中它希望this指针是推送到堆栈上的最后一个参数。当调用WndProc时,窗口代码不会这样做——本质上将其转换为对垃圾指针的函数调用。
可以做的是创建一个静态方法,该方法可以执行以下操作:
LRESULT Client::CreateMen(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
// The OS makes sure GWLP_USERDATA is always 0 before being initialized by the application
Client* client = (Client*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(msg == WM_INIT)
{
client = new Client();
SetWindowLongPtr(hwnd, GWLP_USERDATA, client);
}
if(msg == WM_DESTROY)
{
client = (Client*)GetWindowLongPtr(hwnd, GWLP_USERDATA, client);
SetWindowLongPtr(hwnd, GWLP_USERDATA, NULL);
delete client;
client = NULL;
}
if(client)
{
// Do stuff with the client instance
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
我还没有测试过这个,所以它可能有一些错误,但如果你有任何问题,请告诉我,如果需要,我会改进它。
- 如何通过派生类函数更改基类中的向量
- 库函数需要一个 std::function<void(void)>,如何传入类函数?
- 在类函数中初始化外部作用域变量
- c++ 在非类函数中使用类变量
- SDL_PollEvent() 无法捕获类函数内部SDL_QUIT?
- 从类成员函数到类 C 函数指针的转换
- 如何在模板类函数中分配结构值?
- 有没有办法将重载的类函数绑定到函数对象?
- 启动类函数作为失去引用的线程
- C++调用使用重写函数的父类函数
- 将值传递到另一个类函数在打印时为零
- 计算对类函数的所有调用次数
- 由于签名差异,调用了错误的子类函数
- 使用宏调用类函数
- 虚拟基类函数中派生类的大小
- 模板类/函数中的交叉前向声明
- 在C++中使用非静态类函数的函数
- 无法访问基类函数 C++
- 类函数返回到另一个类函数返回打印不同的值
- 如何将WndProc用作类函数