65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的Win32窗口包装类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (36投票s)

2002年7月11日

2分钟阅读

viewsIcon

506413

downloadIcon

7797

如何在不使用 MFC 的情况下,创建一个面向对象的 Win32 应用程序。

引言

我喜欢面向对象编程。 在我的职业 C++ 生涯中,我只使用过 MFC。 因此,当我想要制作一个古老的 Win32/SDK 应用程序时,我一想到不使用 OO 范式就会感到畏缩。 如果你像我一样,想摆脱旧的 C 编程风格,这里有一些代码可以帮助你编写自己的窗口封装类。

所有的例子在哪里?

几乎不可能找到一个好的窗口封装类的例子。 我的游戏开发书籍中没有一个有。 我的通用 Windows 编程书籍也没有。 进行 Google 搜索只给了我一个很好的例子,创建一个 Win32 窗口封装类。 你会认为会有更多的人这样做。 不幸的是,没有更多例子,因为要让它工作并不容易。

主要问题

当你创建一个 WNDCLASSEX 结构时,你需要给该结构一个指向你的窗口过程的指针,在 lpfnWndProc 成员中。 窗口过程是一个回调函数,一种由 Windows 在需要时直接调用的特殊函数。

为了使回调函数正常工作,在 Windows 头文件中定义了严格的 typedef。 如果你试图使用一个类成员作为回调函数,编译器会给你一个错误,说该成员的原型与所需的 typedef 不匹配。

解决方案

为了绕过这个编译器错误,我们需要使窗口过程 static。 从这个静态方法中,我们再调用类的另一个方法来实际处理消息。

为了调用正确窗口的消息处理程序,我们需要使用 SetWindowLongGetWindowLong API 函数获取窗口类的指针。 我们通过 CreateWindow 函数的 LPVOID lpParam // 窗口创建数据 参数将 this 指针发送到窗口过程。

当收到 WM_NCCREATE 消息时,窗口过程将窗口长值设置为指针,然后能够调用正确的消息处理程序。

class CBaseWindow
{
public:
    // there are more members and methods
    // but you can look at the code to see them

    // static message handler to put in WNDCLASSEX structure
    static LRESULT CALLBACK stWinMsgHandler(HWND hwnd, 
                UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
    // the real message handler
    virtual LRESULT CALLBACK WinMsgHandler(HWND hwnd, 
                UINT uMsg, WPARAM wParam, LPARAM lParam)=0;

    // returns a pointer the window (stored as the WindowLong)
    inline static CBaseWindow *GetObjectFromWindow(HWND hWnd)
    {
        return (CBaseWindow *)GetWindowLong(hWnd, GWL_USERDATA);
    }
};

LRESULT CALLBACK CBaseWindow::stWinMsgHandler(HWND hwnd, 
                   UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CBaseWindow* pWnd;

    if (uMsg == WM_NCCREATE)
    {
        // get the pointer to the window from
        // lpCreateParams which was set in CreateWindow
        SetWindowLong(hwnd, GWL_USERDATA, 
           (long)((LPCREATESTRUCT(lParam))->lpCreateParams));
    }

    // get the pointer to the window
    pWnd = GetObjectFromWindow(hwnd);

    // if we have the pointer, go to the message handler of the window
    // else, use DefWindowProc
    if (pWnd)
        return pWnd->WinMsgHandler(hwnd, uMsg, wParam, lParam);
    else
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

BOOL CBaseWindow::Create(DWORD dwStyles, RECT* rect)
{ 
    // Create the window

    // send the this pointer as the window creation parameter
    m_hwnd = CreateWindow(szClassName, szWindowTitle, dwStyles, 
        rect->left, rect->top, rect->right - rect->left, 
        rect->bottom - rect->top, NULL, NULL, hInstance, 
        (void *)this);

    return (m_hwnd != NULL);
}

结论

虽然演示 (和源代码) 是你用窗口封装类可以做的非常简单粗略的例子,但我希望它能帮助你使你的 Win32 编程项目更容易理解,并且你的代码更具可重用性。

如果你能找到关于这个主题的更多信息,我很乐意在文章中添加一个链接部分。

归功于应归之

© . All rights reserved.