设为首页 加入收藏

TOP

12.1.9 创建一个自动化组件的技巧
2013-10-07 00:16:07 来源: 作者: 【 】 浏览:79
Tags:12.1.9 创建 一个 自动化 组件 技巧

12.1.9  创建一个自动化组件的技巧

1.问题阐述

前面创建的COM对象都是定制接口对象,也就是所谓的前绑定。编译器在编译的时候装载类型库,分别使用了 #include 方法和 #import 方法来实现。装载了类型库后,编译器就知道如何编译接口函数的调用了。脚本语言是解释执行的语言,它在执行的时候不会知道具体的函数的地址,那么在脚本语言中,如何调用COM组件呢?

2.实现技巧

为了使脚本语言支持COM组件的调用,MS提供了另外一个接口,即Idispatch接口,又称为自动化接口,也被称为后绑定接口。自动化组件,即实现了Idispatch接口的组件。IDispatch接口用IDL形式说明如下:

[
object,
uuid(00020400-0000-0000-C000-000000000046),
//IDispatch接口的IID =IID_IDispatch
pointer_default(unique)
]
interface IDispatch : IUnknown
{
typedef [unique] IDispatch * LPDISPATCH; // 转定义 IDispatch * 为 LPDISPATCH
    HRESULT GetTypeInfoCount([out] UINT * pctinfo); 
HRESULT GetTypeInfo([in] UINT iTInfo,[in] LCID lcid,
[out] ITypeInfo ** ppTInfo);
    HRESULT GetIDsOfNames(     // 根据函数名字,取得函数序号(DISPID)
[in] REFIID riid,
[in, size_is(cNames)] LPOLESTR * rgszNames,
[in] UINT cNames,
[in] LCID lcid,
[out, size_is(cNames)] DISPID * rgDispId
);
    [local]         //本地版函数
HRESULT Invoke( 
[in] DISPID dispIdMember,
[in] REFIID riid,
[in] LCID lcid,
[in] WORD wFlags,
[in, out] DISPPARAMS * pDispParams,
[out] VARIANT * pVarResult,
[out] EXCEPINFO * pExcepInfo,
[out] UINT * puArgErr
);
    [call_as(Invoke)]       //远程版函数
HRESULT RemoteInvoke(
[in] DISPID dispIdMember,
[in] REFIID riid,
[in] LCID lcid,
[in] DWORD dwFlags,
[in] DISPPARAMS * pDispParams,
[out] VARIANT * pVarResult,
[out] EXCEPINFO * pExcepInfo,
[out] UINT * pArgErr,
[in] UINT cVarRef,
[in, size_is(cVarRef)] UINT * rgVarRefIdx,
[in, out, size_is(cVarRef)] VARIANTARG * rgVarRef
);
}

IDispatch接口有4个函数,解释语言的执行器就通过仅有的4个函数来执行组件所提供的功能。

其中GetIDsOfNames将读取一个函数的名称并返回其调度ID,又称为DISPID。DISPID并不是一个GUID,而只是一个长整数,它标识的是一个函数。对于IDispatch的每一个特定的实现,DISPID是唯一的。IDispatch的每一个实现都有其自己的IID。为执行某个函数,自动化控制程序将把DISPID传给Invoke成员函数。

Invoke可以将DISPID作为函数指针数组的索引,这一点同常规COM接口是相似的。但是自动化服务并不需要按此种方式实现Invoke。一个简单的自动化服务器可以根据DISPID用一个case语句执行不同的代码。IDispatch::Invoke将实现一组按索引来访问的函数,Invoke的一个实现所实现的函数集被称为一个调度接口,而COM接口是一个指向一个函数指针数组的指针,此数组的前3个元素分别是QueryInterface、AddRef及Release。Invoke函数参数含义:第一个参数是控制程序待调用函数的DISPID;第二个参数是保留值,必须为IID_NULL;第三个参数为保存位置信息;第四个参数为所指的调用函数的类型,它的值可以是DISPATCH_METHOD、DISPATCH_PROPERTYGET和DISPATCH_PROPERTYPUT值中的一个;第五个参数是传给被调用函数的参数;第六个参数是返回值。

