COM 组件设计与应用09IDispatch 接口VC6.docx

上传人:b****5 文档编号:2939031 上传时间:2022-11-16 格式:DOCX 页数:14 大小:459.59KB
下载 相关 举报
COM 组件设计与应用09IDispatch 接口VC6.docx_第1页
第1页 / 共14页
COM 组件设计与应用09IDispatch 接口VC6.docx_第2页
第2页 / 共14页
COM 组件设计与应用09IDispatch 接口VC6.docx_第3页
第3页 / 共14页
COM 组件设计与应用09IDispatch 接口VC6.docx_第4页
第4页 / 共14页
COM 组件设计与应用09IDispatch 接口VC6.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

COM 组件设计与应用09IDispatch 接口VC6.docx

《COM 组件设计与应用09IDispatch 接口VC6.docx》由会员分享,可在线阅读,更多相关《COM 组件设计与应用09IDispatch 接口VC6.docx(14页珍藏版)》请在冰豆网上搜索。

COM 组件设计与应用09IDispatch 接口VC6.docx

COM组件设计与应用09IDispatch接口VC6

COM组件设计与应用(九)

IDispatch接口forvc6.0

作者:

杨老师

下载源代码

一、前言

   终于写到了第九回,我也一直期盼着写这回的内容耶,为啥呢?

因为自动化(automation)是非常常用、非常有用、非常精彩的一个COM功能。

由于WORD、EXCEL等OFFICE软件提供了“宏”的功能,就连我们使用的VC开发环境也提供了“宏”功能,更由于HTML、ASP、JSP等都要依靠脚本(Script)的支持,更体现出了自动化接口的重要性。

   如果你使用vc6.0的开发环境,请继续阅读。

   如果你使用2003,请阅读下一回。

二、IDispatch接口

   如果是编译型语言,那么我们可以让编译器在编译的时候装载类型库,也就是装载接口的描述。

在第七回文章当中,我们分别使用了#include方法和#import方法来实现的。

装载了类型库后,编译器就知道应该如何编译接口函数的调用了---这叫“前绑定”。

但是,如果想在脚本语言中使用组件,问题就大了,因为脚本语言是解释执行的,它执行的时候不会知道具体的函数地址,怎么办?

自动化接口就为此诞生了---“后绑定”。

   自动化组件,其实就是实现了IDispatch接口的组件。

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

IDispatch接口用IDL形式说明如下:

(注1)

[

object,

uuid(00020400-0000-0000-C000-000000000046),//IDispatch接口的IID=IID_IDispatch

pointer_default(unique)

]

interfaceIDispatch:

IUnknown

{

typedef[unique]IDispatch*LPDISPATCH;//转定义IDispatch*为LPDISPATCH

HRESULTGetTypeInfoCount([out]UINT*pctinfo);//有关类型库的这两个函数,咱们以后再说

HRESULTGetTypeInfo([in]UINTiTInfo,[in]LCIDlcid,[out]ITypeInfo**ppTInfo);

HRESULTGetIDsOfNames(//根据函数名字,取得函数序号(DISPID)

[in]REFIIDriid,

[in,size_is(cNames)]LPOLESTR*rgszNames,

[in]UINTcNames,

[in]LCIDlcid,

[out,size_is(cNames)]DISPID*rgDispId

);

[local]//本地版函数

HRESULTInvoke(//根据函数序号,解释执行函数功能

[in]DISPIDdispIdMember,

[in]REFIIDriid,

[in]LCIDlcid,

[in]WORDwFlags,

[in,out]DISPPARAMS*pDispParams,

[out]VARIANT*pVarResult,

[out]EXCEPINFO*pExcepInfo,

[out]UINT*puArgErr

);

[call_as(Invoke)]//远程版函数

HRESULTRemoteInvoke(

[in]DISPIDdispIdMember,

[in]REFIIDriid,

[in]LCIDlcid,

[in]DWORDdwFlags,

[in]DISPPARAMS*pDispParams,

[out]VARIANT*pVarResult,

[out]EXCEPINFO*pExcepInfo,

[out]UINT*pArgErr,

[in]UINTcVarRef,

[in,size_is(cVarRef)]UINT*rgVarRefIdx,

[in,out,size_is(cVarRef)]VARIANTARG*rgVarRef

);

}

以上IDispatch接口函数的讲解,我们留到后回中进行介绍。

如何在组件程序中实现这些函数那?

还好,还好,就象IUnknown一样,MFC和ATL都帮我们已经完成了。

本回我们着重介绍组件的编写,下回则介绍组件的调用方法。

三、用MFC实现自动化组件

   我写的这整个系列文章---《COM组件设计与应用》,多是用ATL写组件程序,但由于自动化非常有用,在后续的文章中,还要给大家介绍组件的“事件”功能,还要介绍如何在MFC的程序中象WORD一样支持“宏”的功能。

这些都要用到MFC,所以就给读者唠一唠啦:

-)

   3-1:

建立一个工作区(Workspace)

   3-2:

建立一个MFCDLL工程(Project),工程名称为“Simple5”

   3-3:

一定要选择automation,切记!

切记!

   3-4:

建立新类

   3-5:

在新建类中支持automation

Classinformation-Name你随便写个类名子啦

Classinformation-Baseclass一定要从CComTarget派生呀,只有它才提供了IDispatch的支持

Automation-None表示不支持自动化,你要选择了它,那就白干啦

Automation-Automation支持自动化,但不能被直接实例化。

后面在讲解多个IDispatch的时候就用到它了,现在先不要着急。

Automation-CreateablebytypeID一定要选择这个项目,这样我们在后面的调用中,VB就能够CreateObject(),VC就能够CreateDispatch()对组件对象实例化了。

注意一点,这个ID其实就是组件的ProgID啦。

   3-6:

启动ClassWizard,选择Automation卡片,准备建立函数

   3-7:

添加函数。

我们要写一个整数加法函数Add()。

   3-8:

再增加一个转换字符串大小写的函数Upper()。

函数返回值是BSTR,这个没有什么疑问,但参数类型怎么居然是LPCTSTR?

在COM中,字符串不是应该使用BSTR吗?

是的,是应该使用BSTR,但由于我们是用MFC写自动化组件,它帮我们进行BSTR和LPCTSTR之间的转换了。

   3-9:

好了,下面开始输入程序代码:

longCDispSimple:

:

Add(longn1,longn2)

{

returnn1+n2;

}

BSTRCDispSimple:

:

Upper(LPCTSTRstr)

{

CStringstrResult(str);

strResult.MakeUpper();

returnstrResult.AllocSysString();

}

   3-10:

编译注册

   如果上面的操作由于疏忽而发生了错误,那么你可以手工进行改正。

其一、步骤<3-6>的对话窗中有“Delete”操作;

其二、你可以打开ODL文件(注2)进行修改,修改时要特别小心函数的声明中,有一个[id(n)]的函数序号,可不要乱了;

其三、同步修改H/CPP中的函数声明和函数体;

其四、在CPP文件中,根据情况也要修改BEGIN_DISPATCH_MAP/END_DISPATCH_MAP()函数影射宏。

   正确编译后,MFC不象ATL那样会自动注册。

你需要手工执行regsvr32.exe进行注册,或者执行菜单“Tools\Registercontrol”

四、用ATL实现双接口组件(操作方法和步骤,请参考《COM组件设计与应用(五)》)

   4-1:

建立一个ATL工程(Project),工程名称为“Simple6”

   4-2:

按默认进行。

选择DLL类型、不合并代理和存根代码、不支持MFC、不支持MTS

   4-3:

NewAtlObject...选择SimpleObject

   4-4:

输入名称和属性,属性按默认进行,也就是dual(双接口)方式(注3)

   4-5:

增加函数。

在ClassView卡片中,选择接口、鼠标右键菜单、AddMethod...

Add([in]VARIANTv1,[in]VARIANTv2,[out,retval]VARIANT*pVal);

Upper([in]BSTRstr,[out,retval]BSTR*pVal);

   关于Add()函数,你依然可以使用Add([in]longn1,[in]longn2,[out,retval]long*pVal)方式。

但这次我们没有使用long,而是使用了VARIANT做参数和返回值。

这里我先卖个关子,往下看,就知道使用VARIANT的精彩之处了。

   4-6:

完成代码

STDMETHODIMPCDispSimple:

:

Add(VARIANTv1,VARIANTv2,VARIANT*pVal)

{

:

:

VariantInit(pVal);//永远初始化返回值是个好习惯

CComVariantv_1(v1);

CComVariantv_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);//转换为字符串

CComBSTRbstr(v_1.bstrVal);

bstr.AppendBSTR(v_2.bstrVal);//字符串连接

pVal->vt=VT_BSTR;

pVal->bstrVal=bstr.Detach();

}

returnS_OK;

}

STDMETHODIMPCDispSimple:

:

Upper(BSTRstr,BSTR*pVal)

{

*pVal=NULL;//永远初始化返回值是个好习惯

CComBSTRs(str);

s.ToUpper();//转换为大写

*pVal=s.Copy();

returnS_OK;

}

   刚才卖的关子,现在开始揭密了......加法函数Add()不使用long类型,而使用VARIANT的

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 合同协议

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1