gpt4 book ai didi

winapi - 为什么我不能绑定(bind)到 winproc?

转载 作者:行者123 更新时间:2023-12-04 00:42:31 27 4
gpt4 key购买 nike

我正在尝试使用 C++11 来解决我最喜欢的指针问题

LRESULT CALLBACK renderMan::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
//some code
WNDPROC crazy = bind(&renderMan::WindowProc,this,std::placeholders::_1,std::placeholders::_2,std::placeholders::_3,std::placeholders::_4);

错误

1>renderman.cpp(50): error C2440: 'initializing' : cannot convert from 'std::_Bind<_Forced,_Ret,_Fun,_V0_t,_V1_t,_V2_t,_V3_t,_V4_t,_V5_t,<unnamed-symbol>>' to 'WNDPROC'
1> with
1> [
1> _Forced=true,
1> _Ret=LRESULT,
1> _Fun=std::_Pmf_wrap<LRESULT (__cdecl glSurface::* )(HWND,UINT,WPARAM,LPARAM),LRESULT,glSurface,HWND,UINT,WPARAM,LPARAM,std::_Nil,std::_Nil,std::_Nil>,
1> _V0_t=glSurface *const ,
1> _V1_t=std::_Ph<1> &,
1> _V2_t=std::_Ph<2> &,
1> _V3_t=std::_Ph<3> &,
1> _V4_t=std::_Ph<4> &,
1> _V5_t=std::_Nil,
1> <unnamed-symbol>=std::_Nil
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called

最佳答案

问题

WNDPROC 是使用 __stdcall 调用约定指向具有特定签名的函数的指针。

std::bind 返回函数对象 而不是函数指针。尽管在源代码级别,函数对象的使用几乎与函数指针相同,但事实是它是完全不同的类型。再多的类型转换也无法解决这个问题。

由于您将 this 指针与 renderMan::WindowProc 方法绑定(bind),很明显 renderMan::WindowProc 不是静态成员函数,因此它使用 thiscall 调用约定。因此,即使您可以获得指向它的指针并将其交给 Windows,Windows 也不会使用正确的调用约定来调用它。

解决方案

处理此问题的最常见方法是将非成员函数(或静态成员函数)注册为 WNDPROC。该函数查找与窗口关联的 this 指针,并将其转发给您的成员函数。

LRESULT CALLBACK WndProcHelper(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
renderMan *that = LookUpPointer(hwnd);
assert(that != nullptr);
return that->WndProc(hwnd, msg, wp, lp);
}

LookUpPointer 的详细信息会因您的方法而异。听起来你只是通过一个全局变量解决了这个问题,因此只有一个窗口实例。

如果您需要从此窗口类实例化多个窗口,您可以维护一个全局(或类静态)表,将 HWND 映射到 renderMan 指针。当你创建一个新的实例时,你将它添加到表中,然后你有一个 LookUpPointer 的简单实现:

std::map<HWND, renderMan*> g_windows;

renderMan *LookUpPointer(HWND hwnd) {
// If there isn't an entry for hwnd in the map, then this will
// will create one, associating it with nullptr.
return g_windows[hwnd];
}

不过,这可能会出现先有鸡还是先有蛋的问题,因为在您取回 HWND 并有机会添加它和指向 map 的指针之前,您会在 CreateWindow 调用期间收到一些消息。例如:

// ... inside a renderMan constructor ...
m_hwnd = CreateWindow(L"renderMan", /* ... */);
g_windows[m_hwnd] = this; // already too late for some messages

解决先有鸡还是先有蛋问题的另一种常见方法是将 renderMan 指针存储在创建参数中,并在 WndProcHelper 中有特殊逻辑以在创建期间将其添加到 map 。

// ... inside the renderMan constructor ...
m_hwnd = CreateWindow(L"renderMan", /* ... */, reinterpret_cast<LPVOID>(this));

// ... and then ...
LRESULT CALLBACK WndProcHelper(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
static std::map<HWND, renderMan*> windows; // still static, but not global :-)
LRESULT result = 0;
renderMan *that = nullptr;
if (msg == WM_NCCREATE) {
auto pCreateStruct = reinterpret_cast<const CREATESTRUCT*>(lp);
that = reinterpret_cast<renderMan*>(pCreateStruct->lpCreateParams);
windows[hwnd] = that;
} else {
that = windows[hwnd];
}
if (that != nullptr) {
result = that->WndProc(hwnd, msg, wp, lp);
}
if (msg == WM_NCCDESTROY) {
windows.erase(hwnd);
}
return result;
}

注意:这是简单的代码,没有足够的错误检查来说明这个想法。一个干净和完整的实现会更优雅地处理错误,记录意外的事情(比如丢失的条目)等。

关于winapi - 为什么我不能绑定(bind)到 winproc?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17382174/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com