MFC程序員的WTL指南_第1頁(yè)
MFC程序員的WTL指南_第2頁(yè)
MFC程序員的WTL指南_第3頁(yè)
MFC程序員的WTL指南_第4頁(yè)
MFC程序員的WTL指南_第5頁(yè)
已閱讀5頁(yè),還剩160頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

MICROSOFT

MFC程序員的WTL指南

2008

[鍵入公司地址]

序言3

第一章ATL界面類(lèi)4

1.1、對(duì)本書(shū)的總體介紹4

1.2、對(duì)這一章的簡(jiǎn)單介紹5

1.2.1、ATL背景知識(shí)ATL和WTL的發(fā)展歷史5

1.2.2、ATL風(fēng)格模板6

1.3、ATL窗口類(lèi)8

1.3.1,定義一個(gè)窗口的實(shí)現(xiàn)8

1.3.2、填寫(xiě)消息映射鏈9

1.3.3、高級(jí)消息映射鏈和嵌入類(lèi)11

1.3.4、ATL程序的結(jié)構(gòu)13

1.3.5、ATL中的對(duì)話(huà)框15

第二章WTL界面基類(lèi)18

2.1、WTL總體印象18

2.2、開(kāi)始寫(xiě)WTL程序18

2.2.1、WTL對(duì)消息映射的增強(qiáng)20

2.2.2、從WTL的應(yīng)用程序生成向?qū)艿玫绞裁?4

第三章工具條與狀態(tài)條35

3.1、主窗口的工具條和狀態(tài)條35

第四章對(duì)話(huà)框與控件48

第五章高級(jí)對(duì)話(huà)框用戶(hù)界面類(lèi)67

第六章包容ActiveX控件82

第七章分隔窗口96

第八章屬性頁(yè)與向?qū)?12

第九章GDI類(lèi),通用對(duì)話(huà)框,初始化類(lèi)127

9.1、GDI封裝類(lèi)127

9.1.1、封裝類(lèi)的通用函數(shù)128

9.2.3、與MFC封裝類(lèi)的不同之處130

9.3、資源裝載(Resource-Loading)函數(shù)130

9.4、使用通用對(duì)話(huà)框133

9.4.1>CFileDialog類(lèi)134

9.4.2、CFolderDialog類(lèi)136

9.5、其它有用的類(lèi)和全局函數(shù)138

9.5.1、對(duì)結(jié)構(gòu)的封裝138

9.5.2、處理雙類(lèi)型參數(shù)的類(lèi)138

9.6、其它工具類(lèi)138

9.7、全局函數(shù)140

9.8、宏142

9.9、例子工程143

第十章支持拖放操作146

序言

我一直在尋找這樣一個(gè)類(lèi)庫(kù):他對(duì)Windows的窗口提供面向?qū)ο蟮姆庋b,有靈活的消息響應(yīng)機(jī)

制和比較完備的界面框架解決方案,對(duì)標(biāo)準(zhǔn)控件提供簡(jiǎn)練實(shí)用的封裝,支持操作系統(tǒng)的新特性,支

持功能擴(kuò)充和二次開(kāi)發(fā),有代碼自動(dòng)生成向?qū)C(jī)制,生成的程序使用較少的系統(tǒng)資源,最后是有完

全的代碼支持和文檔支持。

你會(huì)說(shuō)那就用MFC吧!

是的,我一直使用MFC,但我對(duì)MFC已經(jīng)越來(lái)越厭倦了。陳舊的類(lèi)庫(kù)使得它無(wú)法支持操作系統(tǒng)

的新特性(MFC的類(lèi)庫(kù)從4.21版之后就沒(méi)有更新了,而那時(shí)是1998年,人們使用Windows95和

windowsNT4),臃腫的消息映射機(jī)制和為了兼容性而保留下來(lái)的代碼使得程序效率低下,面面俱到

的框架結(jié)構(gòu)使得生成的應(yīng)用程序龐大并占用過(guò)多的系統(tǒng)資源。當(dāng)一個(gè)功能簡(jiǎn)單的程序使用動(dòng)態(tài)鏈接

也超過(guò)200K,占用3%-4%的系統(tǒng)資源時(shí),我決定放棄MFC,尋找一個(gè)新的功能類(lèi)似的類(lèi)庫(kù)。我研

究過(guò)很多類(lèi)似的代碼,不是過(guò)于簡(jiǎn)單,無(wú)法用于應(yīng)用程序的開(kāi)發(fā),就是缺乏代碼和文檔的支持。在

CodeProject上有一個(gè)名為Class的類(lèi)庫(kù),我也研究過(guò)它的代碼,具備了基本的界面框架,對(duì)控件也有

了簡(jiǎn)單的封裝,但是不實(shí)用,龐大的虛函數(shù)機(jī)制使得對(duì)象非常臃腫,無(wú)法減少對(duì)資源的占用。我甚

至仿照MFC做了一個(gè)簡(jiǎn)單的類(lèi)庫(kù)miniGUL形成了基本的框架解決方案,但是最后放棄了,原因很

簡(jiǎn)單:無(wú)法用于應(yīng)用程序的開(kāi)發(fā)。-個(gè)應(yīng)用程序界面框架錯(cuò)綜復(fù)雜,要考慮的事情太多,開(kāi)發(fā)者不

可能在應(yīng)用程序和界面框架兩線(xiàn)作戰(zhàn)。就在我即將絕望的時(shí)候,我遇到了WTL。

由于工作的需要經(jīng)常開(kāi)發(fā)一些COM組件,在要求不能使用MFC的場(chǎng)合就是用ATL。ATL提供

了對(duì)窗口的面向?qū)ο蟮胤庋b和簡(jiǎn)單的消息映射機(jī)制,但是ATL過(guò)于簡(jiǎn)單,用它開(kāi)發(fā)應(yīng)用程序幾乎不

可能。要想讓ATL具備界面框架解決方案的功能還需要做很多事情,幸運(yùn)的是WTL就做了這些事

情。WTL是個(gè)很奇特的東西,它由微軟公司一群熱情的程序員維護(hù),它從未出現(xiàn)在微軟的官方產(chǎn)品

名單上,但可以從微軟的官方網(wǎng)站下載最新的WTL。它沒(méi)有正式的文檔支持,用WTL做關(guān)鍵字在

MSDN中檢索只能得到0個(gè)結(jié)果,但是全世界的開(kāi)發(fā)網(wǎng)站上都有針對(duì)WTL的討論組和郵件列表,任

何問(wèn)題都會(huì)得到熱情的解答。我認(rèn)真地對(duì)比了MFC和WTL,發(fā)現(xiàn)二者有很多相通之處,MFC的功

能幾乎都能在WTL中實(shí)現(xiàn),只是方法不同而已。我?guī)缀醪毁M(fèi)吹灰之力就將以前寫(xiě)的一個(gè)MFC程序

