1 了解窗口
2 窗口程序原理
事件驅(qū)動模式

窗口程序的運行過程

DispatchMessage會在內(nèi)部調(diào)用消息處理的回調(diào)函數(shù)

應(yīng)用程序之間也可互相發(fā)送消息
PostMessage 將一個消息放到其他程序的消息隊列中
SendMessage 越過消息隊列直接調(diào)用目標程序的窗口過程
RegisterClassEx 用來注冊窗口過程 即用來注冊處理窗口消息的回調(diào)函數(shù)
2 分析窗口程序
2.1 模塊與句柄
exe dll裝入內(nèi)存后稱為模塊,每個模塊都有一個唯一標識的句柄,在win32中,模塊句柄在數(shù)值上等于內(nèi)存中裝入的起始地址,用來標識各種資源
使用GetModuleHandle來獲取模塊句柄
例子

當(dāng)參數(shù)為NULL,會獲取調(diào)用者本模塊的句柄

在win32中實例句柄就是模塊句柄
hInstance hModule
在C語言編程中 hInstance通過WinMain由系統(tǒng)傳入
在win32匯編中,hInstance需要自己獲取
windows中幾乎所有的東西都是用句柄標識的,如文件句柄、窗口句柄、線程句柄、模塊句柄等
2.2 創(chuàng)建窗口
窗口類中定義窗口的屬性

初始化

hIcon 窗口圖標句柄 預(yù)定義 可通過LoadIcon指定
hCursor 光標句柄 預(yù)定義(IDC_ARROW...) 可通過LoadCursor指定
lpszMenuName 菜單字符串
hInstance 指定窗口類屬于哪個模塊 GetModuleHandle
cbSize 指定結(jié)構(gòu)的長度
style 窗口風(fēng)格 CS_HREDRAW CS_VREDRAW CS_DBLCLKS
hbrBackground 刷子句柄 指定窗口客戶區(qū)的背景色 如BLACK_BRUSH、WHITE_BRUSH 使用 GetStockObject來獲取刷子句柄 也可以指定顏色值 如 COLOR_BACKGROUND,COLOR_HIGHLIGHT,COLOR_MENU,COLOR_WINDOW等,需要加1
lpszClassName 指定類的名稱
cbWndExtra cbClsExtra 預(yù)留的空間 用來存放自定義數(shù)據(jù)
lpfnWndProc 回調(diào)函數(shù)
使用CreateWindowEx來建立窗口
HWND CreateWindowEx(
DWORD dwExStyle, // extended window style WS_EX_* 可參考MSDN
LPCTSTR lpClassName, // pointer to registered class name
LPCTSTR lpWindowName, // pointer to window name
DWORD dwStyle, // window style 可參考MSDN WS_*
int x, // horizontal position of window
int y, // vertical position of window
int nWidth, // window width
int nHeight, // window height
HWND hWndParent, // handle to parent or owner window 上級窗口,上級窗口銷毀時,下級窗口也會被銷毀
HMENU hMenu, // handle to menu, or child-window identifier 菜單句柄 可替換窗口類中的菜單 當(dāng)dwStyle為WS_CHILD時,表示子窗口的ID
HINSTANCE hInstance, // handle to application instance 模塊句柄
LPVOID lpParam // pointer to window-creation data 傳給窗口的參數(shù) 這個參數(shù)在WM_CREATE消息中可以被獲取
);



常見的窗口樣式

ShowWindow用來顯示窗口
BOOL ShowWindow(
HWND hWnd, // handle of window
int nCmdShow // show state of window
);

UpdateWindow繪制客戶區(qū) 向窗口發(fā)送了一條WM_PAINT消息
BOOL UpdateWindow(
HWND hWnd // handle of window
);
CreateWindowEx也可以創(chuàng)建子窗口 如Button Edit
創(chuàng)建一個button

注意 hMenu在這里表示子窗口的ID
2.3 消息循環(huán)
消息循環(huán)的一般形式

消息格式


