#include <windows.h>
//函數返回值類型("LONG") 函數類型(回調函數"_stdcall") 函數名 (函數參數);
LRESULT CALLBACK WndProc (HWND, UINT,WPARAM, LPARAM);
int WINAPI WinMain (HINSTANCE hInstance,HINSTANCE hPreInstance, PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName [] =TEXT ("HelloWin");
HWND hwnd;
MSG msg;
WNDCLASS wndclass; //WNDCLASS結構定義在WINUSER.H中,包含10個字段
//類風格:當窗口尺寸改變(水平/垂直)時,所有基於該窗口類的窗口都將被重繪。
wndclass.style =CS_HREDRAW | CS_VREDRAW;
//處理所有基於該窗口類創建的窗口的所有消息
wndclass.lpfnWndProc= WndProc;
//類預留空間,字節數爲0
wndclass.cbClsExtra= 0;
//窗口預留空間,字節數爲0
wndclass.cbWndExtra= 0;
//應用程序的實例句柄,問:每個窗口類的這個字段都是“應用程序的實例句柄”?
wndclass.hInstance= hInstance;
//使用預定義圖標:NULL, 圖標標識符
//加載自定義圖標:程序實例句柄hInstance, 圖標標識
wndclass.hIcon =LoadIcon (NULL, IDI_APPLICATION);
//當鼠標指針出現在這類窗口的客戶區時,將變成一個小箭頭
wndclass.hCursor= LoadCursor (NULL, IDC_ARROW);
//返回一個白色畫刷句柄,畫刷句柄:用於區域填充的像素着色模式,
//Windows有幾個標準畫刷("庫存"畫刷)
wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH);
//無菜單:NULL
wndclass.lpszMenuName= NULL;
//窗口類的名稱。貌似:Windows實現了窗口類的模板,而這裏定義一個窗口類,以及//接下來的註冊窗口類,都是使用Windows的窗口類模板確實創建一個類
wndclass.lpszClassName = szAppName;
//註冊窗口類,分配相應的內存(分配內存時總要做錯誤檢查)
if(!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR);
return 0 ;
}
//當HELLOWIN調用CreateWindow時,Windows完成其必須的操作,
//並調用WndProc(發送WM_CREATE消息)
hwnd = CreateWindow ( szAppName, // 窗口類名稱:基於該窗口類創建一個窗口
TEXT ("The Hello Program"), // 窗口標題
WS_OVERLAPPEDWINDOW, // 窗口風格:普通的層疊(overlapped)窗口
CW_USEDEFAULT, // 初始x座標:窗口左上角相對於屏幕左上角的初始位置
CW_USEDEFAULT, // 初始y座標
CW_USEDEFAULT, // 初始x方向尺寸
CW_USEDEFAULT, // 初始y方向尺寸
NULL, // 父窗口句柄:新建窗口爲頂級窗口(如應用程序窗口),則參數爲NULL
NULL, // 窗口菜單句柄:沒有菜單,爲NULL
hInstance, //程序實例句柄
NULL); // 創建參數
//iCmdShow的初值是什麼?
//該參數決定窗口在屏幕中的初始顯示形式:正常顯示、最小化、最大化
ShowWindow(hwnd, iCmdShow);
//調用之後,新建窗口在屏幕中完全可見
UpdateWindow(hwnd);
//消息循環
//NULL,0,0:希望獲取由該程序所創建的所有窗口的所有消息
//GetMessage函數,當msg.message != WM_QUIT (其值爲0xx12)時,返回非0值,
//否則返回0,此時退出消息循環。
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg); //消息解釋
DispatchMessage (&msg); //分發消息到各個窗口(MSG結構中有HWND參數)
}
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINTmessage, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
switch (message)
{
case WM_CREATE:
//SND_FILENAME | SND_ASYNC:使用文件名、異步播放
PlaySound (TEXT ("A whole new world.wav"), NULL, SND_FILENAME| SND_ASYNC);
return 0;
case WM_PAINT:
//&ps:對客戶區進行繪製的信息。BeginPaint調用,
//使用畫刷擦除背景、使整個客戶區有效,返回“設備環境句柄”(顯示硬件)。
hdc = BeginPaint (hwnd, &ps);
//以像素爲單位的客戶區的位置信息
GetClientRect (hwnd, &rect);
//在&rect內繪製單行/水平/垂直居中的文本
DrawText (hdc, TEXT ("hello Windows XP !"), -1, &rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
//釋放設備環境句柄
EndPaint (hwnd, &ps);
return 0;
case WM_DESTROY:
//PostQuitMessage函數將WM-QUIT消息插入到消息隊列,
//使得GetMessage返回0,從而退出消息循環
PostQuitMessage (0);
return 0;
}
//對所有窗口過程沒有處理的消息進行默認處理
return DefWindowProc (hwnd, message, wParam, lParam);
}
/*
提醒您注意:如果您使用MicrosoftVisual C++ 爲此程序建立新項目,那麼您得加上連結程序所需的鏈接庫文件。從Project菜單選擇 Setting選項,然後選取Link頁面標籤。從Category清單方塊中選擇General,然後在 Object/Library Modules文字方塊添加WINMM.LIB(Windows multimedia-Windows多媒體)。您這樣做是因爲HELLOWIN將使用多媒體功能呼叫,而內定的項目中又不包括多媒體鏈接庫文件。不然連結程序報告了錯誤信息,表明PlaySound函數不可用。
HELLOWIN將存取文件HELLOWIN.WAV,該文件在本書所附光盤的HELLOWIN目錄中。執行HELLOWIN.EXE時,內定的目錄必須是HELLOWIN。在Visual C++中執行此程序時,雖然執行文件會產生在HELLOWIN的RELEASE或DEBUG子目錄中,但執行程序的目錄還是必須在HELLOWIN中。
*/
1、Windows、窗口類、窗口、窗口過程的關係
一般,應用程序不直接調用窗口過程,而由Windows自身調用(通過消息機制)。若應用程序希望調用自身的窗口過程,則可通過調用函數SendMessage實現。
2、Windows消息
Windows消息分爲隊列消息和非隊列消息。
隊列消息是指那些由Windows放入程序的消息隊列中的消息。在消息循環中檢索,並被投遞到窗口過程。
非隊列消息是由Windows對窗口過程的直接調用產生的。
隊列消息主要由用戶的輸入產生,如按鍵消息、字符消息、鼠標消息、定時器消息、重繪消息、退出消息等。
非隊列消息包含除隊列消息以外的其他所有消息。非隊列消息通常由調用特定的Windows函數引起。如調用CreateWindow、UpdateWindow等函數的時候。
對於用戶來說,不用區分消息類型,Windows內部承擔了這部分複雜度。從窗口過程的角度看,這些消息是以有序、同步方式到來的。
筆者認爲:隊列消息就是普通的用戶消息,需要排隊;而非隊列消息到來就會被放在隊首,不需要排隊。
<Windows程序設計>原文:
雖然Windows程序可有多個執行線程,但每個線程的消息隊列僅爲哪些其窗口過程在該線程內執行的窗口進行消息處理。換言之,消息循環和窗口過程不是併發運行的。
當一個消息循環從其自身的消息隊列中檢索消息,並調用DispatchMessage函數將檢索到的消息發送給窗口過程時,只有在窗口過程將控制權還給Windows後,DispatchMessage纔會返回。
註釋:消息處理,其本質是窗口過程的調用。因此,消息循環其實是一個函數嵌套調用的過程,內層返回,外層才能繼續。
但是,窗口過程可以調用爲其發送其他消息的函數。這種情形下,在該函數調用返回之前,窗口過程必須將第二個消息處理完畢,此時窗口過程才處理前一條消息。例如,當一個
窗口過程調用UpdateWindow時,Windows會以一條WM_PAINT消息來調用窗口過程。當窗口過程處理完WM_PAINT消息後,UpdateWindow調用纔將控制權返還給窗口過程。
註釋:消息處理雖然不能被中斷,但是一個消息的處理過程中可以發送另一個消息,形成消息的嵌套,也就是窗口過程的嵌套。
但是,消息處理時發送的消息需要在消息隊列中排隊嗎?那麼怎麼知道該消息已經處理完畢而返回到調用過程呢?還是使用了其他的手段,如SendMessage類似的?
這就意味着,窗口過程必須是可重入(reentrant)的。那麼,與“可重入”相關的問題必須注意。
這段話不理解:
在許多情況下,窗口過程必須保留其從消息中獲取的消息,並在處理其他消息時使用該消息。這種信息必須保存在窗口過程所定義的靜態變量中,或保存在全局變量中。