首先,让我说我是 WinAPI 的新手,我正在尝试学习基础知识。也就是说,我正在尝试创建一些对象,以使我以后使用 WinAPI 的工作变得更加容易。其中之一是窗口类……类。另一个当然是 Window 类。
我正在尝试使消息处理变得简单,例如 myClassInst.addHandler(WM_PAINT, PaintFunction)。为此,我想我会使用一个将 uint 映射到函数指针的映射。看起来不错。
但是现在,消息没有被处理。经过一些调试后,我发现每当我尝试在类的 WndProc 处理程序中以任何方式使用 map 时,它都会默默地失败。我没有编译错误,没有运行时错误,没有崩溃;该功能立即在那里结束,直到下一条消息进来。我无法为我的生活弄清楚为什么。也许有人可以帮助我?
下面是我的代码片段,全部在我的 WinClass 类的私有(private)部分中。静态 dummyProc 消息传递器是我发现允许特定类 WndProc 的唯一方法,所以它就在那里。这是有效的,因为我的 WndProc myHandler 的第一部分确实有效,调试消息的输出证明了这一点。它只是在我尝试使用 map 的那一刻停止,即使只是为了获取它的大小。
*注意:WindowFunction 是一个指向带有 HWND 参数的函数的指针的类型定义。
std::map<unsigned int, WindowFunction> messageMap;
static LRESULT CALLBACK dummyProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
WinClass* context=(WinClass*)GetWindowLong(hwnd, GWL_USERDATA);
return context->myHandler(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK myHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
std::cout<<"Message: "<<msg<<std::endl; // This gets output
std::cout<<" Contains "<<messageMap.size()<<" items"<<std::endl; // This does not
std::cout<<" And me!"<<std::endl; // Nothing works below the map usage.
for (std::map<unsigned int, WindowFunction>::iterator it=messageMap.begin(); it!=messageMap.end(); ++it) {
std::cout<<" Have: "<<it->first<<std::endl;
if (msg==it->first) {
(it->second)(hwnd);
break;
}
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
编辑 因此,经过进一步测试后,我发现了更多信息。上下文值始终为 0,虽然我不明白这怎么会允许 myHandler 被调用,但这是一个问题。所以我更改了我的代码以尝试从 WM_CREATE 消息设置 GWL_USERDATA...我发现我的 dummyProc 永远不会收到 WM_CREATE 消息。
下面是新的 dummyProc,带有调试输出:
static LRESULT CALLBACK dummyProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
std::cout<<"Create would be "<<WM_CREATE<<std::endl;
std::cout<<"The message was "<<msg<<std::endl;
if (msg==WM_CREATE) {
SetLastError(0);
SetWindowLong(hwnd, GWL_USERDATA, lParam);
std::cout<<"ERROR: "<<GetLastError()<<std::endl;
}
long thelong=GetWindowLong(hwnd, GWL_USERDATA);
std::cout<<"Long: "<<thelong<<std::endl;
WinClass* context=(WinClass*)thelong;
std::cout<<"Context: "<<context<<std::endl;
return context->myHandler(hwnd, msg, wParam, lParam);
}
它说的是 WM_CREATE 的值为 1,但消息从 36 开始,然后是 129 和 130。我的 WM_CREATE 消息发生了什么?
这是创建窗口本身的代码:
hand = CreateWindowEx(WS_EX_CLIENTEDGE, 我的类(class).我的名字, 标题, WS_OVERLAPPEDWINDOW, x, y, w, h, parent , 无效的, 安装, &我的类(class));
这些参数中的大多数是传递给 Window 类的构造函数(此代码所在的位置)的参数。 myClass 参数是一个 WinClass 实例。所有 WinClass 实例都将 dummyProc 设置为其 WndProc 处理程序。测试表明 &myClass 在调用时确实是一个有效的非 NULL 指针。
那么是什么阻止了 WM_CREATE 消息?
最佳答案
正如@Ben Voigt 所说,您没有正确初始化GWLP_USERDATA
,而且您也没有处理尚未初始化的情况。
请注意,即使您修改后的代码也不正确。在 WM_CREATE
上,lParam
值不是您的用户数据指针。它是指向 CREATESTRUCT
的指针,其中一个成员是您的用户数据值。
尝试以下操作来替换您的 dummyProc
函数:
static LRESULT CALLBACK dummyProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (uMsg == WM_NCCREATE)
SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>( reinterpret_cast<LPCREATESTRUCT>(lParam)->lpCreateParams ));
WinClass* context=(WinClass*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if (!context) return DefWindowProc(hwnd, msg, wParam, lParam);
return context->myHandler(hwnd, msg, wParam, lParam);
}
关于c++ - 使用 map 时 WinAPI WndProc 静默失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22133430/