用WTL改寫(xiě)了,使用靜態(tài)鏈接的WTL程序比使用動(dòng)態(tài)鏈接的MFC程序還要小,資源占用只有MFC

程序的一半。

但是一時(shí)的熱情不能解決文檔缺乏的困擾,雖然網(wǎng)上有很多使用WTL的例子和說(shuō)明文章,兒乎

把MFC能實(shí)現(xiàn)的各種稀奇古怪的效果都實(shí)現(xiàn)了。就在這個(gè)時(shí)候我看到了邁克爾.敦(MichaelDunn)

的“WTLforMFCProgrammers”系列文章,我的感覺(jué)和1995年我第一次見(jiàn)到MSDN時(shí)一樣,幾乎是

迫不及待地將其讀完,同時(shí)也萌發(fā)了將其翻譯成漢語(yǔ)的沖動(dòng)。于是給Michael寫(xiě)了封郵件,希望能夠

得到授權(quán)將他的文章翻譯成漢語(yǔ)(事實(shí)上在這之前我已經(jīng)翻譯了兩章了)。在得到授權(quán)確認(rèn)后才發(fā)現(xiàn)這

個(gè)工作是多么的困難,但為時(shí)已晚,只能硬著頭皮撐下去。

第一章ATL界面類(lèi)

你需要開(kāi)發(fā)平臺(tái)SDK。你要使用WTL不能沒(méi)有它,你可以使用在線(xiàn)升級(jí)安裝開(kāi)發(fā)平臺(tái)SDK,

也可以下載全部文件后在本地安裝。在使用之前要將SDK的包含文件(.h頭文件)和庫(kù)文件(.Lib

文件)路徑添加到VC的搜索目錄,SDK有現(xiàn)成的工具完成這個(gè)工作,這個(gè)工具位于開(kāi)發(fā)平臺(tái)SDK

程序組的“VisualStudioRegistration”文件夾里(這是針對(duì)VC++6.0的)。

你需要安裝WTL。你可以從微軟的網(wǎng)站上下載WTL的8.()版,在安裝之前可以先查看“Intro

ductiontoWTL-Part1”和“EasyinstallationofWTL”這兩篇文章,了解一下所要安裝的文件的信息,

雖然現(xiàn)在這些文章有些過(guò)時(shí),但還是可以提供很多有用的信息。有一件我認(rèn)為不該在本篇文章中提

到的事是告訴VC如何搜索WTL的包含文件路徑,如果你用的VC6,用鼠標(biāo)點(diǎn)擊Tools\Options,轉(zhuǎn)

到Directories標(biāo)簽頁(yè),在顯示路徑的列表框中選擇IncludeFiles,然后將WTL的包含文件的存放路

徑添加到包含文件搜索路徑列表中。

你需要了解MFC。很好地了解MFC將有助于你理解后面提到的有關(guān)消息映射的宏并能夠編輯那

些標(biāo)有“不要編輯(DONOTEDIT)”的代碼而不會(huì)出現(xiàn)問(wèn)題。

你需要清楚地知道如何使用Win32API編程。如果你是直接從MFC開(kāi)始學(xué)習(xí)Windows編程,

沒(méi)有學(xué)過(guò)API級(jí)別的消息處理方式,那很不幸你會(huì)在使用WTL時(shí)遇到麻煩。如果不了解Windows

消息中WPARAM參數(shù)和LPARAM參數(shù)的意義,則需要讀一些這方面的文章(在CodeProject有大

量的此類(lèi)文章)。

你需要知道C++模板的語(yǔ)法,你可以到VCForumFAQ相關(guān)的連接尋求答案。

我只是討論了一些涵蓋VC6的特點(diǎn),不過(guò)據(jù)我了解所有的程序都可以在VC7上使用。由于我

不使用VC7,我無(wú)法對(duì)那些在VC7中出現(xiàn)的問(wèn)題提供幫助,不過(guò)你還是可以放心的在此張貼你的

問(wèn)題,因?yàn)槠渌娜丝赡軙?huì)幫助你。

1.1、對(duì)本書(shū)的總體介紹

WTL具有兩面性,確實(shí)是這樣的。雖然它沒(méi)有MFC的界面類(lèi)庫(kù)那樣強(qiáng)大的功能,但是能夠生

成很小的應(yīng)用程序。如果你象我一樣使用MFC進(jìn)行界面編程,你會(huì)覺(jué)得MFC提供的界面控件封裝

類(lèi)使用起來(lái)非常舒服,更不用說(shuō)MFC內(nèi)置的消息處理機(jī)制。當(dāng)然,如果你也象我■?樣不希望自己的

程序僅僅因?yàn)槭褂昧薓FC的框架就增加兒百K的大小的話(huà),WTL就是你的選擇。當(dāng)然,我們還要

克服一些障礙:

1>ATL樣式的模板類(lèi)初看起來(lái)有點(diǎn)怪異:

2>沒(méi)有類(lèi)向?qū)У闹С?,所以要手工處理所有的消息映射(名叫VisualFC的第三方插件可以提供

相應(yīng)向?qū)В?/p>

3>MSDN沒(méi)有正式的文檔支持,你需要到處去收集有關(guān)的文檔,甚至是查看WTL的源代碼;

4>買(mǎi)不到參考書(shū)籍;

5>沒(méi)有微軟的官方支持;

6>ATL/WTL的窗口與MFC的窗口有很大的不同,你所了解的有關(guān)MFC的知識(shí)并不完全適用于

WTLo

從另一方面來(lái)講,WTL也有它自身的優(yōu)勢(shì):

1>不需要學(xué)習(xí)或掌握復(fù)雜的文檔/視圖框架;

2>具有MFC的基本的界面特色,比如DDX/DDV和命令狀態(tài)UI更新功能(比如菜單的Check

標(biāo)記和Enable標(biāo)記等);

3>增強(qiáng)了一些MFC的特性(比如更加易用的分隔窗口);

4>可生成比靜態(tài)鏈接的MFC程序更小的應(yīng)用程序(WTL的所有源代碼都是靜態(tài)鏈接到你的程序

中的,除了CRT之類(lèi));

