闲时顺手翻了翻《Windows Graphics Programming》,发现里面的示例代码很不错,对设计应用程序框架和理解现有的应用程序框架很有帮助(尤其是MFC)。先来看一个很简单的用面向对象的思想包装API函数的KWindow类。示例代码贴出来,申明一下,代码不是我写的,但有可能做一些改动,加了很多罗嗦的注释,只是想节约以后阅读的时间。 下载示例project KWindow类需要完成注册窗口、创建窗口、处理窗口消息等用API编写程序时要处理的任务。由于每个窗口类对不同的消息会有不同的处理,所以首先想到了消息处理函数采用虚函数来实现(这种方式缺点是消息太多会使虚函数表过大,MFC采用消息映射,这里只是为了简单),因为虚函数肯定是成员函数,有this指针,Win32 API不能把一个虚函数作为窗口消息处理函数。通常的解决办法是采用静态函数,在这个静态函数里在想办法产生一个指向代表当前窗口的KWindow实例的指针来调用对应窗口的消息处理函数。
// win.h
#pragma once
// 以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);
}
};

// win.cpp
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <assert.h>
#include <tchar.h>
#include ".\win.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;
}

// Hello.cpp
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <assert.h>
#include <tchar.h>

#include "win.h"

const TCHAR szMessage[] = _T("Hello, World !");
const TCHAR szFace[] = _T("Times New Roman");
const TCHAR szHint[] = _T("Press ESC to quit.");
const TCHAR szProgram[] = _T("HelloWorld3");

// copy CenterText from Hello2.cpp

class KHelloWindow : public KWindow
  {
void CenterText(HDC hDC, int x, int y, LPCTSTR szFace,
LPCTSTR szMessage, int point)
 {
HFONT hFont = CreateFont(
point * GetDeviceCaps(hDC, LOGPIXELSY) / 72,
0, 0, 0, FW_BOLD, TRUE, FALSE, FALSE,
ANSI_CHARSET, OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS,
PROOF_QUALITY, VARIABLE_PITCH, szFace);
assert(hFont);

HGDIOBJ hOld = SelectObject(hDC, hFont);

SetTextAlign(hDC, TA_CENTER | TA_BASELINE);

SetBkMode(hDC, TRANSPARENT);
SetTextColor(hDC, RGB(0, 0, 0xFF));
TextOut(hDC, x, y, szMessage, _tcslen(szMessage));
SelectObject(hDC, hOld);
DeleteObject(hFont);
}

void OnKeyDown(WPARAM wParam, LPARAM lParam)
 {
if (wParam==VK_ESCAPE )
 {
PostMessage(m_hWnd, WM_CLOSE, 0, 0);
}
}

void OnDraw(HDC hDC)
 {
TextOut(hDC, 0, 0, szHint, lstrlen(szHint));
CenterText(hDC, GetDeviceCaps(hDC, HORZRES)/2,
GetDeviceCaps(hDC, VERTRES)/2,
szFace, szMessage, 72);
}

// 修改默认窗口属性
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(NULL_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = NULL;
wc.hIconSm = NULL;
}

public:

};

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE,
LPSTR lpCmd, int nShow)
  {
KHelloWindow win;

win.CreateEx(0, szProgram, szProgram, WS_POPUP, 0, 0,
GetSystemMetrics(SM_CXSCREEN),
GetSystemMetrics(SM_CYSCREEN),
NULL, NULL, hInst);

win.ShowWindow(nShow);
win.UpdateWindow();

return win.MessageLoop();
}

|