一個(gè)典型的Win32窗口應用程序的框架是這樣的:
程序入口點(diǎn)(WinMain函數)-->注冊窗口類(lèi)(調用ReGISterClass函數或RegisterClassEx函數)-->創(chuàng )建主窗口(調用CreateWindow函數或CreateWindowEx函數)-->顯示主窗口(調用ShowWindow函數)-->更新主窗口(調用UpdateWindow函數)-->進(jìn)入消息循環(huán)(GetMessage、TranslateMessage、DispatchMessage)并處理各種Windows消息(窗口過(guò)程函數)-->程序出口點(diǎn)(WinMain返回)。就像下面這個(gè)例子一樣:
#include<Windows.h>
#include<tchar.h>
//窗口類(lèi)名和窗口標題
TCHARszWindowClass[]=_T("HELLOWINDOWS");
TCHARszWindowTitle[]=_T("ThisistheMAINwindow");
//窗口過(guò)程函數
LRESULTCALLBACKWndProc(HWNDhWnd,UINTmsg,WPARAMwParam,LPARAMlParam)
{
//LogMessage(logfile,msg,wParam,lParam);//
switch(msg)
{
caseWM_DESTROY:
PostQuitMessage(0);
return0;
default:
returnDefWindowProc(hWnd,msg,wParam,lParam);
}
}
intWINAPI_tWinMain(HINSTANCEhInstance,HINSTANCE,LPTSTRlpCmdLine,intnCmdShow)
{
//注冊窗口類(lèi)
WNDCLASSEXwcex;
wcex.cbSize =sizeof(WNDCLASSEX);
wcex.style =CS_HREDRAW|CS_VREDRAW;
wcex.lpfnWndProc=(WNDPROC)WndProc;
wcex.cbClsExtra =0;
wcex.cbWndExtra =0;
wcex.hInstance =hInstance;
wcex.hIcon =NULL;
wcex.hCursor =LoadCursor(NULL,IDC_ARROW);
wcex.hbrBackground=(HBRUSH)(COLOR_WINDOW 1);
wcex.lpszMenuName=NULL;
wcex.lpszClassName=szWindowClass;
wcex.hIconSm =NULL;
RegisterClassEx(&wcex);
//創(chuàng )建主窗口
HWNDhWnd=CreateWindowEx(0,szWindowClass,szWindowTitle,WS_OVERLAPPEDWINDOW,
128,96,512,480,HWND_DESKTOP,NULL,hInstance,NULL);
if(!hWnd)
returnFALSE;
//顯示并更新主窗口
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
//進(jìn)入消息循環(huán)
MSGmsg;
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
//程序退出
}
這個(gè)例子很十分簡(jiǎn)單,只是顯示一個(gè)窗口就完事了;不過(guò)麻雀雖小,五臟俱全,它基本上可以作為一個(gè)Win32窗口程序的框架了。
下面來(lái)看它的窗口過(guò)程WndProc,它只處理了一個(gè)消息:WM_DESTROY,其余的消息都交給了Windows去處理(調用DefWindowProc)。對于一個(gè)實(shí)際的Windows程序來(lái)說(shuō),要在窗口過(guò)程中處理的消息會(huì )很多;然而Windows消息成百上千,無(wú)論你處理多少消息,剩下的你還是得調用DefWindowProc交給Windows系統去處理。這次我們就來(lái)看看,從程序啟動(dòng)到退出,DefWindowProc到底要幫我們做多少的工作。
實(shí)驗的思想很簡(jiǎn)單,把所有傳遞給窗口過(guò)程的消息都記錄在一個(gè)Log文件中,我們就可以察看在一個(gè)程序的生命過(guò)程中的所有消息了。在上面的例子中,我們在窗口函數WndProc的最開(kāi)始調用一個(gè)方法(形如注釋掉的那一行:LogMessage(logfile,msg,wParam,lParam)),把傳遞來(lái)的消息類(lèi)型,WPARAM參數,LPARAM參數順序都記錄下來(lái),就會(huì )形成一個(gè)WIndows消息Log文件了。
下面是兩次實(shí)驗的結果(假設上面的例子編譯后得到HelloWin.EXE):
實(shí)驗一:在文件管理其中選中HelloWin.EXE,按回車(chē)鍵啟動(dòng),顯示主窗口后馬上按下ALT F4把它關(guān)閉,得到的LOG文件如下:
時(shí)間 消息碼 參數 參數 描述
HH:MM:SS.MSS MSG WPARAM LPARAM DECRIPTION
03:21:39.187 0x0024 0x00000000 0x0012F910 WM_GETMINMAXINFO 獲取最大化最小化信息
03:21:39.187 0x0081 0x00000000 0x0012F908 WM_NCCREATE 窗口非客戶(hù)區被創(chuàng )建
03:21:39.187 0x0083 0x00000000 0x0012F930 WM_NCCALCSIZE 計算非客戶(hù)區的大小
(WPARAM:FALSE->不必指出窗口客戶(hù)區的有效區域)
03:21:39.187 0x0001 0x00000000 0x0012F8D4 WM_CREATE 主窗口被創(chuàng )建
03:21:39.187 0x0018 0x00000001 0x00000000 WM_SHOWWINDOW
(WPARAM:TRUE->顯示窗口LPARAM:0->指出這個(gè)消息是調用ShowWindow函數發(fā)來(lái)的)
03:21:39.187 0x0046 0x00000000 0x0012FEB0 WM_WINDOWPOSCHANGING 窗口位置(包括大?。┱诟淖?br style="font-size: 14px; ">03:21:39.203 0x001C 0x00000001 0x00000584 WM_ACTIVATEAPP 窗口進(jìn)程激活狀態(tài)改變
(WPARAM:TRUE->Activate激活LPARAM:線(xiàn)程ID=0x0584)
03:21:39.203 0x0086 0x00000001 0x00000000 WM_NCACTIVATE 非客戶(hù)區的激活狀態(tài)需要改變
(WPARAM:TRUE->Activate激活)
03:21:39.203 0x007F 0x00000002 0x00000000 WM_GETICON 獲取小圖標2
(WPARAM:2---->ICON_SMALL2)
03:21:39.203 0x007F 0x00000000 0x00000000 WM_GETICON 獲取小圖標
(WPARAM:0---->ICON_SMALL)
03:21:39.203 0x007F 0x00000001 0x00000000 WM_GETICON 獲取大圖標
(WPARAM:1---->ICON_BIG)
03:21:39.203 0x0006 0x00000001 0x00000000 WM_ACTIVATE 窗口激活狀態(tài)改變
(WPARAM:1---->WA_ACTIVE激活)
03:21:39.203 0x0281 0x00000001 0xC000000F WM_IME_SETCONTEXT 輸入法TRUE->Active
03:21:39.203 0x0282 0x00000002 0x00000000 WM_IME_NOTIFY 輸入法IMN_OPENSTATUSWINDOW
03:21:39.203 0x0007 0x00000000 0x00000000 WM_SETFOCUS 窗口獲得輸入焦點(diǎn)
03:21:39.218 0x0085 0x00000001 0x00000000 WM_NCPAINT 非客戶(hù)區需要重畫(huà)
(WPARAM:1---->整個(gè)窗口(WindowFrame)都需要重畫(huà)
03:21:39.218 0x0014 0x0101005D 0x00000000 WM_ERASEBKGND 擦除背景
03:21:39.218 0x0047 0x00000000 0x0012FEB0 WM_WINDOWPOSCHANGED 窗口位置(包括大?。┮呀?jīng)改變
03:21:39.218 0x0083 0x00000001 0x0012FAEC WM_NCCALCSIZE 計算非客戶(hù)區的大小
(WPARAM:TRUE->NCCALCSIZE_PARAMS參數有效(根據該參數來(lái)計算重畫(huà)區域)
03:21:39.218 0x0085 0x00000001 0x00000000 WM_NCPAINT 非客戶(hù)區需要重畫(huà)
(WPARAM:1---->整個(gè)窗口(WindowFrame)都需要重畫(huà)
03:21:39.218 0x0014 0x890109B8 0x00000000 WM_ERASEBKGND 擦除背景
03:21:39.218 0x0005 0x00000000 0x01BE01F8 WM_SIZE 窗口大小已經(jīng)改變
(WPARAM:0->SIZE_RESTORED既不是最大化也不是最小化(MSDN如此說(shuō)……))
03:21:39.218 0x0003 0x00000000 0x007E0084 WM_MOVE 窗口已被移動(dòng)
(LPARAM:x=84[132]y=7e[126]指出了窗口客戶(hù)區的新坐標)
03:21:39.218 0x000F 0x00000000 0x00000000 WM_PAINT 窗口客戶(hù)區需要重畫(huà)
03:21:39.218 0x007F 0x00000002 0x00000000 WM_GETICON 2---->ICON_SMALL2
03:21:39.218 0x007F 0x00000000 0x00000000 WM_GETICON 0---->ICON_SMALL
03:21:39.218 0x007F 0x00000001 0x00000000 WM_GETICON 1---->ICON_BIG
=================================================================================== 實(shí)驗二:在文件管理其中用鼠標雙擊HelloWin.EXE啟動(dòng)程序,顯示主窗口后馬上移動(dòng)鼠標到窗口右上角的關(guān)閉按鈕把它關(guān)閉,得到的LOG文件如下: 時(shí)間 消息碼 參數 參數 描述
03:21:39.375 0x0101 0x0000000D 0xC01C0001 WM_KEYUP 鍵盤(pán)有按鍵被按下
(WPARAM:0D--->VK_RETURN(回車(chē)鍵)LPARAM:RECNT:1;SCCODE:1C;NON-EXKEY)
03:21:41.000 0x0104 0x00000012 0x20380001 WM_SYSKEYDOWN 系統鍵被按下
(WPARAM:12--->VK_MENU(ALT鍵) LPARAM:RECNT:1;SCCODE:38;ALT-DOWN)
03:21:41.609 0x0104 0x00000073 0x203E0001 WM_SYSKEYDOWN 系統鍵被按下
(WPARAM:73--->VK_F4(F4鍵) LPARAM:RECNT:1;SCCODE:3E;ALT-DOWN(ALT鍵同時(shí)被按下))
=======================================================================================
03:21:41.609 0x0112 0x0000F060 0x00000000 WM_SYSCOMMAND 系統命令
(WPARAM:F060->SC_CLOSE)
03:21:41.609 0x0010 0x00000000 0x00000000 WM_CLOSE 窗口需要被關(guān)閉
03:21:41.609 0x0046 0x00000000 0x0012F8A0 WM_WINDOWPOSCHANGING 窗口位置(包括大?。┱诟淖?br style="font-size: 14px; ">03:21:41.609 0x0047 0x00000000 0x0012F8A0 WM_WINDOWPOSCHANGED 窗口位置(包括大?。┮呀?jīng)改變
03:21:41.609 0x0086 0x00000000 0x00000000 WM_NCACTIVATE 窗口非客戶(hù)區激活狀態(tài)改變
(WPARAM:FALSE->InActivate非激活狀態(tài))
03:21:41.625 0x0006 0x00000000 0x00000000 WM_ACTIVATE 窗口激活狀態(tài)改變
(WPARAM:0----->WA_INACTIVATE非激活狀態(tài))
03:21:41.625 0x001C 0x00000000 0x00000584 WM_ACTIVATEAPP 窗口進(jìn)程激活狀態(tài)改變
(WPARAM:FALSE->InActivate TID=0584)
03:21:41.625 0x0008 0x00000000 0x00000000 WM_KILLFOCUS 窗口失去輸入焦點(diǎn)
03:21:41.625 0x0281 0x00000000 0xC000000F WM_IME_SETCONTEXT 輸入法FALSE->InActivate
03:21:41.625 0x0282 0x00000001 0x00000000 WM_IME_NOTIFY 輸入法IMN_CLOSESTATUSWINDOW
03:21:41.625 0x0002 0x00000000 0x00000000 WM_DESTROY 窗口被銷(xiāo)毀
03:21:41.625 0x0082 0x00000000 0x00000000 WM_NCDESTROY 窗口非客戶(hù)區被銷(xiāo)毀
HH:MM:SS.MSS MSG WPARAM LPARAM DECRIPTION
04:29:01.421 0x0024 0x00000000 0x0012F910 WM_GETMINMAXINFO
04:29:01.421 0x0081 0x00000000 0x0012F908 WM_NCCREATE
04:29:01.421 0x0083 0x00000000 0x0012F930 WM_NCCALCSIZE
04:29:01.421 0x0001 0x00000000 0x0012F8D4 WM_CREATE
04:29:01.421 0x0018 0x00000001 0x00000000 WM_SHOWWINDOW
04:29:01.421 0x0046 0x00000000 0x0012FEB0 WM_WINDOWPOSCHANGING
04:29:01.437 0x001C 0x00000001 0x00000584 WM_ACTIVATEAPP
04:29:01.437 0x0086 0x00000001 0x00000000 WM_NCACTIVATE
04:29:01.437 0x007F 0x00000002 0x00000000 WM_GETICON
04:29:01.437 0x007F 0x00000000 0x00000000 WM_GETICON
04:29:01.437 0x007F 0x00000001 0x00000000 WM_GETICON
04:29:01.437 0x0006 0x00000001 0x00000000 WM_ACTIVATE
04:29:01.437 0x0281 0x00000001 0xC000000F WM_IME_SETCONTEXT
04:29:01.437 0x0007 0x00000000 0x00000000 WM_SETFOCUS
04:29:01.437 0x0085 0x00000001 0x00000000 WM_NCPAINT
04:29:01.437 0x0014 0x840108B2 0x00000000 WM_ERASEBKGND
04:29:01.437 0x0047 0x00000000 0x0012FEB0 WM_WINDOWPOSCHANGED
04:29:01.437 0x0083 0x00000001 0x0012FAEC WM_NCCALCSIZE
04:29:01.437 0x0085 0x00000001 0x00000000 WM_NCPAINT
04:29:01.437 0x0014 0x0F01093A 0x00000000 WM_ERASEBKGND
04:29:01.437 0x0005 0x00000000 0x01BE01F8 WM_SIZE
04:29:01.437 0x0003 0x00000000 0x007E0084 WM_MOVE
04:29:01.437 0x000F 0x00000000 0x00000000 WM_PAINT
04:29:01.437 0x007F 0x00000002 0x00000000 WM_GETICON
04:29:01.437 0x007F 0x00000000 0x00000000 WM_GETICON
04:29:01.437 0x007F 0x00000001 0x00000000 WM_GETICON
========================================================================================
04:29:01.828 0x0084 0x00000000 0x009E0266 WM_NCHITTEST 光標移動(dòng)或鼠標鍵被按下
(LPARAM:當前光標位置(相對于屏幕左上角)x=0266[614]y=009E[236])
04:29:01.828 0x0020 0x00A40268 0x02000001 WM_SETCURSOR 鼠標導致的光標移動(dòng)
(LPARAM:Hit-Test碼:01->HTCLIENT在客戶(hù)區 鼠標消息碼:0200->MOUSEMOVE鼠標移動(dòng))
04:29:01.828 0x0200 0x00000000 0x002001E2 WM_MOUSEMOVE 鼠標移動(dòng)
(LPARAM:鼠標當前位置x=01E2[482]y=0020[32])
*************此處省略N個(gè)[WM_NCHITTEST-WM_SETCURSOR-WM_MOUSEMOVE]消息***************
04:29:01.984 0x0084 0x00000000 0x007F0268 WM_NCHITTEST
(LPARAM:當前光標位置(相對于屏幕左上角)x=0268[616]y=007F[127])
04:29:01.984 0x0020 0x00A40268 0x02000001 WM_SETCURSOR
(LPARAM:Hit-Test碼:01->HTCLIENT在客戶(hù)區 鼠標消息碼:0200->MOUSEMOVE鼠標移動(dòng))
04:29:01.984 0x0200 0x00000000 0x000101E4 WM_MOUSEMOVE
(LPARAM:鼠標當前位置x=01E4[484]y=0001[1])
04:29:02.000 0x0084 0x00000000 0x007D0269 WM_NCHITTEST
(LPARAM:當前光標位置(相對于屏幕左上角)x=0269[617]y=007D[125])
04:29:02.000 0x0020 0x00A40268 0x02000002 WM_SETCURSOR 鼠標導致的光標移動(dòng)
(LPARAM:Hit-Test碼:02->HTCAPTION在標題區 鼠標消息碼:0200->MOUSEMOVE鼠標移動(dòng))
04:29:02.000 0x00A0 0x00000002 0x007D0269 WM_NCMOUSEMOVE 非客戶(hù)區的鼠標移動(dòng)
(WPARAM:Hit-Test碼:02->HTCAPTION LPARAM:光標位置:x=0269[617]y=007D[125])
************此處省略N個(gè)[WM_NCHITTEST-WM_SETCURSOR-WM_MOUSEMOVE]消息******************
04:29:02.234 0x0084 0x00000000 0x0075026D WM_NCHITTEST
(LPARAM:當前光標位置(相對于屏幕左上角)x=026D[621]y=0075[117])
04:29:02.234 0x0020 0x00A40268 0x02000014 WM_SETCURSOR
(LPARAM:Hit-Test碼:14->HTTOPRIGHT在右上角 鼠標消息碼:0200->MOUSEMOVE鼠標移動(dòng))
04:29:02.234 0x00A0 0x00000014 0x0075026D WM_NCMOUSEMOVE
(WPARAM:Hit-Test碼:14->HTTOPRIGHT LPARAM:光標位置:x=026D[621]y=0075[117]
04:29:02.296 0x0084 0x00000000 0x0075026D WM_NCHITTEST
(LPARAM:當前光標位置(相對于屏幕左上角)x=026D[621]y=0075[117])
04:29:02.296 0x0020 0x00A40268 0x02010014 WM_SETCURSOR
(LPARAM:Hit-Test碼:14->HTTOPRIGHT在右上角 鼠標消息碼:0201->LBUTTONDOWN鼠標左鍵被按下
04:29:02.296 0x00A1 0x00000014 0x0075026D WM_NCLBUTTONDOWN 鼠標左鍵在非客戶(hù)區按下
(LPARAM:當前光標位置(相對于屏幕左上角)x=026D[621]y=0075[117])
04:29:02.484 0x0215 0x00000000 0x00000000 WM_CAPTURECHANGED 正在失去鼠標捕獲
(LPARAM:0---->HWND_DESKTOP桌面將要獲得鼠標)
===========================================================================================
04:29:02.484 0x0112 0x0000F060 0x0075026D WM_SYSCOMMAND F060-->SC_CLOSE
04:29:02.484 0x0010 0x00000000 0x00000000 WM_CLOSE
04:29:02.484 0x0046 0x00000000 0x0012F5E4 WM_WINDOWPOSCHANGING
04:29:02.484 0x0047 0x00000000 0x0012F5E4 WM_WINDOWPOSCHANGED
04:29:02.484 0x0086 0x00000000 0x00000000 WM_NCACTIVATE
04:29:02.484 0x0006 0x00000000 0x00000000 WM_ACTIVATE
04:29:02.484 0x001C 0x00000000 0x00000584 WM_ACTIVATEAPP
04:29:02.484 0x0008 0x00000000 0x00000000 WM_KILLFOCUS
04:29:02.484 0x0281 0x00000000 0xC000000F WM_IME_SETCONTEXT
04:29:02.484 0x0282 0x00000001 0x00000000 WM_IME_NOTIFY
04:29:02.484 0x0002 0x00000000 0x00000000 WM_DESTROY
04:29:02.484 0x0082 0x00000000 0x00000000 WM_NCDESTROY
在實(shí)驗二中,打星號(*)的部分省略了很多個(gè)[WM_NCHITTEST-WM_SETCURSOR-WM_MOUSEMOVE]消息,鼠標移動(dòng)過(guò)程中它們一直產(chǎn)生,唯一不同的是指示的鼠標位置不同。
由上兩個(gè)LOG文件記錄的Windows消息可以對比看出,從我們開(kāi)始啟動(dòng)程序(無(wú)論是從鍵盤(pán)還是鼠標雙擊啟動(dòng))到主窗口最終顯示在我們面前,Windows已經(jīng)處理了從開(kāi)始的WM_GETMINMAXINFO消息到第一條雙劃線(xiàn)前的WM_GETICON消息;而從我們關(guān)閉一個(gè)窗口(無(wú)論是按下ALT F4還是鼠標點(diǎn)擊“關(guān)閉”按鈕)到程序最后退出,Windows要處理從第二條雙劃線(xiàn)后的WM_SYSCOMMAND到最后的WM_NCDESTROY消息。而程序在運行過(guò)程中產(chǎn)生的消息在兩條雙劃線(xiàn)之間(有上面兩個(gè)LOG文件可以看出區別來(lái),跟程序的行為相關(guān)的)。值得一提的是程序最后收到的一條消息WM_QUIT,是由PostQuitMessage函數發(fā)送的,在消息循環(huán)中被GetMessage捕獲,GetMessage函數捕獲到WM_QUIT消息之后返回FALSE,于是WinMain函數退出消息循環(huán),是不交給窗口過(guò)程去處理的,所以上面沒(méi)有記錄下來(lái);之后程序便退出了。
在寫(xiě)windows程序的時(shí)候,我們也可以通過(guò)記錄windows消息的方式去調試程序的,至于怎么來(lái)我就不羅嗦啦:)
聯(lián)系客服