1、Windows程式開發流程:
Windows 程式分為「程式程式碼」和「UI資源」兩大部分,透過RC編譯器整合為一個完整的EXE 檔案。
所謂UI 資源是指功能選單、對話方塊外貌、程式圖示、游標形狀等等東西。
這些UI 資源的實際內容(二進位制程式碼)系藉助各種工具產生,並以各種副檔名存在,如.ico、.bmp、.cur 等等。程式設計師必須在一個所謂的資源描述檔(.rc)中描述它們。
RC 編譯器(RC.EXE)讀取RC 檔的描述後將所有UI資源檔集中製作出一個.RES 檔,再與程式程式碼結合在一起,這才是一個完整的Windows可執行檔案。
2、Windows程式與作業系統之間的關係Windows 程式的進行系依靠外部發生的事件來驅動。換句話說,程式不斷等待(利用一個while 迴路),等待任何可能的輸入,然後做判斷,然後再做適當的處理。上述的「輸入」是由作業系統捕捉到之後,以訊息形式(一種資料結構)進入程式之中。
3、Windows視窗生命週期如下:1.程式初始化過程中呼叫CreateWindow,為程式建立了一個視窗,作為程式的螢幕舞臺。CreateWindow產生視窗之後會送出 wM_CREATE直接給視窗函式,後者於是可以在此時做些初始化操作(例如配置記憶體、開啟檔案、讀初始資料……)。
2在程式活著的過程中,不斷以 GetMessage從訊息佇列中抓取訊息。如果這個訊息是WM_oUIT,GetMessage會傳回0而結束while迴圈,進而結束整個程式。
3.DispatchMessage透過Windows USER模組的協助與監督,把訊息分派至視窗函式。訊息將在該處被判別並處理。
4.程式不斷進行第2步和第3步的操作。
5.當使用者按下系統選單中的Close命令項時,系統送出WM_CLOSE。通常程式的視窗函式不攔截此訊息,於是 DefWindowProc處理它。
6.DefWindowProc收到 WM_CLOSE後,呼叫 DestroyWindow把視窗清除。Destroy Window本身又會送出WM_DESTROY。
7.程式對WM_DESTROY的標準反應是呼叫PostQuitMessage。
8.PostQuitMessage沒什麼其它操作,就只送出 WM_QUIT 訊息,準備讓訊息迴圈中的GetMessage取得,如步驟2,結束訊息迴圈。
3.Windows窗體原理Windows的三大核心繫統:負責視窗物件產生和訊息分發的USER模組,負責影象顯示繪製的GDI模組,負責記憶體、程序、IO管理的KERNEL模組。
試想象一下如何在一個畫素陣列上產生視窗物件,其實就是使用GDI繪製視窗,不停的以一定的頻率重新整理顯示在螢幕上,這就是圖形介面,如果由在DOS或Windows DOS模擬器下編寫圖形介面的經驗這個比較好理解。所以說其實USER模組中的視窗產生是依靠GDI模組的(包括選單、捲軸等都是使用GDI來繪製的)。
那麼,下面我們就從USER模組和GDI模組來說說Windows 的窗體原理。
如果接觸過Win32 SDK程式設計的知道一個標準Windows窗體的產生過程:
設計視窗類、註冊視窗類、建立視窗、顯示視窗、啟動訊息迴圈泵迴圈獲取訊息分發到窗體過程函式處理。貼上一個標準Windows窗體的產生程式碼:
#include <windows.h> LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ static TCHAR szAppName[] = TEXT ("視窗類名稱"); HWND hwnd; MSG msg; WNDCLASSEX wndclassex = {0}; //設計視窗類 wndclassex.cbSize = sizeof(WNDCLASSEX); wndclassex.style = CS_HREDRAW | CS_VREDRAW; wndclassex.lpfnWndProc = WndProc; wndclassex.cbClsExtra = 0; wndclassex.cbWndExtra = 0; wndclassex.hInstance = hInstance; wndclassex.hIcon = LoadIcon (NULL, IDI_APPLICATION); wndclassex.hCursor = LoadCursor (NULL, IDC_ARROW); wndclassex.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH); wndclassex.lpszMenuName = NULL; wndclassex.lpszClassName = szAppName; wndclassex.hIconSm = wndclassex.hIcon; //註冊視窗類 if (!RegisterClassEx (&wndclassex)) { MessageBox (NULL, TEXT ("RegisterClassEx failed!"), szAppName, MB_ICONERROR); return 0; } //產生視窗 hwnd = CreateWindowEx (WS_EX_OVERLAPPEDWINDOW, szAppName, TEXT ("視窗名稱"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); //顯示視窗 ShowWindow (hwnd, iCmdShow); UpdateWindow (hwnd); //啟動訊息迴圈泵迴圈獲取訊息分配到窗體過程函式處理 while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg); DispatchMessage (&msg); } return msg.wParam;} //窗體過程函式LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){ HDC hdc; PAINTSTRUCT ps; switch (message) { case WM_CREATE: return (0); case WM_PAINT: hdc = BeginPaint (hwnd, &ps); EndPaint (hwnd, &ps); return (0); case WM_DESTROY: PostQuitMessage (0); return (0); } return DefWindowProc (hwnd, message, wParam, lParam);}
需要明白的是,所有Windows的窗體及控制元件歸根結底都是使用CreateWindow或CreateWindowEx來建立的,他們都需要標準Windows窗體的產生過程。
普通的窗體好理解,主要需要弄清楚是對話方塊及控制元件的產生和訊息分派處理流程。
對話方塊及其子控制元件的管理依靠Windows內建的對話方塊管理器,對話方塊管理器的工作包括:
1.根據我們在資源設計器中設計的對話方塊及子控制元件產生的.rc檔案來自動生成對話方塊和子控制元件(如果有手動編寫.rc檔案的經歷的話,知道編寫RC檔案其實就是指定視窗和子控制元件大小、型別、樣式等引數,對話方塊管理器將這些引數傳入CreateWindow函式產生窗體)
2.模態對話方塊直接顯示窗體,非模態對話方塊訊息指明WS_VISIBLE屬性的話,需要呼叫ShowWindow來顯示窗體。
3.維護一個訊息迴圈泵,對於模態對話方塊來說這個訊息泵的訊息不經過父視窗,所以表現為模態;對於非模態對話方塊這個訊息泵訊息經過主視窗,必須由主視窗傳給非模態對話方塊,表現為非模態。
4.維護一個內建的窗體過程函式,對於對話方塊來說會處理對話方塊的關閉開啟及子視窗的焦點、tab等,對於子控制元件也是一樣,每個子控制元件會有自己型別的窗體過程函式,窗體過程函式處理子控制元件的獲得或失去焦點、按下或彈起、建立等表現樣式和行為。
對於對話方塊來說,他會開放一個對話方塊過程函式,讓部分訊息先透過對話方塊管理函式處理,如果對話方塊過程函式不處理才交給預設的內建過程函式處理,對於子控制元件來說,他們並沒有開放過程函式,而是由內建窗體函式將要處理的訊息發給父視窗處理。
那麼對話方塊管理器完成了標準Windows窗體的產生中後半部分工作,至於設計視窗類和註冊視窗類這是由Windows自己預先做好了的,如常見的“button”、“listbox”、“edit”類等等。
那麼既然所有的窗體(包括對話方塊和控制元件)產生過程一樣,那麼我們就可以將對話方塊管理器的部分工作替換掉:
1.不使用對話方塊讀取.rc模板的方式,直接將引數傳遞給CreateWindow函式來建立對話方塊和控制元件,這就是常見的動態建立控制元件原理。
2.設定控制元件自繪製如BS_OWNDRAW屬性,開放控制元件的WM_DRAWITEM訊息給父視窗,由父視窗來繪製按鈕樣式,這就是常見的控制元件重繪原理。
3.替換內建的窗體函式,將訊息傳到自定義的窗體過程函式處理,這就是常見的控制元件子類化原理。
下一節講:MFC對話方塊原理