首页 文章

使用对象方法作为WinApi WndProc回调[重复]

提问于
浏览
6

这个问题在这里已有答案:

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

error:类型'LRESULT(WindowConsole ::)(HWND __,UINT,WPARAM,LPARAM)'的参数与'LRESULT(*)(HWND __,UINT,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;
}

3 回答

  • 4

    通常是这个顺序的东西:

    #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(尝试)中检索它并使用它来调用派生类的虚拟窗口过程 .

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

  • 10

    您链接的另一个问题仅适用于部分 .

    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

  • 1

    我用一个简单的解决方案 . winproc是一个模板函数 . 消息接收器位于setwindowptr内 .

    如果接收器具有带消息名称的函数,例如onpaint,那么wm_paint包含在消息开关中 .

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

相关问题