想作Windows平臺高級工程師,卻連窗口原理都不懂,朋友都勸我放棄~

一、Windows程序開發流程:

Windows 程序分爲「程序代碼」和「UI資源」兩大部分,經過RC編譯器整合爲一個完整的EXE 文件。程序員

所謂UI 資源是指功能菜單、對話框外貌、程序圖標、光標形狀等等東西。編程

這些UI 資源的實際內容(二進制代碼)系藉助各類工具產生,並以各類擴展名存在,如.ico、.bmp、.cur 等等。程序員必須在一個所謂的資源描述檔(.rc)中描述它們。windows

RC 編譯器(RC.EXE)讀取RC 檔的描述後將全部UI資源檔集中製做出一個.RES 檔,再與程序代碼結合在一塊兒,這纔是一個完整的Windows可執行文件。數據結構

二、Windows程序與操做系統之間的關係

Windows 程序的進行系依靠外部發生的事件來驅動。換句話說,程序不斷等待(利用一個while 迴路),等待任何可能的輸入,而後作判斷,而後再作適當的處理。上述的「輸入」是由操做系統捕捉到以後,以消息形式(一種數據結構)進入程序之中。函數

三、Windows窗口生命週期以下:

1.程序初始化過程當中調用CreateWindow,爲程序創建了一個窗口,做爲程序的屏幕舞臺。CreateWindow產生窗口以後會送出 wM_CREATE直接給窗口函數,後者因而能夠在此時作些初始化操做(例如配置內存、打開文件、讀初始數據……)。工具

2在程序活着的過程當中,不斷以 GetMessage從消息隊列中抓取消息。若是這個消息是WM_oUIT,GetMessage會傳回0而結束while循環,進而結束整個程序。開發工具

3.DispatchMessage經過Windows USER模塊的協助與監督,把消息分派至窗口函數。消息將在該處被判別並處理。ui

4.程序不斷進行第2步和第3步的操做。spa

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窗體的產生過程:

  1. 設計窗口類、
  2. 註冊窗口類、
  3. 建立窗口、
  4. 顯示窗口、
  5. 啓動消息循環泵循環獲取消息分發到窗體過程函數處理。

貼上一個標準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.替換內建的窗體函數,將消息傳到自定義的窗體過程函數處理,這就是常見的控件子類化原理

須要Windows操做系統和開發工具的小夥伴,能夠加羣免費領取噢~

相關文章
相關標籤/搜索