c++ - 使用 map 时 WinAPI WndProc 静默失败

标签 c++ windows class winapi wndproc

首先,让我说我是 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/

相关文章:

c++ - 返回相同值的随机数生成器(C++)

c++ - 'double (*bag)[VECT_SIZE]' 是什么函数参数?

windows - 如何使用命令行卸载 Apache

java - 有些jar文件是通过双击运行的,而有些则不是

windows - 英特尔 RCS 日志记录

css - 文章分页类拆分 div 并弄乱页面布局

c++ - 使用子方法 C++

c++ - GDB::重写的运算符新函数的调用堆栈不完整?

c++ - 如何在 BST 的这个简单递归实现中摆脱警告

javascript - 修改对象属性时如何触发回调?