/*------------------------------------------------------------
HELLOWIN.C -- Displays "Hello, Windows 98!" in client area
(c) Charles Petzold, 1998
------------------------------------------------------------*/
#include <windows.h>
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("HelloWin") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, // window class name
TEXT (" The Hello Program"), // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
//showwindow 第一個參數剛剛建立的表單,第二個參數是從winmain函數中傳入的,此處改成了SW_SHOWMAXIMIZED代表最大化顯示
ShowWindow (hwnd,SW_SHOWMAXIMIZED) ;
UpdateWindow (hwnd) ;
/* msg變數是型態為 MSG 的結構,型態 MSG在 WINUSER.H中定義如下:
typedef struct tagMSG
{
HWND hwnd ;
UINT message ;
WPARAM wParam ;
LPARAM lParam ;
DWORD time ;
POINT pt ;
}
* POINT 資料型態也是一個結構,它在 WINDEF.H 中定義如下:
typedef struct tagPOINT
{
LONG x ;
LONG y ;
}*/
while (GetMessage (&msg, NULL, 0, 0))
/*GetMessage
GetMessage (&msg, NULL, 0, 0)
這一呼叫傳給 Windows一個指標,指向名為 msg的MSG 結構。第二、第三和第四個參數設定為 NULL 或者 0,
表示程式接收它自己建立的所有視窗的所有訊息。Windows用從訊息佇列中取出的下一個訊息來填充訊息結構
的各個欄位,結構的各個欄位包括:
hwnd 接收訊息的視窗控制代碼。在 HELLOWIN程式中,這一參數與 CreateWindow 傳回的 hwnd
值相同,因為這是該程式擁有的唯一視窗。
message 訊息標識符。這是一個數值,用以標識訊息。對於每個訊息,均有一個對應的標識
符,這些標識符定義於 Windows表標頭檔(其中大多數在 WINUSER.H 中) ,以首碼 WM( 「window message」 ,
視窗訊息)開頭。例如,使用者將滑鼠游標放在HELLOWIN顯示地區之內,並按下滑鼠左按鈕,Windows就在
訊息佇列中放入一個訊息,該訊息的 message 欄位等於 WM_LBUTTONDOWN。這是一個常數,其值為0x0201。
wParam 一個32位的「message parameter(訊息參數) 」 ,其含義和數值根據訊息的不同而不
同。
lParam 一個32 位的訊息參數,其值與訊息有關。
time 訊息放入訊息佇列中的時間。
pt 訊息放入訊息佇列時的滑鼠座標。
只要從訊息佇列中取出訊息的 message 欄位不為 WM_QUIT (其值為0x0012) , GetMessage 就傳回一個非零值。
WM_QUIT訊息將導致GetMessage 傳回 0。*/
{
TranslateMessage (&msg) ;//將 msg結構傳給 Windows,進行一些鍵盤轉換
DispatchMessage (&msg) ;
/* DispatchMessage又將 msg結構回傳給 Windows。然後,Windows將該訊息發送給適當的視窗訊息處理常式,讓它進 行處理。這也就是說,Windows將呼叫視窗訊息處理常式。在HELLOWIN 中,這個視窗訊息處理常式就是 WndProe 函 數。處理完訊息之後,WndProc 傳回到 Windows。此時,Windows還停留在 DispatchMessage 呼叫中。在結束DispatchMessage 呼叫的處理之後,Windows回到HELLOWIN,並且接著從下一個 GetMessage呼叫開始訊息迴圈。*/
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
/*視窗訊息處理常式的四個參數與 MSG 結構的前四個欄位是相同的。第一個參數 hwnd是接收訊息的視窗
的控制代碼,它與 CreateWindow 函數的傳回值相同。對於與HELLOWIN相似的程式(只建立一個視窗),這個參
數是程式所知道的唯一視窗控制代碼。如果程式是依據同一視窗類別別(同時也是同一視窗訊息處理常式)建立多個
視窗,則 hwnd標識接收訊息的特定視窗。
第二個參數與 MSG 結構中的 message 欄位相同,它是標識訊息的數值。最後兩個參數都是 32 位的訊息參數,
提供關於訊息的更多資訊。這些參數包含每個訊息型態的詳細資料。有時訊息參數是兩個存放在一起的 16位
值,而有時訊息參數又是一個指向字串或資料結構的指標。
程式通常不直接呼叫視窗訊息處理常式,視窗訊息處理常式通常由 Windows本身呼叫。通過呼叫 SendMessage
函數,程式能夠直接呼叫它自己的視窗訊息處理常式。*/
{
HDC hdc ;//裝置內容控制代碼
PAINTSTRUCT ps ;//繪圖結構
RECT rect ;
switch (message)
{
case WM_CREATE:
PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ;
return 0 ;
case WM_PAINT:
/* WndProc 處理的第二個訊息為 WM_PAINT。這個訊息在 Windows程式設計中是很重要的。當視窗顯示地區的一
部分顯示內容或者全部變為「無效」,以致於必須「更新畫面」時,將由這個訊息通知程式。
顯示地區的顯示內容怎麼會變得無效呢?在最初建立視窗的時候,整個顯示地區都是無效的,因為程式還沒有
在視窗上畫什麼東西。第一條 WM_PAINT 訊息(通常發生在 WinMain 中呼叫UpdateWindow 時)指示視窗訊息
處理常式在顯示地區上畫一些東西。
在使用者改變HELLOWIN視窗的大小後,顯示地區的顯示內容重新變得無效。讀者應該還記得,HELLOWIN 中
wndclass結構的 style欄位設定為標誌 CS_HREDRAW和 CS_VREDRAW,這樣的格式設定指示 Windows,在視窗
大小改變後,就把整個視窗顯示內容當成無效。然後,視窗訊息處理常式將收到一條 WM_PAINT 訊息。
當使用者將 HELLOWIN 最小化,然後再次將視窗恢複為以前的大小時,Windows 將不會儲存顯示地區的內容。
在圖形環境下,視窗顯示地區涉及的資料量很大。因此,Windows令視窗無效,視窗訊息處理常式接收一條
WM_PAINT 訊息,並自動回復其視窗的內容。
在移動視窗以致其相互重迭時,Windows不儲存一個視窗中被另一個視窗所遮蓋的內容。在這一部分不再被遮
蓋之後,它就被標誌為無效。視窗訊息處理常式接收到一條 WM_PAINT 訊息,以更新視窗的內容。
對 WM_PAINT的處理幾乎總是從一個 BeginPaint呼叫開始:
hdc = BeginPaint (hwnd, &ps) ;
而以一個 EndPaint呼叫結束:
EndPaint (hwnd, &ps) ;
在這兩個呼叫中,第一個參數都是程式的視窗控制代碼,第二個參數是指向型態為 PAINTSTRUCT 的結構指標。
PAINTSTRUCT結構中包含一些視窗訊息處理常式,可以用來更新顯示地區的內容。我們將在下一章中討論該結
構的各個欄位。現在我們只在BeginPaint和 EndPaint函數中用到它。*/
hdc = BeginPaint (hwnd, &ps) ;
GetClientRect (hwnd, &rect) ;
DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_DESTROY://關閉表單的訊息
PostQuitMessage (0) ;//該函數在程式的訊息佇列中插入一個 WM_QUIT 訊息。前面提到過,GetMessage 對於除了 WM_QUIT 之外的從訊息佇列中取出的所有訊息都傳回非 0值。而當GetMessage 得到一個 WM_QUIT 訊息時,它傳回 0。這將導 致WinMain 退出訊息迴圈,並終止程式。然後程式執行下面的敘述:
return 0 ;
}
//有時候,DefWindowProc處理完訊息後會產生其它的訊息。例如,假設使用者執行 HELLOWIN,並且使用者最
//終單擊了 Close按鈕,或者假設用鍵盤或滑鼠從系統功能表中選擇了 Close, DefWindowProc 處理這一鍵盤或者
//滑鼠輸入, 在檢測到使用者選擇了 Close選項之後, 它給視窗訊息處理常式發送一條 WM_SYSCOMMAND訊息。WndProc這個訊息傳給DefWindowProc。DefWindowProc 給視窗訊息處理常式發送一條 WM_CLOSE訊息來響
//應之。WndProc 再次將它傳給 DefWindowProc。DestroyWindow呼叫DestroyWindow 來響應這條 WM_CLOSE 消
//息。DestroyWindow導致Windows給視窗訊息處理常式發送一條 WM_DESTROY 訊息。WndProc 再呼叫
//PostQuitMessage,將一條WM_QUIT訊息放入訊息佇列中,以此來響應此訊息。這個訊息導致 WinMain中的消
//息迴圈終止,然後程式結束。
return DefWindowProc (hwnd, message, wParam, lParam) ;
}