记得以前看过一本书,叫做《windows图形编程》,作者是Yuan Feng,机械工业出版社出版的,该书从Win32API开始介绍,讲述了Win32 GDI和DirectDraw API的技术细节,里面好多技术都研究得特别深入。最让我难忘的是它基本上用Win32API完成了一套类似于MFC的图形框架,不过与MFC不同的是,MFC里面消息映射机制还不算是完全的面向对象的,而它则完全用面向对象的技术方法实现了图形库。
最近上网查资料,偶然发现他最基础的那个窗口基类居然能在网上找到代码。真是喜出往外了。
看看他的用面向对象技术封装的KWindow类吧。呵呵,我就喜欢在类名前加个大写字母K了,真是与我爱好一样啊。
头文件KWindow.h:
- #if _MSC_VER > 1000
- #pragma once
- #endif // _MSC_VER > 1000
- // 以K开头来命名类,是希望与MFC有明显区别
- class KWindow
- {
- protected:
- // 处理WM_PAINT消息,由WndProc调用
- virtual void OnDraw(HDC hDC)
- {
- }
- // 处理WM_KEYDOWN消息,由WndProc调用
- virtual void OnKeyDown(WPARAM wParam, LPARAM lParam)
- {
- }
- // 真正的消息分发/处理函数
- virtual LRESULT WndProc(HWND hWnd, UINT uMsg,
- WPARAM wParam, LPARAM lParam);
- // API中注册的消息处理函数,不能是成员函数,因为成员函数有this指针
- static LRESULT CALLBACK WindowProc(HWND hWnd,
- UINT uMsg, WPARAM wParam, LPARAM lParam);
- // 派生类可以在这里修改窗口的属性,如图标、菜单等
- virtual void GetWndClassEx(WNDCLASSEX & wc);
- public:
- // 保存该窗口对应的HWND
- HWND m_hWnd;
- // m_hWnd 由CreateEx成员函数调用API函数CreateWindowEx赋值
- KWindow(void)
- {
- m_hWnd = NULL;
- }
- // destructor
- virtual ~KWindow(void)
- {
- }
- // 调用API函数CreateWindowEx创建窗口
- virtual bool CreateEx(DWORD dwExStyle,
- LPCTSTR lpszClass, LPCTSTR lpszName, DWORD dwStyle,
- int x, int y, int nWidth, int nHeight, HWND hParent,
- HMENU hMenu, HINSTANCE hInst);
- // 注册窗口
- bool RegisterClass(LPCTSTR lpszClass, HINSTANCE hInst);
- // 消息循环
- virtual WPARAM MessageLoop(void);
- BOOL ShowWindow(int nCmdShow) const
- {
- return ::ShowWindow(m_hWnd, nCmdShow);
- }
- BOOL UpdateWindow(void) const
- {
- return ::UpdateWindow(m_hWnd);
- }
- };
KWindow.cpp文件
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #include <assert.h>
- #include <tchar.h>
- #include "KWindow.h"
- // 真正的消息分发/处理函数
- LRESULT KWindow::WndProc(HWND hWnd, UINT uMsg,
- WPARAM wParam, LPARAM lParam)
- {
- switch( uMsg )
- {
- case WM_KEYDOWN:
- OnKeyDown(wParam, lParam);
- return 0;
- case WM_PAINT:
- {
- PAINTSTRUCT ps;
- BeginPaint(m_hWnd, &ps);
- OnDraw(ps.hdc);
- EndPaint(m_hWnd, &ps);
- }
- return 0;
- case WM_DESTROY:
- PostQuitMessage(0);
- return 0;
- }
- return DefWindowProc(hWnd, uMsg, wParam, lParam);
- }
- // API中注册的消息处理函数,将操作系统的消息分发到正确的KWindow对象
- LRESULT CALLBACK KWindow::WindowProc(HWND hWnd, UINT uMsg,
- WPARAM wParam, LPARAM lParam)
- {
- KWindow * pWindow;
- if ( uMsg == WM_NCCREATE ) // 窗口创建时收到的第一个消息
- {
- // 通过lParam找出该窗口对应的KWindow指针,并调用
- // SetWindowLong(GWL_USERDATA)保存
- assert( ! IsBadReadPtr((void *) lParam,
- sizeof(CREATESTRUCT)) );
- MDICREATESTRUCT * pMDIC = (MDICREATESTRUCT *)
- ((LPCREATESTRUCT) lParam)->lpCreateParams;
- pWindow = (KWindow *) (pMDIC->lParam);
- assert( ! IsBadReadPtr(pWindow, sizeof(KWindow)) );
- SetWindowLong(hWnd, GWL_USERDATA, (LONG) pWindow);
- }
- else
- {
- // 调用GetWindowLong(GWL_USERDATA)找回在WM_NCCREATE消息中保存的
- // KWindow指针
- pWindow=(KWindow *)GetWindowLong(hWnd, GWL_USERDATA);
- }
- if ( pWindow )
- {
- return pWindow->WndProc(hWnd, uMsg, wParam, lParam);
- }
- else
- {
- return DefWindowProc(hWnd, uMsg, wParam, lParam);
- }
- }
- bool KWindow::RegisterClass(LPCTSTR lpszClass, HINSTANCE hInst)
- {
- WNDCLASSEX wc;
- if ( ! GetClassInfoEx(hInst, lpszClass, &wc) )
- {
- GetWndClassEx(wc);
- wc.hInstance = hInst;
- wc.lpszClassName = lpszClass;
- if ( !RegisterClassEx(&wc) )
- return false;
- }
- return true;
- }
- bool KWindow::CreateEx(DWORD dwExStyle,
- LPCTSTR lpszClass, LPCTSTR lpszName, DWORD dwStyle,
- int x, int y, int nWidth, int nHeight, HWND hParent,
- HMENU hMenu, HINSTANCE hInst)
- {
- if ( ! RegisterClass(lpszClass, hInst) )
- return false;
- // use MDICREATESTRUCT to pass this pointer, support MDI child window
- MDICREATESTRUCT mdic;
- memset(& mdic, 0, sizeof(mdic));
- mdic.lParam = (LPARAM) this;
- m_hWnd = CreateWindowEx(dwExStyle, lpszClass, lpszName,
- dwStyle, x, y, nWidth, nHeight,
- hParent, hMenu, hInst, & mdic);
- return m_hWnd != NULL;
- }
- // 派生类中可以改写默认属性
- void KWindow::GetWndClassEx(WNDCLASSEX & wc)
- {
- memset(& wc, 0, sizeof(wc));
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.style = 0;
- wc.lpfnWndProc = WindowProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = NULL;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = NULL;
- wc.hIconSm = NULL;
- }
- // Message Loop
- WPARAM KWindow::MessageLoop(void)
- {
- MSG msg;
- while ( GetMessage(&msg, NULL, 0, 0) )
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
- return msg.wParam;
- }
如何使用它呢?请看例子:
- const TCHAR szHint[] = _T("Press ESC to quit.");
- class KHelloWindow : public KWindow
- {
- virtual void OnKeyDown(WPARAM wParam, LPARAM lParam)
- {
- if (wParam==VK_ESCAPE )
- {
- PostMessage(m_hWnd, WM_CLOSE, 0, 0);
- }
- }
- virtual void OnDraw(HDC hDC)
- {
- TextOut(hDC, 0, 0, szHint, lstrlen(szHint));
- }
- // 修改默认窗口属性
- virtual void GetWndClassEx(WNDCLASSEX & wc)
- {
- memset(& wc, 0, sizeof(wc));
- wc.cbSize = sizeof(WNDCLASSEX);
- wc.style = 0;
- wc.lpfnWndProc = WindowProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = NULL;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = NULL;
- wc.hIconSm = NULL;
- }
- public:
- };
- int APIENTRY WinMain(HINSTANCE hInstance,
- HINSTANCE hPrevInstance,
- LPSTR lpCmdLine,
- int nCmdShow)
- {
- KHelloWindow win;
- win.CreateEx(0, _T("Hello"), _T("Hello"), WS_OVERLAPPEDWINDOW,GetSystemMetrics(SM_CXSCREEN)/4, GetSystemMetrics(SM_CYSCREEN)/4,
- GetSystemMetrics(SM_CXSCREEN)/2,
- GetSystemMetrics(SM_CYSCREEN)/2,
- NULL, NULL, hInstance);
- win.ShowWindow(nCmdShow);
- win.UpdateWindow();
- return win.MessageLoop();
- }
编译运行后效果如图:
如果大家写过稍微复杂一点的win32的程序的话,就会发现如果采用这种结构,这比一个书上典型的win32程序要简洁得多了。