5>你可以修正自己使用的WTL中的BUG,而不會(huì)影響其他的應(yīng)用程序(相比之下,如果你修正

了有BUG的MFC/CRT動(dòng)態(tài)庫(kù)就可能會(huì)引起其它應(yīng)用程序的崩潰;

6>如果你仍然需要使用MFC,MFC的窗口和ATL/WTL的窗口可以“和平共處”。

在本文中,我將首先介紹ATL的窗口類(lèi),畢竟WTL是構(gòu)建于ATL之上的,并附加了一系列類(lèi),

所以需要很好地了解ATL的窗口類(lèi)。介紹完ATL之后我將介紹WTL的特性,并展示它是如何使界

面編程變得輕而易舉。

1.2、對(duì)這一章的簡(jiǎn)單介紹

WTL是個(gè)很酷的工具,在理解這一點(diǎn)之前需要首先介紹ATL。WTL是構(gòu)建與ATL之上的,并

附加了一系列類(lèi)。如果你是個(gè)使用MFC的程序員,你可能沒(méi)有機(jī)會(huì)接觸到ATL的界面類(lèi),所以請(qǐng)容

忍我在開(kāi)始WTL之前先羅索一些別的東西,繞道來(lái)介紹一下ATL是很有必要地。

在本文的第一部分,我將給出一點(diǎn)ATL的背景知識(shí),包括一些編寫(xiě)ATL代碼所必須知道的基礎(chǔ)

知識(shí),快速地解釋一些令人不知所措的ATL模板類(lèi)和基本的ATL窗口類(lèi)。

1.2.1、ATL背景知識(shí)ATL和WTL的發(fā)展歷史

ATL”活動(dòng)模板庫(kù)”是一個(gè)很古怪的名字。那些年紀(jì)大的人可能還記得,它最初被稱(chēng)為“網(wǎng)絡(luò)組件

模板庫(kù)”,這可能是它更準(zhǔn)確的稱(chēng)呼,因?yàn)锳TL的目的就是使編寫(xiě)組件對(duì)象和ActiveX控件更容易一

些(ATL是在微軟開(kāi)發(fā)新產(chǎn)品ActiveX-某某的過(guò)程中開(kāi)發(fā)的,那些ActiveX-某某現(xiàn)在被稱(chēng)為某某.

NET)o由于ATL只是為了便于編寫(xiě)組件對(duì)象而存在的,所以?xún)H提供了簡(jiǎn)單的界面類(lèi),相當(dāng)于MFC

的窗口類(lèi)(CWnd)和對(duì)話(huà)框類(lèi)(CDialog)。幸運(yùn)地是,這些類(lèi)非常的靈活,能夠在其基礎(chǔ)上構(gòu)建象

WTL這樣的附加類(lèi)。

WTL現(xiàn)在已經(jīng)是第三次修正版了,最初的版本是3.1,現(xiàn)在的最新版本是&0(WTL的版本號(hào)之

所以這樣選擇,是為了與ATL的版本匹配,所以不存在1和2這樣的版本號(hào))。WTL3.1可以與VC

6和VC9一起使用,但是在VC9下需要定義幾個(gè)預(yù)處理標(biāo)號(hào)。WTL8向下兼容WTL3.1,并且不

作任何修改就可以與VC9一起使用,現(xiàn)在看來(lái)沒(méi)有任何理由還使用3.1來(lái)進(jìn)行新的開(kāi)發(fā)工作。

1.2.2、ATL風(fēng)格模板

即使你能夠毫不費(fèi)力地閱讀C++的模板類(lèi)代碼,仍然有兩件事可能會(huì)使你有些頭暈,以下面這

個(gè)類(lèi)的定義為例:

classCMyWnd:publicCWindowlmpl<CMyWnd>

};

這樣作是合法的,因?yàn)镃++的語(yǔ)法解釋說(shuō)即使CMyWnd類(lèi)只是被部分定義,類(lèi)名CMyWnd已

經(jīng)被列入遞歸繼承列表,是可以使用的。將類(lèi)名作為模板類(lèi)的參數(shù)是因?yàn)锳TL要做另一件詭秘的事

情,那就是編譯期間的虛函數(shù)調(diào)用機(jī)制。

如果你想要了解它是如何工作地,請(qǐng)看下面的例子:

template<classT>

classBl

(

public:

voidSayHi()

(

T*pT=static_cast<T*>(this);//HUH??我將在卜面解釋

pT->PrintClassName();

)

protected:

voidPrintClassName(){cout?"ThisisBl";}

);

classDI:publicB1<D1>

(

//Nooverriddenfunctionsatall

};

classD2:publicB1<D2>

(

protected:

voidPrintClassName(){cout?"ThisisD2";}

};

main()

(

Dldl;

D2d2;

dl.SayHi();//打印"ThisisBl"

d2.SayHi();〃打印"ThisisD2"

這句代碼static_cast<T*>(this)就是竅門(mén)所在。它根據(jù)函數(shù)調(diào)用時(shí)的特殊處理將指向B1類(lèi)型的

指針由is指派為D1或D2類(lèi)型的指針,因?yàn)槟0宕a是在編譯其間生成的,所以只要編譯器生成正

確的繼承列表,這樣指派就是安全的。如果你寫(xiě)成:

classD3:publicB1<D2>

就會(huì)有麻煩。之所以安全是因?yàn)閠his對(duì)象只可能是指向D1或D2(在某些情況下)類(lèi)型的對(duì)象,

不會(huì)是其他的東西。注意這很像C++的多態(tài)性,只是SayHi()方法不是虛函數(shù)。

要解釋這是如何工作的,首先看對(duì)每個(gè)SayHi()函數(shù)的調(diào)用,在第一個(gè)函數(shù)調(diào)用,對(duì)象B1被指

派為D1,所以代碼被解釋成:

voidBl<Dl>::SayHi()

(

DI*pT=static_cast<Dl*>(this);

pT->PrintClassName();

由于Dl沒(méi)有重載PrintClassNameO,所以查看基類(lèi)Bl,Bl有PrintClassName(),所以Bl的Print

ClassName。被調(diào)用。

現(xiàn)在看第二個(gè)函數(shù)調(diào)用SayHi(),這一次對(duì)象被指派為D2類(lèi)型,SayHi()被解釋成:

voidBl<D2>::SayHi()

(

D2*pT=static_cast<D2*>(this);

pT->PrintClassName();

這一次,D2含有PrintClassNameO方法,所以D2的PrintClassNameO方法被調(diào)用。

這種技術(shù)的有利之處在于:

1>不需要使用指向?qū)ο蟮闹羔槪?/p>

2>節(jié)省內(nèi)存,因?yàn)椴恍枰摵瘮?shù)表;

3>因?yàn)闆](méi)有虛函數(shù)表所以不會(huì)發(fā)生在運(yùn)行時(shí)調(diào)用空指針指向的虛函數(shù);

4>所有的函數(shù)調(diào)用在編譯時(shí)確定(區(qū)別于C++的虛函數(shù)機(jī)制使用的動(dòng)態(tài)鏈接),有利于編譯程序

對(duì)代碼的優(yōu)化。

節(jié)省虛函數(shù)表在這個(gè)例子中看起來(lái)無(wú)足輕重(每個(gè)虛函數(shù)只有4個(gè)字節(jié)),但是設(shè)想一下如果有

15個(gè)基類(lèi),每個(gè)類(lèi)含有20個(gè)方法,加起來(lái)就相當(dāng)可觀了。

1.3、ATL窗口類(lèi)

