閑時順手翻了翻《Windows Graphics Programming》,發(fā)現(xiàn)里面的示例代碼很不錯,對設(shè)計應(yīng)用程序框架和理解現(xiàn)有的應(yīng)用程序框架很有幫助(尤其是MFC)。先來看一個很簡單的用面向?qū)ο蟮乃枷氚bAPI函數(shù)的KWindow類。示例代碼貼出來,申明一下,代碼不是我寫的,但有可能做一些改動,加了很多羅嗦的注釋,只是想節(jié)約以后閱讀的時間。 下載示例project KWindow類需要完成注冊窗口、創(chuàng)建窗口、處理窗口消息等用API編寫程序時要處理的任務(wù)。由于每個窗口類對不同的消息會有不同的處理,所以首先想到了消息處理函數(shù)采用虛函數(shù)來實(shí)現(xiàn)(這種方式缺點(diǎn)是消息太多會使虛函數(shù)表過大,MFC采用消息映射,這里只是為了簡單),因?yàn)樘摵瘮?shù)肯定是成員函數(shù),有this指針,Win32 API不能把一個虛函數(shù)作為窗口消息處理函數(shù)。通常的解決辦法是采用靜態(tài)函數(shù),在這個靜態(tài)函數(shù)里在想辦法產(chǎn)生一個指向代表當(dāng)前窗口的KWindow實(shí)例的指針來調(diào)用對應(yīng)窗口的消息處理函數(shù)。
// win.h
#pragma once
// 以K開頭來命名類,是希望與MFC有明顯區(qū)別
class KWindow
  {
protected:
// 處理WM_PAINT消息,由WndProc調(diào)用
virtual void OnDraw(HDC hDC)
 {
}
// 處理WM_KEYDOWN消息,由WndProc調(diào)用
virtual void OnKeyDown(WPARAM wParam, LPARAM lParam)
 {
}
// 真正的消息分發(fā)/處理函數(shù)
virtual LRESULT WndProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam);
// API中注冊的消息處理函數(shù),不能是成員函數(shù),因?yàn)槌蓡T函數(shù)有this指針
static LRESULT CALLBACK WindowProc(HWND hWnd,
UINT uMsg, WPARAM wParam, LPARAM lParam);
// 派生類可以在這里修改窗口的屬性,如圖標(biāo)、菜單等
virtual void GetWndClassEx(WNDCLASSEX & wc);
public:
// 保存該窗口對應(yīng)的HWND
HWND m_hWnd;
// m_hWnd 由CreateEx成員函數(shù)調(diào)用API函數(shù)CreateWindowEx賦值
KWindow(void)
 {
m_hWnd = NULL;
}
// destructor
virtual ~KWindow(void)
 {
}
// 調(diào)用API函數(shù)CreateWindowEx創(chuàng)建窗口
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);
// 消息循環(huán)
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"

// 真正的消息分發(fā)/處理函數(shù)
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中注冊的消息處理函數(shù),將操作系統(tǒng)的消息分發(fā)到正確的KWindow對象
LRESULT CALLBACK KWindow::WindowProc(HWND hWnd, UINT uMsg,
WPARAM wParam, LPARAM lParam)
  {
KWindow * pWindow;

if ( uMsg == WM_NCCREATE ) // 窗口創(chuàng)建時收到的第一個消息
 {
// 通過lParam找出該窗口對應(yīng)的KWindow指針,并調(diào)用
// 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
 {
// 調(diào)用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;
}

// 派生類中可以改寫默認(rèn)屬性
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);
}

// 修改默認(rèn)窗口屬性
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();
}

|