WinAPI簡單入門
不要覺得奇怪,,雖然我們擁有眾多“所見即所得”的編程方式來開發(fā)眾多界面精美的應(yīng) 用程序,,這些可視化的編程環(huán)境提供了大量的類庫和控件,但是在開發(fā)者享受方便的同時,, 他們的手腳已經(jīng)不知不覺的受到了限制,,有很多深入到Windows內(nèi)部的操作它們無法完成, 為什么,?因為所用的類庫不支持,。
事實上這些類庫與控件都是架構(gòu)在Window API的基礎(chǔ)上面的,API即 Application Programming Interface -- 應(yīng)用編程接口 的縮寫,,它不僅為應(yīng)用程序所調(diào)用,,同時也是 Windows的一部分,Windows自身的運行也調(diào)用這些API函數(shù),。要了解如何使用API就必須了 解一些Windows的運行機制,。
簡單地說,Windows是由事件驅(qū)動的搶占式多任務(wù)操作系統(tǒng),。事件驅(qū)動是相對于過程驅(qū) 動而言的,,它改變了原來文件的順序執(zhí)行方式;Windows既然是多任務(wù)系統(tǒng),,就必須能同時 處理多個事件,,系統(tǒng)為應(yīng)用程序生成一個消息隊列,消息在上面被張貼和發(fā)送,,應(yīng)用程序只 要從其消息隊列中取出消息,,然后一一執(zhí)行就可以了。
現(xiàn)在,,我將使用最最基本的范例程序 HelloWin 來說明WIN32 API的運行機制
首先,,一個程序一定要有進入點,Win32 App的進入點函數(shù)的名稱是WinMain,,它的原型如下 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)
hInstance是所謂的“實例句柄”,它是一個數(shù)值,,當(dāng)程序在Windows下運行的時候,,它被用 來唯一的標(biāo)示這個程序,雖然用戶可能同時運行多個同一個程序,,即運行多個“實例”,,我 們可以看到,每一個實例都有不同的hInstance值,。
hPrevInstance,,簡單地說就是沒用…它是存在于16位Windows程序中的,在編寫 Windows 9x/NT/2000 程序的時候,,總應(yīng)該是NULL,。
szCmdLine是一個指針,,指向一個以0為終結(jié)的字串,里面包含傳給該程序的命令行參數(shù),, 如果想要讓程序處理命令行,,那么這個參數(shù)就有用了。
iCmdShow參數(shù)是一個數(shù)值,,指示窗口將如何被顯示,,這個數(shù)值由在Windows下運行該程序的 程序所決定,通常是SW_SHOWNORMAL,。
接下來是注冊一個窗口類,,窗口總是從窗口類的基礎(chǔ)上創(chuàng)建的,窗口類用以標(biāo)示處理窗口消 息的窗口過程,,注冊窗口類時使用 RegisterClassEx() 函數(shù),,它只需要一個參數(shù),一個指向 類型為 WNDCLASSEX 的結(jié)構(gòu)指針,。
具體注冊初始是這樣的: WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX); //結(jié)構(gòu)的大小
wcex.style = CS_HREDRAW | CS_VREDRAW; //類風(fēng)格 wcex.lpfnWndProc = (WNDPROC)WndProc; //窗口類的窗口過程 wcex.cbClsExtra = 0; //在類結(jié)構(gòu)中預(yù)留的空間 wcex.cbWndExtra = 0; //在Windows內(nèi)部保存的窗口結(jié)構(gòu)中預(yù)留的空間 wcex.hInstance = hInstance; //程序的實例句柄 wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_EXAMPLE); //程序圖標(biāo) wcex.hCursor = LoadCursor(NULL, IDC_ARROW); //結(jié)構(gòu)的大小 wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); //指定窗口的背景顏色 wcex.lpszMenuName = (LPCSTR)IDC_EXAMPLE; //菜單 wcex.lpszClassName = szWindowClass; //類名,,和程序名相同 wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); //也是程序圖標(biāo)
return RegisterClassEx(&wcex);
接下來,定義一個HWND,,然后使用 CreateWindow() 函數(shù),,原型如下: HWND CreateWindow( LPCTSTR lpClassName, // 窗口類名 LPCTSTR lpWindowName, // 窗口標(biāo)題 DWORD dwStyle, // 窗口風(fēng)格 int x, // 初始x int y, // 初始y int nWidth, // 窗口寬 int nHeight, // 窗口高 HWND hWndParent, // 父窗口句柄 HMENU hMenu, // 菜單句柄 HINSTANCE hInstance, // 實例句柄 LPVOID lpParam // 創(chuàng)建參數(shù) );
在 CreateWindow() 調(diào)用返回之后,Windows內(nèi)部已經(jīng)創(chuàng)建了這窗口,。但是窗口并為顯示,, 還需要兩個調(diào)用,一個是 ShowWindow(hwnd, iCmdShow):第一個參數(shù)是剛剛創(chuàng)建的窗口 句柄,,第二個參數(shù)是傳遞給WinMain的nCmdShow,;另一個是 UpdateWindow(hwnd) ,導(dǎo)致 客戶區(qū)域被繪制,。
接下來,,程序通過執(zhí)行一塊被稱為“消息循環(huán)”的代碼從消息隊列中取出消息
while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
消息循環(huán)以 GetMessage 開始,它從消息隊列中取出一條消息,,只要從消息隊列中取出消 息的 Message 域不為 WM_QUIT,,GetMessage 就返回一個非零值,否則將導(dǎo)致程序退出 消息循環(huán),,然后程序中止,,返回 msg 結(jié)構(gòu)的 wParam 參數(shù)。在循環(huán)中,,TranslateMessage 將 msg 結(jié)構(gòu)的內(nèi)容進行修改,,而 DispatchMessage 找出準(zhǔn)備調(diào)用的窗口過程。
上面進行的僅僅是準(zhǔn)備性工作:注冊窗口類,、創(chuàng)建窗口,、顯示窗口,、進入消息循環(huán)取出消息 而實際的動作都發(fā)生在窗口過程中。
LRESULT CALLBACK WndProc(HWND hWnd, //剛剛創(chuàng)建的窗口句柄 UINT message, //得到的消息 WPARAM wParam, LPARAM lParam //消息的進一步詳細的參數(shù) )
在程序中窗口過程通常是命名為 WndProc 的函數(shù),,其實窗口過程可以任意的命名,,一個 Windows程序可以包含多個窗口過程,一個窗口過程總是與調(diào)用了 RegisterClassEx 注冊的 窗口類相關(guān)聯(lián),,CreateWindow 函數(shù)根據(jù)窗口類來創(chuàng)建窗口,,但是一個窗口類可以被用來創(chuàng) 建多個窗口。
消息收到之后,,接下來應(yīng)該根據(jù)消息的不同來進行處理 switch(message) { case …: … …
HelloWin程序只需要處理兩條消息,,即 WM_PAINT 和 WM_DESTROY。
WM_PAINT 消息在Windows程序中的地位極其重要,,當(dāng)窗口客戶區(qū)的一部分或者全部變?yōu)?BR>“無效”,,必須進行刷新的時候,將由這條消息通知程序,。
為什么客戶區(qū)域會變得無效呢,?在創(chuàng)建窗口的時候,整個客戶區(qū)都是無效的,,因為還沒有畫 任何的東西,。第一條 WM_PAINT 消息指示窗口過程在窗口上面畫一些東西;還有在用戶改 變了窗口的大小之后,,客戶區(qū)域重新變得無效,,除此之外最小化窗口之后再還原、窗口的一 部分被覆蓋,,都會引發(fā)這條消息,。
WM_DESTROY消息則是當(dāng)用戶按下“關(guān)閉”按鈕的時候被觸發(fā),標(biāo)準(zhǔn)的處理方法是調(diào)用 PostQuitMessage 將一條 WM_QUIT 消息插入消息隊列,,這將使得 GetMessage 函數(shù)調(diào)用 返回0,,從而退出消息循環(huán),結(jié)束整個程序,。
其實,,從上面可以看出,Windows程序的這種運行機制并不是很難理解,,真正困難的是不知 道調(diào)用什么函數(shù)去完成想要的操作,以及怎樣調(diào)用那些函數(shù),,從而靈活的進行底層API程序 開發(fā),,這是一個循序漸進的積累過程,沒有捷徑可走的,。請各位一定要記住,。
|