?? 見招拆招《windows程序設計》(二) .txt
字號:
見招拆招《Windows程序設計》(二)
作者:Zoologist 于2007-10-15上傳
--------------------------------------------------------------------------------
窗口和消息
在前一章,程序使用函數MessageBox來向使用者輸出文字。MessageBox函數會建立一個「窗口」。在Windows中,「窗口」一詞有確切的含義。一個窗口就是屏幕上的一個矩形區域,它接收使用者的輸入并以文字或圖形的格式顯示輸出內容。
MessageBox函數建立一個窗口,但這只是一個功能有限的特殊窗口。消息窗口有一個帶關閉按鈕的標題列、一個選項圖標、一行或多行文字,以及最多四個按鈕。當然,必須選擇Windows提供給您的圖標與按鈕。
MessageBox函數非常有用,但下面不會過多地使用它。我們不能在消息框中顯示圖形,而且也不能在消息框中添加菜單。要添加這些對象,就需要建立自己的窗口,現在就開始。
自己的窗口
建立窗口很簡單,只需調用CreateWindow函數即可。我們在MSDN上可以找到這個函數的原形:
HWND CreateWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
);
CreateWindow的第一個參數就是所謂的「窗口類別名稱」,并且該窗口類別連接所謂的「窗口消息處理程序」。在我們使用CreateWindow之前,有一點背景知識會對您大有幫助。
總體結構
進行Windows程序設計,實際上是在進行一種對象導向的程序設計(OOP)。這點在Windows中使用得最多的對象上表現最為明顯。這種對象正是Windows之所以命名為「Windows」的原因,它具有人格化的特征,甚至可能會在您的夢中出現,這就是那個叫做「窗口」的東西。
桌面上最明顯的窗口就是應用程序窗口。這些窗口含有顯示程序名稱的標題列、菜單甚至可能還有工具列和滾動條。另一類窗口是對話框,它可以有標題列也可以沒有標題列。
裝飾對話框表面的還有各式各樣的按鍵、單選按鈕、復選框、清單方塊、滾動條和文字輸入區域。其中每一個小的視覺對象都是一個窗口。更確切地說,這些都稱為「子窗口」或「控件窗口」或「子窗口控件」。
作為對象,使用者會在屏幕上看到這些窗口,并通過鍵盤和鼠標直接與它們進行交互操作。更有趣的是,程序寫作者的觀點與使用者的觀點極其類似。窗口以「消息」的形式接收窗口的輸入,窗口也用消息與其它窗口通訊。對消息的理解將是學習如何寫作Windows程序所必須越過的障礙之一。
這有一個Windows的消息范例:我們知道,大多數的Windows程序都有大小合適的應用程序窗口。也就是說,您能夠通過鼠標拖動窗口的邊框來改變窗口的大小。通常,程序將通過改變窗口中的內容來響應這種大小的變化。您可能會猜測(并且您也是正確的),是Windows本身而不是應用程序在處理與使用者重新調整窗口大小相關的全部雜亂程序。由于應用程序能改變其顯示的樣子,所以它也「知道」窗口大小改變了。
應用程序是如何知道使用者改變了窗口的大小的呢?由于程序寫作者習慣了往常的文字模式程序,操作系統沒有設置將此類消息通知給使用者的機制。問題的
關鍵在于理解Windows所使用的架構。當使用者改變窗口的大小時,Window給程序發送一個消息指出新窗口的大小。然后程序就可以調整窗口中的內容,以響應大小的變化。
「Windows給程序發送消息。」我們希望讀者不要對這句話視而不見。它到底表達了什么意思呢?我們在這里討論的是程序代碼,而不是一個電子郵件系統。操作系統怎么給程序發送消息呢?
其實,所謂「Windows給程序發送消息」,是指Windows呼叫程序中的一個函數,該函數的參數描述了這個特定消息。這種位于Windows程序中的函數稱為「窗口消息處理程序」。
無疑,讀者對程序呼叫操作系統的做法是很熟悉的。例如,程序在打開磁盤文件時就要使用有關的系統呼叫。讀者所不習慣的,可能是操作系統呼叫程序,而這正是Windows對象導向架構的基礎。
程序建立的每一個窗口都有相關的窗口消息處理程序。這個窗口消息處理程序是一個函數,既可以在程序中,也可以在動態鏈接庫中。Windows通過呼叫窗口消息處理程序來給窗口發送消息。窗口消息處理程序根據此消息進行處理,然后將控制傳回給Windows。
更確切地說,窗口通常是在「窗口類別」的基礎上建立的。窗口類別標識了處理窗口消息的窗口消息處理程序。使用窗口類別使多個窗口能夠屬于同一個窗口類別,并使用同一個窗口消息處理程序。例如,所有Windows程序中的所有按鈕均依據同一個窗口類別。這個窗口類別與一個處理所有按鈕消息的窗口消息處理程序(位于Windows的動態鏈接庫中)聯結。
在對象導向的程序設計中,對象是程序與數據的組合。窗口是一種對象,其程序是窗口消息處理程序。數據是窗口消息處理程序保存的信息和Windows為每個窗口以及系統中那個窗口類別保存的信息。
窗口消息處理程序處理給窗口發送消息。這些消息經常是告知窗口,使用者正使用鍵盤或者鼠標進行輸入。這正是按鍵窗口知道它被「按下」的奧妙所在。在窗口大小改變,或者窗口表面需要重畫時,由其它消息通知窗口。
Windows程序開始執行后,Windows為該程序建立一個「消息隊列」。這個消息隊列用來存放該程序可能建立的各種不同窗口的消息。程序中有一小段程序代碼,叫做「消息循環」,用來從隊列中取出消息,并且將它們發送給相應的窗口消息處理程序。有些消息直接發送給窗口消息處理程序,不用放入消息隊列中。
如果您對這段Windows架構過于簡略的描述將信將疑,就讓我們去看看在實際的程序中,窗口、窗口類別、窗口消息處理程序、消息隊列、消息循環和窗口消息是如何相互配合的。這或許會對您有些幫助。
HELLOWIN程序
建立一個窗口首先需要注冊一個窗口類別,那需要一個窗口消息處理程序來處理窗口消息。處理窗口消息對每個Windows程序都帶來了些負擔。程序3-1所示的HELLOWIN程序中整個做的事情差不多就是料理這些事情。
程序3-1 HELLOWIN.ASM
;MASMPlus 代碼模板 - 普通的 Windows 程序代碼
.386
.Model Flat, StdCall
Option Casemap :None
Include windows.inc
Include user32.inc
Include kernel32.inc
Include gdi32.inc
Include winmm.inc
includelib gdi32.lib
IncludeLib user32.lib
IncludeLib kernel32.lib
IncludeLib winmm.lib
include macro.asm
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
.DATA
szAppName db "HelloWin",0
.DATA?
hInstance dd ?
.CODE
START: ;從這里開始執行
invoke GetModuleHandle,NULL
mov hInstance,eax
invoke WinMain,hInstance,NULL,NULL,SW_SHOWDEFAULT
invoke ExitProcess,0
WinMain proc hInst:DWORD,hPrevInst:DWORD,CmdLine:DWORD,CmdShow:DWORD
LOCAL wndclass :WNDCLASSEX
LOCAL msg :MSG
local hWnd :HWND
mov wndclass.cbSize,sizeof WNDCLASSEX
mov wndclass.style,CS_HREDRAW or CS_VREDRAW
mov wndclass.lpfnWndProc,offset WndProc
mov wndclass.cbClsExtra,0
mov wndclass.cbWndExtra,0
push hInst
pop wndclass.hInstance
invoke LoadIcon,NULL,IDI_APPLICATION
mov wndclass.hIcon,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wndclass.hCursor,eax
invoke GetStockObject,WHITE_BRUSH
mov wndclass.hbrBackground,EAX
mov wndclass.lpszMenuName,NULL
mov wndclass.lpszClassName,offset szAppName
mov wndclass.hIconSm,0
invoke RegisterClassEx, ADDR wndclass
.if (EAX==0)
invoke MessageBox,NULL,CTXT("This program requires Windows NT!"),addr szAppName,MB_ICONERROR
ret
.endif
invoke CreateWindowEx,
NULL,
ADDR szAppName, ;window class name
CTXT("http://www.aogosoft.com"), ;window caption
WS_OVERLAPPEDWINDOW, ;window style
200, ;initial x position
200, ;initial y position
400, ;initial x size
200, ;initial y size
NULL, ;parent window handle
NULL, ;window menu handle
hInst, ;program instance handle
NULL ;creation parameters
mov hWnd,eax
invoke ShowWindow,hWnd,SW_SHOWNORMAL
invoke UpdateWindow,hWnd
StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0
cmp eax, 0
je ExitLoop
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
jmp StartLoop
ExitLoop:
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWin:DWORD,uMsg:DWORD,wParam :DWORD,lParam :DWORD
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -