介紹在VC++ 6.0下編寫COM客戶程序的三種方法,雖然每一種方法都可以達到使用代碼組件的目的,但詳細瞭解並掌握所有方法會爲根據具體情況選擇適當方法提供更大的餘地。
COM庫函數
---------------------------------------------------
利用COM庫函數使用代碼組件的方法是介紹的三種方法中實現起來最麻煩和困難的方法。它要求開發人員必須具有對COM原理的深入理解。該方法實現步驟如下:
1. 首先添加COM初始和終止代碼。在應用程序類的初始化實例函數InitInstance()中添加如下代碼:
CoInitialize(NULL);
……
CoUnInitialize();
上述語句運行在MFC框架/非MFC框架中,但由於本文程序使用MFC框架,所以也可以利用AfxOleInit()函數對其進行初始化。
2. 然後用#include 語句包含對組件頭文件的引用並創建組件對象。在頭文件中包含了接口的C++定義以及說明接口ID IID和類ID CLSID的符號化常量。創建工作在初始化對話框函數中進行:
IAccount pAccount=NULL;
……
CoCreateInstance(CLSID_Account,
NULL,
CLSCTX_INPROC_SERVER,
IID_Iaccount,
reinterpret_cast (&pAccount));
3. 最後釋放組件對象。該工作應在程序退出之前完成,比如在消息WM_CLOSE的響應函數中進行:
if(pAccount!=NULL)
pAccount->Realease();
對該代碼組件中的其他功能函數的調用,可以通過組件對象的接口指針pAccount來進行:
……
BSTR bstrResult;
PAccount-> Post(100,bstrResult);
SysFreeString(bstrResult);
……
由於COM支持類在comdef. h中定義,所以還要包含對該頭文件的引用,纔可以使程序正常運行。
---------------------------------------------------
類嚮導
---------------------------------------------------
通過類嚮導可以直接閱讀組件的類型庫,併產生包裝類型庫中每個接口的類,通過這些類的成員函數可以訪問組件接口的方法和屬性,與使用ActiveX控件的方法有些類似。
首先添加對COM組件進行初始化的代碼。我們可以通過類嚮導的From a Type Library加入組件的.tlb類型庫文件,並從中引入其接口類。在本例中引入的類型庫文件中只包含一個從ColeDispatchDriver派生的組件包裝類IAccount。通過包裝類的成員,可以瞭解到組件接口能提供哪些服務,而且可以通過它們訪問組件接口的方法和屬性。
在初始化對話框函數裏用COleDispatchDriver類的CreateDispatch()成員函數創建Account組件對象:
IAccount m_account;
……
m_account.CreateDispatch(“ATLSample.Account.1”));
其中ProgID值“ATLSample. Account. 1”可以通過Microsoft Visual Studio Tools 6.0裏的OLE View工具查找到,其前提是該組件已被成功註冊過。
釋放Account組件對象也可以用COleDispatch-Driver類的ReleaseDispatch()函數來完成。
對於在COM庫函數方法中用過的Post方法可用下述方法調用:
CString str=m_account. Post(100);
可以看出此種方法實現了同樣的功能但實現起來要比上一種方法簡單些,而且對理解COM的要求也不高。
---------------------------------------------------
#import 指令
---------------------------------------------------
#import 指令方法非常簡便。對於類型庫文件採用該指令是非常合適的,因爲不管是調試版本還是發行版本,對於類型庫文件而言,其路徑是固定的。#import指令在執行時將會從待引入的類型庫中提取出兩個文件:一個.tlh文件和一個.tli文件,後者僅僅是包裝類的函數實現,而前者則包含了許多有關的重要信息。智能接口指針也在其中定義:
_COM_SMARTPTR_TYPEDEF(IAccount,__uuidof(IAccount));
在實際編譯時,編譯器會將其展開成下述代碼,並通過_com_ptr_t模板類爲接口IAccount定義一個智能指針IAccountPtr。之所以說其是智能指針,是由於它替代IAccount時,會自動處理CoCreate-Instance和所有的IUnknow方法,使用起來非常方便:
typedef _com_ptr_t<_com_IIID< Iaccount,__uuidof(IAccount)>> IAccountPtr;
由於有了智能指針,我們就可以調用_com_ptr_t模板類的CreateInstance()函數來完成對接口指針的創建工作:
IAccountPtr m_account=NULL;
m_account.CreateInstance(__uuidof(Account));
由於在生成的.tlh文件中包含結構聲明和declspec(uuid(“”))聲明,所以在這裏可以很方便地用__uuidof(Account)獲取接口的GUID。declspec(uuid(“”))聲明將GUID和類及每個接口聯繫起來,允許開發人員以uuidof操作符來獲取類和接口的GUID。
需要特別指出的是: 爲防止原有代碼和新引入的代碼之間發生名字衝突,編譯器會定義一個由類型庫名稱標識的命名空間,並在其中聲明的任何名稱內附加一個標識符。而爲了避免指定命名空間標識,可以在#import 語句後加上using namespace,而且還可以用rename_namespace來改變命名空間。比如在本例中可以進行如下處理:
#import “Account.tlb” rename_namespace(“AccountDriver”)
using namespace AccountDriver;
這樣,在使用智能接口指針IAccountPtr時只需定義即可:
IAccountPtr m_account;
至於對代碼組件中的函數和屬性的調用則同前兩種方法一樣,也是通過m_account來完成訪問的。由於_com_ptr_t模板類和智能指針的引入,#import 指令方法是這三種方法中使用COM組件最簡單的一種。