3.实例代码

本实例演示如何创建双接口组件。启动ATL COM AppWizard,工程名为Object。选择DLL类型、不合并代理和存根代码、不支持MFC、不支持MTS。“New Atl Object”选择“Simple Object”,输入名称DFun,属性按默认设置,增加函数Add,如图12-7所示。
选择“Attributes”选项卡,设置双接口的属性如图12-8所示。

 
图12-7  双接口设置向导 
 
图12-8  设置双接口属性
在Idl中组件描述如下:
import "oaidl.idl";
import "ocidl.idl";
[
object,
uuid(DAB964C5-24E5-4648-8765-F8D8AA9D6F23),
dual,
helpstring("IDFun Interface"),
pointer_default(unique)
]
interface IDFun : IDispatch
{
[id(1), helpstring("method Add")] HRESULT Add([in]long n1,[in]long
n2,[out,retval]long* pVal );
};
[
uuid(51000335-57C3-4D25-8A05-8768264350F0),
version(1.0),
helpstring("Object 1.0 Type Library")
]
library OBJECTLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
 [
uuid(DF7E08FC-51B3-4498-9D14-63E5E704133E),
helpstring("DFun Class")
]
coclass DFun
{
[default] interface IDFun;
};
增加函数,在 ClassView 选项卡中,选择接口,单击鼠标右键菜单,在弹出菜单中添加接口函数。
Add([in] VARIANT v1, [in] VARIANT v2, [out, retval] VARIANT * pVal);
Upper([in] BSTR str, [out,retval] BSTR * pVal);
函数实现的参考代码如下:
/************************************************************************/
/* 转换为小写
/************************************************************************/
STDMETHODIMP CDFun::Lower(BSTR bstr, BSTR *pVal)
{
*pVal = NULL; 
CComBSTR s(bstr);
s.ToLower(); // 转换为小写
*pVal = s.Copy();
return S_OK;
}
/************************************************************************/
/* 加法运算
/* 整数的加法运算和字符串的加法运算
/************************************************************************/
STDMETHODIMP CDFun::Add(VARIANT  v1, VARIANT  v2,VARIANT*  pVal)
{
::VariantInit( pVal ); 
     CComVariant v_1( v1 );
CComVariant v_2( v2 );
 if((v1.vt & VT_I4) && (v2.vt & VT_I4) ) // 如果都是整数类型

v_1.ChangeType( VT_I4 );   // 转换为整数
v_2.ChangeType( VT_I4 );   // 转换为整数
     pVal->vt = VT_I4;
pVal->lVal = v_1.lVal + v_2.lVal; // 加法
}
else
{
v_1.ChangeType( VT_BSTR );   // 转换为字符串
v_2.ChangeType( VT_BSTR );   // 转换为字符串
     CComBSTR bstr( v_1.bstrVal );
bstr.AppendBSTR( v_2.bstrVal ); // 字符串连接
     pVal->vt = VT_BSTR;
pVal->bstrVal = bstr.Detach();
}
return S_OK;
}
最后在脚本中调用COM接口实例,创建一个记事本,更改扩展名为vbs,脚本的参考代码如下:
Set obj = CreateObject("Object.DFun")
MsgBox obj.Lower("接口函数Lower:THIS IS  A TEST")
MsgBox obj.Add("1+2=" ,obj.Add(1,2))
Set obj = Nothing
运行执行结果如图12-9和图12-10所示。
 
图12-9  调用COM接口中的
Lower函数
 
图12-10  调用
COM接口中
的Add函数

【责任编辑:夏书 TEL:(010)68476606】

回书目   上一节   下一节

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇12.2.1 VC++实现Office自动化 下一篇12.2.2 VC++读/写Word文档

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: