




版權(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025三月份辦公樓地下室側(cè)墻防水基面處理勞務(wù)協(xié)議
- 灌溉自動(dòng)化控制系統(tǒng)考核試卷
- 環(huán)保編織品在綠色建筑內(nèi)外裝飾考核試卷
- 工業(yè)機(jī)器人焊接工藝與控制考核試卷
- 電子專(zhuān)用材料生命周期評(píng)價(jià)考核試卷
- 體育賽事服務(wù)與觀眾滿(mǎn)意度考核試卷
- 涂料店鋪布局優(yōu)化考核試卷
- 《萬(wàn)里長(zhǎng)征》新民主主義革命的興起課件
- 文案-北京明天第一城商業(yè)策劃案
- 2025第二季度離婚后量子密鑰分發(fā)設(shè)備處置協(xié)議
- 大學(xué)語(yǔ)文課程建設(shè)與改革實(shí)施方案
- 【上海市靜安區(qū)寶山路街道社區(qū)養(yǎng)老問(wèn)題調(diào)查報(bào)告】
- 公文筐測(cè)驗(yàn)(案例題解示范)
- 大學(xué)森林生態(tài)教案
- 蛙泳教學(xué)教案
- 醫(yī)學(xué)英語(yǔ)詞匯學(xué)(山東聯(lián)盟)智慧樹(shù)知到答案章節(jié)測(cè)試2023年山東第一醫(yī)科大學(xué)
- 口腔一般檢查方法口腔一般檢查方法
- 冠狀動(dòng)脈粥樣硬化性心臟病 (心內(nèi)科)
- JJF(紡織)071-2016織物摩擦帶電荷密度測(cè)試儀(法拉第筒法)校準(zhǔn)規(guī)范
- GB/T 4857.10-2005包裝運(yùn)輸包裝件基本試驗(yàn)第10部分:正弦變頻振動(dòng)試驗(yàn)方法
- FZ/T 07004-2019紡織行業(yè)綠色工廠(chǎng)評(píng)價(jià)導(dǎo)則
評(píng)論
0/150
提交評(píng)論