三 ATL基本使用 這一部分將重點介紹ATL的基本使用過程
由於ATL已經被集成在Microsoft Visulal Studio的Visual C++開發環境中
因此要使用ATL必須先安裝Visual C++
在下面的討論中有關COM的基本知識請參閱有關的文檔
這裡不再詳細說明
給出的圖是在Microsoft Windows
平台下Visual Studio
的使用示意圖
使用ATL開發一個COM應用基本可以分為以下幾個步驟
創建一個新的ATL工程
並對工程的選項進行適當的配置
向新創建的工程添加新的ATL類
並對該類進行一些初始配置工作
根據COM應用的基本要求向新的ATL類加入新的接口定義
並實現相應的接口成員函數
編譯連接工程
注冊COM應用
下面將根據這些步驟依次介紹ATL的基本使用過程
創建工程 首先啟動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將創建相應的工程
加入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>
按鈕進入下一步
進入對象屬性設置對話框
如圖
和圖
所示
對象屬性設置分為兩個過程
先是對象名字標識的設定
然後是對對象的基本屬性進行設置
首先是對象的名字標識設置
在對象標識編輯框中輸入待創建對象的名字
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類的接口中加入成員函數的定義
以及接口成員函數的實現過程
加入接口定義實現接口函數 加入了ATL類定義之後
我們可以打開Visual C++集成環境下項目管理器(Workspace)中的Class View來檢查生成的類定義的情況
我們可以看到一個新的類已經生成
同時
還生成了相應的接口定義
ATL Object Wizard為我們生成了類定義的
h 和
cpp文件
此外還有用於接口定義的IDL文件
有了這些文件以後
我們就可以為接口加入成員函數
完成類的定義
首先在Class View中選中相應的接口
顯示為接口IATLTest
單擊鼠標右鍵打開菜單
如圖
此彈出式菜單定義了為接口加入屬性和方法的操作
選取其中的
Add Method
項
可以為接口加入方法成員
選取
Add Property
則可以為接口加入新的屬性成員
加入屬性和方法的對話框可以參看圖
和圖
如果我們要在接口中加入一個方法
則選取
Add Method
菜單命令
假設方法名為ABC
方法的返回類型為COM規定的HRESULT類型
我們也可以定義非HRESULT返回類型的函數
但是這需要手工修改接口定義的IDL文件
我們定義ABC方法的一個參數為a
類型為整數型
完成了方法的定義以後
單擊
OK
按鈕則把此方法加入到接口中
屬性的加入過程是類似的
屬性加入對話框要求指定屬性的類型
名字以及屬性的訪問方式
在屬性和方法的編輯對話框中都有一個
Attributes
按鈕
在給出了一個屬性或方法的基本定義之後
單擊此按鈕
可以對屬性和方法的一些高級特性進行設置
方法成員加入以後
我們可以通過Class View來檢查ATL為我們所做的工作
首先我們看到ATL在接口的定義中加入了該方法的定義
同時在對應的ATL類定義中
也加入了一個相應的方法的定義
在類對應的
cpp文件中
加入了此方法的實現框架
此後
我們只要在這個函數框架中加入該方法的代碼邏輯
一個接口函數的定義和實現就基本完成了
依照這種方式
我們可以完成整個COM對象的定義和實現
完成以上的步驟之後
我們就可以編譯連接應用了
編譯連接應用注冊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
= s
ActiveXObject Class
{
CLSID
From:http://tw.wingwit.com/Article/os/xtgl/201311/8934.html