简单的Win32窗口包装类






4.81/5 (36投票s)
2002年7月11日
2分钟阅读

506413

7797
如何在不使用 MFC 的情况下,创建一个面向对象的 Win32 应用程序。
引言
我喜欢面向对象编程。 在我的职业 C++ 生涯中,我只使用过 MFC。 因此,当我想要制作一个古老的 Win32/SDK 应用程序时,我一想到不使用 OO 范式就会感到畏缩。 如果你像我一样,想摆脱旧的 C 编程风格,这里有一些代码可以帮助你编写自己的窗口封装类。
所有的例子在哪里?
几乎不可能找到一个好的窗口封装类的例子。 我的游戏开发书籍中没有一个有。 我的通用 Windows 编程书籍也没有。 进行 Google 搜索只给了我一个很好的例子,创建一个 Win32 窗口封装类。 你会认为会有更多的人这样做。 不幸的是,没有更多例子,因为要让它工作并不容易。
主要问题
当你创建一个 WNDCLASSEX
结构时,你需要给该结构一个指向你的窗口过程的指针,在 lpfnWndProc
成员中。 窗口过程是一个回调函数,一种由 Windows 在需要时直接调用的特殊函数。
为了使回调函数正常工作,在 Windows 头文件中定义了严格的 typedef。 如果你试图使用一个类成员作为回调函数,编译器会给你一个错误,说该成员的原型与所需的 typedef 不匹配。
解决方案
为了绕过这个编译器错误,我们需要使窗口过程 static
。 从这个静态方法中,我们再调用类的另一个方法来实际处理消息。
为了调用正确窗口的消息处理程序,我们需要使用 SetWindowLong
和 GetWindowLong
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 编程项目更容易理解,并且你的代码更具可重用性。
如果你能找到关于这个主题的更多信息,我很乐意在文章中添加一个链接部分。