好了,關(guān)于ATL的背景知識(shí)已經(jīng)講的夠多了,該正式講ATL的了。ATL在設(shè)計(jì)時(shí),接口定義和

實(shí)現(xiàn)是嚴(yán)格區(qū)分開(kāi)的,這在窗口類(lèi)的設(shè)計(jì)中最為明顯。這一點(diǎn)類(lèi)似于COM,COM的接口定義和實(shí)

現(xiàn)是完全分開(kāi)的(或者可能有多個(gè)實(shí)現(xiàn))。

ATL有一個(gè)專(zhuān)門(mén)為窗口設(shè)計(jì)的類(lèi),可以做全部的窗口操作,這就是CWindow。它實(shí)際上就是對(duì)

HWND操作的包裝類(lèi),對(duì)幾乎所有以HWND句柄為第一個(gè)參數(shù)的窗口API的進(jìn)行了封裝,例如:

SetWindowText()和DestroyWindow()oCWindow類(lèi)有一個(gè)公有成員m_hWnd,使你可以直接對(duì)窗口

的句柄操作,CWindow還看一個(gè)操作符HWND,你可以將CWindow對(duì)象傳遞給以HWND為參數(shù)

的函數(shù),但這與CWnd::GetSafeHwnd()(譯者加I:MFC的方法)沒(méi)有任何相同之處。

CWindow與MFC的CWnd類(lèi)有很大的不同,創(chuàng)建一個(gè)CWindow對(duì)象占用很少的資源,因?yàn)?/p>

只有一個(gè)數(shù)據(jù)成員,沒(méi)有MFC窗口中的對(duì)象鏈。MFC內(nèi)部維持這個(gè)對(duì)象鏈,此對(duì)象鏈將HWND映

射到CWnd對(duì)象。還有--點(diǎn)與MFC的CWnd類(lèi)不同的是:當(dāng)一個(gè)CWindow對(duì)象超出了作用域,它

所關(guān)聯(lián)的窗口并不被銷(xiāo)毀掉,這意味著你并不需要隨時(shí)記得分離你所創(chuàng)建的臨時(shí)CWindow對(duì)象。

在ATL類(lèi)中對(duì)窗口過(guò)程的實(shí)現(xiàn)是CWindowImpl。CWindowImpl包含有所有窗口實(shí)現(xiàn)代碼,例

如:窗口類(lèi)的注冊(cè),窗口的子類(lèi)化,消息映射以及基本的WindowProc。函數(shù)??梢钥闯鲞@與MFC的

設(shè)計(jì)有很大的不同,MFC將所有的代碼都放在CWnd類(lèi)中。

另外兩個(gè)獨(dú)立的類(lèi)是對(duì)話(huà)框的實(shí)現(xiàn),它們分別是CDialoglmpI和CAxDialoglmpLCDialoglmpl用

于實(shí)現(xiàn)普通的對(duì)話(huà)框,而CAxDialoglmpl實(shí)現(xiàn)含有ActiveX控件的對(duì)話(huà)框。

1.3.1、定義一個(gè)窗口的實(shí)現(xiàn)

任何非對(duì)話(huà)框窗口都是從CWindowImpl派生的,你的新類(lèi)需要實(shí)現(xiàn)三樣?xùn)|西:

1>定義窗口類(lèi)(通過(guò)DECLARE_WND_CLASS或DECLARE_WND_CLASS_EX宏實(shí)現(xiàn));

2>生成消息映射鏈(通過(guò)BEGIN_MSG_MAP和END_MSG_MAP宏實(shí)現(xiàn));

3>窗口使用的默認(rèn)窗口類(lèi)型(稱(chēng)為windowtraits)。

窗口類(lèi)的定義通過(guò)DECLARE_WND_CLASS宏或DECLARE_WND_CLASS_EX宏來(lái)實(shí)現(xiàn)。

這兩個(gè)宏定義了一個(gè)CWndClassInfo結(jié)構(gòu),這個(gè)結(jié)構(gòu)封裝了WNDCLASSEX結(jié)構(gòu)。DECLARE_WND_

CLASS宏讓你指定窗口類(lèi)的類(lèi)名,其他參數(shù)使用默認(rèn)設(shè)置,而DECLARE_WND_CLASS_EX宏還犬

許你指定窗口類(lèi)的類(lèi)型和窗口的背景顏色。你也可以用NULL作為類(lèi)名,ATL會(huì)自動(dòng)為你生成一個(gè)

類(lèi)名。

讓我們開(kāi)始定義一個(gè)新類(lèi),在后面的章節(jié)我們會(huì)逐步完成這個(gè)類(lèi)的定義。

classCMyWindow:publicCWindowlmpl<CMyWindow>

DECLARE_WND_CLASS(_T("MyWindowClass"))

接下來(lái)是生成消息映射鏈,ATL的消息映射鏈比MFC簡(jiǎn)單得多,ATL的消息映射鏈被展開(kāi)為

switch語(yǔ)句,switch語(yǔ)句正確的消息處理者并調(diào)用相應(yīng)的函數(shù)。使用消息映射鏈的宏是BEGIN_MSG

_MAP和END_MSG_MAP,讓我們?yōu)槲覀兊拇翱谔砑右粋€(gè)空的消息映射鏈。

classCMyWindow:publicCWindowlmpl<CMyWindow>

public:

DECLARE_WND_CLASS<_T("MyWindowClass"))

BEGIN_MSG_MAP(CMyWindow)

END_MSG_MAP()

我將在下一節(jié)展開(kāi)講如何如何添加消息處理到消息映射鏈。最后,我們需要為我們的窗口類(lèi)定

義窗口的特征,窗口的特征就是窗口類(lèi)型和擴(kuò)展窗口類(lèi)型的聯(lián)合體,用于創(chuàng)建窗口時(shí)指定窗口的類(lèi)

型。窗口類(lèi)型被指定為參數(shù)模板,所以窗口的調(diào)用者不需要為指定窗口的正確類(lèi)型而煩心,下面是

是同ATL類(lèi)CWinTraits定義窗口類(lèi)型的例子:

TypedefCWinTraits<WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,WS_EX_APPWINDOW>CMyWindowTraits;

classCMyWindow:publicCWindowlmpl<CMyWindowzCWindow,CMyWindowTraits>

public:

DECLARE_WND_CLASS(_T("MyWindowClass"))

BEGIN_MSG_MAP(CMyWindow)

END_MSG_MAP()

調(diào)用者可以重載CMyWindowTraits的類(lèi)型定義,但是一般情況下這是沒(méi)有必要的,ATL提供了

兒個(gè)預(yù)先定義的特殊的類(lèi)型,其中之一就是CFrameWinTraits,一個(gè)非常棒的框架窗口:

typedefCWinTraits<WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,

WS_EX_APPWINDOW|WS_EX_WINDOWEDGE>CFrameWinTraits;_________

