【问题标题】:Use object method as WinApi WndProc callback [duplicate]使用对象方法作为 WinApi WndProc 回调 [重复]
【发布时间】:2013-01-17 16:25:19
【问题描述】:

我正在尝试创建一个在父窗口中显示控制台窗口的小类。 (您可以想象那里显示的聊天或调试信息)
现在,由于不同的实例确实有不同的私有变量(例如消息数组或父窗口),我需要使用非静态方法作为 Windows 事件的回调。
我已经想到了一些方法,我将实际的类实例传递给静态回调函数,然后在其上调用正确的方法,但是在 winAPI 中,一切都是使用 TranslateMessageDispatchMessage 完成的,这让我没有机会使用参数我自己的。
我在这里找到了一些代码:Class method as winAPI callback,但我不明白,我认为这不是我所需要的。如果是,请给我提供的代码的进一步解释。
我得到的错误:

错误:“LRESULT (WindowConsole::)(HWND__, UINT, WPARAM, LPARAM)”类型的参数不匹配“LRESULT (*)(HWND__,单位, WPARAM, LPARAM)'

我不知道括号中的星号是什么意思,但这是不匹配的。
和代码:

class WindowConsole {
   char messages[255][255];
   HWND mainWindow;
   public:
     int width;
     int height;
     inline HWND create(HWND parent);
     inline bool update();
     inline LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
};

HWND WindowConsole::create(HWND parent) {
    HINSTANCE inst =  GetModuleHandle (0);
    WNDCLASSEX wincl;

    /* The Window structure */
    wincl.hInstance = inst;
    wincl.lpszClassName = "ConsoleClass";
    wincl.lpfnWndProc = this->WndProc;      /* This function is called by windows */
    /* more WNDCLASSEX crap...*/

    mainWindow = CreateWindow (
          /*PARAMS*/
    );
    ShowWindow(mainWindow,1);
    return mainWindow;

}
bool WindowConsole::update() {
   return true;
}
LRESULT CALLBACK WindowConsole::WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message)                  /* handle the messages */
    {
           /*EVENT crap*/
    }

    return 0;
}

【问题讨论】:

  • 好吧,他们都没有帮助我。找了很久,找到了很多关于这个问题的话题,但就是没看懂。
  • 看看 user16100... 的回答和 msdn-article 的链接...

标签: c++ oop class winapi


【解决方案1】:

通常是这样的:

#include <windows.h>

class BaseWindow {

     static LRESULT CALLBACK internal_WndProc(HWND hWnd, int msg, WORD wParam, LONG lParam) {
        BaseWindow *c = (BaseWindow *)GetWindowLong(hWnd,GWLP_USERDATA);

        if (c == NULL)
            return DefWindowProc(hWnd, msg, wParam, lParam);

        return c->WindowProc(hWnd, msg, wParam, lParam);
    }

public:
    virtual int WindowProc(HWND hWnd, int msg, WPARAM wParam, LPARAM lParam) = 0;

    BaseWindow(HINSTANCE instance) {
        WNDCLASS window_class = {0};
        HWND window;
        HMENU my_menu;

        window_class.lpfnWndProc = (WNDPROC)internal_WndProc;
        /* fill in window_class here */
        RegisterClass(&window_class);

        window = CreateWindow(
            "My Application", "Stupidity", 
            WS_OVERLAPPEDWINDOW, 
            CW_USEDEFAULT, CW_USEDEFAULT, 
            CW_USEDEFAULT, CW_USEDEFAULT, 
            NULL, my_menu, instance, NULL);

        // save the address of the class as the Window's USERDATA.
        SetWindowLong(window, GWLP_USERDATA, (long)this);
    }
};

这样,您就可以从 BaseWindow 派生一个类。在您的派生类中,您提供了一个“WindowProc”,它覆盖了 BaseWindow 中的(纯虚拟)一个。这里的技巧相当简单:因为你不能直接传递参数,你将类的地址存储在窗口的 GWLP_USERDATA 中,然后在窗口 proc 中(尝试)检索它并使用它来调用派生类的 virtual窗口过程

顺便说一句,请注意这是草图,而不是完成的作品(可以这么说)。虽然它应该按原样编译,但结果实际上不会起作用,除非您填写大量不在这里的部分(例如,WNDCLASS 结构的其他字段只是最明显的字段之一)。

【讨论】:

  • 谢谢你,用你的例子,我制作了一些东西,至少,编译没有错误。现在有一个明显的问题:我在哪里放置循环来捕获窗口事件并调度它们?我是否必须让我的程序异步(添加另一个线程?)?
  • @TomášZato:消息循环(基本上)总是在 WinMain 中,通常只会创建窗口的实例,然后进入消息循环。不,您通常不想在单独的线程中运行它。
  • 好吧,但是我的班级可以创建很多窗口,因为我可以创建很多实例。那么我应该将窗口处理程序 (HWND) 保存在某个全局变量中,以便在 WinMain() 中为它们中的每一个分配事件吗?
  • 如果要覆盖非客户区消息,此方法不起作用。
  • here 及以下所述,SetWindowLongPtr() / GetWindowLongPtr 必须用于 64 位可执行文件。
【解决方案2】:

您链接到的另一个问题仅部分适用。

WindowProc 方法确实需要是静态的。然后在调用 CreateWindowEx 之后立即调用 SetWindowLongPtr,GWLP_USERDATA 作为第二个参数,this 作为第三个参数。这将 HWND 与类实例相关联。然后在静态 WindowProc 方法中调用 GetWindowLongPtr(同样使用 GWLP_USERDATA)来获取接收到 UI 事件的 WindowConsole 实例。

这里都详细解释了:

http://msdn.microsoft.com/en-us/library/windows/desktop/ff381400(v=vs.85).aspx

【讨论】:

    【解决方案3】:

    我使用一个简单的解决方案。 winproc 是一个模板函数。 消息接收者在 setwindowptr 内。

    如果接收者有一个带有消息名称的函数,例如 onpaint ,那么 wm_paint 会包含在消息切换中。

    http://www.thradams.com/codeblog/wndproc.htm

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-31
      • 1970-01-01
      相关资源
      最近更新 更多