官术网_书友最值得收藏!

2.1 基于Windows的應(yīng)用程序設(shè)計(jì)

讀者要理解Visual C++應(yīng)用程序的開發(fā)過程,需要先理解Windows程序的運(yùn)行機(jī)制。由于Visual C++是基于Windows操作系統(tǒng)的集成開發(fā)環(huán)境,需要明白在Windows環(huán)境下編程和在其他環(huán)境下編程的一些根本性的差別。對于Windows程序運(yùn)行的一些根本性的概念,是一個(gè)Visual C++程序員所必須掌握的。

Windows程序設(shè)計(jì)是一種完全不同于傳統(tǒng)的DOS方式的程序設(shè)計(jì)方法。其內(nèi)部運(yùn)行原理是一種事件驅(qū)動方式的程序設(shè)計(jì)模式,主要是基于消息的。當(dāng)用戶需要完成某種功能時(shí)會調(diào)用操作系統(tǒng)的某種支持,然后操作系統(tǒng)將用戶的需要包裝成消息,并投遞到消息隊(duì)列中,最后應(yīng)用程序從消息隊(duì)列中取得消息并進(jìn)行響應(yīng),其流程如圖2-1所示。

圖2-1 Windows程序設(shè)計(jì)

2.1.1 基于Windows的應(yīng)用程序接口(API)

Windows程序設(shè)計(jì)中,應(yīng)用程序要完成某個(gè)功能,通常都是以函數(shù)調(diào)用的形式實(shí)現(xiàn)的。同樣,應(yīng)用程序也通常以函數(shù)調(diào)用的方式來通知操作系統(tǒng)執(zhí)行相應(yīng)的功能。Windows操作系統(tǒng)將它所能夠完成的功能寫成函數(shù)、常量、變量等形式,并提供給應(yīng)用程序使用,而應(yīng)用程序開發(fā)人員無須考慮其底層的源代碼及其工作機(jī)制的內(nèi)部細(xì)節(jié)。應(yīng)用程序?qū)@些函數(shù)的調(diào)用就叫做系統(tǒng)調(diào)用。這些函數(shù)、常量、變量等的集合就是Windows操作系統(tǒng)提供的應(yīng)用程序編程接口(Application Programming Interface),簡稱Windows API。

如果把進(jìn)行Windows編程看作是程序設(shè)計(jì)人員在創(chuàng)作一幅藝術(shù)作品,比如一幅畫,那么Windows API就是程序員手中的筆。通過這支筆,程序員可以畫出多姿多彩的圖畫,如圖2-2所示。

圖2-2 API

例如,Windows中創(chuàng)建窗口的CreateWindow函數(shù)就是一個(gè)API函數(shù),在應(yīng)用程序中調(diào)用這個(gè)函數(shù),操作系統(tǒng)就會按照該函數(shù)提供的參數(shù)信息產(chǎn)生一個(gè)相應(yīng)的窗口,如下所示即調(diào)用CreateWindow函數(shù)。

CreateWindow(szWindowClass,szTitle);

此外,Windows提供了許多API函數(shù),其函數(shù)名和參數(shù)名通常以英文單詞來命名,用戶通過其英文含義便可清楚地知道該API函數(shù)及其每個(gè)參數(shù)的用途。如顯示窗口用ShowWindow,退出Windows操作系統(tǒng)用ExitWindows等。此外,API函數(shù)的正確拼寫格式及各參數(shù)的詳細(xì)信息都可以在MSDN(Microsoft Developer Network,微軟開發(fā)者網(wǎng)絡(luò),專門為開發(fā)人員進(jìn)行軟件開發(fā)所提供的一個(gè)服務(wù))中快速檢索到。

說明

讀者不要將這里的API與Java API或其他API混淆。API正如其語義一樣,已成為一種被廣泛使用的專業(yè)術(shù)語。如果某個(gè)系統(tǒng)或某個(gè)設(shè)備提供給某種應(yīng)用程序,用于對其進(jìn)行操作的函數(shù)、類或組件等的集合,就稱為該系統(tǒng)的API。

2.1.2 句柄的原理

在Windows編程中開發(fā)者會經(jīng)常接觸到一個(gè)稱為句柄(HANDLE)的概念,句柄是指使用一個(gè)四字節(jié)長的整數(shù),用于標(biāo)識應(yīng)用程序中的不同對象或同類對象中的不同實(shí)例。Windows程序中產(chǎn)生的任何資源(要占用某一塊或大或小的內(nèi)存),如圖標(biāo)、光標(biāo)、位圖、窗口和應(yīng)用程序的實(shí)例(已加載到內(nèi)存運(yùn)行中的程序)等,操作系統(tǒng)都要將其放入到相應(yīng)的內(nèi)存中,并為這些內(nèi)存指定一個(gè)唯一的標(biāo)識號,這個(gè)標(biāo)識號即是該資源的句柄。

比如在大街上來來往往的汽車,有許多是相同型號、相同品牌的,也有許多是不同型號、大小的汽車。如何分辨某一輛汽車是屬于誰的呢?就是通過車牌號,因?yàn)檐嚺铺柺俏ㄒ坏模敲窜嚺铺柧褪瞧囘@個(gè)資源的句柄,如圖2-3所示。

圖2-3 句柄

操作系統(tǒng)要管理和操作這些資源,首先都是通過句柄來找到對應(yīng)的資源的。一般來說,按資源的類型,可以將句柄分成圖標(biāo)句柄(HICON)、光標(biāo)句柄(HCURSOR)、位圖句柄(HBITMAP)、窗口句柄(HWND)、應(yīng)用程序?qū)嵗浔℉INSTANCE)等類型。例如,操作系統(tǒng)給每一個(gè)窗口指定的一個(gè)唯一的標(biāo)識號即窗口句柄。以指定的標(biāo)識號作為句柄來創(chuàng)建窗口的語句如下。

hWnd = CreateWindow(szWindowClass,szTitle)

2.1.3 Windows應(yīng)用程序入口——WinMain()函數(shù)

WinMain()函數(shù)是所有Win32程序的入口函數(shù),這個(gè)函數(shù)是應(yīng)用程序的基礎(chǔ),類似于DOS下的main()函數(shù)。當(dāng)Windows操作系統(tǒng)啟動一個(gè)程序時(shí),其調(diào)用的就是該程序的WinMain()函數(shù),當(dāng)WinMain()函數(shù)結(jié)束或返回時(shí),Windows應(yīng)用程序就結(jié)束了。

一般來說,WinMain()函數(shù)接受4個(gè)參數(shù)。這些參數(shù)都是系統(tǒng)調(diào)用WinMain()函數(shù)時(shí),傳遞給應(yīng)用程序的,其原型如下。

int WINAPI WinMain(
        HINSTANCE hInstance,      //當(dāng)前運(yùn)行的實(shí)例句柄
        HINSTANCE hPrevInstance,  //當(dāng)前實(shí)例的上一個(gè)句柄
        LPSTR lpCmdLine,          //命令行指針
        int nCmdShow,             //顯示窗口狀態(tài)
);

各參數(shù)說明如下。

● hInstance:該應(yīng)用程序當(dāng)前實(shí)例的句柄。同一臺計(jì)算機(jī)上可運(yùn)行同一個(gè)應(yīng)用程序的多個(gè)實(shí)例。每啟動一個(gè)這樣的實(shí)例,操作系統(tǒng)都要給該實(shí)例分配一個(gè)標(biāo)識號,即實(shí)例句柄。隨后系統(tǒng)調(diào)用程序中的WinMain函數(shù),并將該實(shí)例句柄傳遞給參數(shù)hInstance。

● hPrevInstance:由同一個(gè)應(yīng)用程序產(chǎn)生的先前實(shí)例的句柄。對于一個(gè)32位程序,該參數(shù)往往為NULL。

● lpCmdLine:是一個(gè)字符串,里面包含有傳遞給應(yīng)用程序的參數(shù)串。例如,在Visual C++開發(fā)環(huán)境中給應(yīng)用程序傳遞參數(shù),單擊【Project】|【Settings】菜單項(xiàng),在彈出的【Project Settings】對話框中選擇【Debug】標(biāo)簽,在該標(biāo)簽頁的【Program arguments】編輯框中輸入想要傳遞給應(yīng)用程序的參數(shù)。

● nCmdShow:指定程序窗口應(yīng)該如何顯示,如參數(shù)SW_SHOWMAXIMIZED將激活窗口并將其最大化,SW_MINIMIZE將最小化指定的窗口,SW_HIDE將隱藏窗口,并激活另外一個(gè)窗口等。

如果WinMain在消息循環(huán)之前返回,程序沒有正常運(yùn)行,返回值為0。如果在消息循環(huán)之后返回,返回值為WM_QIUT消息的wParam參數(shù)。

一般來說,一個(gè)完整的Win32程序,其實(shí)現(xiàn)大致可分為4個(gè)步驟。例如,在Windows中創(chuàng)建一個(gè)窗口,并在該窗口中響應(yīng)鍵盤及鼠標(biāo)消息,其程序?qū)崿F(xiàn)步驟如下。

1 WinMain函數(shù)的定義。

2 創(chuàng)建一個(gè)窗口。

3 進(jìn)行消息循環(huán)。

4 完成回調(diào)函數(shù)。

說明

在Visual C++ 6.0中使用MFC進(jìn)行Windows編程時(shí),開發(fā)者可能找不到WinMain函數(shù),這是因?yàn)镸FC將WinMain函數(shù)隱藏在應(yīng)用程序的框架中,編譯時(shí)會自動將該函數(shù)鏈接到可執(zhí)行文件中。開發(fā)者可以重寫WinMain函數(shù),但一般不需要這樣做。

2.1.4 消息及消息隊(duì)列機(jī)制

在應(yīng)用程序中,用戶所有的操作都是通過消息機(jī)制(Message)來傳遞給操作系統(tǒng)的。操作系統(tǒng)將每個(gè)事件都包裝成一個(gè)稱為消息的結(jié)構(gòu)體MSG來傳遞給應(yīng)用程序。例如,用戶在某個(gè)程序活動時(shí)按了一下鍵盤鍵,操作系統(tǒng)馬上能感知到這一事件,并且能夠知道用戶按下的是哪一個(gè)鍵。操作系統(tǒng)并不決定對這一事件如何作出反應(yīng),而是將這一事件轉(zhuǎn)交給應(yīng)用程序。由應(yīng)用程序決定如何對這一事件作出反應(yīng),對事件作出反應(yīng)的過程就是消息響應(yīng)。

比如,有只蚊子叮了某個(gè)人一口,神經(jīng)末梢(相當(dāng)于操作系統(tǒng))馬上感知到這個(gè)事件,并傳遞給了大腦(相當(dāng)于應(yīng)用程序)。大腦最終決定如何對這一事件作出反應(yīng)。如將蚊子趕走,或是將蚊子拍死。其中蚊子叮人就產(chǎn)生了消息,而用戶的反應(yīng)就是消息響應(yīng)。在Windows編程中,消息與應(yīng)用程序的關(guān)系如圖2-4所示。

圖2-4 消息與應(yīng)用程序的關(guān)系

了解了消息的概念后,讀者可以再來看看消息隊(duì)列(Queue)的概念。Windows本身維護(hù)一個(gè)系統(tǒng)消息隊(duì)列,對于每一個(gè)正在運(yùn)行的Windows應(yīng)用程序,系統(tǒng)會為其建立一個(gè)“消息隊(duì)列”,用于存放該應(yīng)用程序可能創(chuàng)建的各種消息。消息隊(duì)列是一個(gè)先進(jìn)先出的緩沖區(qū),通常是一個(gè)某種變量類型的數(shù)組。消息隊(duì)列里的每一個(gè)元素就是一條消息。操作系統(tǒng)將生成的每個(gè)消息按先后順序放進(jìn)消息隊(duì)列里。第一條消息放入第一格,第二條消息放入第二格,依此類推。

一般來說,應(yīng)用程序中包含一段消息循環(huán)代碼,用于從消息隊(duì)列中檢索這些消息。應(yīng)用程序總是取走隊(duì)列中的第一條消息。消息取走后,第二條消息成為第一條,剩余的消息依次前移。應(yīng)用程序取得消息后,便能夠知道用戶的操作和程序狀態(tài)的變化,并把它們分發(fā)到相應(yīng)的函數(shù)中進(jìn)行處理。

例如,若應(yīng)用程序從隊(duì)列里取到了一條WM_CHAR消息,那一定是用戶輸入了一個(gè)字符,并且能夠知道輸入的是哪個(gè)字符。應(yīng)用程序得到消息后,就要對消息進(jìn)行處理,這就是通常說的消息響應(yīng)。消息響應(yīng)是用戶通過編碼實(shí)現(xiàn)的,這也是Windows程序的主要代碼。

在消息響應(yīng)代碼中,很可能又要調(diào)用操作系統(tǒng)提供的API函數(shù),以便完成特定的功能。如果用戶收到窗口的WM_CLOSE消息,可以調(diào)用API函數(shù)DestroyWindow來關(guān)閉該窗口,或是用MessageBox函數(shù)來提示用戶是否真的要關(guān)閉窗口。

因此,使用Visual C++編寫Windows程序時(shí)需要掌握以下兩點(diǎn)。

● 不同的消息所代表的用戶操作和程序狀態(tài)。

● 要讓操作系統(tǒng)執(zhí)行某個(gè)功能所對應(yīng)的API函數(shù)。

提示

Windows編程的主要代碼都集中在對消息的處理上,或者說編寫消息響應(yīng)(處理)函數(shù)是進(jìn)行Windows編程的主要工作。

主站蜘蛛池模板: 邹平县| 麻栗坡县| 龙里县| 金溪县| 田阳县| 天等县| 临安市| 务川| 河东区| 普洱| 廉江市| 曲阳县| 鄄城县| 利津县| 新余市| 定西市| 前郭尔| 阿拉善左旗| 施秉县| 裕民县| 临汾市| 苍山县| 荆州市| 天峨县| 无棣县| 永安市| 磐安县| 无为县| 商都县| 大埔县| 汝城县| 淄博市| 滁州市| 浦城县| 二连浩特市| 武川县| 岐山县| 巫山县| 扎赉特旗| 霸州市| 囊谦县|