VC++ ATL 学习总结
生活随笔
收集整理的這篇文章主要介紹了
VC++ ATL 学习总结
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ATL (一種微軟程序庫)
ATL,Active Template Library活動模板庫,是一種微軟程序庫,支持利用C++語言編寫ASP代碼以及其它ActiveX程序。通過活動模板庫,可以建立COM組件,然后通過ASP頁面中的腳本對COM對象進行調用。這種COM組件可以包含屬性頁、對話框等控件。
中文名 ATL 類 ? ?型 一種微軟程序庫 支 ? ?持 C++語言 年 ? ?份 1993年
目錄
1 什么是ATL
2 ATL基本技術
3 ATL基本使用
4 應用舉例
什么是ATL
自從1993年Microsoft首次公布了COM技術以后,Windows平臺上的開發模式發生了巨大的變化,以COM為基礎的一系列軟件組件化
技術將Windows編程帶入了組件化時代。廣大的開發人員在為COM帶來的軟件組件化趨勢歡欣鼓舞的同時,對于COM開發技術的難度
和煩瑣的細節也感到極其的不便。COM編程一度被視為一種高不可攀的技術,令人望而卻步。開發人員希望能夠有一種方便快捷的
COM開發工具,提高開發效率,更好地利用這項技術。
針對這種情況,Microsoft公司在推出COM SDK以后,為簡
化COM編程,提高開發效率,采取了許多方案,特別是在MFC(Microsoft Foundation Class)中加入了對COM和OLE的支持。但是
隨著Internet的發展,分布式的組件技術要求COM組件能夠在網絡上傳輸,而又盡量節約寶貴的網絡帶寬資源。采用MFC開發的COM
組件由于種種限制不能很好地滿足這種需求,因此Microsoft在1995年又推出了一種全新的COM開發工具ATL。
ATL是ActiveX Template Library 的縮寫,它是一套C++模板庫。使用ATL能夠快速地開發出高效、簡潔的代碼(Effective and Slim?
code),同時對COM組件的開發提供最大限度的代碼自動生成以及可視化支持。為了方便使用,從MicrosoftVisual C++5.0版本開始
,Microsoft把ATL集成到Visual C++開發環境中。1998年9月推出的Visual Studio 6.0 集成了ATL 3.0版本。ATL已經成為Microsoft標
準開發工具中的一個重要成員,日益受到C++開發人員的重視。
ATL究竟給開發人員帶來了什么樣的益處呢?這還要先從ATL產生以前的COM開發方式說起。
在ATL產生以前,開發COM組件的方法主要有兩種:一是使用COM SDK直接開發COM組件,另一種方式是通過MFC提供的COM支持
來實現。
直接使用COM SDK開發COM組件是最基本也是最靈活的方式。通過使用Microsoft提供的開發包,我們可以直接編寫COM程序。但是
,這種開發方式的難度和工作量都很大,一方面,要求開發者對于COM的技術原理具有比較深入的了解(雖然對技術本身的深刻理解
對使用任何一種工具都是非常有益的,但對于COM這樣一整套復雜的技術而言,在短時間內完全掌握是很難的),另一方面,直接使
用COM SDK要求開發人員自己去實現COM應用的每一個細節,完成大量的重復性工作。這樣做的結果是,不僅降低了工作效率,同時
也使開發人員不得不把許多精力投入到與應用需求本身無關的技術細節中。雖然這種開發方式對于某些特殊的應用很有必要,但這種編
程方式并不符合組件化程序設計方法所倡導的可重用性,因此,直接采用COM SDK不是一種理想的開發方式。
使用MFC提供的COM支持開發COM應用可以說在使用COM SDK基礎上提高了自動化程度,縮短了開發時間。MFC采用面向對象的方
式將COM的基本功能封裝在若干MFC的C++類中,開發者通過繼承這些類得到COM支持功能。為了使派生類方便地獲得COM對象的
各種特性,MFC中有許多預定義宏,這些宏的功能主要是實現COM接口的定義和對象的注冊等通常在COM對象中要用到的功能。開發
者可以使用這些宏來定制COM對象的特性。
另外,在MFC中還提供對Automation和 ActiveX Control的支持,對于這兩個方面,Visual C++也提供了相應的AppWizard和
ClassWizard支持,這種可視化的工具更加方便了COM應用的開發。
MFC對COM和OLE 的支持確實比手工編寫COM程序有了很大的進步。但是MFC對COM的支持是不夠完善和徹底的,例如對COM接
口定義的IDL語言,MFC并沒有任何支持,此外對于近些年來COM和ActiveX技術的新發展MFC也沒有提供靈活的支持。這是由MFC設
計的基本出發點決定的。MFC被設計成對Windows平臺編程開發的面向對象的封裝,自然要涉及Windows編程的方方面面,COM作
為Windows平臺編程開發的一個部分也得到MFC的支持,但是MFC對COM的支持是以其全局目標為出發點的,因此對COM 的支持必
然要服從其全局目標。從這個方面而言,MFC對COM的支持不能很好的滿足開發者的要求。
隨著Internet技術的發展,Microsoft將ActiveX技術作為其網絡戰略的一個重要組成部分大力推廣,然而使用MFC開發的ActiveX?
Control,代碼冗余量大(所謂的“肥代碼 Fat Code”),而且必須要依賴于MFC的運行時刻庫才能正確地運行。雖然MFC的運行時
刻庫只有部分功能與COM有關,但是由于MFC的繼承實現的本質,ActiveX Control必須背負運行時刻庫這個沉重的包袱。如果采用靜
態連接MFC運行時刻庫的方式,這將使ActiveX Control代碼過于龐大,在網絡上傳輸時將占據寶貴的網絡帶寬資源;如果采用動態連
接MFC運行時刻庫的方式,這將要求瀏覽器一方必須具備MFC的運行時刻庫支持。總之MFC對COM技術的支持在網絡應用的環境下也
顯得很不靈活。
解決上述COM開發方法中的問題正是ATL的基本目標。
首先ATL的基本目標就是使COM應用開發盡可能地自動化,這個基本目標就決定了ATL只面向COM開發提供支持。目標的明確使ATL對
COM技術的支持達到淋漓盡致的地步。對COM開發的任何一個環節和過程,ATL都提供支持,并將與COM開發相關的眾多工具集成到
一個統一的編程環境中。對于COM/ActiveX的各種應用,ATL也都提供了完善的Wizard支持。所有這些都極大地方便了開發者的使用
,使開發者能夠把注意力集中在與應用本身相關的邏輯上。
其次,ATL因其采用了特定的基本實現技術,擺脫了大量冗余代碼,使用ATL開發出來的COM應用的代碼簡練高效,即所謂的“Slim?
Code”。ATL在實現上盡可能采用優化技術,甚至在其內部提供了所有C/C++開發的程序所必須具有的C啟動代碼的替代部分。同時
ATL產生的代碼在運行時不需要依賴于類似MFC程序所需要的龐大的代碼模塊,包含在最終模塊中的功能是用戶認為最基本和最必須的
。這些措施使采用ATL開發的COM組件(包括ActiveX Control)可以在網絡環境下實現應用的分布式組件結構。
第三,ATL的各個版本對Microsoft的基于COM的各種新的組件技術如MTS、ASP等都有很好的支持,ATL對新技術的反應速度大大快
于MFC。ATL已經成為Microsoft支持COM應用開發的主要開發工具,因此COM技術方面的新進展在很短的時間內都會在ATL中得到反
映。這使開發者使用ATL進行COM編程可以得到直接使用COM SDK編程同樣的靈活性和強大的功能。
本文的目的就是希望在有限的篇幅中能夠使讀者對ATL的使用和基本原理有一個初步的了解,為廣大的COM開發人員更好地使用ATL開
發起到拋磚引玉的作用。
ATL基本技術編輯
雖然使用ATL開發COM 應用是一件非常簡單的事情,但是在ATL簡單易用的界面后面卻包含著復雜的技術。面對ATL生成的大量代碼,
我們即使不去深入地了解這些代碼的含義也可以開發出COM應用來,但是如果我們要充分地挖掘ATL的潛力,開發出更靈活、強大的
COM應用,則必須對ATL使用的基本技術有所了解。研究ATL的實質最好的教材就是由Visual C++提供的ATL源代碼。本文這一部分只
是對ATL中用到的最基本的技術進行簡單的介紹。
簡單地說來,ATL中所使用的基本技術包括以下幾個方面:
COM技術
C++模板類技術(Template)
C++多繼承技術(Multi-Inheritance)
COM技術是理解ATL的基礎,使用ATL進行開發要對COM技術的基本概念有最低限度的了解。由于COM是一項非常復雜龐大的技術體
系,限于本文的篇幅,這里不再贅述。對于本文中提到的COM基本概念也不做過多的解釋,請讀者參閱有關的參考書籍。
作為ATL最核心的實現技術的模板是對標準C++語言的擴展,但是在大多數的C++編程環境中,人們很少使用它,這是因為模板的功能
雖然很強,但是它內部機制比較復雜,需要比較多的C++知識和經驗才能靈活地使用它。在MFC中的CObjectArray等功能類就是由模
板來定義的。完全通過模板來定義程序的整體類結構,ATL是迄今為止做得最為成功的。
所謂模板類簡單地說是對類的抽象。我們知道C++語言用類定義了構造對象(這里指C++對象而不是COM對象)的方式,對象是類的
實例,而模板類定義的是類的構造方式,使用模板類定義實例化的結果產生的是不同的類。因此可以說模板類是“類的類”。
在C++語言中模板類的定義格式如下:
注意:<;和>;是左右尖括號,可能無法正常顯示。
template<class T>
classMyTemp
{
MyTemp<T>(){};
~MyTemp<T>(){};
intMyFunc(inta);
}
………….
IntMyTemp<T>::MyFunc(inta)
{
}
首先使用C++的關鍵字“template”來聲明一個模板類的定義。在關鍵字后面是用尖括號括起來的類型參數。正是根據這個類型參數,
編譯器才能在編譯過程中將模板類的具體定義轉化為一個實際的類的定義,即生成一個新的類。接下來的定義方式與普通的類定義十分
相似,只是在類的函數定義中都要帶有類型參數的說明。
下面的程序段說明了模板類的用法:
typedefMyTemp<MyClass>myclassfromtemp;
myclassfromtempm;
inta=m.Myfunc⑽;
通常在使用模板類時為了方便起見,使用一個關鍵字“typedef”為新定義出來的類取一個名字。在上面的程序段中假設“MyClass”
是一個由用戶定義的類,通過將這個類的名字作為類型參數傳遞給模板類,我們可以創建一個新的類,這個類的行為將以模板類的定義
為基礎,例如它具有模板類定義的所有成員函數,同時這個類又是對模板類行為的一種修改,這種修改是通過用戶提供的類型參數來實
現的。賦予模板類以不同的類型參數,則得到行為框架相似但具體行為不同的一組類的集合。有了新的類的定義以后,我們可以象使用
普通類一樣來創建一個類的實例,即一個新的對象,并且調用這個對象的成員函數。
模板類是對標準C++語言的最新擴展,雖然它的功能很強大,但是要想使用好模板類需要相當多的關于語言和編程的經驗和知識,而且
錯誤地使用模板類又會對程序的結構和運行效率帶來大的副作用,因此一般的編程環境和編程書籍對模板類的使用都采取謹慎的態度。
而ATL的核心就是由幾十個模板類構成的,通過研究ATL的源代碼可以使我們對模板類的使用有比較深刻全面的認識。
多繼承技術同模板一樣,是C++語言中極具爭議性的技術。使用多繼承技術可以使程序的設計和實現更加靈活,但是,由于多繼承的復
雜性和自身概念上的一些問題,使多繼承在各種面向對象的語言環境中得到的支持都非常有限。例如Small Talk根本就不允許多繼承,
同樣MFC也不支持多繼承技術。
多繼承最大的問題是所謂的“鉆石結構”。例如下面的代碼:
class A
{
.....
};
class B : public A
{
...
};
class C : public A
{
.....
};
class D : public C,B
{
........
}
由于類D同時從類C和B繼承,因此在下面的語句中就會發生歧義:
1
2
D*pD=newD;
(A*)pD->Func(...);
由于類D通過類C和類B 分別繼承了類A,這里的強制轉化就會發生歧義。
ATL使用了C++最新規范中加入的兩個運算符號static_cast、dynamic_cast代替簡單的強制轉化,從而消除多繼承帶來的歧義。使用這
兩個運算符號,我們可以在對象運行過程中獲取對象的類型信息。上面的代碼可以采用下面的方式修改:
1
2
D*pD=newD;
static_cast<A*>(static_cast<B*>(pD))->Func(...);
為什么模板類和多繼承技術會成為ATL主要的工具呢?原因在于,采用模板可以在編譯過程中快速的生成具有用戶定制功能的類,這對
于COM這樣一個復雜的技術體系在實現效率上得到了很大的提高。通過使用模板類,用戶可以把精力集中在自己開發的類的基本邏輯
上,在完成了自己的類的設計以后,通過繼承不同的模板類,生成不同的類,就可以快速地實現COM的功能,同時又避免了采用單繼
承結構造成的大量功能冗余。
總之,正是由于在設計實現過程中采用了模板類和多繼承技術,才使ATL成為一個小巧靈活的COM開發工具,能夠適應開發人員對
COM應用開發的各種需要。
ATL基本使用
這一部分將重點介紹ATL的基本使用過程。由于ATL已經被集成在Microsoft Visulal Studio的Visual C++開發環境中,因此要使用ATL
必須先安裝Visual C++。在下面的討論中有關COM的基本知識請參閱有關的文檔,這里不再詳細說明。
使用ATL開發一個COM應用基本可以分為以下幾個步驟:
創建一個新的ATL工程,并對工程的選項進行適當的配置。
向新創建的工程添加新的ATL類,并對該類進行一些初始配置工作。
根據COM應用的基本要求向新的ATL類加入新的接口定義,并實現相應的接口成員函數。
編譯連接工程,注冊COM應用。
下面將根據這些步驟依次介紹ATL的基本使用過程(給出的是Visual Studio 6.0的使用):
1. 創建工程
首先啟動Visual C++集成開發環境,選擇“File”菜單下的“New...”命令,在“New”對話框中選擇“Project”頁。
選擇“ATL COM AppWizard”項,這是創建ATL工程的AppWizard向導入口。然后在“Project name”編輯框中輸入工程的名字,單
擊“OK”按鈕,進入AppWizard對話框。
在AppWizard對話框中主要的設置選項有:
COM服務程序的類型:
-動態連接庫(Dynamic Linking Library) 最終產生一個動態連接庫(DLL)形式的COM服務程序;
-應用程序(Executable application)最終產生一個可執行程序類型(EXE)的COM服務程序;
- NT服務(NT Service):產生一個以NT服務方式運行的COM服務程序。
允許嵌入Proxy/Stub代碼。由Microsoft提供的MIDL編譯IDL文件以后,將產生用于對象調度(Marshaling)的Proxy/Stub的代碼。
傳統地,這部分代碼與COM服務程序的代碼是分離的,但是由于新的COM標準支持多線程環境下的COM對象服務,因此在動態連接
庫的COM服務程序中也要有Proxy/Stub的支持。為了支持在網絡上的傳輸,ATL允許用戶選擇將Proxy/Stub的代碼包括在生成的DLL
代碼中。這個選項在EXE和NT服務類型的COM應用條件下不可選。
允許支持MFC。由于ATL對除COM以外的基本的Windows編程方面的支持極為有限,同時許多程序員對MFC又非常熟悉,因此在ATL
的工程設置中允許在ATL工程內部支持使用MFC,即可以使用MFC定義的類。這在一方面來看是非常方便的,特別是對于習慣于使用
MFC的開發人員來說,能夠使用MFC提供的各種功能強大的類的支持,而不必直接使用Windows SDK。從另一個方面來看,在ATL工
程中使用MFC同時就喪失了ATL代碼輕量級的特點。
支持MTS。MTS是Microsoft Transaction Server的縮寫,它是Microsoft在COM技術方面的一個新的分支,這里不作詳細說明。
完成上面的設置以后,可以選擇FINISH完成工程的設置,ATL將創建相應的工程。
2. 加入ATL類
完成工程的創建和設置以后,下一步就是向工程中加入一個新的ATL類。Visual Studio集成環境提供了向導工具“ATL Object Wizard
”用于加入一個新的ATL類。操作過程并不復雜,只是一組對話框操作而已。
首先通過集成環境的“Insert”菜單下的“New ATL Object…”命令進入“ATL Object Wizard”對話框。
這個對話框即為創建ATL對象的向導起始界面。對話框的左邊部分說明了待創建對象的基本類型,這里主要有以下的幾種類型:
對象(Object)基本的COM對象類型;
控制(Control)ActiveX Control類型的ATL對象;
其他(Miscellaneous)輔助功能,如對話框的生成等;
數據訪問(Data Access)數據訪問,支持MTS等。
右邊部分說明了每種類型的詳細內容,對于一般的COM服務程序,使用對象表中的簡單對象(Simple Object)就可以了。
選定待創建對象的基本類型以后,單擊“Next>;”按鈕進入下一步,進入對象屬性設置對話框,如圖4和圖5所示。
對象屬性設置分為兩個過程:先是對象名字標識的設定,然后是對對象的基本屬性進行設置。首先是對象的名字標識設置。
在對象標識編輯框中輸入待創建對象的名字,ATL對象向導將同步地根據用戶輸入的對象標識設定該對象的C++標識和COM標識。對象
的C++標識包括對象的類名,cpp文件名和頭文件名。COM標識包括對象在類型庫中的CoClass段和實現的主接口的名字,同時還有在
系統注冊表中的類型名以及ProgID。
對象名字標識設置完成以后,選擇對象屬性頁(Attribute)進入對象的屬性設置頁面。
對象的屬性設置是ATL對象創建過程中最復雜的部分,包括以下幾個主要部分:
對象的線程模型(Thread Model)
對象的線程模型是COM對象在多線程環境下被訪問時對訪問方式的控制,缺省情況下在ATL中采用的是套間模型Apartment,由系統通
過消息隊列方式提供并發控制。
對象的接口模型(Interface)
COM對象的接口可以是雙接口(Dual Interface)。雙接口不同于普通接口(Custom Interface) 之處在于雙接口是從Automation基
本接口IDispatch繼承的,而普通接口是從IUnknown接口直接繼承來的。缺省的接口模型是雙接口。
對象的聚合模型(Aggregate)
COM規范不允許對象的實現繼承,但是可以通過聚合方式重用其它的COM對象。ATL對象屬性設置中的聚合模型可以指定待創建的
COM對象是否支持聚合模型。缺省的選項是支持對象的聚合。
對象對錯誤處理的支持(Support ISupportErrorInfo)
選取這個選項可以在對象的運行過程中支持錯誤處理。缺省情況下這個選項不被選中。
對象對連接點的支持(Support Connection Points)
連接點是COM對象的事件機制。選中這個選項可以使待創建的COM對象具有發出事件的能力。缺省情況下該選項不被選中。
對象對自由線程調度的支持(Free Thread Marshaller,簡稱FTM)
對象的自由線程調度是對象在處于自由線程模型狀態下,為了簡化對象的訪問過程而采用的一種優化策略。缺省情況下該選項不被選中
。
對于上述的任何一個選項的詳細描述都涉及到COM技術一些核心的內容,并且都已超出本文的范圍,因此本文只對ATL給出的缺省選項
加以說明,對這些內容感興趣的讀者可以參考Microsoft提供的文檔。
完成了上面的設置以后,就可以按“OK”按鈕完成對象的創建過程。下一步就是向所生成的ATL類的接口中加入成員函數的定義,以及
接口成員函數的實現過程。
3. 加入接口定義,實現接口函數
加入了ATL類定義之后,我們可以打開Visual C++集成環境下項目管理器(Workspace)中的Class View來檢查生成的類定義的情況。
我們可以看到一個新的類已經生成,同時,還生成了相應的接口定義。ATL Object Wizard為我們生成了類定義的.h 和.cpp文件,此外
還有用于接口定義的IDL文件。有了這些文件以后,我們就可以為接口加入成員函數,完成類的定義。
首先在Class View中選中相應的接口,顯示為接口IATLTest,單擊鼠標右鍵打開菜單,如圖7。此彈出式菜單定義了為接口加入屬性和
方法的操作。選取其中的“Add Method...”項,可以為接口加入方法成員;選取“Add Property...”則可以為接口加入新的屬性成員
。
加入屬性和方法的對話框可以參看圖8和圖9。如果我們要在接口中加入一個方法,則選取“Add Method...”菜單命令。假設方法名為
ABC,方法的返回類型為COM規定的HRESULT類型。我們也可以定義非HRESULT返回類型的函數,但是這需要手工修改接口定義的
IDL文件。我們定義ABC方法的一個參數為a,類型為整數型。完成了方法的定義以后,單擊“OK”按鈕則把此方法加入到接口中。
屬性的加入過程是類似的。屬性加入對話框要求指定屬性的類型、名字以及屬性的訪問方式。在屬性和方法的編輯對話框中都有一個“
Attributes”按鈕,在給出了一個屬性或方法的基本定義之后,單擊此按鈕,可以對屬性和方法的一些高級特性進行設置。
方法成員加入以后,我們可以通過Class View來檢查ATL為我們所做的工作。首先我們看到ATL在接口的定義中加入了該方法的定義;
同時在對應的ATL類定義中,也加入了一個相應的方法的定義;在類對應的.cpp文件中,加入了此方法的實現框架。此后,我們只要在
這個函數框架中加入該方法的代碼邏輯,一個接口函數的定義和實現就基本完成了。依照這種方式,我們可以完成整個COM對象的定
義和實現。
完成以上的步驟之后,我們就可以編譯連接應用了。
4. 編譯連接應用、注冊COM服務程序
對ATL工程的編譯連接過程包括下面的幾個步驟:
使用MIDL編譯工程的IDL文件,形成接口定義的頭文件和用于調度(Marshalling)的代碼;
編譯工程的.cpp文件形成目標文件;
連接目標文件,形成應用模塊;
注冊COM服務程序。
關于工程編譯連接的其它部分同Visual C++中MFC工程的編譯連接過程相似,這里只重點介紹一下COM服務程序的注冊過程。
在ATL中,COM服務程序的注冊是在工程編譯連接的最后階段,由ATL輔助完成的。在手工的COM編程中,服務程序的注冊是比較麻
煩的工作。在ATL中,系統通過讀取在建立工程過程中形成的注冊腳本文件來完成注冊工作。注冊腳本(Register Script 簡稱RGS)是
ATL提供的文本方式的注冊輔助文件。下面是注冊腳本文件的一個實例。
HKCR - 表示注冊表中COM對象的注冊項,是HKEY_CLASS_ROOT的縮寫
{
AuthTest.ActiveXObject.1 = s 'ActiveXObject Class'
{
CLSID = s ''
} - 對象的ProgID
AuthTest.ActiveXObject = s 'ActiveXObject Class'
{
CLSID = s ''
} -對象的與版本無關的ProgID
NoRemove CLSID -對象CLSID注冊項
{
ForceRemove = s 'ActiveXObject Class'
{
ProgID = s 'AuthTest.ActiveXObject.1'
VersionIndependentProgID = s 'AuthTest.ActiveXObject'
InprocServer32 = s '%MODULE% -服務器類型,表示DLL服務器
{
val ThreadingModel = s 'both' -線程模型,這里是BOTH型
}
}
}
}
RGS文件包含注冊COM服務程序的各項內容,通常我們不必修改此RGS文件,必要時我們也可以手工修改RGS文件來定制模塊的注冊過
程。
應用舉例
上面介紹了使用ATL創建一個COM服務程序的基本過程。在介紹過程中,我們實際上已經生成了一個COM服務程序的基本框架,只是
沒有填寫實際的內容。在下面部分,我們實際開發一個十分簡單的COM服務程序,并且為它編寫一段客戶代碼進行測試,使大家對使
用ATL開發COM服務程序的過程有一個全面整體的了解。
我們要開發的服務程序的功能很簡單,它只實現一個接口,這個接口名字是ISimpleInterface,接口只有一個成員函數,叫做Welcome
。這個函數的功能只是輸出一個“Hello World!”的字符串。
按照上一部分介紹的創建COM服務程序的步驟,我們進行如下的操作:
1.打開Visual C++集成開發環境;
2.創建一個稱為SimpleTest的ATL工程;
3.在這個工程中插入新的對象,對象的名字是SimpleInterface;
4.設置接口ISimpleInterface的有關屬性,使它成為一個雙接口;
5.在對象的接口ISimpleInterface中加入方法Welcome;
6.打開ATL加入的Welcome方法的框架,可以看到如下的代碼段:
STDMETHODIMPCActiveXObject::get_TestProp(long*pVal)
{
?
AFX_MANAGE_STATE(AfxGetStaticModuleState())
?
//TODO:Addyourimplementationcodehere
?
returnS_OK;
?
}
7.將程序框架中的注釋部分替換為下面的代碼:
1
::MessageBox(NULL,_T(”HelloWorld!”),_T(”Welcome”),MB_OK);
Welcome方法被調用時將彈出一個消息框。
8.編譯連接工程。
上面的步驟完成以后,我們就有了一個簡單的COM服務程序,而且已經被注冊到當前系統中。
下面我們要完成一個簡單的COM客戶程序。一個COM客戶程序簡單地說是使用COM組件對象的程序。客戶程序調用COM對象的基本
流程是:
創建COM對象的實例。這可以通過調用Windows系統的API函數CoCreateInstance來完成。
通過接口調用函數。
調用IUnknown::Release釋放COM對象實例
我們的客戶程序是使用MFC編寫的一個基于對話框的簡單應用程序。具體的過程如下:
1.打開Visual C++集成開發環境;
創建一個稱為SimpleClient的基于對話框的MFC工程;
在對話框中加入一個按鈕,名字為TEST;
在SimpleClientDlg.cpp文件中加入如下的代碼:
⑴ 在cpp文件 #include “simpleclientdlg.h”之后加入下面的代碼:
#include"d:\simpletest\simpletest.h"
#include"d:\simpletest\simpletest_i.c"
加入的頭文件是在編譯COM服務程序過程中自動生成的,其中包含接口本身的定義、接口IID的定義和COM對象的CLSID的定義。包含
該頭文件可以使客戶程序能夠使用COM服務程序。
⑵ 在按鈕TEST的消息控制函數中加入如下的代碼:
CoInitialize(0);
HRESULThr;
ISimpleInterface*pIntf=NULL;
hr=CoCreateInstance(CLSID_SimpleInterface,NULL,CLSCTX_SERVER,
IID_ISimpleInterface,(void**)&pIntf);
if(SUCCEEDED(hr))
{
pIntf->Welcome();
pIntf->Release();
}
CoUninitialize();
上面的代碼首先通過系統API CoCreateInstance創建COM對象,得到接口的指針,然后調用接口成員函數Welcome,最后通過
IUnknown::Release()函數釋放COM對象實例。
編譯連接客戶程序
最后,我們可以測試客戶程序是否正常運行。啟動客戶程序,當單擊“TEST”按鈕時我們可以看到彈出一個消息框,這正是我們的
COM服務程序提供的功能。
========
ATL與COM之間的關系、ATL的特點與基本使用方法
http://blog.csdn.net/chenyujing1234/article/details/7753930?
ATL,Active Template Library活動模板庫
是一種微軟程序庫,支持利用C++語言編寫ASP代碼以及其它ActiveX程序。通過活動模板庫,可以建立COM組件,然后通過ASP頁面
中的腳本對COM對象進行調用。這種COM組件可以包含屬性頁、對話框等等控件。
ATL簡介
?一. 什么是ATL
自從1993年Microsoft首次公布了COM技術以后,Windows平臺上的開發模式發生了巨大的變化,以COM為基礎的一系列軟件組件化
技術將Windows編程帶入了組件化時代。廣大的開發人員在為COM帶來的軟件組件化趨勢歡欣鼓舞的同時,對于COM開發技術的難度
和煩瑣的細節也感到極其的不便。
COM編程一度被視為一種高不可攀的技術,令人望而卻步。開發人員希望能夠有一種方便快捷的COM開發工具,提高開發效率,更好
地利用這項技術。針對這種情況,Microsoft公司在推出COM SDK以后,為簡化COM編程,提高開發效率,采取了許多方案,特別是
在MFC(Microsoft Foundation Class)中加入了對COM和OLE的支持。但是隨著Internet的發展,分布式的組件技術要求COM組件
能夠在網絡上傳輸,而又盡量節約寶貴的網絡帶寬資源。采用MFC開發的COM組件由于種種限制不能很好地滿足這種需求,因此
Microsoft在1995年又推出了一種全新的COM開發工具ATL。
ATL是ActiveX Template Library 的縮寫,它是一套C++模板庫。使用ATL能夠快速地開發出高效、簡潔的代碼(Effective and Slim?
code),同時對COM組件的開發提供最大限度的代碼自動生成以及可視化支持。為了方便使用,從Microsoft Visual C++ 5.0版本開
始,Microsoft把ATL集成到Visual C++開發環境中。1998年9月推出的Visual Studio 6.0 集成了ATL 3.0版本。目前,ATL已經成為
Microsoft標準開發工具中的一個重要成員,日益受到C++開發人員的重視。
1、 ATL究竟給開發人員帶來了什么樣的益處呢?這還要先從ATL產生以前的COM開發方式說起。
1、1 ?在ATL產生以前,開發COM組件的方法主要有兩種:
(1)一是使用COM SDK直接開發COM組件;
直接使用COM SDK開發COM組件是最基本也是最靈活的方式。通過使用Microsoft提供的開發包,我們可以直接編寫COM程序。但是
,這種開發方式的難度和工作量都很大,一方面,要求開發者對于COM的技術原理具有比較深入的了解(雖然對技術本身的深刻理解
對使用任何一種工具都是非常有益的,但對于COM這樣一整套復雜的技術而言,在短時間內完全掌握是很難的);
另一方面,直接使用COM SDK要求開發人員自己去實現COM應用的每一個細節,完成大量的重復性工作。這樣做的結果是,不僅降低
了工作效率,同時也使開發人員不得不把許多精力投入到與應用需求本身無關的技術細節中。雖然這種開發方式對于某些特殊的應用很
有必要,但這種編程方式并不符合組件化程序設計方法所倡導的可重用性,因此,直接采用COM SDK不是一種理想的開發方式。
(2)另一種方式是通過MFC提供的COM支持來實現。
使用MFC提供的COM支持開發COM應用可以說在使用COM SDK基礎上提高了自動化程度,縮短了開發時間。MFC采用面向對象的方
式將COM的基本功能封裝在若干MFC的C++類中,開發者通過繼承這些類得到COM支持功能。為了使派生類方便地獲得COM對象的
各種特性,MFC中有許多預定義宏,這些宏的功能主要是實現COM接口的定義和對象的注冊等通常在COM對象中要用到的功能。開發
者可以使用這些宏來定制COM對象的特性。
另外,在MFC中還提供對Automation 和 ActiveX Control的支持,對于這兩個方面,Visual C++也提供了相應的AppWizard和
ClassWizard支持,這種可視化的工具更加方便了COM應用的開發。
MFC對COM和OLE 的支持確實比手工編寫COM程序有了很大的進步。但是MFC對COM的支持是不夠完善和徹底的,例如對COM接
口定義的IDL語言,MFC并沒有任何支持,此外對于近些年來COM和ActiveX技術的新發展MFC也沒有提供靈活的支持。這是由MFC設
計的基本出發點決定的。MFC被設計成對Windows平臺編程開發的面向對象的封裝,自然要涉及Windows編程的方方面面,COM作
為Windows平臺編程開發的一個部分也得到MFC的支持,但是MFC對COM的支持是以其全局目標為出發點的,因此對COM 的支持必
然要服從其全局目標。從這個方面而言,MFC對COM的支持不能很好的滿足開發者的要求。
1、2 ?隨著Internet技術的發展,Microsoft將ActiveX技術作為其網絡戰略的一個重要組成部分大力推廣
然而使用MFC開發的ActiveX Control,代碼冗余量大(所謂的“肥代碼 Fat Code”),而且必須要依賴于MFC的運行時刻庫才能正
確地運行。雖然MFC的運行時刻庫只有部分功能與COM有關,但是由于MFC的繼承實現的本質,ActiveX Control必須背負運行時刻庫
這個沉重的包袱。
(1)如果采用靜態連接MFC運行時刻庫的方式,這將使ActiveX Control代碼過于龐大,在網絡上傳輸時將占據寶貴的網絡帶寬資源;
(2)如果采用動態連接MFC運行時刻庫的方式,這將要求瀏覽器一方必須具備MFC的運行時刻庫支持。總之MFC對COM技術的支持
在網絡應用的環境下也顯得很不靈活。
2、解決上述COM開發方法中的問題正是ATL的基本目標。
(1)首先ATL的基本目標就是使COM應用開發盡可能地自動化,這個基本目標就決定了ATL只面向COM開發提供支持。目標的明確使
ATL對COM技術的支持達到淋漓盡致的地步。對COM開發的任何一個環節和過程,ATL都提供支持,并將與COM開發相關的眾多工具
集成到一個統一的編程環境中。對于COM/ActiveX的各種應用,ATL也都提供了完善的Wizard支持。所有這些都極大地方便了開發者
的使用,使開發者能夠把注意力集中在與應用本身相關的邏輯上。
(2)其次,ATL因其采用了特定的基本實現技術,擺脫了大量冗余代碼,使用ATL開發出來的COM應用的代碼簡練高效,即所謂
的“Slim Code”。ATL在實現上盡可能采用優化技術,甚至在其內部提供了所有C/C++開發的程序所必須具有的C啟動代碼的替代部
分。
同時ATL產生的代碼在運行時不需要依賴于類似MFC程序所需要的龐大的代碼模塊,包含在最終模塊中的功能是用戶認為最基本和最必
須的。這些措施使采用ATL開發的COM組件(包括ActiveX Control)可以在網絡環境下實現應用的分布式組件結構。
(3)第三,ATL的各個版本對Microsoft的基于COM的各種新的組件技術如MTS、ASP等都有很好的支持,ATL對新技術的反應速度大
大快于MFC。ATL已經成為Microsoft支持COM應用開發的主要開發工具,因此COM技術方面的新進展在很短的時間內都會在ATL中得
到反映。這使開發者使用ATL進行COM編程可以得到直接使用COM SDK編程同樣的靈活性和強大的功能。
本文的目的就是希望在有限的篇幅中能夠使讀者對ATL的使用和基本原理有一個初步的了解,為廣大的COM開發人員更好地使用ATL開
發起到拋磚引玉的作用。
二. ATL基本技術
雖然使用ATL開發COM 應用是一件非常簡單的事情,但是在ATL簡單易用的界面后面卻包含著復雜的技術。面對ATL生成的大量代碼,
我們即使不去深入地了解這些代碼的含義也可以開發出COM應用來,但是如果我們要充分地挖掘ATL的潛力,開發出更靈活、強大的
COM應用,則必須對ATL使用的基本技術有所了解。研究ATL的實質最好的教材就是由Visual C++提供的ATL源代碼。
本文這一部分只是對ATL中用到的最基本的技術進行簡單的介紹。
簡單地說來,ATL中所使用的基本技術包括以下幾個方面:
COM技術 C++模板類技術(Template) C++多繼承技術(Multi-Inheritance)
1、COM技術是理解ATL的基礎
使用ATL進行開發要對COM技術的基本概念有最低限度的了解。由于COM是一項非常復雜龐大的技術體系,限于本文的篇幅,這里不
再贅述。對于本文中提到的COM基本概念也不做過多的解釋,請讀者參閱有關的參考書籍。 eg: <<COM技術內幕.pdf>>
2、作為ATL最核心的實現技術的模板是對標準C++語言的擴展
但是在大多數的C++編程環境中,人們很少使用它,這是因為模板的功能雖然很強,但是它內部機制比較復雜,需要比較多的C++知識
和經驗才能靈活地使用它。在MFC中的CObjectArray等功能類就是由模板來定義的。完全通過模板來定義程序的整體類結構,ATL是迄
今為止做得最為成功的。
所謂模板類簡單地說是對類的抽象。我們知道C++語言用類定義了構造對象(這里指C++對象而不是COM對象)的方式,對象是類的實
例,而模板類定義的是類的構造方式,使用模板類定義實例化的結果產生的是不同的類。因此可以說模板類是“類的類”。
在C++語言中模板類的定義格式如下:
注意:<和>是左右尖括號,可能無法正常顯示。
template < class T> class MyTemp
?{
MyTemp( ){ };
?~MyTemp( ) { };
?int MyFunc( int a) ;
}
………….
?Int MyTemp::MyFunc( int a) { }
?
首先使用C++的關鍵字“template”來聲明一個模板類的定義。在關鍵字后面是用尖括號括起來的類型參數。正是根據這個類型參數,
編譯器才能在編譯過程中將模板類的具體定義轉化為一個實際的類的定義,即生成一個新的類。接下來的定義方式與普通的類定義十分
相似,只是在類的函數定義中都要帶有類型參數的說明。
下面的程序段說明了模板類的用法:
typedef MyTemp myclassfromtemp;
?myclassfromtemp m;
int a = m.Myfunc(10);
通常在使用模板類時為了方便起見,使用一個關鍵字“typedef”為新定義出來的類取一個名字。
在上面的程序段中假設“MyClass”是一個由用戶定義的類,通過將這個類的名字作為類型參數傳遞給模板類,我們可以創建一個新的
類,這個類的行為將以模板類的定義為基礎,例如它具有模板類定義的所有成員函數,同時這個類又是對模板類行為的一種修改,這種
修改是通過用戶提供的類型參數來實現的。
賦予模板類以不同的類型參數,則得到行為框架相似但具體行為不同的一組類的集合。有了新的類的定義以后,我們可以象使用普通類
一樣來創建一個類的實例,即一個新的對象,并且調用這個對象的成員函數。
模板類是對標準C++語言的最新擴展,雖然它的功能很強大,但是要想使用好模板類需要相當多的關于語言和編程的經驗和知識,而且
錯誤地使用模板類又會對程序的結構和運行效率帶來大的副作用,因此一般的編程環境和編程書籍對模板類的使用都采取謹慎的態度。
而ATL的核心就是由幾十個模板類構成的,通過研究ATL的源代碼可以使我們對模板類的使用有比較深刻全面的認識。
3、多繼承技術同模板一樣,是C++語言中極具爭議性的技術。
使用多繼承技術可以使程序的設計和實現更加靈活,但是,由于多繼承的復雜性和自身概念上的一些問題,使多繼承在各種面向對象的
語言環境中得到的支持都非常有限。例如Small Talk根本就不允許多繼承,同樣MFC也不支持多繼承技術。
多繼承最大的問題是所謂的“鉆石結構”。
例如下面的代碼:
[cpp] view plain copy
class A { ..... }; ??
class B : public A { .. . }; ?
class C : public A { ..... }; ??
class D : public C,B { ........ } ??
?
由于類D同時從類C和B繼承,因此在下面的語句中就會發生歧義:?
[cpp] view plain copy
D* pD = new D; ??
A*)pD->Func(...); ??
?
由于類D通過類C和類B 分別繼承了類A,這里的強制轉化就會發生歧義。
ATL使用了C++最新規范中加入的兩個運算符號 static_cast、dynamic_cast代替簡單的強制轉化,從而消除多繼承帶來的歧義。使用這
兩個運算符號,我們可以在對象運行過程中獲取對象的類型信息。上面的代碼可以采用下面的方式修改:
[cpp] view plain copy
D* pD = new D; ??
static_cast(static_cast(pD))->Func(...); ?
?
為什么模板類和多繼承技術會成為ATL主要的工具呢?原因在于,采用模板可以在編譯過程中快速的生成具有用戶定制功能的類,這對
于COM這樣一個復雜的技術體系在實現效率上得到了很大的提高。通過使用模板類,用戶可以把精力集中在自己開發的類的基本邏輯
上,在完成了自己的類的設計以后,通過繼承不同的類,生成不同的模板類,就可以快速地實現COM的功能,同時又避免了采用單繼
承結構造成的大量功能冗余。
總之,正是由于在設計實現過程中采用了模板類和多繼承技術,才使ATL成為一個小巧靈活的COM開發工具,能夠適應開發人員對
COM應用開發的各種需要。
三. ATL基本使用
這一部分將重點介紹ATL的基本使用過程。由于ATL已經被集成在Microsoft Visulal Studio的Visual C++開發環境中,因此要使用ATL
必須先安裝Visual C++。在下面的討論中有關COM的基本知識請參閱有關的文檔,這里不再詳細說明。給出的圖是在Microsoft?
Windows 98平臺下Visual Studio 6.0的使用示意圖。
使用ATL開發一個COM應用基本可以分為以下幾個步驟:
(1)創建一個新的ATL工程,并對工程的選項進行適當的配置。
(2)向新創建的工程添加新的ATL類,并對該類進行一些初始配置工作。
(3)根據COM應用的基本要求向新的ATL類加入新的接口定義,并實現相應的接口成員函數。
(4)編譯連接工程,注冊COM應用。
下面將根據這些步驟依次介紹ATL的基本使用過程。
1、創建工程
首先啟動Visual C++集成開發環境,選擇“File”菜單下的“New...”命令,在“New”對話框中選擇“Project”頁。
選擇“ATL COM AppWizard”項,這是創建ATL工程的AppWizard向導入口。然后在“Project name”編輯框中輸入工程的名字,單
擊“OK”按鈕,進入AppWizard對話框。在AppWizard對話框中主要的設置選項有:
(1、1)COM服務程序的類型:
- 動態連接庫(Dynamic Linking Library) 最終產生一個動態連接庫(DLL)形式的COM服務程序;
- 應用程序(Executable application)最終產生一個可執行程序類型(EXE)的COM服務程序;
- NT服務(NT Service):產生一個以NT服務方式運行的COM服務程序。
(1、2)允許嵌入Proxy/Stub代碼。由Microsoft提供的MIDL編譯IDL文件以后,將產生用于對象調度(Marshaling)的Proxy/Stub
的代碼。傳統地,這部分代碼與COM服務程序的代碼是分離的,但是由于新的COM標準支持多線程環境下的COM對象服務,因此在
動態連接庫的COM服務程序中也要有Proxy/Stub的支持。為了支持在網絡上的傳輸,ATL允許用戶選擇將Proxy/Stub的代碼包括在生
成的DLL代碼中。這個選項在EXE和NT服務類型的COM應用條件下不可選。
(1、3)允許支持MFC。由于ATL對除COM以外的基本的Windows編程方面的支持極為有限,同時許多程序員對MFC又非常熟悉,因
此在ATL的工程設置中允許在ATL工程內部支持使用MFC,即可以使用MFC定義的類。這在一方面來看是非常方便的,特別是對于習慣
于使用MFC的開發人員來說,能夠使用MFC提供的各種功能強大的類的支持,而不必直接使用Windows SDK。從另一個方面來看,在
ATL工程中使用MFC同時就喪失了ATL代碼輕量級的特點。
(4)支持MTS。MTS是Microsoft Transaction Server的縮寫,它是Microsoft在COM技術方面的一個新的分支,這里不作詳細說明
。
完成上面的設置以后,可以選擇FINISH完成工程的設置,ATL將創建相應的工程。
2、加入ATL類
完成工程的創建和設置以后,下一步就是向工程中加入一個新的ATL類。
Visual Studio集成環境提供了向導工具“ATL Object Wizard”用于加入一個新的ATL類。操作過程并不復雜,只是一組對話框操作而
已。
首先通過集成環境的“Insert”菜單下的“New ATL Object…”命令進入“ATL Object Wizard”對話框。
這個對話框即為創建ATL對象的向導起始界面。對話框的左邊部分說明了待創建對象的基本類型,這里主要有以下的幾種類型:
對象(Object)基本的COM對象類型;
控制(Control)ActiveX Control類型的ATL對象;
其他(Miscellaneous)輔助功能,如對話框的生成等;
數據訪問(Data Access)數據訪問,支持MTS等。
右邊部分說明了每種類型的詳細內容,對于一般的COM服務程序,使用對象表中的簡單對象(Simple Object)就可以了。
選定待創建對象的基本類型以后,單擊“Next>”按鈕進入下一步,進入對象屬性設置對話框,如圖4和圖5所示。 對象屬性設置分
為兩個過程:先是對象名字標識的設定,然后是對對象的基本屬性進行設置。首先是對象的名字標識設置。 在對象標識編輯框中輸
入待創建對象的名字,ATL對象向導將同步地根據用戶輸入的對象標識設定該對象的C++標識和COM標識。對象的C++標識包括對象
的類名,cpp文件名和頭文件名。COM標識包括對象在類型庫中的CoClass段和實現的主接口的名字,同時還有在系統注冊表中的類型
名以及ProgID。 對象名字標識設置完成以后,選擇對象屬性頁(Attribute)進入對象的屬性設置頁面。 對象的屬性設置是ATL
對象創建過程中最復雜的部分,包括以下幾個主要部分: 對象的線程模型(Thread Model) 對象的線程模型是COM對象在多
線程環境下被訪問時對訪問方式的控制,缺省情況下在ATL中采用的是套間模型Apartment,由系統通過消息隊列方式提供并發控制。?
對象的接口模型(Interface) COM對象的接口可以是雙接口(Dual Interface)。雙接口不同于普通接口(Custom Interface) 之
處在于雙接口是從Automation基本接口IDispatch繼承的,而普通接口是從IUnknown接口直接繼承來的。缺省的接口模型是雙接口。?
對象的聚合模型(Aggregate) COM規范不允許對象的實現繼承,但是可以通過聚合方式重用其它的COM對象。ATL對象屬
性設置中的聚合模型可以指定待創建的COM對象是否支持聚合模型。缺省的選項是支持對象的聚合。 對象對錯誤處理的支持
(Support ISupportErrorInfo) 選取這個選項可以在對象的運行過程中支持錯誤處理。缺省情況下這個選項不被選中。 對象對
連接點的支持(Support Connection Points) 連接點是COM對象的事件機制。選中這個選項可以使待創建的COM對象具有發出事
件的能力。缺省情況下該選項不被選中。 對象對自由線程調度的支持(Free Thread Marshaller, 簡稱FTM) 對象的自由線程調
度是對象在處于自由線程模型狀態下,為了簡化對象的訪問過程而采用的一種優化策略。缺省情況下該選項不被選中。 對于上述的
任何一個選項的詳細描述都涉及到COM技術一些核心的內容,并且都已超出本文的范圍,因此本文只對ATL給出的缺省選項加以說明,
對這些內容感興趣的讀者可以參考Microsoft提供的文檔。 完成了上面的設置以后,就可以按“OK”按鈕完成對象的創建過程。下
一步就是向所生成的ATL類的接口中加入成員函數的定義,以及接口成員函數的實現過程。
3.、加入接口定義,實現接口函數
加入了ATL類定義之后,我們可以打開Visual C++集成環境下項目管理器(Workspace)中的Class View來檢查生成的類定義的情況。
我們可以看到一個新的類已經生成,同時,還生成了相應的接口定義。ATL Object Wizard為我們生成了類定義的.h 和.cpp文件,此外
還有用于接口定義的IDL文件。有了這些文件以后,我們就可以為接口加入成員函數,完成類的定義。 首先在Class View中選中相
應的接口,顯示為接口IATLTest,單擊鼠標右鍵打開菜單,如圖7。此彈出式菜單定義了為接口加入屬性和方法的操作。選取其中
的“Add Method...”項,可以為接口加入方法成員;選取“Add Property...”則可以為接口加入新的屬性成員。 加入屬性和方法
的對話框可以參看圖8和圖9。如果我們要在接口中加入一個方法,則選取“Add Method...”菜單命令。假設方法名為ABC,方法的返
回類型為COM規定的HRESULT類型。我們也可以定義非HRESULT返回類型的函數,但是這需要手工修改接口定義的IDL文件。我們定
義ABC方法的一個參數為a,類型為整數型。完成了方法的定義以后,單擊“OK”按鈕則把此方法加入到接口中。 屬性的加入過程
是類似的。屬性加入對話框要求指定屬性的類型、名字以及屬性的訪問方式。在屬性和方法的編輯對話框中都有一個“Attributes”按
鈕,在給出了一個屬性或方法的基本定義之后,單擊此按鈕,可以對屬性和方法的一些高級特性進行設置。 方法成員加入以后,我
們可以通過Class View來檢查ATL為我們所做的工作。首先我們看到ATL在接口的定義中加入了該方法的定義;同時在對應的ATL類定義
中,也加入了一個相應的方法的定義;在類對應的.cpp文件中,加入了此方法的實現框架。此后,我們只要在這個函數框架中加入該方
法的代碼邏輯,一個接口函數的定義和實現就基本完成了。依照這種方式,我們可以完成整個COM對象的定義和實現。 完成以上
的步驟之后,我們就可以編譯連接應用了。
4、 編譯連接應用、注冊COM服務程序
對ATL工程的編譯連接過程包括下面的幾個步驟: 使用MIDL編譯工程的IDL文件,形成接口定義的頭文件和用于調度(Marshalling)
的代碼; 編譯工程的.cpp文件形成目標文件; 連接目標文件,形成應用模塊; 注冊COM服務程序。 關于工程編譯
連接的其它部分同Visual C++中MFC工程的編譯連接過程相似,這里只重點介紹一下COM服務程序的注冊過程。 在ATL中,COM
服務程序的注冊是在工程編譯連接的最后階段,由ATL輔助完成的。在手工的COM編程中,服務程序的注冊是比較麻煩的工作。在ATL
中,系統通過讀取在建立工程過程中形成的注冊腳本文件來完成注冊工作。注冊腳本(Register Script 簡稱RGS)是ATL提供的文本方式的
注冊輔助文件。下面是注冊腳本文件的一個實例。 HKCR - 表示注冊表中COM對象的注冊項,是HKEY_CLASS_ROOT的縮寫 {?
AuthTest.ActiveXObject.1 = s 'ActiveXObject Class' { CLSID = s '' } - 對象的ProgID AuthTest.ActiveXObject = s 'ActiveXObject?
Class' { CLSID = s '' } -對象的與版本無關的ProgID NoRemove CLSID -對象CLSID注冊項 { ForceRemove = s 'ActiveXObject?
Class' { ProgID = s 'AuthTest.ActiveXObject.1' VersionIndependentProgID = s 'AuthTest.ActiveXObject' InprocServer32 = s?
'%MODULE% -服務器類型,表示DLL服務器 { val ThreadingModel = s 'both' -線程模型,這里是BOTH型 } } } } RGS文件包
含注冊COM服務程序的各項內容,通常我們不必修改此RGS文件,必要時我們也可以手工修改RGS文件來定制模塊的注冊過程。
四. 應用ATL的一個例子
上面介紹了使用ATL創建一個COM服務程序的基本過程。在介紹過程中,我們實際上已經生成了一個COM服務程序的基本框架,只是
沒有填寫實際的內容。在下面部分,我們實際開發一個十分簡單的COM服務程序,并且為它編寫一段客戶代碼進行測試,使大家對使
用ATL開發COM服務程序的過程有一個全面整體的了解。
我們要開發的服務程序的功能很簡單,它只實現一個接口,這個接口名字是ISimpleInterface,接口只有一個成員函數,叫做Welcome
。這個函數的功能只是輸出一個“Hello World!”的字符串。
按照上一部分介紹的創建COM服務程序的步驟,我們進行如下的操作:
1 打開Visual C++集成開發環境;
2 創建一個稱為SimpleTest的ATL工程;
3 在這個工程中插入新的對象,對象的名字是SimpleInterface;
4 設置接口ISimpleInterface的有關屬性,使它成為一個雙接口;
5 在對象的接口ISimpleInterface中加入方法Welcome;
6 打開ATL加入的Welcome方法的框架,可以看到如下的代碼段: STDMETHODIMP CActiveXObject::get_TestProp(long *pVal) {?
AFX_MANAGE_STATE(AfxGetStaticModuleState()) // TODO: Add your implementation code here return S_OK; }
7 將程序框架中的注釋部分替換為下面的代碼: ::MessageBox(NULL,_T(”Hello World!”),_T(”Welcome”), MB_OK); Welcome方
法被調用時將彈出一個消息框。
8 編譯連接工程。 上面的步驟完成以后,我們就有了一個簡單的COM服務程序,而且已經被注冊到當前系統中。 下面我們要完
成一個簡單的COM客戶程序。一個COM客戶程序簡單地說是使用COM組件對象的程序。
客戶程序調用COM對象的基本流程是:
創建COM對象的實例。這可以通過調用Windows系統的API函數CoCreateInstance來完成。 通過接口調用函數。 調用
IUnknown::Release釋放COM對象實例 我們的客戶程序是使用MFC編寫的一個基于對話框的簡單應用程序。具體的過程如下:
1 打開Visual C++集成開發環境; 創建一個稱為SimpleClient的基于對話框的MFC工程; 在對話框中加入一個按鈕,名字為
TEST; 在SimpleClient.cpp文件中加入如下的代碼:
(1) 在cpp文件 #include “simpleclientdlg.h”之后加入下面的代碼: #include “d:/simpletest/simpletest_i.h” // 根據需要修
改頭文件的路徑 加入的頭文件是在編譯COM服務程序過程中自動生成的,其中包含接口本身的定義、接口IID的定義和COM對象的
CLSID的定義。包含該頭文件可以使客戶程序能夠使用COM服務程序。
(2) 在按鈕TEST的消息控制函數中加入如下的代碼: HRESULT hr; ISimpleInterface* pIntf = NULL; hr = CoCreateInstance
(CLSID_SimpleInterface, NULL, CLSCTX_SERVER , IID_ISimpleInterface, (void **)& pIntf); if(SUCCEEDED(hr)) { pIntf-
>Welcome(); pIntf->Release(); } 上面的代碼首先通過系統API CoCreateInstance創建COM對象,得到接口的指針,然后調用接
口成員函數Welcome,最后通過IUnknown::Release()函數釋放COM對象實例。 編譯連接客戶程序 最后,我們可以測試客戶
程序是否正常運行。啟動客戶程序,當單擊“TEST”按鈕時我們可以看到彈出一個消息框,這正是我們的COM服務程序提供的功能。
?========
ATL編程總結
http://blog.csdn.net/lee353086/article/details/7097440內容概要
?[1] 在Visual Studio2008下使用Visual C++ ATL項目向導,完成一個COM服務( DLL),可在HTML中調用。
?[2]用Visual Studio打包成安裝文件, 在客戶端自動注冊。
?假設讀者有在Visual Studio 2008下的C++開發經驗,主要是給自己看的,很多地方省略了。
正文
建立COM控件
第一步:選擇[Visual C++]->[ATL Project],輸入項目名稱后,點擊[OK]繼續
第二步:項目向導中“Server type”選擇“Dynamic-link library(DLL)”,“Additional options”選擇“Allowmerging of?
proxy/stub code”
第三步:為你的ATL項目(容器)添加供外部使用的Class (ATL Simple Object)。選項頁 “ C++”的“Short name”輸入欄中輸入你
的Class名稱,其它輸入框會自動更新。
第四步:“Threading?
model”選“Apartment”;“Interface”選“Dual”;“Aggregation”選“No”;“Support”選“Connection points”和“I?
Object With Site(IE objects support)”。
第五步:在“Class View”中,右鍵單擊要添加方法的Interface的名稱,在彈出菜單中選擇“Add Method”,添加方法。為參數列表
添加參數要注意,“retval”屬性的參數只能放在參數列表的最后一個,并且只能有一個,要返回字符串,參數類型可以選擇“BSTR*”
,要返回Long類型,參數類型可以選擇“LONG *”。完成后,在函數體內添加代碼。
第六步:添加IE支持
在你新的類名的H文件的“ ? ? ? ? publicIObjectWithSiteImpl<你的類名>,”代碼段后面添加下面這個代碼段“
? ? ? ? ?publicIObjectSafetyImpl<你的類名,INTERFACESAFE_FOR_UNTRUSTED_CALLER|
INTERFACESAFE_FOR_UNTRUSTED_DATA>,”。
在“COM_INTERFACE_ENTRY(IObjectWithSite)”后面插入“COM_INTERFACE_ENTRY(IObjectSafety)”代碼段。
第七步(最后一步):右鍵單擊資源文件選擇“View Code”找到“CompanyName”等信息做修改。修改資源文件的語言為“中文
(簡體)”,否則,用戶查看文件信息(你寫的中文注釋)會是亂碼。
第八步:按F7編譯Solution,如何沒有錯誤,IDE會自動為你注冊COM服務。你也可以使用regsvr32命令手動注冊或反注冊生成的DLL
文件。
測試COM控件
我們新建的這個COM服務用“ActiveXControl test Container”這個容器做測試,會找不到這個COM,我們的ATL項目生成的DLL可
能不是嚴格意義上的Active X控件的緣故。
用VB程序做測試
通過在VB項目里Add reference添加COM組件
示例代碼如下
[vb] view plain copy
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e AsSystem.EventArgs) Handles Button1.Click ??
??
? ? Dim objTestATL As Simple_ATLLib.First_ATL ?
? ? Dim lngReturnValue As Long ?
? ? objTestATL = New Simple_ATLLib.First_ATL ?
? ? lngReturnValue = objTestATL.AddNumbers(5, 7) ?
? ? MsgBox("The value of 5 + 7 is: " & lngReturnValue) ?
??
End Sub ?
其中“Simple_ATLLib”是項目名稱加lib,“First_ATL”是你剛才新建的Classs名稱,“AddNumbers”是你為這個Class新建的方法
名。
用HTML頁面做測試
下面是示例代碼,其中classid可以從First_ATL.rgs中查找,其中“First_ATL”是你要在HTML中實例化的Class的名稱。
[html] view plain copy
<object ?classid="clsid:F0FF2E0D-A56B-40A4-A4D1-F84032606F20" ?id="Dean" name = "Dean" ></object> ?
??
<form id="form1" ?name="form1" method="post" action=""> ?
??
? <a href="#" οnclick="return CallUSB();">js調用ActiveX測試</a> ??
??
? <input id="Write" name="Write"type="button" value="vb調用ActiveX測試"/> ?
??
</form> ?
??
<SCRIPT LANGUAGE="JavaScript"> ?
??
//JavaScript調用Demo ?
??
function CallUSB() ? ?
{ ?
??
? ? ? ? ?try{ ? ??
? ? ? ? ? ? ? ? ? ?varUSBContent = Dean.AddNumbers(5, 7); ? ?
? ? ? ? ? ? ? ? ? ?alert(USBContent); ? ?
? ? ? ? ?}catch (e) { ? ?
? ? ? ? ? ? ? ? ? ?alert("錯誤號: " +e ); ? ?
? ? ? ? ?} ? ? ??
?return false; ? ?
} ??
</SCRIPT> ?
?
配置安裝包
第一步:在當前Solution中添加New Project,選擇project類型為“[Other project Types]->[Setup and Deployment]->[Setup?
Wizard]”。在向導的選項卡中選擇“Primaryoutput from 你的ATL項目名稱”,其它可以取默認值。
第二步:修改公司名稱、語言類型、安裝位置等信息。
第三步:“Detected Dependencies”中有些DLL你不需要打包進來,可以排除它們。
第四步(最后一步):點擊你的“Primary output”的那一項,在屬性窗口中找到“register”屬性,它的默認值
為“vsdrpDoNotRegister”,改為“vsdrpCOMSelfReg”。這樣你的程序在用戶機器中安裝好后,你的DLL也在用戶機器中注冊好了
。
?其它
[1]在添加的ATL Simple Object類型的Class,public域里,可以修改原FinalRelease的聲明為STDMETHOD(FinalRelease)();
然后在CPP文件里實現這個聲明,可以實現當IE窗口關閉時,做一些對象清理工作。
遺留問題
[1]本文不包含數字簽名的相關信息
[2]ActiveX在IE中正常,但是不能在Firefox中正常運行
========
ATL編程初級教程
http://www.cnblogs.com/weiqubo/archive/2011/01/29/1947540.html介紹
本教程的目的是告訴你如何使用ATL創建一個COM服務器,并使用Visual C++和Visual Basic程序來分別調用這個服務器。我并不
想深入探討COM的細節,也不想讓你深陷于IDL之中。這一教程只是為VC++的新手程序員設計的,告訴他們利用ATL來創建一個COM
對象有多么簡單,并讓他們能對ATL產生更多的興趣。
第1步:啟動ATL COM Wizard
你所需要做的第一件事情就是啟動Visual C++并創建一個新的工程,選擇“ATL COM Wizard”,工程名為“Simple_ATL”。設
置好工程的路徑之后,單擊OK按鈕。你會看到,屏幕上給了你若干選項。第一個選項為“Server Type”。我們將要創建一個服務器
DLL,所以請確認服務器的類型選為“Dynamic Link Library”。我們并不需要關心下面的其它三個復選框,所以我們可以將它們忽略
掉。按下Finish按鈕,這樣向導就會為你產生適當的文件了。之后,一個“New Project Information”窗口就會出現,你可以從上面
得知向導都會創建什么文件,按下“OK”接受這一切。
第2步:創建一個新的ATL對象
請確認你能在VC++的IDE中看到Workspace View,如果不能的話則請單擊“View”菜單,然后選擇“Workspace”。在這個視
圖中你會看到三個選項卡,請單擊“ClassView”欄,你應該會看到“Simple_ATL Classes”。請在此右擊鼠標鍵,并在彈出菜單中選
擇“New ATL Object”,你將會看到下面這樣的窗口:
默認的選擇項“Simple Object”就是我們所要的了,請單擊next按鈕,你會來到“ATL Object Wizard Properties”窗口中。在
“Short Name”文本框中輸入“First_ATL”。請注意,這時候向導就會自動地填寫其它的文本框。然后,單擊頂部的“Attributes”
標簽,在這里你需要做一些選擇。第一項線程模型(Threading Model)的選擇,我們選擇默認的單元(Apartment)模型。對于接口
(Interface),我們選擇雙重(Dual)。最后,因為我們的程序與聚合(Aggregation)無關,所以我們選擇“No”的單選按鈕。你
不必關心底部的三個復選框,直接單擊OK就可以了,這時候向導就會為我們創建一個新的ATL簡單對象。
第3步:添加一個方法
如果你現在在工作區中單擊了“ClassView”標簽,那么你會注意到向導在其中添加了一串東西。我們想添加的第一個東西是一個
方法,可以在“IFirst_ATL”上右擊鼠標鍵,并選擇“Add Method”。
一旦你單擊了“Add Method”之后,你就會看到“Add Method to Interface”窗口。在返回值類型(Return Type)處你會看
到,這個方法會默認返回HRESULT,在大多數情況下你不需要改變它。下一個文本框允許我們輸入方法的名稱,我們可以輸
入“AddNumbers”。最后一個文本框是讓我們輸入參數的,由于我們想做兩個數的相加并獲得一個返回的結果,所以我們需要三個參
數,并且最后一個參數是一個指針。現在,我們不必看那關于IDL的300頁教程了,可以直接在參數文本框中輸入:
[in] long Num1, [in] long Num2, [out] long *ReturnVal
簡單地說來,我們聲明了兩個long類型的參數,這兩個值是傳入的([in]),還有一個最后傳出的返回值結果([out])。(你第一
次看到這樣的東西可能會有些奇怪,但是如果你讀了一兩本關于COM的書的話,就會覺得親切多了。)現在就可以單擊OK按鈕了。然
后,單擊“ClassView”標簽,并展開所有的“+”標志,使得樹型視圖完全展開。你會在接口(IFirst_ATL)的頂部看到我們
的“AddNumbers”方法以及我們給予它的參數。在這個方法上雙擊鼠標鍵,并插入以下的代碼:
STDMETHODIMP CFirst_ATL::AddNumbers(long Num1,?
? ? ? ? ? ? ? ? ?long Num2, long *ReturnVal)
{
? ? ?// TODO: Add your implementation code here
? ? ?*ReturnVal = Num1 + Num2;
? ? ?return S_OK;
}
第4步:編譯DLL
無論你相信與否,你已經擁有一個用ATL編寫的COM服務器了!當然,我們還需要編譯它。請按下F7鍵,這樣VC++就可以編譯了
。編譯器工作片刻后就會在注冊表中注冊你的新DLL了,這樣一來其它的程序就可以使用它了。讓我們來測試一下。
第5步:在Visual Basic中測試COM服務器
那么,先讓我們用VB來測試這個COM服務器吧。(如果你沒有VB的話,你可以跳過這一節,直接在VC++中測試。)啟動VB,并
選擇“標準EXE(Standard EXE)”建立工程,并在對話框上放置一個命令按鈕。現在,我們需要添加COM服務器的引用,請單擊“
工程(Project)”菜單并選擇“引用(References)”,找到“Simple ATL 1.0 Type Library”并選擇它。
單擊確定(OK)按鈕之后,你可以雙擊先前放置的命令按鈕,VB會切換到這個按鈕的代碼窗口。添加以下的代碼:
Private Sub Command1_Click()
? ? ?Dim objTestATL As SIMPLE_ATLLib.First_ATL
? ? ?Set objTestATL = New First_ATL
? ? ?Dim lngReturnValue As Long
? ? ?objTestATL.AddNumbers 5, 7, lngReturnValue
? ? ?MsgBox "The value of 5 + 7 is: " & lngReturnValue
? ? ?Set objTestATL = Nothing
End Sub
如果你是個VB的程序員,那么這些代碼對于你是很直觀的:我們聲明了一個對象,并從COM服務器調用“AddNumbers”的方法
,然后顯示結果。現在按下F5來運行這個VB工程,單擊命令按鈕,你就會看到期望的結果了:
并不是很難吧?那么我們再來一次,這一次用VC++。
第6步:在Visual C++中測試COM服務器
如果你的Simple_ATL工程仍然開著,那么就關了它并創建一個新工程。選擇“Win32 Console Application”,起名為“Test_ATL
”,在下一個窗口中單擊OK按鈕接受所有默認值,最后單擊Finish按鈕。現在,你應該有了一個空工程。那么,按下Ctrl+N為工程加入
一個新文件,選擇“C++ Source File”并命名為“Test_ATL.cpp”,單擊OK接受。你現在應該有了一個打開的空白文件,我們需要在
其中添加一些代碼來測試COM服務器。代碼如下:
// 你需要指明Simple_ATL工程的路徑來引用這個頭文件
#include "..\Simple_ATL\Simple_ATL.h"
#include <iostream.h>
// 把以下的內容從Simple_ATL工程目錄的Simple_ATL_i.c文件中復制過來
// 注意:你也可以直接包含Simple_ATL_i.c文件,我在此只想清楚地表明這些const常量來自何處以及它們的樣子
const IID IID_IFirst_ATL =
? ? ?{0xC8F6E230,0x2672,0x11D3,
? ? ?{0xA8,0xA8,0x00,0x10,0x5A,0xA9,0x43,0xDF}};
const CLSID CLSID_First_ATL =
? ? ?{0x970599E0,0x2673,0x11D3,
? ? ?{0xA8,0xA8,0x00,0x10,0x5A,0xA9,0x43,0xDF}};
void main(void)
{
? ? ?// 聲明一個HRESULT變量以及一個Simple_ATL接口的指針
? ? ?HRESULT ? ? ? ? ?hr;
? ? ?IFirst_ATL ? ? ? *IFirstATL = NULL;
? ? ?// 現在初始化COM
? ? ?hr = CoInitialize(0);
? ? ?// 使用SUCCEEDED宏來看看我們是否能夠獲得接口的指針
? ? ?if(SUCCEEDED(hr))
? ? ?{
? ? ? ? ?hr = CoCreateInstance( CLSID_First_ATL, NULL,?
? ? ? ? ? ? ?CLSCTX_INPROC_SERVER,
? ? ? ? ? ? ?IID_IFirst_ATL, (void**) &IFirstATL);
? ? ? ? ?// 如果成功了,那么調用AddNumbers方法
? ? ? ? ?// 否則給用戶顯示一條適當的信息
? ? ? ? ?if(SUCCEEDED(hr))
? ? ? ? ?{
? ? ? ? ? ? ?long ReturnValue;
? ? ? ? ? ? ?IFirstATL->AddNumbers(5, 7, &ReturnValue);
? ? ? ? ? ? ?cout << "The answer for 5 + 7 is: "?
? ? ? ? ? ? ? ? ?<< ReturnValue << endl;
? ? ? ? ? ? ?IFirstATL->Release();?
? ? ? ? ?}
? ? ? ? ?else
? ? ? ? ?{
? ? ? ? ? ? ?cout << "CoCreateInstance Failed." << endl;
? ? ? ? ?}
? ? ?}
? ? ?// 卸載COM
? ? ?CoUninitialize();
}
第7步:編譯并運行程序
現在你可以按下F5鍵來編譯程序,然后按下Ctrl+F5來運行之。你應該可以看到一個DOS窗口,給出了你所期望的結果。
分類: ATL
========
總結
以上是生活随笔為你收集整理的VC++ ATL 学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring.net 类库目录
- 下一篇: Flex命令行学习总结