/*下列注釋函數均在平台SDK文檔中說明,並在不同的標頭檔中聲明,其中絕大多數在WINUSER.H中聲明。*/
#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 ; //視窗控制代碼類HWND;
MSG msg ; //P54 訊息;
WNDCLASS wndclass ; //P47 註冊視窗類別,產生對象;解釋:視窗類別定義了視窗的一般特徵,因此可以使用同一視窗類別建立許多不同的視窗。
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
//1.。。見上:CS_HREDRAW 視窗的水平方向尺寸;CS_VREDRAW 視窗的垂直方向尺寸;這兩個標示符確保了文本串既是在改變了視窗大小後仍位於視窗中央。
wndclass.lpfnWndProc = WndProc ;
//2.。。見上:即此程式的第二個函數。其處理基於這個視窗類別建立的所有視窗的全部資訊。在c語言中像這樣在語句中使用函數名時,實際引用提供的是指向函數的指標。//lpfn “指向函數的長指標”
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
//3和4.。。上面兩個域用於在類結構和windows內部儲存的視窗結構中預留一些額外空間;程式可以根據需要來使用預留的空間,此處沒有使用,所以賦值為0; cb “count of bytes(位元組數)”
wndclass.hInstance = hInstance ;
//5.。。上面的一個域是程式的執行個體控制代碼(他也是WinMain的參數之一)
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
//6.。。見上:LoadIcon載入表徵圖供程式使用.
//第一個參數設為NULL是來擷取預先定義(預設)的表徵圖控制代碼;
//若載入定製的表徵圖(表徵圖應該儲存在磁碟.EXE程式檔案中),這個參數應該設定為程式的執行個體控制代碼hInstance;
//第二個參數標識表徵圖,對預先定義的表徵圖此參數是以IDI開始的標示符,標示符在WINUSER.H中定義;
//LoadIcon函數返回該表徵圖的控制代碼
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
//7.。。見上:LoadCursor載入滑鼠指標供程式使用;(可以參考LoadIcon)
//LoadCursor函數載入一個預先定義的滑鼠游標(命名為IDC_ARROW),並返回游標的控制代碼。該控制代碼被賦給WNDCLASS結構的hCursor域。
//當滑鼠游標在基於這個類建立的視窗的用戶端區域上出現時,它變成一個小箭頭。
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
//8.。。GetStockObject擷取一個繪圖物件,在這個例子中,是擷取繪製視窗背景的刷子;
//調用則返回一個刷子(此時為‘白色刷子的’)的控制代碼。
wndclass.lpszMenuName = NULL ;
//9.。。上個域指定視窗類別菜單。因此程式沒有應用程式菜單,所以該欄位被設定為NULL。
wndclass.lpszClassName = szAppName ;
//10.。。上句是給出一個類名。對於小程式類名可以和程式名相同,即存放在szAppName變數中的字串“HelloWin”;
//上述字串是由ASCII字元組成還是由Unicode字元組成取決於是否定義了UNICODE標示符;
if (!RegisterClass (&wndclass)) //RegisterClass 是為程式視窗註冊視窗類別;該函數只有一個參數,即指向WNDCLASS結構的指標。
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ; //MessageBox 是顯示訊息框;
return 0 ;
}
//如下:CreateWindow 是根據視窗類別建立一個視窗;返回被建立的視窗的控制代碼,該控制代碼存放在變數hwnd中。
hwnd = CreateWindow (szAppName, // window class name 是程式註冊的視窗類別名稱;這就是如何把我們正在建立的視窗與一個視窗相連接類的方式。
TEXT ("The Hello Program"), // window caption(標題,說明)
WS_OVERLAPPEDWINDOW, // window style 視窗風格(轉到定義看看):標題列,菜單框,縮小放大關閉表徵圖及四周表示視窗大小的邊框。 //“| WS_VSCROLL | WS_HSCROLL” 加上這個 就能使用 垂直滾動(WS_VSCROLL) 和 水平滾動(WS_HSCROLL) // WS ‘窗戶風格’; 垂直 ‘vertical’; 水平 ‘horizontal’;
CW_USEDEFAULT, // initial x position 下面四個CW_USEDEFAULT都表示是使用windows預設尺寸;
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle 當建立一個“最進階”視窗,如應用程式視窗時,則“父視窗控制代碼”的參數設定為NULL。
NULL, // window menu handle 因視窗沒有菜單則“視窗菜單控制代碼”設定為NULL;
hInstance, // program instance handle “程式執行個體控制代碼”設定為執行個體控制代碼,它是作為WinMain的參數傳遞給這個程式的;
NULL) ; // creation parameters “建立參數” 指標設定為NULL,可以用這個指標訪問以後想要引用的程式中的資料;
//ShowWindow 在螢幕上顯示視窗;兩個參數:一、視窗控制代碼;二、是作為參數傳給WinMain的iCmdShow,它確定最初如何在螢幕上顯示視窗。
//第二個參數:1.如果視窗按常規顯示,那麼從WinMain接收並傳遞給ShowWindow的就是SW_SHOWNORMAL;
//2.最大化,則為SW_SHOWMAXIMIZED;3.若只顯示在工作列上,則為SW_SHOWMINNOACTIVE。
ShowWindow (hwnd, iCmdShow) ;
//如果第二個參數是SW_SHOWNORMAL,則視窗的用戶端區域被視窗類別中定義的背景刷子所覆蓋。函數調用UpdateWindow,導致用戶端區域被繪製。
UpdateWindow (hwnd) ; //指示視窗重新整理自身;它通過給下面的視窗過程(即 WndProc函數)發送一個WM_PAINT訊息來做到這一點。
//調用完UpdateWindow後視窗就出現在顯示器上。程式現在必須讀入使用者鍵盤和滑鼠輸入的資料。windows為當前啟動並執行每個windows程式維護一個“訊息佇列”
//在發生輸入事件後,windows將事件轉化為一個“訊息”,並將訊息放入程式訊息佇列中。
//程式通過執行一段稱為“訊息迴圈”的代碼從訊息佇列中取出訊息。如下:
while (GetMessage (&msg, NULL, 0, 0)) //GetMessage 從訊息佇列中擷取訊息; msg 是前面定義的‘訊息’類型,其結構體具體可參見MSG的定義;
{ //NULL,0,0 是表示程式接收它自己建立的所有視窗的所有訊息。詳情見 P55.
TranslateMessage (&msg) ; //TranslateMessage 將msg結構傳給Windows, 轉換某些鍵盤資訊;(第六章將深入討論)
DispatchMessage (&msg) ; //DispatchMessage 將訊息發送給視窗過程;
}
return msg.wParam ;
}
// 上面的都是準備工作,實際的動作發生在視窗過程中。視窗過程確定了在視窗的用戶端區域中顯示些什麼,以及視窗如何響應使用者輸入。
//視窗過程可以任意命名(此程式是WndProc),一個windows程式可以包含多個視窗過程,一個視窗過程總是與調用RegisterClass註冊的特定視窗類別相關聯。
//程式一般不直接調用視窗過程。視窗過程由windows本身直接調用。通過調用SendMessage函數,程式能夠直接調用它自己的視窗過程。
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)//四個參數與Message的前四個域是相同的,參見MSG的定義和P56。
{
HDC hdc ;
PAINTSTRUCT ps ;
RECT rect ;
switch (message)
{
case WM_CREATE: //充當的是 WndProc函數的第二個參數
PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ;
//如上:PlaySound 播放一個音效檔;第二個參數只有當音效檔是一種資源時才被使用。
return 0 ; //視窗過程在處理訊息時,必須返回0.
case WM_PAINT:
// InvalidateRect(hwnd,NULL,TRUE);
//如果在處理WM_PAINT訊息時在更的矩形外繪圖,可以在調BeginPaint前調用它;它使整個客戶區變為無效,並擦出背景;
//但是,如果改成FALSE,則不擦出背景,原有的東西將保留在原處;詳見P71整頁;
hdc = BeginPaint (hwnd, &ps) ;
//對WM_PAINT的處理總是從BeginPaint(開始視窗繪製函數)的調用開始 ;第二個參數是指向類型為PAINTSTRUCT的結構指標
GetClientRect (hwnd, &rect) ;
//GetClientRect 擷取視窗客戶區的尺寸;第二個參數是指標,指向RECT類型的rectangle結構。
//rectangle結構有4個LONG域,分別為left,top,right,buttom(底部)。
//GetClientRect將這4個網域設定為視窗用戶端區域的尺寸。left和top域通常設定為0,right和buttom網域設定為用戶端區域的寬度和高度(像素點數);
DrawText (hdc, TEXT ("Hello, Windows 7!"), -1, &rect,
DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
//DrawText 顯示文本串(即輸出為文本);
//五個參數:1、是從BeginPaint返回的裝置描述表控制代碼;2、是要輸出的文本;3、是-1,指示文本串是以位元組0終結的;
/5、是一系列的位標識,均在WINUSER.H中定義;標誌指示文本須顯示在一行上,水平方向和垂直方向都位於第4個參數指定的矩形地區,因此輸出文本顯示在用戶端區域中央;
EndPaint (hwnd, &ps) ; //EndPaint 結束視窗繪製;第二個參數是指向類型為PAINTSTRUCT的結構指標(同上:BeginPaint函數)。
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ; //PostQuitMessage 在訊息佇列中插入一條“退出”訊息;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ; //DefWindowProc 執行預設的訊息處理(即視窗過程不予處理的訊息被傳給它);
}