1.3.2、填寫(xiě)消息映射鏈

ATL的消息映射鏈?zhǔn)菍?duì)開(kāi)發(fā)者不太友好的部分,也是WTL對(duì)其改進(jìn)最大的部分。類(lèi)向?qū)е辽?/p>

可以讓你添加消息響應(yīng),然而ATL沒(méi)有消息相關(guān)的宏和象MFC那樣的參數(shù)自動(dòng)展開(kāi)功能,在ATL

中只有三種類(lèi)型的消息處理,一個(gè)是WM_NOTIFY,一個(gè)是WM_COMMAND,第三類(lèi)是其他窗口

消息宏MESSAGE_HANDLER。讓我們開(kāi)詔為我們的窗口添加WM.CLOSE和WM_DESTROY的消

息處理函數(shù)。

classCMyWindow:publicCWindowlmpl<CMyWindow,CWindow,CFrameWinTraits>

(

public:

DECLARE_WND_CLASS(_T("MyWindowClass"))

BEGIN_MSG_MAP(CMyWindow)

MESSAGE_HANDLER(WM_CLOSE,OnClose)

MESSAGE_HANDLER(WM_DESTROY,OnDestroy)

END_MSG_MAP()

LRESULTOnClose(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

(

DestroyWindow();

return0;

)

LRESULTOnDestroy(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

(

PostQuitMessage(O);

return0;

}

};

你可能注意到消息響應(yīng)函數(shù)得到的是原始的WPARAM和LPARAM值,你需要自己將其展開(kāi)為

相應(yīng)的消息所需要的參數(shù)。還有第四個(gè)參數(shù)bHandled,這個(gè)參數(shù)在消息相應(yīng)函數(shù)調(diào)用前被ATL設(shè)置

為T(mén)RUE,如果在你的消息響應(yīng)處理完之后需要ATL調(diào)用默認(rèn)的WindowProc。處理該消息,你可以

將bHandled設(shè)置為FALSE0這與MFC不同,MFC是顯式地調(diào)用基類(lèi)的響應(yīng)函數(shù)來(lái)實(shí)現(xiàn)的默認(rèn)的消

息處理的。

讓我們?cè)偬砑右粋€(gè)對(duì)WM_COMMAND消息的處理,假設(shè)我們的窗口有一個(gè)ID為IDC_ABOUT

的About菜單:

classCMyWindow:publicCWindowlmpl<CMyWindow,CWindow,CFrameWinTraits>

(

public:

DECLARE_WND_CLASS(_T("MyWindowClass"))

BEGIN_MSG_MAP(CMyWindow)

MESSAGE_HANDLER(WM_CLOSE,OnClose)

MESSAGE_HANDLER(WM_DESTROY,OnDestroy)

COMMAND_ID_HANDLER(IDC_ABOUT,OnAbout)

END_MSG_MAP()

LRESULTOnClose(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

(

DestroyWindow();

return0;

}

LRESULTOnDestroy(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

{

PostQuitMessage(O);

return0;

)

LRESULTOnAbout(WORDwNotifyCode,WORDwID,HWNDhWndCtl,BOOL&bHandled)

(

MessageBox(_T(nSampleATLwindow1*),_T("AboutMyWindow'*));

return0;

)

};

需要注意的是COMMAND_HANDLER宏已經(jīng)將WM_COMMAND消息的參數(shù)展開(kāi)了,同樣,

NOTIFY—HANDLER宏也將WM_NOTIFY消息的參數(shù)展開(kāi)了。

1.3.3、高級(jí)消息映射鏈和嵌入類(lèi)

ATL的另一個(gè)顯著不同之處就是任何C++類(lèi)都可以響應(yīng)消息,而MFC只是將消息響應(yīng)任務(wù)分給

TCWnd類(lèi)和CCmdTarget類(lèi),夕卜力口幾個(gè)有PreTranslateMessage()方法的類(lèi)。ATL的這種特性

允許我們編寫(xiě)所謂的“嵌入類(lèi)”,為我們的窗口添加特性只需將該類(lèi)添加到繼承列表中就行了,就這么

簡(jiǎn)單!

一個(gè)基本的帶有消息映射鏈的類(lèi)通常是模板類(lèi),將派生類(lèi)的類(lèi)名作為模板的參數(shù),這樣它就可

以訪(fǎng)問(wèn)派生類(lèi)中的成員,比如m_hWnd(CWindow類(lèi)中的HWND成員)。讓我們來(lái)看■?個(gè)嵌入類(lèi)的

例子,這個(gè)嵌入類(lèi)通過(guò)響應(yīng)WM_ERASEBKGND消息來(lái)畫(huà)窗口的背景。

template<classT,COLORREFt_crBrushColor>

classCPaintBkgnd:publicCMessageMap

(

public:

CPaintBkgnd(){m_hbrBkgnd=CreateSolidBrush(t_crBrushColor);}

~CPaintBkgnd(){DeleteObject(m_hbrBkgnd);}

BEGIN_MSG_MAP(CPaintBkgnd)

MESSAGE_HANDLER(WM_ERASEBKGND,OnEraseBkgnd)

END_MSG_MAP()

LRESULTOnEraseBkgnd(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

(

T*pT=static_cast<T*>(this);

HDCde=(HDC)wParam;

RECTrcClient;

pT->GetClientRect(&rcClient);

FillRect(de,&rcClient,m_hbrBkgnd);

return1;//wepaintedthebackground

)

protected:

HBRUSHm_hbrBkgnd;

);

讓我們來(lái)研究,一下這個(gè)新類(lèi)。首先,CPaintBkgnd有兩個(gè)模板參數(shù):使用CPaintBkgnd的派生類(lèi)

的名字和用來(lái)畫(huà)窗口背景的顏色(t_前綴通常用來(lái)作為模板類(lèi)的模板參數(shù)的前綴)。CPaintBkgnd也是

從CMessageMap派生的,這并不是必須的,因?yàn)樗行枰憫?yīng)消息的類(lèi)只需使用BEGIN_MSG_MAP

宏就足夠了,所以你可能看到其他的一些嵌入類(lèi)的例子代碼,它們并不是從該基類(lèi)派生的。

構(gòu)造函數(shù)和析構(gòu)函數(shù)都相當(dāng)簡(jiǎn)單,只是創(chuàng)建和銷(xiāo)毀Windows畫(huà)刷,這個(gè)畫(huà)刷由參數(shù)t_crBrushColor

決定顏色。接著是消息映射鏈,它響應(yīng)WM_ERASEBKGND消息,最后由響應(yīng)函數(shù)OnEraseBkgnd。

使用構(gòu)造函數(shù)創(chuàng)建的畫(huà)刷填充窗口的背景。在OnEraseBkgnd。中有兩件事需要注意:-是它使用了

一個(gè)派生的窗口類(lèi)的方法(即GetClientRectO),我們?nèi)绾沃琅缮?lèi)中有GetClientRect()方法呢?如

果派生類(lèi)中沒(méi)有這個(gè)方法我們的代碼也不會(huì)有任何問(wèn)題,由編譯器確認(rèn)派生類(lèi)T是從CWindow派生

的。另一-個(gè)是OnEraseBkgnd。沒(méi)有將消息參數(shù)wParam展開(kāi)為設(shè)備上下文(DC)。

想要使用這個(gè)嵌入類(lèi)有兩件事需要做:

首先,將它加入到繼承列表:

classCMyWindow:publicCWindowlmpl<CMyWindowzCWindow,CFrameWinTraits>,

_________________publicCPaintBkgndvCMyWindow,RGB(0,0,255)>_______________

其次,需要CMyWindow將消息鏈入CPaintBkgnd類(lèi),在CMyWindow的消息映射鏈中加入CHAIN

_MSG_MAP宏:

classCMyWindow:publicCWindowlmpl<CMyWindow,CWindow,CFrameWinTraits>,

publicCPaintBkgnd<CMyWindow,RGB(0/0/255)>

typedefCPaintBkgnd<CMyWindow,RGB(O,O,255)>CPaintBkgndBase;

BEGIN_MSG_MAP(CMyWindow)

MESSAGE_HANDLER(WM_CLOSEZOnClose)

MESSAGE_HANDLER(WM_DESTROY,OnDestroy)

COMMAND_HANDLER(IDC_ABOUT,OnAbout)

CHAIN_MSG_MAP(CPaintBkgndBase)

END_MSG_MAP()

};

任何CMyWindow沒(méi)有處理的消息都被傳遞給CPaintBkgndo應(yīng)該注意的是WM_CLOSE,WM_

DESTROY和IDC_ABOUT消息將不會(huì)傳遞,因?yàn)檫@些消息一旦被處理消息映射鏈的查找就會(huì)中止。

