?? 見招拆招《windows程序設計》(二) .txt
字號:
LOCAL hdc :HDC
LOCAL ps :PAINTSTRUCT
local rect :RECT
.if uMsg==WM_CREATE
invoke PlaySound,CTEXT("C:\WINDOWS\system32\LoopyMusic.wav"),NULL, SND_FILENAME or SND_ASYNC
.elseif uMsg == WM_PAINT
invoke BeginPaint,hWin,addr ps
mov hdc,eax
invoke GetClientRect,hWin,addr rect
invoke DrawText,hdc,CTEXT("Hello,Windows XP!"),-1,addr rect, DT_SINGLELINE or DT_CENTER or DT_VCENTER
invoke EndPaint, hWin,addr ps
.elseif uMsg == WM_DESTROY
invoke PostQuitMessage,NULL
.else
invoke DefWindowProc,hWin,uMsg,wParam,lParam
.endif
ret
WndProc endp
END START
程序建立一個普通的應用程序窗口,如圖3-1所示。在窗口顯示區域的中央顯示「Hello,Windows XP!」。同時還可以聽到播放的音樂。
圖3-1 HELLOWIN窗口
提醒您注意:我們需要在文件頭部添加
Include winmm.inc 和 IncludeLib winmm.lib
WINMM.LIB(Windows multimedia-Windows多媒體)。您這樣做是因為HELLOWIN將使用多媒體功能,而內定的項目中又不包括多媒體鏈接庫文件。不然連結程序報告了錯誤信息,表明PlaySound函數不可用。
通盤考量
實際上,每一個Windows程序代碼中都包括HELLOWIN.ASM程序的大部分。沒人能真正記住此程序的全部寫法;通常,Windows程序寫作者在開始寫一個新程序
時總是會復制一個現有的程序,然后再做相應的修改。
MasmPlus的用戶可以通過菜單上的"新建"' Masm工程 ' Win32 EXE來調出窗口程序的模版
很容易你會發現模版程序同我們上面的例子幾乎沒有什么差別。《Windows環境下32位匯編語言程序設計》的讀者會發現有一些不同,MasmPlus的模版似乎"多初始化了一些東西",這是因為《Win》一書上的程序使用了 RtlZeroMemory API來對stWndClass直接填0,因此可以省略一些單獨填0的動作。
上面提到,HELLOWIN將在其窗口的中央顯示字符串。這種說法不是完全正確的。文字實際顯示在程序顯示區域的中央,它在圖3-1中是標題列和邊界范圍內的大片白色區域。這區別對我們來說很重要;顯示區域就是程序自由繪圖并且向使用者顯示輸出結果的窗口區域。
如果您認真思考一下,將會發現雖然只有幾十行程序代碼,這個窗口卻令人驚訝地具有許多功能。您可以用鼠標按住標題列,在屏幕上移動窗口;可以按住大小邊框,改變窗口的大小。在窗口大小改變時,程序自動地將「Hello,Windows XP!」字符串重新定位在顯示區域的中央。您可以按最大化按鈕,放大HELLOWIN以充滿整個屏幕;也可以按最小化按鈕,將程序縮小成一個圖示。您可以在系統菜單中執行所有選項(就是按下在標題列最左端的小圖示);也可以從系統菜單中選擇 Close選項,或者單擊標題列最右端的關閉按鈕,或者雙擊標題列最左端的圖標,來關閉窗口以終止程序的執行。
我們將在本章的余下部分對此程序作一詳細的檢查。當然,我們首先要從整體上看一下。
HELLOWIN.ASM入口在Start標號處,有一個WinMain函數,還有另外一個函數,名為WndProc。這就是窗口消息處理程序。注意,在HELLOWIN.ASM中沒有直接調用WndProc的程序代碼。當然,在WinMain中有對WndProc的參考,而這就是該函數要在程序開頭附近聲明的原因。
Windows函數呼叫
HELLOWIN至少呼叫了18個Windows函數。下面以它們在HELLOWIN中出現的次序列出這些函數以及各自的簡明描述:
LoadIcon 加載圖標供程序使用。
LoadCursor 加載鼠標光標供程序使用。
GetStockObject 取得一個圖形對象(在這個例子中,是取得繪制窗口背景的畫刷對象)。
RegisterClass 為程序窗口注冊窗口類別。
MessageBox 顯示消息框。
CreateWindow 根據窗口類別建立一個窗口。
ShowWindow 在屏幕上顯示窗口。
UpdateWindow 指示窗口自我更新。
GetMessage 從消息隊列中取得消息。
TranslateMessage 轉譯某些鍵盤消息。
DispatchMessage 將消息發送給窗口消息處理程序。
PlaySound 播放一個聲音文件。
BeginPaint 開始繪制窗口。
GetClientRect 取得窗口顯示區域的大小。
DrawText 顯示字符串。
EndPaint 結束繪制窗口。
PostQuitMessage 在消息隊列中插入一個「退出程序」消息。
DefWindowProc 執行內定的消息處理。
上面這些函數在MSDN上都能查到,并在不同的表頭文件中聲明,其中絕大多數聲明在Windows.inc中。
大寫字母標識符
讀者可能注意到,HELLOWIN.C中有幾個大寫的標識符,這些標識符是在Windows表頭文件中定義的。有些標識符含有兩個字母或者三個字母的前綴,這些前綴后頭接著一個底線:
這些是簡單的數值常數。前綴指示該常數所屬的類別,如表3-1所示。
表3-1
前綴 類別
CS 窗口類別樣式
CW 建立窗口
DT 繪制文字
IDI 圖示ID
IDC 游標ID
MB 消息框
SND 聲音
WM 窗口消息
WS 窗口樣式
奉勸程序寫作者不要費力氣去記憶Windows程序設計中的數值常數。實際上,Windows中使用的每個數值常數在表頭文件中均有相應的標識符定義。
新的數據型態
HELLOWIN.ASM中的其它標識符是新的數據型態,也在Windows表頭文件中使用typedef敘述或者#define敘述加以定義了。最初是為了便于將Windows程序從原來的16位系統上移植到未來的使用32位(或者其它)技術的操作系統上。這種作法并不如當時每個人想象的那樣順利,但是這種概念基本上是正確的。
有時這些新的數據型態只是為了方便縮寫。例如,用于WndProc的第二個參數的UINT數據型態只是一個unsigned int (無正負號整數),在Windows XP中,這是一個32位的值。用于WinMain的第三個參數的PSTR數據型態是指向一個字符串的指針,即是一個char *。
其它數據型態的含義不太明顯。例如,WndProc的第三和第四個參數分別被定義為WPARAM和LPARAM,這些名字的來源有點歷史背景:當Windows還是16位系統時,WndProc的第三個參數被定義為一個WORD,這是一個16位的 無正負號短(unsigned short)整數,而第四個參數被定義為一個LONG,這是一個32位有正負號長整數,從而導致了文字「PARAM」前面加上了前置前綴「W」和「L」。當然,在32位的Windows中,WPARAM被定義為一個UINT,而LPARAM被定義為一個LONG(這就是C中的long整數型態),因此窗口消息處理程序的這兩個參數都是32位的值。這也許有點奇怪,因為WORD數據型態在WindowsXP中仍然被定義為一種16位的 無正負號整數,因此「PARAM」前的「W」就有點誤用了。
WndProc函數傳回一個型態為LRESULT的值,該值簡單地被定義為一個LONG。WinMain函數被指定了一個WINAPI型態(在表頭文件中定義的所有Windows函數都被指定這種型態),而WndProc函數被指定一個CALLBACK型態。這兩個標識符都被定義為_stdcall,表示在Windows本身和使用者的應用程序之間發生的函數呼叫的呼叫參數傳遞方式。
HELLOWIN還使用了Windows表頭文件中定義的四種數據結構(我們將在本章稍后加以討論)。這些數據結構如表3-2所示。
表3-2
結構 含義
MSG 消息結構
WNDCLASS 窗口類別結構
PAINTSTRUCT 繪圖結構
RECT 矩形結構
前面兩個數據結構在WinMain中使用,分別定義了兩個名為msg和wndclass的結構,后面兩個數據結構在WndProc中使用,分別定義了ps和rect結構。
句柄簡介
最后,還有三個大寫標識符(見表3-3),用于不同型態的「句柄」:
表3-3
標識符 含義
HINSTANCE 執行實體(程序自身)句柄
HWND 窗口句柄
HDC 設備內容句柄
句柄在Windows中使用非常頻繁。在本章結束之前,我們將遇到HICON(圖標句柄)、HCURSOR(鼠標光標句柄)和HBRUSH(畫刷句柄)。
句柄是一個(通常為32位的)整數,它代表一個對象。Windows中的句柄類似傳統C或者MS-DOS程序設計中使用的文件句柄。程序幾乎總是通過呼叫Windows函數取得句柄。程序在其它Windows函數中使用這個句柄,以使用它代表的對象。代號的實際值對程序來說是無關緊要的。但是,向您的程序提供代號的Windows模塊知道如何利用它來使用相對應的對象。
匈牙利表示法
讀者可能注意到,HELLOWIN.ASM中有一些變量的名字顯得很古怪。如szCmdLine,它是傳遞給WinMain的參數。
許多Windows程序寫作者使用一種叫做「匈牙利表示法」的變量命名通則。這是為了紀念傳奇性的Microsoft程序寫作者Charles Simonyi。非常簡單,變量名以一個或者多個小寫字母開始,這些字母表示變量的數據型態。例如,szCmdLine中的sz代表「以0結尾的字符串」。在hInstance和hPrevInstance中的h前綴表示「句柄」;在iCmdShow中的i前綴表示「整數」。WndProc的后兩個參數也使用匈牙利表示法。正如我在前面已經解釋過的,盡管wParam應該更適當地被命名為uiParam(代表「無正負號整數」),但是因為這兩個參數是使用數據型態WPARAM和LPARAM定義的,因此保留它們傳統的名字。
在命名結構變量時,可以用結構名(或者結構名的一種縮寫)的小寫作為變量名的前綴,或者用作整個變量名。例如,在HELLOWIN.ASM的WinMain函數中,msg變量是MSG型態的結構;wndclass是WNDCLASSEX型態的一個結構。在WndPmc函數中,ps是一個PAINTSTRUCT結構,rect是一個RECT結構。上述的說法在區分大小寫的C語言中是有效的,而在匯編語言中這樣使用很可能導致錯誤。
匈牙利表示法能夠幫助程序寫作者及早發現并避免程序中的錯誤。由于變量名既描述了變量的作用,又描述了其數據型態,就比較容易避免產生數據型態不合的錯誤。
表3-4列出了在本書中經常用到的變量前綴。
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -