对VS2008生成智能win32程序简单理解
程序中創建了主窗口,所以它必須為主窗口注冊一個窗口類,創建窗口并且提供一個消息循環來為窗口處理消息。
注冊窗口類
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_HELLOCEME));
wc.hCursor = 0;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = szAppName;
return RegisterClass(&wc);
}
?
?
style域為窗口設置了類的風格。在Windows CE中,類風格被限制為:
CS_GLOBALCLASS 表示類是全局的。這個標志只是出于兼容性才提供的,因為Windows CE中所有窗口類都是進程級全局類。
CS_HREDRAW 告訴系統如果窗口改變了水平大小,就強制重畫窗口。
CS_VREDRAW 告訴系統如果窗口改變了垂直大小,就強制重畫窗口。
CS_NOCLOSE 如果[關閉]按鈕出現在標題欄上,則使其失效。
CS_PARENTDC 讓窗口使用父窗口的設備環境變量
CS_DBLCLKS 允許[雙擊]通知(Windows CE下敲擊兩次為雙擊)傳遞給父窗口
?
lpfnWndProc分配的是窗口的窗口過程的地址。因為該域定義為指向窗口過程的指針,所以在源代碼中,必須在域被設置之前,定義該過程的聲明。否則,編譯器類型檢查時會警告該行。
cbClsExra允許程序員為類結構增加額外的空間來存儲只有應用程序才知道的類特定數據。cbWndExtra更加便于使用,這個域為Windows內部結構增加空間,該結構負責維護窗口每個實例的狀態。不在窗口結構本身里存儲大量的數據,應用程序應該存儲一個指向應用程序特定結構的指針,該結構包含窗口每個實例的數據。在Windows CE里,cbClsExtra 和cbWndExtra域必須時4字節的倍數。
hInstance域設置為程序的實例句柄,該句柄指明擁有窗口的進程。hIcon域設置為窗口默認圖標的句柄,但在Windows CE中并不支持該域,所以該域應該設置為NULL。(在Windows CE中,會在類的第一個窗口被創建后設置類的圖標。對于Hello3,沒有圖標提供,并且與其它Windows版本不同,Windows CE中沒有任何預定義圖標用于裝載。)
除非應用程序是為帶鼠標的Windows CE系統設計的,否則hCursor域應該設置為NULL。幸運的是,如果系統不支持光標,調用LoadCursor (IDC_ARROW) 函數會返回NULL。
hbrBackground域規定Windows CE如何畫窗口背景。Windows用這個域中指定的刷子brush(一個小的預定義的像素數組)來畫窗口背景。Windows CE提供許多預定義的刷子,你可以用GetStockObject函數來裝載。如果hbrBackground域是NULL,窗口必須處理WM_ERASEBKGND消息,重畫窗口背景。
lpszMenuName域必須設置為NULL,因為Windows CE不直接支持有菜單的窗口。在Windows CE中,菜單由主窗口創建的命令工具條、命令帶或菜單條控件提供。
lpszClassName設置為程序員定義的字符串,用于為Windows指明類的名字。Hello3用的是“MyClass”做為類名。
整個WNDCLASS類被填充后,RegisterClass函數被調用,并用指向WNDCLASS結構的指針作為唯一的參數。如果函數成功,一個標記窗口類的值被返,如果失敗,函數返回0。
消息循環
主窗口創建后,WinMain進入消息循環,這是每個Windows 應用程序的心臟。
while (GetMessage (&msg, NULL, 0, 0)) {
TranslateMessage (&msg);
DispatchMessage (&msg);
}
該循環很簡單:調用GetMessage函數,從應用程序消息隊列中獲取下一個消息。如果沒有消息可用,則調用進入等待期,阻塞應用程序線程直到消息可用。當消息可用,該函數返回包含在MSG結構的消息數據。MSG結構自身包含幾個域,有的用于識別消息,有的提供特定消息參數,有的識別在消息被發送之前,被筆觸摸過的最后屏幕位置點。該位置信息不同于標準Win32消息位置數據,在XP下,返回的位置是當前鼠標位置而不是最后點擊(或者tapped,在Windows CE里)的位置。
TranslateMessage 把適當的鍵盤信息轉換成字符信息。(后面會討論其它信息過濾器,比如IsDialogMsg。)DispatchMessage 接下來告訴Windows把消息發給應用程序適當的窗口。
獲取消息、轉換消息、分發消息這個過程會一直循環到GetMessage 收到WM_QUIT消息,這會使GetMessage返回0,這一點不同于其它消息。從while子句可以看出,GetMessage返回0將導致循環終止。
消息循環終止后,程序除了清理和退出外幾乎不做什么。在Hello3里,程序簡單的從WinMain中返回。WinMain的返回值成為程序的返回碼。傳統上,最后一個消息WM_QUIT的wParam參數值包含有返回值。為了響應應用程序對PostQuitMessage的調用,WM_QUIT消息被發送出去,此時WM_QUIT的wParam參數值被填充。
窗口過程
發送或提交(send 或 post方式)主窗口的消息被送到MainWndProc過程中。和所有窗口過程一樣,MainWndProc原型如下:
LRESULT CALLBACK MainWndProc (HWND hWnd, UINT wMsg, WPARAM wParam,
LPARAM lParam);
返回值類型LRESULT 實際上就是long型(在Windows里long是一個32位值),寫成這種形式是為源代碼和機器之間提供一個中間級。雖然你可以輕易的從包含文件中確定Windows編程時使用的變量的真實類型,但當你試圖把代碼做跨平臺的轉換時會產生問題。雖然了解變量類型的大小對計算內存使用是有用的,但沒有什么好的理由去使用(實際上有很多不使用的理由)windows.h文件中提供的類型定義。
CALLBACK 類型指明該函數是EXE的外部入口點,這是Windows直接調用該過程所必須的。在桌面系統里,CALLBACK 指出參數是按類Pascal風格從右到左方式壓進程序棧的,這和標準C語言方式相反。為外部入口點使用Pascal語言棧框架的原因可以追朔到Windows開發非常早的時期。使用固定大小、Pascal棧方式,意味著由被調用的過程來清理棧,而不是留給調用者來清理。這種方式可以有效的減少Windows及其附屬程序的大小,所以早期的微軟開發者認為這是一個好的方式。在Windows CE里,應用程序對所有函數都使用C??蚣?#xff0c;不管是否是外部調用。
傳給窗口過程的第一個參數是窗口句柄,當您需要定義具體的窗口實例的時候,這個句柄是很有用的。wMsg參數表示發給窗口的消息。這不是WinMain消息循環里使用的MSG結構,而是一個包含消息值的unsigned整型。剩余兩個參數,wParam 和lParam, 傳遞和具體消息有關的數據給窗口過程。它們的名字來自Win16時代,那時wParam是個16位值而lParam是32位值。同其它Win32操作系統一樣,在Windows CE里,兩個都是32位的。
和傳統的窗口過程一樣,Hello3的窗口過程通過一個switch語句解析wMsg消息ID。該switch語句包含2個case語句,一個用來解析WM_PAINT消息,另一個用來解析WM_DESTROY消息。這個窗口過程大概是窗口過程所能簡化到及至的一個窗口過程了。
WM_PAINT
繪制窗口,處理WM_PAINT消息,這在任何Windows 程序中都是很重要的功能之一。窗口的外觀是在程序處理WM_PAINT消息的過程中完成的。除了用您在注冊窗口類時指定的刷子繪制默認背景外,Windows對處理該消息不提供任何幫助。Hello3中處理WM_PAINT消息如下:
case WM_PAINT:
// Get the size of the client rectangle
GetClientRect (hWnd, &rect);
hdc = BeginPaint (hWnd, &ps);
DrawText (hdc, TEXT ("Hello Windows CE!"), -1, &rect,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
EndPaint (hWnd, &ps);
return 0;
在窗口繪制之前,程序必須確定窗口大小。在Windows程序里,一個標準窗口被劃分為兩個區域--非客戶區和客戶區。窗口標題欄和可變大小的邊框通常占據了窗口的非客戶區,這個區域由Windows負責繪制??蛻魠^屬于窗口的內部區域,由應用程序負責繪制。應用程序通過調用GetClientRect 函數來確定客戶區的大小和位置。該函數返回一個RECT結構,包含左上角、右下角坐標等描述客戶區矩形邊界的信息。分成客戶區和非客戶區的好處是,應用程序不必繪制那些窗口標準元素,例如標題欄。
其它版本的Windows提供一系列WM_NCxxx消息,允許您的應用程序繪制非客戶區。在Windows CE里,窗口很少有標題欄。因為很少有非客戶區,所以Windows CE不發送非客戶端消息給窗口過程。
WM_PAINT消息里執行的所有繪制工作都必須由兩個函數BeginPaint 和EndPaint包圍。BeginPaint 函數返回設備環境句柄HDC。設備環境是物理顯示設備(例如視頻顯示器或打印機)的邏輯代表。Windows程序從不直接修改顯示硬件。相反,Windows用設備環境將程序與具體硬件隔離開。
BeginPaint 填充一個PAINTSTRUCT結構,其結構如下:
typedef struct tagPAINTSTRUCT {
HDC hdc;
BOOL fErase;
RECT rcPaint;
BOOL fRestore;
BOOL fIncUpdate;
BYTE rgbReserved[32];
} PAINTSTRUCT;
hdc就是BeginPaint函數返回的句柄。fErase指出窗口過程是否需要重畫窗口背景。rcPaint是RECT結構,定義了需要重畫的客戶區。并假設在每個WM_PAINT消息中,整個客戶區窗口都需要重畫。當性能是需要考慮的問題時,該域是很有用的,因為有時僅僅需要重畫部分窗口即可。即使當程序嘗試重畫rcPaint矩形以外的區域時,Windows也會阻止這么做的。該結構的其它域,fRestore, fIncUpdate, 和rgbReserved,屬于Windows內部使用,應用程序可以忽略掉它們。
程序中唯一的繪制工作是在窗口繪制一行文本。程序調用DrawText函數來完成該繪制。如果您看一下該函數,很容易會明白這個調用在窗口上繪制了一行字符串“Hello Windows CE”。在DrawText返回后,調用EndPaint來通知Windows程序已經完成了窗口更新。
EndPaint調用同時也使沒有被繪制的窗口其它區域有效。Windows保持一份無效窗口區域(也就是需要重畫的區域)列表和有效區域(也就是已經更新的區域)列表。不論您是否在窗口畫了什么,通過成對的調用BeginPaint和EndPaint,會通知Windows由您來處理窗口的無效區域。實際上,您必須調用BeginPaint和EndPaint,或者通過其它方式使窗口無效區域變有效,否則Windows會不斷發送WM_PAINT消息給窗口,直到無效區域變有效。
WM_DESTROY
程序中處理的另一個消息是WM_DESTROY。當窗口即將被銷毀時,該消息被送出。因為該窗口是應用程序主窗口,當窗口被銷毀時應用程序將終止。處理WM_DESTROY消息的代碼調用PostQuitMessage消息來觸發該動作。PostQuitMessage函數將WM_QUIT消息放到到消息隊列里。該函數的參數是返回碼的值,該值放在WM_QUIT消息的wParam參數里傳回應用程序。
如前所述,消息循環看到WM_QUIT消息就會退出循環。WinMain 接著調用TermInstance,在Hello3里,該函數什么也不做,只是返回。WinMain 接著返回,并終止程序。
轉載于:https://blog.51cto.com/xyzlmn/818943
總結
以上是生活随笔為你收集整理的对VS2008生成智能win32程序简单理解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 结对开发——求最大值
- 下一篇: codeforce 606A - Mag