使用typedef是必要地,因?yàn)楹晔穷A(yù)處理宏,只能有?個(gè)參數(shù),如果我們將CPaintBkgnd<CMyWindow,

RGB(0,0,255)>作為參數(shù)傳遞,那個(gè)“,”會(huì)使預(yù)處理器認(rèn)為我們使用了多個(gè)參數(shù)。

你可以在繼承列表中使用多個(gè)嵌入類(lèi),每一個(gè)嵌入類(lèi)使用一個(gè)CHAIN_MSG_MAP宏,這樣消

息映射鏈就會(huì)將消息傳遞給它。這與MFC不同,MFC的CWnd派生類(lèi)只能有一個(gè)基類(lèi),MFC自動(dòng)

將消息傳遞給基類(lèi)。

1.3.4、ATL程序的結(jié)構(gòu)

到目前為止我們已經(jīng)有了一個(gè)完整的主窗口類(lèi)(即使不完全有用),讓我們看看如何在程序中使

用它。一個(gè)ATL程序包含一個(gè)CComModule類(lèi)型的全局變量.Module,這和MFC的程序都有一個(gè)

CWinApp類(lèi)型的全局變量theApp有些類(lèi)似,唯一,不同的是在ATL中這個(gè)變量必須命名為.Module。

下面是stdafx.h文件的開(kāi)始部分:

//stdafx.h:

#defineSTRICT

#defineVC_EXTRALEAN

#include<atlbase.h>//基本的ATL類(lèi)

externCComModule_Module;//全局_Module

^include<atlwin.h>//ATL窗口類(lèi)

allbase.h是包含最基本的Window編程的頭文件,所以我們不需要再包含windows.h,tchar.h之

類(lèi)的頭文件。在CPP文件中聲明了.Module變量:

//main.cpp:

CComModule_Module;

CComModule含有程序的初始化和關(guān)閉函數(shù),需要在WinMain。中顯示的調(diào)用。讓我們從這里開(kāi)

始:

//main.cpp:

CComModule_Module;

intWINAPIWinMain(HINSTANCEhlnst,HINSTANCEhlnstPrev,LPSTRszCmdLine,intnCmdShow)

(

_Module.lnit(NULL,hlnst);

_Module.Term();

}一

Init()的第一個(gè)參數(shù)只有COM的服務(wù)程序才有用,由于我們的EXE不含有COM對(duì)象,我們只

需將NULL傳遞給Init()就行了。ATL不提供自己的WinMain。和類(lèi)似MFC的消息隊(duì)列,所以我們需

要?jiǎng)?chuàng)建CMyWindow對(duì)象并添加消息隊(duì)列才能使我們的程序運(yùn)行。

//main.cpp:

#include"MyWindow.h',

CComModule_Module;

intWINAPIWinMain(HINSTANCEhlnst,HINSTANCEhlnstPrev,LPSTRszCmdLine,intnCmdShow)

.Module.lnit(NULL,hlnst);

CMyWindowwndMain;

MSGmsg;

//創(chuàng)建和顯示主窗口

if(NULL==wndMain.Create(NULL,CWindow::rcDefault,_T(nMyFirstATLWindow")))

(

//窗口失敗

return1;

)

wndMain.ShowWindow(nCmdShow);

wndMain.UpdateWindow();

//運(yùn)行消息循環(huán)

while(GetMessage(&msg7NULL,0,0)>0)

(

TranslateMessage(&msg);

DispatchMessage(&msg);

}

_Module.Term();

returnmsg.wParam;

)

上面的代碼唯一需要說(shuō)明的是:CWindow::rcDefault,它是CWindow中的成員(靜態(tài)數(shù)據(jù)成員),

數(shù)據(jù)類(lèi)型是RECT。與調(diào)用CreateWindowO時(shí)使用CW_USEDEFAULT指定窗口的寬度和高度一樣,

ATL使用rcDefault作為窗口的最初大小。

在ATL代碼內(nèi)部,ATL使用了一些類(lèi)似匯編語(yǔ)言的方法將窗口的句柄與相應(yīng)的窗口對(duì)象聯(lián)系起

來(lái)。從外部來(lái)看,就可以毫無(wú)問(wèn)題的在線(xiàn)程之間傳遞CWindow對(duì)象,而MFC的CWnd卻不能這樣

做。圖1就是我們的窗口:

圖1ATL的應(yīng)用程序

我們得承認(rèn)這確實(shí)沒(méi)有什么激動(dòng)人心的地方。我們將添加一個(gè)About菜單并顯示一個(gè)對(duì)話(huà)框,

主要是為它增加??些情趣。

1.3.5、ATL中的對(duì)話(huà)框

我們?cè)谇懊嫣岬竭^(guò),ATL有兩個(gè)對(duì)話(huà)框類(lèi),我們的About對(duì)話(huà)框使用CDialoglmpl。生成一個(gè)新

對(duì)話(huà)框和生成一個(gè)主窗口幾乎一樣,只有兩點(diǎn)不同:

1>窗口的基類(lèi)是CDialoglmpl,而不是CWindowImpl。

2>你需要定義名稱(chēng)為IDD的公有成員,用來(lái)保存對(duì)話(huà)框的資源ID。

現(xiàn)在開(kāi)始為About對(duì)話(huà)框定義一個(gè)新類(lèi):

classCAboutDIg:publicCDialoglmpl<CAboutDlg>

(

public:

enum{IDD=IDD_ABOUT};

BEGIN_MSG_MAP(CAboutDlg)

END_MSG_MAP()

};

ATL沒(méi)有在內(nèi)部實(shí)現(xiàn)對(duì)“OK”和“Cancel”兩個(gè)按鈕的響應(yīng)處理,所以我們需要自己添加這些代碼,

如果用戶(hù)用鼠標(biāo)點(diǎn)擊標(biāo)題欄的關(guān)閉按鈕,WM_CLOSE的響應(yīng)函數(shù)就會(huì)被調(diào)用。我們還需要處理

WM」NITDIALOG消息,這樣我們就能夠在對(duì)話(huà)框出現(xiàn)時(shí)正確的設(shè)置鍵盤(pán)焦點(diǎn),下面是完整的類(lèi)定

義和消息響應(yīng)函數(shù)。

classCAboutDIg:publicCDialoglmpl<CAboutDlg>

(

public:

enum{IDD=IDDABOUT};

BEGIN_MSG_MAP(CAboutDlg)

MESSAGE_HANDLER(WM_INITDIALOG,OnlnitDialog)

MESSAGE_HANDLER(WM_CLOSE,OnClose)

COMMAND_ID_HANDLER(IDOK,OnOKCancel)

COMMAND_ID_HANDLER(IDCANCEL,OnOKCancel)

END_MSG_MAP(j

LRESULTOnlnitDialog(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

(

CenterWindow();

returnTRUE;//letthesystemsetthefocus

)

LRESULTOnClose(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

(

EndDialog(IDCANCEL);

return0;

}

LRESULTOnOKCancel(WORDwNotifyCode,WORDwID,HWNDhWndCtl,BOOL&bHandled)

(

EndDialog(wlD);

return0;

}

};

我使用一個(gè)消息響應(yīng)函數(shù)同時(shí)處理“OK”和“Cancel”兩個(gè)按鈕的WM_COMMAND消息,因?yàn)槊?/p>

令響應(yīng)函數(shù)的wID參數(shù)就已經(jīng)指明了消息是來(lái)自“OK”按鈕還是來(lái)自“Cancel”按鈕。

顯示對(duì)話(huà)框的方法與MFC相似,創(chuàng)建一個(gè)新對(duì)話(huà)框類(lèi)的實(shí)例,然后調(diào)用DoModaK)方法。現(xiàn)在

我們回到主窗口,添加一個(gè)帶有About菜單項(xiàng)的菜單用來(lái)顯示我們的對(duì)話(huà)框,這需要再添加兩個(gè)消

息響應(yīng)函數(shù),一個(gè)是響應(yīng)WM_CREATE,另一個(gè)是響應(yīng)菜單的IDC_ABOUT命令。

classCMyWindow:publicCWindowlmpl<CMyWindowzCWindow,CFrameWinTraits^

publicCPaintBkgnd<CMyWindow,RGB(0/0,255)>

(

public:

BEGIN_MSG_MAP(CMyWindow)

MESSAGE_HANDLER(WM_CREATE,OnCreate)

COMMAND_ID_HANDLER(IDC_ABOUT,OnAbout)

//...

CHAIN_MSG_MAP(CPaintBkgndBase)

END_MSG_MAP()

LRESULTOnCreate(UINTuMsg,WPARAMwParam,LPARAMIParam,BOOL&bHandled)

(

HMENUhmenu=LoadMenu(_Module.GetResourcelnstance(),MAKEINTRESOURCE(IDR_MENU1));

SetMenu(hmenu);

return0;

}

LRESULTOnAbout(WORDwNotifyCode,WORDwID,HWNDhWndCtl,BOOL&bHandled)

(

CAboutDIgdig;

dlg.DoModal();

return0;

)

II...

};

在指定對(duì)話(huà)框的父窗口的方式上有些不同,MFC是通過(guò)構(gòu)造函數(shù)將父窗口的指針傳遞給對(duì)話(huà)框,

而在ATL中是將父窗口的指針作為DoModal()方法的第一個(gè)參數(shù)傳遞給對(duì)話(huà)框的,如果象上面的代

碼一樣沒(méi)有指定父窗口,ATL會(huì)使用GetActiveWindow。得到的窗口(也就是我們的主框架窗口)作

為對(duì)話(huà)框的父窗口。

對(duì)LoadMenu。方法的調(diào)用展示了CComModule的另一個(gè)方法一GetResourcelnstance。,它返回

你的EXE的HINSTANCE實(shí)例,和MFC的AfxGetResourceHandle。方法相似。(當(dāng)然還有CCom

Module::GetModuleInstance(),它相當(dāng)于MFC的AfxGetInstanceHandle()o)

圖2就是主窗口和對(duì)話(huà)框的顯示效果:

圖2帶對(duì)話(huà)框的應(yīng)用程序主窗口

第二章WTL界面基類(lèi)

在這一部分我們講的內(nèi)容包括生成一個(gè)基本的主窗口和WTL提供的一些友好改進(jìn),比如UI界

面的更新(如菜單上的選擇標(biāo)記)和更好的消息映射機(jī)制。為了更好地掌握本章的內(nèi)容,你應(yīng)該安

裝WTL并將WTL庫(kù)的頭文件目錄添加到VC的搜索目錄中,還要將WTL的應(yīng)用程序生成向?qū)?fù)制

到正確的位置。WTL的發(fā)布版本中有文檔具體介紹如何做這些設(shè)置,如果遇到困難可以查看這些文

檔。

2.1、WTL總體印象

WTL的類(lèi)大致可以分為幾種類(lèi)型:

1>主框架窗口的實(shí)現(xiàn)-CFrameWindowImpl,CMDIFrameWindowImpl

2>控件的封裝-CButton,CListViewCtrl

3>GDI對(duì)象的封裝-CDC,CMenu

4>一些特殊的界面特性-CSplitterWindow,CUpdateUI,CDialogResize,CCustomDraw

5>實(shí)用的工具類(lèi)和宏-CString,CRect,BEGIN_MSG_MAP_EX

本篇文章將深入地介紹框架窗口類(lèi),還將簡(jiǎn)要地講一下有關(guān)的界面特性類(lèi)和工具類(lèi),界面特性

類(lèi)和工具類(lèi)中絕大多數(shù)都是獨(dú)立的類(lèi),盡管有一些是嵌入類(lèi),例如:CDialogResizeo