lpMsg為指向MSG結(jié)構(gòu)體的指針,接收返回消息
若獲取的消息WM_QUIT eax中的返回值為0
TranslateMessage進行一些鍵盤消息的轉(zhuǎn)換,將鍵盤消息的掃描碼轉(zhuǎn)換成ASC碼在消息隊列中插入WM_CHAR WM_SYSCHAR消息 遇到非鍵盤消息不處理
DispathMessage將消息發(fā)送到窗口處理過程,窗口過程返回后DispathMessage才返回
其它形式的消息循環(huán)
PeekMessage
BOOL PeekMessage(
LPMSG lpMsg, // pointer to structure for message
HWND hWnd, // handle to window
UINT wMsgFilterMin, // first message
UINT wMsgFilterMax, // last message
UINT wRemoveMsg // removal flags PM_NOREMOVE 取一條消息后在消息隊列中刪除該消息 PM_REMOVE 取一條消息不刪除
);
無論應(yīng)用程序消息隊列是否有消息,PeekMessage函數(shù)都立即返回,程序得以繼續(xù)執(zhí)行后面的語句(無消息則執(zhí)行其它指令,有消息時一般要將消息派發(fā)出去,再執(zhí)行其它指令)。
GetMessage函數(shù)只有在消息隊列中有消息時返回,隊列中無消息就會一直等,直至下一個消息出現(xiàn)時才返回。在等的這段時間,應(yīng)用程序不能執(zhí)行任何指令。
2.4 窗口過程
窗口過程的一般結(jié)構(gòu)

注意 proc后面的uses偽操作在子程序進入和退出時自動插上push和pop寄存器指令,來保護這些寄存器的值
uMsg的windows標準窗口預(yù)定義的值的范圍為0-03ffh
用戶自定義的消息可以從04ooh開始 一般為WM_USER+1,WM_USER+2,...
wParam和lParam為消息附帶的參數(shù),不同消息不一樣
當(dāng)窗口決定關(guān)閉時,需要程序調(diào)用DestoryWindow來摧毀窗口,并用PostQuitMessage向消息循環(huán)發(fā)送WM_QUIT消息來退出消息循環(huán)。
DefWindowProc來處理用戶不管的消息,采取默認方式來處理窗口消息

附錄 B實驗
3 窗口間的通信
3.1 窗口間消息的互發(fā)
不同的應(yīng)用程序之間可以使用SendMessage和PostMessage互相發(fā)送消息
LRESULT SendMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to send
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
BOOL PostMessage(
HWND hWnd, // handle of destination window
UINT Msg, // message to post
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
);
對于不同的msg, wParam和lParam的含義是不同的
wsprintf win32 api中用來格式化字符串輸出的函數(shù)
windows在處理SendMessage時 傳遞字符串時使用了共享內(nèi)容
注意 在用戶自定義的消息中,不要在消息參數(shù)中傳遞指針 會引發(fā)非法訪問內(nèi)存
3.2 在窗口間傳遞數(shù)據(jù)
WM_COPYDATA消息用于在不同應(yīng)用間傳遞數(shù)據(jù)
WM_COPYDATA
wParam = (WPARAM) (HWND) hwnd; // handle of sending window
lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // pointer to structure with data
數(shù)據(jù)包含在COPYDATASTRUCT結(jié)構(gòu)體中
typedef struct tagCOPYDATASTRUCT { // cds
DWORD dwData; //Specifies up to 32 bits of data to be passed to the receiving application
DWORD cbData; //Specifies the size, in bytes, of the data pointed to by the lpData member.
PVOID lpData; //Points to data to be passed to the receiving application. This member can be NULL.
} COPYDATASTRUCT;
3.3 SendMessage和PostMessage的區(qū)別
SendMessage相當(dāng)于直接調(diào)用其他窗口的窗口過程來處理某個消息,并等待窗口過程處理完成后返回
PostMessage則將某個消息放入目標窗口的消息隊列中并直接返回,不能用于任何參數(shù)中用到指針的消息