1. 創建自動化服務器CustomServer
/***************** http://blog.csdn.net/elysium *************************/
新建MFC AppWizard(EXE),工程名稱爲CustomServer,選擇單/多文檔格式,在第三步中包含其他支持,選中“自動操作”(若選擇基於對話框的工程,Automation“自動操作”出現在第二步中),如圖:
創建了自動化應用程序框架後,我們會看到在工程目錄下有兩個特殊的文件,一個是CustomServer.reg,文件記錄了新創建的自動化服務器所需要的註冊信息,當使用安裝程序在別的機器上安裝自動化服務器時需要這個文件。
該文件內容大致如下:
HKEY_CLASSES_ROOT/CustomServer.Document = Custom Document HKEY_CLASSES_ROOT/CLSID/{9158903B-5FE5-428E-BFCF-A7E045377DD3} = Custom Document |
另外一個文件是odl類型文件(Object Definition Language),該文件記錄了自動化服務器的方法和屬性,它由類嚮導維護,編譯時自動編譯。當然idl文件(Interface Definition Language)也可以實現odl文件的樣板類庫定義。
文件如下:
[ uuid(6D4DE28F-A071-4FCE-9C97-EAA7E8BA3000), version(1.0) ]
library CustomServer
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
// Primary dispatch interface for CCustomServerDoc
[ uuid(D7E458B7-3BD0-49FD-A027-039EFBE2874E) ]
dispinterface ICustomServer
{
properties:
// NOTE - ClassWizard will maintain property information here.
// Use extreme caution when editing this section.
//{{AFX_ODL_PROP(CCustomServerDoc)
//類嚮導在此添加屬性
//}}AFX_ODL_PROP
methods:
// NOTE - ClassWizard will maintain method information here.
// Use extreme caution when editing this section.
//{{AFX_ODL_METHOD(CCustomServerDoc)
//類嚮導在此添加方法
[id(1)] double Power(double dBase, double dExponent);
//}}AFX_ODL_METHOD
};
// Class information for CCustomServerDoc
[ uuid(9158903B-5FE5-428E-BFCF-A7E045377DD3) ]
coclass Document
{
[default] dispinterface ICustomServer;
};
//{{AFX_APPEND_ODL}}
//}}AFX_APPEND_ODL}}
};
爲了應用ole自動化,應用程序嚮導會在InitInstance()裏面調用AfxOleInit完成初始化Ole和COM,(注意,非常非常重要,大多數OLE服務無法運行時應首先檢查是否初始化了OLE,當然ole服務器也要安裝了纔行,否則使用CreateDispatch返回失敗信息)
CCommandLineInfo對象的m_bRunAutomated標誌用來設置自動化服務器是否在後臺運行,而m_bRunEmbedded用來設置是否在複合文檔中支持嵌入對象,該CCommandLineInfo對象通過ParseCommandLine()函數實現設置。
然後我們爲自動化服務器添加方法,可以使用Ctrl+W,或者View菜單下ClassWizard,打開ClassWizard對話框,選擇Automation標籤,ClassName中選中文檔類,單擊Add Method,輸入一個外部方法名,如“Power”,內部名自動出現,當然也可以更改,在Return Type選擇返回值類型,在Parameter List中Name中輸入參數名字,Type中選擇參數類型,若有多個參數可重複添加,然後單擊edit code可以編輯方法(其實方法的聲明也可以在ClassView下使用Add Method添加)。
接下來我們會在ClassView中看到下圖結構:
我們會在文檔發佈接口類中看到文檔發佈接口的ID被聲明成一個靜態常量GUID,發佈接口本身通過宏映射實現
static const IID IID_ICustomServer =
{ 0xd7e458b7, 0x3bd0, 0x49fd, { 0xa0, 0x27, 0x3, 0x9e, 0xfb, 0xe2, 0x87, 0x4e } };
BEGIN_INTERFACE_MAP(CCustomServerDoc, CDocument)
INTERFACE_PART(CCustomServerDoc, IID_ICustomServer, Dispatch)
END_INTERFACE_MAP()
我們也可以看到添加的一個“Power”方法的宏映射:
BEGIN_DISPATCH_MAP(CCustomServerDoc, CDocument)
//{{AFX_DISPATCH_MAP(CCustomServerDoc)
DISP_FUNCTION(CCustomServerDoc, "Power", Power, VT_R8, VTS_R8 VTS_R8)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()
DISP_FUNCTION的第一個參數是實現函數的類名,第二個是函數的外部名,第三個是內部函數名,第四個是函數返回的VARIANT類型,最後一個是以空格分隔的列表,是傳遞給函數的VARIANT參數的數據類型列表。這些參數的定義在AfxDisp.h中。
下面我們爲Power函數添加實現代碼,記得要在#include "stdafx.h"之後#include "math.h"。
/////////////////////////////////////////////////////////////////////////////
// CCustomServerDoc commands
double CCustomServerDoc::Power(double dBase, double dExponent)
{
// TODO: Add your dispatch handler code here
return pow(dBase, dExponent);
}
ok,編譯運行,成功後我們會在輸出目錄中發現一個tlb文件,該文件包含了發送方法的類型信息。
2. 創建自動化客戶端CustomClient
我們創建一個基於對話框的CustomClient客戶程序來測試自動化服務器CustomServer。
首先初始化OLE庫(不要忘了我們在做什麼)
使用類嚮導從自動化服務器的樣板類庫(tlb文件)創建ole發佈驅動類,注意發佈驅動類的名字缺省使用前綴I,調用IDispatch接口的Invoke來激活自動化服務器對象,不要與COM接口定義類混淆。
進入Class Wizard,選擇Automation項,單擊Add Class,選擇From a Type Library,導入CustomServer.tlb,該發佈驅動類會自動生成頭文件及實現文件,該類派生自COleDispatchDrive,包含了用來創建發佈接口指針的函數。
在開始#include "CustomServer.h",在主對話框的OnInitDialog中編寫處理代碼。
// TODO: Add extra initialization here
ICustomServer ICustomServer; // 聲明發送類事例
//調用CreateDispatch()函數,創建自動化服務器文檔對象,然後把它的發佈接口指針保存在
//m_lpDispatch成員變量中。
if (ICustomServer.CreateDispatch("CustomServer.Application"))
{
double dBase = 4;
double dExponent = 2;
double dResult = ICustomServer.Power(dBase, dExponent);
CString strMsg;
strMsg.Format("Result of power(%f, %f) is %f/n", dBase, dExponent, dResult);
AfxMessageBox(strMsg);
}
//當發佈類超出作用域(此處爲OnInitDialog),發佈接口類會被自動釋放
//也可以使用ReleaseDispatch()立即手工釋放指針,從而避免在程序運行中產生多個自動化服務器實例
//AttachDispatch可以附加一個發佈接口指針來與一個已經存在的自動化服務器對象連接
//DetachDispatch去除一個發佈接口指針,與一個自動化服務器對象斷開連接