2.2、開(kāi)始寫(xiě)WTL程序

如果你沒(méi)有用WTL的應(yīng)用程序生成向?qū)б矝](méi)關(guān)系(我將在后面介紹這個(gè)向?qū)У挠梅ǎ?,WTL的程

序的代碼結(jié)構(gòu)很像ATL的程序,本章使用的例子代碼有別于第一章的,主要是為了顯示W(wǎng)TL的特性,

沒(méi)有什么實(shí)用價(jià)值。

這一節(jié)我們將在WTL生成的代碼基礎(chǔ)上添加代碼,生成一個(gè)新的程序,程序主窗口的客戶(hù)區(qū)顯

示當(dāng)前的時(shí)間。stdafx.h的代碼如下:

^defineSTRICT

#defineWIN32_LEAN_AND_MEAN

ttdefineWTLUSECSTRING

^include<atlbase.h>//基本的ATL類(lèi)

#include<atlapp.h>//基本的WTL類(lèi)

externCAppModule_Module;//WTL派生的CComModule版本

#include<atlwin.h>//ATL窗口類(lèi)

^include<atlframe.h>//WTL主框架窗口類(lèi)

include<atlmisc.h>//WTL實(shí)用工具類(lèi),例如:CString

#include<atlcrack.h>//WTL增強(qiáng)的消息宏

atlapp.h是你的工程中第一個(gè)包含的頭文件,這個(gè)文件內(nèi)定義了有關(guān)消息處理的類(lèi)和CApp

Module,CAppModule是從CComModuIe派生的類(lèi)。如果你打算使用CString類(lèi),你需要手工定義_WTL

_USE_CSTRING標(biāo)號(hào),因?yàn)镃String類(lèi)是在atlmisc.h中定義的,而許多包含在atlmisc.h之前的頭

受件.會(huì)用至UCString,定義_WTL_USE_CSTRING之后,atlapp.h就會(huì)向前聲明CString類(lèi),其他的

頭文件就知道CString類(lèi)的存在,從而避免編譯器為此報(bào)錯(cuò)。

接下來(lái)定義框架窗口。我們的SDI窗口是從CFrameWindowImpl派生的,在定義窗口類(lèi)時(shí)使用

DECLARE_FRAME_WND_CLASS代替前面使用的DECLARE_WND_CLASS。下面時(shí)MyWindow.h

中窗口定義M開(kāi)始部務(wù):

classCMyWindow:publicCFrameWindowlmpl<CMyWindow>

(

public:

DECLARE_FRAME_WND_CLASS(_T("FirstWTLwindow"),IDR_MAINFRAME);

BEGIN_MSG_MAP(CMyWindow)

CHAIN_MSG_MAP(CFrameWindowlmpl<CMyWindow>)

END_MSG_MAP()

};

DECLARE_FRAME_WND_CLASS有兩個(gè)參數(shù),窗口類(lèi)名(類(lèi)名可以是NULL,ATL會(huì)替你生

成一個(gè)類(lèi)名)和資源ID,初建窗口時(shí)WTL用這個(gè)ID裝載圖標(biāo),菜單和快捷鍵表。我們還要象CFrame

Windowlmpl中的消息處理(例如WM_SIZE和WM_DESTROY消息)那樣將消息鏈入窗口的消息中。

現(xiàn)在來(lái)看看WinMain。函數(shù),它和第一部分中的例子代碼中的WinMain。函數(shù)兒乎一樣,只是創(chuàng)

建窗口部分的代碼略微不同。

//main.cpp:

include"stdafx.h"

#include"MyWindow.h"

CAppModule_Module;

intAPIENTRYWinMain(HINSTANCEhlnst,HINSTANCEhPrevlnstzLPSTRIpCmdLine,intnCmdShow)

(

_Module.lnit(NULL,hlnstance);

CMyWindowwndMain;

MSGmsg;

//創(chuàng)建主窗口

if(NULL==wndMain.CreateEx())

return1;//Windowcreationfailed

//顯示窗口

wndMain.ShowWindow(nCmdShow);

wndMain.UpdateWindow();

//標(biāo)準(zhǔn)Win32消息循環(huán)

while(GetMessage(&msg,NULL,0,0)>0)

TranslateMessage(&msg);

DispatchMessage(&msg);

)

_Module.Term();

returnmsg.wParam;

}

CFrameWindowImpl中的CreateEx。函數(shù)的參數(shù)使用了常用的默認(rèn)值,所以我們不需要特別指定

任何參數(shù)。正如前面介紹的,CFrameWindowImpl會(huì)處理資源的裝載,你只需要使用IDR_MAIN

FRAME作為ID定義你的資源就行了(譯者注:主要是圖標(biāo),菜單和快捷鍵表),你也可以直接使用

本章的例子代碼。

如果你現(xiàn)在就運(yùn)行程序,你會(huì)看到主框架窗口,事實(shí)上它沒(méi)有做任何事情。我們需要手工添加

一些消息處理,所以現(xiàn)在是介紹WTL的消息映射宏的最佳時(shí)間。

2.2.1、WTL對(duì)消息映射的增強(qiáng)

將Win32Api通過(guò)消息傳遞過(guò)來(lái)的WPARAM和LPARAM數(shù)據(jù)分解出來(lái)是一件麻煩的事情,并

且很容易出錯(cuò),不幸得是ATL并沒(méi)有為我們提供更多的幫助,我們?nèi)匀恍枰獜南⒅蟹纸膺@些數(shù)據(jù),

當(dāng)然WM_COMMAND和WM_NOTIFY消息除外。但是WTL的出現(xiàn)拯救了這一切!

WTL的增強(qiáng)消息映射宏定義在atlcrack.h(這個(gè)名字來(lái)源于“消息解密者”,是一個(gè)與windowsx.h

的宏所使用的相同術(shù)語(yǔ))中。首先將BEGIN_MSG_MAP改為BEGIN_MSG_MAP_EX,帶_EX的版

本產(chǎn)生“解密”消息的代碼。

classCMyWindow:publicCFrameWindowlmpl<CMyWindow>

(

public:

BEGIN_MSG_MAP_EX(CMyWindow)

CHAIN_MSG_MAP(CFrameWindowlmpl<CMyWindow>)

END_MSG_MAP()

};

對(duì)于我們的時(shí)鐘程序,我們需要處理WM_CREATE消息來(lái)設(shè)置定時(shí)器,WTL的消息處理使用

MSG_作為前綴,后面是消息名稱(chēng),例如MSG_WM_CREATE?這些宏只是代表消息響應(yīng)處理的名稱(chēng),

現(xiàn)在我們來(lái)添加對(duì)WM_CREATE消息的響應(yīng)函數(shù):

classCMyWindow:publicCFrameWindowlmpl<CMyWindow>

(

public:

BEGIN_MSG_MAP_EX(CMyWindow)

MSG_WM_CREA

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論