前言:
最近在看侯捷的《深入淺出MFC》,在理解MFC時覺得必須要掌握win32,才能更好的理解MFC,才能寫出更有用的程式。於是將自己對win32程式的理解寫了下來,供朋友們參考。文中的兩幅圖是從書中截取的。
本文:
現在有很多想走VC這條路的朋友,一開始就是MFC,雖然啃過一段時間書後,能寫出一些小程式,但越往後你就會越覺得困難。我的一個網友昨天跟我聊天的時候說“TMD,MFC用的越來越覺得不爽,早知道開始學VC的時候聽朋友之勸,先學Win32編程好了”。的確,MFC把大部分精華都封裝起來了,我們只能用它現成的庫,或尤其派生出一些自己的庫。如果不瞭解Win32編程,我們就不懂程式的運作原理,那麼我們如何操控程式,我們還哪有自主權?
如果你從來沒有在事件驅動(event driven)系統中撰寫過以訊息為基礎(message based)的應用程式,就想一步跨入MFC,直接用Application wizard開發windows程式,我覺得不大可能。雖然你可以繼承MFC中的類,來開發出一個頗具規模的windows應用程式,但如果你不瞭解windows程式的運作本質(event driven,message based ),是不可能進入高深境界的。正如侯大師所言:“勿在浮沙築高台”,不會走千萬別想跑。
在正式學習MFC之前,需要掌握的東西(個人認為)有:瞭解windows程式的事件驅動機制(包括訊息的產生、捕獲、指派和處理等)。另外還有一個比較重要的就是C++中多態(polymorphism)和虛函數的理解(不說精通,起碼也得達到熟練)。
下面簡單說一下Win32程式架構。
一個Win32程式是由程式碼和UI(User Interface)兩大部分組成,當我們編輯好這兩部分後,再由RC(resource compiler)編譯器將這兩部分整合成一個EXE檔案。程式碼不用說了,UI資源指的是一些如菜單、對話方塊、位元影像、滑鼠指標、表徵圖等,我們必須在一個.rc檔案中描述它們。
另外,程式要想成功編譯運行,還需要加入一些函數庫和標頭檔。Windows程式調用的函數可以分為C Runtimes和Windows API兩種,LIBC.LIB是C Runtimes的靜態串連版,MSVCRT.LIB是C Runtimes的動態串連版。GDI32.DLL、USER32.DLL和KERNEL32.DLL是32位Windows API的三大函數庫。所有的windows程式都要包含windows.h,但windows.h只包含GDI32.DLL、USER32.DLL和KERNEL32.DLL中的函數,如果你還想加入別的dll,就需要加入相應的標頭檔。下面是win32程式開發的流程:
Windows程式的運行是靠外來事件來驅動的,就是說,程式一直出於一個等待的狀態,如果有一個事件發生,程式就會判斷是什麼事件,然後做出相應的處理。那麼每一個windows程式都必須有一個迴路才能實現一直等待。這個迴路如下:
MSG msg;
while( GetMessage( &msg, NULL, 0, 0 ) ){
TranslateMessage( &msg );
DispatchMessage( &msg );
}
MSG結構在windows內部是這樣定義的:
typedef struct tagMsg{
HWND hWnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG;
其中message就是指各種訊息,如WM_MOUSEMOVE、WM_DESTROY等。那麼誰來接收這個訊息並做出相應處理呢?就是視窗,這就需要我們為視窗設計一個函數,即所謂的視窗函數。視窗函數形如:
LRESULT CALLBACK WndProc( HWND hWnd,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
switch ( message ) {
case WM_LBUTTONDOWN:
…
case WM_MOUSEMOVE:
…
case WM_DESTROY:
PostQuitMessage ( 0 );
default:
return DefWindowProc ( hWnd, message, wParam, lParam );
}
return ( 0 );
}
CALLBACK是一種函數調用習慣,被定義為__stdcall,說明此函數為回呼函數,由系統自動調用的,當視窗接收到訊息並DispatchMessage之後,系統就自動調用視窗函數WndProc了。注意視窗函數中訊息的分支結構中default分支必須是return DefWindowProc ( hWnd, message, wParam, lParam );因為不論什麼訊息都必須被處理,DefWindowProc是windows內部預設的訊息處理函數。以上就是windows程式的精要所在,弄懂了這些,才能為學MFC作好準備。Win32程式的運行圖解如下:
那麼視窗的產生和顯示是怎麼實現的呢?下面我們就來產生一個簡單的win32SDK視窗,來看一下windows程式是如何把訊息擷取、指派並處理的,以及寫一個win32視窗程序的主要步驟:
一、程式進入點
windows程式的進入點是WinMain函數,它有四個參數,形式如下:
int WINAPI WinMain ( HINSTANCE hInst,
HINSTANCE hPrevInst,
LPSTR lpCmdLine,
int nCmdShow )
參數說明:hInst 為當前執行個體控制代碼,Windows 環境下用於區別同一應用程式的不同執行個體;hPrevInst應用程式先前執行個體的控制代碼(如果有的話),否則為 NULL,可以用來確定當前執行個體是否為應用程式的第一個執行個體;lpCmdLine是以NULL結尾的命令列字串長指標;nCmdShow指定視窗初始顯示方式的整型常量(1 = 通常;7 = 最小化) 。
二、註冊視窗類別
一個視窗在建立以前,必須進行一些初始化,比如視窗的大小、標題及邊框的顏色等,完成這些工作我們還必須一個API函數RegisterClass來註冊視窗類別:
WNDCLASS wndclass;
//初始化視窗的屬性
…………….
//註冊視窗類別
if(!RegisterClass(&wndclass))
{
MessageBeep(0);
return FALSE;
}
三、建立視窗
視窗屬性設定好並且註冊了視窗類別之後,我們就要建立一個視窗了,CreateWindow函數會完成這個工作,如:
hwnd=CreateWindow(
lpszClassName,
lpszTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL);
建立好視窗之後就要顯示視窗了,如下:
//顯示視窗
ShowWindow(hwnd,nCmdShow);
UpdateWindow(hwnd);
然後進步訊息迴圈,程式出於一直等待的狀態(除非你退出程式)。
//訊息迴圈
while(GetMessage(&Msg,NULL,0,0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
四、視窗函數
這是視窗的生命中樞,因為它是處理各種訊息的地方。上面訊息迴圈中DispatchMessage就是將訊息指派到視窗處理函數,視窗處理函數前面已經作了說明,這裡不再贅述。
這樣,一個win32視窗程序就寫好了,具體詳見附加代碼。
摘自:http://www.cnblogs.com/michaelxu/archive/2006/09/20/509043.html