代码之家  ›  专栏  ›  技术社区  ›  iksemyonov

如何将WiLAPI应用程序封装到C++类中

  •  4
  • iksemyonov  · 技术社区  · 14 年前

    有一个简单的WinAPI应用程序。它目前所做的只是:

    • 向菜单注册托盘图标
    • 最后,它使用互斥锁检查它是否唯一

    • 它保存所有wndclass、hinstance等变量,其中hinstance作为构造函数参数以及icmdshow和其他变量传递(请参见WinMain原型)

    在WinMain中,执行以下操作:

    Application app(hInstance, szCmdLIne, iCmdShow);
    return app.exec();
    

    构造函数执行以下操作:

    registerClass();
    registerTray();
    registerAutostart();
    

    到现在为止,一直都还不错。现在的问题是:如何创建window过程(必须是静态的,因为它是指向函数的c样式指针)并跟踪application对象是什么,也就是说,保持指向应用程序的指针。

    Application

    也许WndProc应该在类之外,而应用程序指针应该是全局的?然后WndProc调用应用程序方法来响应各种事件。

    还有一个可能的解决方案:将应用程序类设为单例。那么从WndProc获取该对象的句柄就很简单了。

    4 回复  |  直到 14 年前
        1
  •  4
  •   Puppy    14 年前

    答案是SetWindowLongPtr。它允许您将void*与给定hWnd相关联。然后,在WndProc中,您只需提取void*、cast并调用member方法。问题解决了。SetWindowLongPtr有一些起伏不定的地方,你必须调用一些其他函数来查看效果或类似的BS,Windows在CreateWindowEx返回之前发送消息,所以你必须准备好让GetWindowLongPtr(hWnd,GWL\u USERDATA)返回NULL。

    当然,这意味着对于给定的WindowProc,所有使用它的实例都必须有一个公共接口,因为对于void*,您可以做的不多。

    不要混淆Get/SetWindowLong和Get/SetWindowLongPtr。Get/SetWindowLong已弃用且不安全。

        2
  •  2
  •   lornova    14 年前

    不要按照提示使用 Get/SetWindowLongPtr 存储您的 this 指针,因为它是一个巨大的安全漏洞!您只需使用映射将HWND与指向类实例的指针相关联。你可以用 <map>

    顺便说一下,你可以在那里找到关于这个话题的很好的讨论: http://blogs.msdn.com/b/oldnewthing/archive/2005/04/22/410773.aspx

        3
  •  2
  •   Indy9000    14 年前

    你可以延长这个班(我 用于回答)如你所愿, 把手。

    #pragma once 
    
    #include <windows.h> 
    #include <process.h> 
    #include <iostream> 
    
    using namespace std; 
    
    static const char *g_AppName  = "Test"; 
    
    class CMyWindow 
    { 
        HWND  _hWnd; 
        int _width; 
        int _height; 
    public: 
        CMyWindow(const int width,const int height):_hWnd(NULL),_width(width),_height(height) 
        { 
            _beginthread( &CMyWindow::thread_entry, 0, this); 
        } 
    
        ~CMyWindow(void) 
        { 
            SendMessage(_hWnd, WM_CLOSE, NULL, NULL); 
        } 
    
    
    private: 
        static void thread_entry(void * p_userdata) 
        { 
            CMyWindow * p_win = static_cast<CMyWindow*> (p_userdata); 
            p_win->create_window(); 
            p_win->message_loop(); 
        } 
    
        void create_window() 
        { 
            WNDCLASSEX wcex; 
    
            wcex.cbSize             = sizeof(WNDCLASSEX); 
            wcex.style              = CS_HREDRAW | CS_VREDRAW; 
            wcex.lpfnWndProc    = &CMyWindow::WindowProc; 
            wcex.cbClsExtra         = 0; 
            wcex.cbWndExtra         = 0; 
            wcex.hInstance          = GetModuleHandle(NULL); 
            wcex.hIcon              = LoadIcon(NULL, IDI_APPLICATION); 
            wcex.hCursor            = LoadCursor(NULL, IDC_ARROW); 
            wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1); 
            wcex.lpszMenuName   = NULL; 
            wcex.lpszClassName  = g_AppName; 
            wcex.hIconSm            = LoadIcon(NULL, IDI_APPLICATION); 
    
            RegisterClassEx(&wcex); 
    
            _hWnd = CreateWindow(g_AppName, g_AppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, GetModuleHandle(NULL), NULL); 
    
            ShowWindow(_hWnd, SW_SHOWDEFAULT); 
            UpdateWindow(_hWnd); 
        } 
    
        void message_loop() 
        { 
            MSG msg = {0}; 
    
            while (GetMessage(&msg, NULL, 0, 0)) 
            { 
                if(msg.message == WM_QUIT) 
                { 
                    break; 
                } 
    
                TranslateMessage(&msg); 
                DispatchMessage(&msg); 
            } 
        } 
    
        static LRESULT WINAPI WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
        { 
            switch(uMsg) 
            { 
            case WM_DESTROY: 
                PostQuitMessage(0); 
                return 0; 
            case WM_POWERBROADCAST: 
                { 
                    //power management code here 
                } 
    
            } 
    
            return DefWindowProc(hWnd, uMsg, wParam, lParam); 
        } 
    }; 
    

    int APIENTRY _tWinMain(HINSTANCE hInstance,
                         HINSTANCE hPrevInstance,
                         LPTSTR    lpCmdLine,
                         int       nCmdShow)
    {
    
        CMyWindow t(640,480);
    
        Sleep(10000);
    
        return 0;
    }
    
        4
  •  0
  •   iksemyonov    14 年前

    我决定将它设为一个单例,因为它是主应用程序类,在程序中拥有该类的单个实例是没有问题的。

    现在我想问另一个相关的问题:假设我有一个偏好对话框。我创建一个对话框作为一个资源,然后给它一个过程,在这个过程中,创建一个控制器对象。这条路对吗?