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去除一个发布接口指针,与一个自动化服务器对象断开连接