一、win32程序基础
Windows程序必须在开始之前做些初始化工作,CreateWindow之前把窗口的外貌和行为在WNDCLASS里设置好,并进行注册:RegisterClass(&wc);
CreateWindow只是创建窗口,之后再利用ShowWindow进行显示。
RegisterClass封装在InitApplication函数中,
CreateWindow封装在InitInstance函数中。这样的封装方式主要是出于历史原因,Windows3.x时代,窗口类只需要注册一次就可以供多个实例instance使用。在MFC在,Init的两个函数封装为CWinApp类的两个虚函数。
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
UNREFERENCED_PARAMETER(lpCmdLine); // 避免編譯時的警告
if (!hPrevInstance)
if (!InitApplication(hInstance))
return (FALSE);
if (!InitInstance(hInstance, nCmdShow))
return (FALSE);
//初始化完成后,winmain进入消息循环:
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg); // 分发到个窗口的WndProc中处理。
}
return (msg.wParam); // 傳回 PostQuitMessage 的參數
}
另外,MFC程序的入口函数,在MFC/SRC/APPMODULE.cpp中
extern "C" int WINAPI
_tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPTSTR lpCmdLine, int nCmdShow)
{
// call shared/exported WinMain
return AfxWinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
}
二、Message Map的雏形
消息处理的最原始函数:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
switch (message) {
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId)
{
case IDM_ABOUT:
DialogBox(_hInst,
"AboutBox", // 對話盒資源名稱
hWnd, // 父視窗
(DLGPROC)About // 對話盒函式名稱
);
break;
case IDM_EXIT:
// 使用者想結束程式。處理方式與 WM_CLOSE 相同。
DestroyWindow (hWnd);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
break;
case WM_DESTROY: // 視窗已經被摧毀 (程式即將結束)。
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, message, wParam, lParam));
}
return (0);
}
大量的switch case语句,可扩展性不好。
是否可以更加模块化呢?定义一个MSGMAP_ENTRY的结构和dim宏:
struct MSGMAP_ENTRY {
UINT nMessage;
LONG (*pfn)(HWND, UINT, WPARAM, LPARAM);
};
#define dim(x) (sizeof(x) / sizeof(x[0]))
定义数组:
// 分别是消息和这个消息的处理函数
struct MSGMAP_ENTRY _messageEntries[] =
{
WM_CREATE, OnCreate,
WM_PAINT, OnPaint,
WM_SIZE, OnSize,
WM_COMMAND, OnCommand,
WM_SETFOCUS, OnSetFocus,
WM_CLOSE, OnClose,
WM_DESTROY, OnDestroy,
} ;
这样以来大量switch的WndProc函数可以变成:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
int i;
for(i=0; i < dim(_messageEntries); i++) { // 遍历对照表,找到就给对应的处理函数,时间复杂度一点都不会增加
if (message == _messageEntries[i].nMessage)
return((*_messageEntries[i].pfn)(hWnd, message, wParam, lParam));
}
return(DefWindowProc(hWnd, message, wParam, lParam));
}
于是WndProc就不需要对用户公开了,有新的消息及其处理,直接加在_messageEntries[]数组之中。
三、dialogue的运行
doModel和modeless。
1, dialog template,在rc文档中定义的外观属性
2, dialog procedure,类似WndProc。
四、Windows程序的生存过程
1,初始化时,CreateWindow创建一个Window;
2,WinMain函数不断的消息循环,使用GetMessage在消息队列中获取Msg;
3, 获取后DispatchMessage,传给对应的WndProc函数;
4, 重复2,3
5, 当按下Close命令时,送出WM_CLOSE,进入WndProc的DefWindowProc处理;
6, DefWindowProc收到WM_CLOSE调用DestroyWindow销毁窗口,同时送出WM_DESTROY;
7, PostQuitMessage
8, PostQuitMessage消息送出WM_QUIT给WinMain,WinMain退出消息循环。