第2個Wiindows程式講解
上次,我們一起寫了一個Windows視窗程式,這個視窗程式雖然非常簡單,但是,程式碼仍然很多,相信,一定會有很多初學者看見這些程式碼而感到頭疼。不用怕,現在,我們就一起來分析一下這些程式碼,相信通過我們共同的努力,一定可以克服這些難題。
首先,我們要做的第一件事情就是包含windows.h標頭檔案,這個不再解釋了,因為,我們前面已經解釋過。
之後,我們定義了一個WinMain函式和一個視窗處理函式MainWndProc。
相信,很多人讀到視窗處理函式,就一定會發暈,不知道它是一個什麼東東,如果大家想要明白視窗處理函式,就必須先明白Windows下的訊息機制,現在,我先簡要介紹一下什麼是訊息機制,如果想要深入研究的人,可以看看《Windows核心程式設計》,windows的訊息機制是藉由訊息系統來完成的。
Windows的訊息系統是由3個部分組成的:
1)訊息佇列:Windows為所有的應用程式都維護一個訊息佇列,應用程式必須從訊息佇列中獲取訊息,然後分派給某個視窗處理函式處理。
2)訊息泵:通過這個訊息泵,應用程式可以從訊息佇列中獲取訊息,然後,再把它分派給適當的視窗,最終由該視窗的視窗處理函式來處理它。
3)視窗處理函式:每個視窗都有一個視窗處理函式,它的任務就是處理髮給該視窗的訊息,處理完訊息後,它通常要返回一個值給Windows,告訴Windows該訊息處理是否成功。
相信通過上面的瞭解,大家大概對訊息機制會有一個整體的把握,下面,我將以一個鍵盤的按鍵訊息為例,告訴大家這個訊息是如何產生,流轉,處理。
當我們按下鍵盤上的一個字元後,比如a,這個時候,鍵盤的硬體會檢測到這個動作,然後通知系統,系統知道後,會為它產生一個訊息:WM_CHAR,之後,系統會將這個訊息傳送到當前程式的訊息佇列,比如當前程式是記事本,那麼這個時候,記事本程式的訊息佇列中會出現一個WM_CHAR訊息,當記事本程式的訊息泵從訊息佇列提取到這個字元的按鍵訊息後,會呼叫當前視窗的處理函式來處理這個字元訊息,當視窗處理函式處理WM_CHAR時,會在螢幕上顯示這個字元,我們這裡,這個字元是a,這就是整個訊息處理的全過程。
好了,現在,我們言歸正傳,繼續分析接下來的程式。WinMain程式,這個是所有Windows程式的入口點,它是必須要有的,上次,我們已經講過,這裡不再提及。
接下來,我們來一起看一下這個WinMain函式都做了什麼?
為了幫助大家理解WinMain函式,我們這裡先使用自然語言進行概括性的描述。
int WINAPI WinMain(HINSTANCE hinstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
1、定義一個WNDCLASS或者WNDCLASSEX變數wcx;
2、設定WNDCLASSEX變數wcx;
3、利用wcx建立註冊一個視窗類MainWClass,視窗類就好比一個模版,Windows系統會參考這個模版,為我們建立視窗;
4、用我們建立的視窗類MainWClass,建立一個視窗;
5、呼叫ShowWindow和UpdateWindow顯示和更新視窗;
6、建立一個訊息泵,這個訊息泵的任務就是不斷從訊息佇列中提取訊息,並將訊息傳遞給當前視窗的處理函式,
當訊息泵接收到WM_QUIT退出訊息後,訊息泵就會退出;
7、程式返回。
}
好了,現在,我們繼續分析WinMain函式的內容: 1)定義一個WNDCLASS或者WNDCLASSEX變數wcx,這個目標是通過如下的程式碼來完成的:
WNDCLASSEX wcx;
2)設定視窗類,具體實現是通過如下的程式碼:wcx.cbSize = sizeof(wcx); // 這個引數設定wcx的大小;
wcx.style = CS_HREDRAW |CS_VREDRAW; // 告訴系統,當視窗大小改變時,重繪整個視窗;
wcx.lpfnWndProc = MainWndProc; // 告訴系統,當前視窗類的訊息處理函式是MainWndProc;
wcx.cbClsExtra = 0; // 這個大家先不用管,設定為0就可以;
wcx.cbWndExtra = 0; // 這個大家也先不用管,設定為0就可以;
wcx.hInstance = hinstance; // 告訴系統當前這個視窗屬於哪個程式,系統會根據這個引數,將該視窗的訊息傳送到這個程式的訊息佇列;
wcx.hIcon = LoadIcon(NULL,IDI_APPLICATION); // 視窗圖示:大家也先不用管,使用這個IDI_APPLICATION值,就可以;
wcx.hCursor = LoadCursor(NULL,IDC_ARROW); //設定這個視窗的游標樣式,大家也先不用管,設定為IDC_ARROW,就可以;
wcx.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // 設定當前視窗的背景顏色,這裡是白色WHITE_BRUSH;
wcx.lpszMenuName = NULL; //當前視窗的選單,我們這個視窗沒有選單,所以,只需要設定為NULL,就可以;
wcx.lpszClassName = "MainWClass"; // 告訴系統,我們這個視窗的類名;
wcx.hIconSm = (HICON)LoadImage(hinstance, // 當前視窗的小圖示,大家先這麼寫,先不用管具體什麼意思,後面會介紹。
MAKEINTRESOURCE(5),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);
3)利用wcx建立註冊一個視窗類MainWClass,具體通過如下的程式碼來完成:if (!RegisterClassEx(&wcx))
{
return 1;
}
4)用我們建立的視窗類MainWClass,建立一個視窗,具體通過如下程式碼來完成:
hwnd = CreateWindow(
"MainWClass", // 視窗類名
"我們的第二個程式", // 視窗標題
WS_OVERLAPPEDWINDOW, // 視窗樣式
CW_USEDEFAULT, // 水平位置X:預設
CW_USEDEFAULT, // 垂直位置Y:預設
CW_USEDEFAULT, // 寬度:預設
CW_USEDEFAULT, // 高度:預設
(HWND)NULL, // 父視窗:無
(HMENU)NULL, // 選單:使用視窗類的選單
hinstance, // 應用程式例項控制程式碼
(LPVOID)NULL); // 視窗建立時資料:無
5)呼叫ShowWindow和UpdateWindow顯示和更新視窗,具體通過如下程式碼來完成:ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
6)建立一個訊息泵,具體通過如下的程式碼來完成:while ((fGotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && fGotMessage != -1)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
7)程式返回,具體通過如下的程式碼來完成:return msg.wParam; //這個msg通常是WM_QUIT,這個wParam是這個訊息的退出碼,通常由PostQuitMessage來設定,主要是通知系統,該程式是否正常退出。
相信,通過上面這段描述,大家一定對這個例子中的WinMain函式有了一個整體的把握,現在,我們趁熱打鐵,再一起分析一下我們這個視窗類的視窗處理函式。現在,我先告訴大家視窗處理函式的格式,具體如下:
LRESULT CALLBACK 視窗處理函式名(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
大家只需要記住,視窗處理函式的格式必須這麼寫,只有函式名可以改變,其它的都不可以改變,這個是系統規定的,記住就可以,其中WPARAM和LPARAM是Windows訊息中的兩個引數,當視窗處理函式被呼叫的時候,hwnd代表了當前的視窗,uMsg代表了當前的訊息,在Windows中,每個訊息都用一個整數來表示。wParam和lParam是這個訊息中的兩個引數。下面,我先給出訊息處理函式的一般流程:
LRESULT CALLBACK 視窗訊息處理函式名(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam
)
{
switch (uMsg)
{
case 訊息1:
{
訊息處理函式1;
break;
}
case 訊息2:
{
訊息處理函式2;
break;
}
...
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
上面描述了訊息處理函式的一般流程,我們按照這個一般流程來講解一下我們的視窗處理函式,具體如下:我們的視窗處理函式,只響應了一個訊息WM_DESTROY,這個訊息是在我們點選視窗的關閉按鈕是產生的,當我們的訊息泵接收到這個訊息後,就會將它發給我們的視窗處理函式,然後,我們的視窗處理函式呼叫函式ExitThread,其中傳遞的是執行緒的退出碼,執行緒正常退出,通常都設定為0,當執行完這個函式後,整個執行緒會結束執行,我們這裡的執行緒只有一個,就是WinMian所在的執行緒,當這個執行緒退出後,整個程式就會結束執行。
對於其它的訊息,我們都使用系統提供的預設訊息處理函式來處理,這個函式的原型如下:
LRESULT DefWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM IParam);
在這個函式中,hWnd就是當前視窗的控制程式碼,Msg就是當前要處理的訊息,wParam和lParam就是當前訊息中的兩個引數。 好了,今天講了很多,相信,大家讀完後,應該會對我們的第2個Windows程式有所理解,希望大家多實踐,如果有暫時不明白的內容,可以先放下,因為主要的內容,我已經告訴你們了,次要的後邊會根據需要講解。
相關文章
- 第2講:程序管理
- 第2個java示例程式(轉)Java
- 雲原生遊戲第 2 講:OpenKruiseGame 設計理念詳解遊戲UIGAM
- [開發教程]第2講:下載Bootstrapboot
- Git回滾程式碼到某個commit(圖文講解 僅需2步)GitMIT
- [開發教程]第12講:Bootstrap程式碼boot
- [開發教程]第27講:Bootstrap選項卡(2)boot
- 《程式設計珠璣》第2章三個問題程式設計
- java7-2 構造程式碼塊的概述和講解Java
- 好程式設計師Python教程從零開始學Python系列-第2講程式設計師Python
- RouteServiceProvider程式碼講解IDE
- 第3講:this指標指標
- 精講響應式WebClient第2篇-GET請求阻塞與非阻塞呼叫方法詳解Webclient
- 8個SQL講解優化SQL優化
- 機器學習之決策樹詳細講解及程式碼講解機器學習
- CSS 第2個li元素樣式CSS
- J2ME程式開發全方位基礎講解彙總
- Oracle 11G 程式講解Oracle
- 掃雷程式思想講解 (轉)
- 智慧領域物件設計(例項講解)-2/2物件
- Android——RxJava2史上最全講解AndroidRxJava
- 第3講:程序排程
- 精講RestTemplate第4篇-POST請求方法使用詳解REST
- 第02講:Flink 入門程式 WordCount 和 SQL 實現SQL
- MySQL講義第8講——資料更新之 DELETEMySqldelete
- 【spring 註解】第2篇:@ComponentScanSpring
- 演算法--揹包九講(詳細講解+程式碼)演算法
- 史上最全的Rxjava2講解(使用篇)RxJava
- Struts2(六)result 返回型別講解型別
- 精講RestTemplate第3篇-GET請求使用方法詳解REST
- USB協議詳解第11講(USB描述符-總結)協議
- 第1個簡單java程式(轉)Java
- WEBLOGIC 13個核心應用講解Web
- 程式碼質量第 2 層 - 可重用的程式碼
- 第2周專案-課後實踐·閱讀程式(2)
- 筆記:《挑戰程式設計競賽(第2版)》(2)筆記程式設計
- Retrofit2與服務端例項講解服務端
- 每週薦書——《程式碼大全第2版》