COM 组件设计与应用(十一)

COM 组件设计与应用(十一
IDispatch 及双接口的调用

作者:杨老师

下载源代码

一、前言
    前段时间,由于工作比较忙,没有能及时地写作。其间收到了很多网友的来信询问和鼓励,在此一并表示感谢。咳......我也需要工作来养家糊口呀......
    上回书介绍了两种方法来写自动化
(IDispatch)接口的组件程序,一是用 MFC 方式编写“纯粹”的 IDispatch 接口;二是用 ATL 方式编写“双接口”的组件。

二、IDispatch 接口和双接口
    使用者要想调用普通的 COM 组件功能,必须要加载这个组件的类型库(Type library)文件 tlb(比如在 VC 中使用 #import)。然而,在脚本程序中,由于脚本是被解释执行的,所以无法使用加载类型库的方式进行预编译。那么脚本解释器如何使用 COM 组件那?这就是自动化(IDispatch)组件大显身手的地方了。IDispatch 接口需要实现4个函数,调用者只通过这4个函数,就能实现调用自动化组件中所有的函数。这4个函数功能如下:
 

HRESULT GetTypeInfoCount(
    [out] UINT * pctinfo)
组件中提供几个类型库?当然一般都是一个啦。
但如果你在一个组件中实现了多个
IDispatch 接口,那就不一定啦(注1)
HRESULT GetTypeInfo(
    [in] UINT iTInfo,
    [in] LCID lcid,
    [out] ITypeInfo ** ppTInfo)
调用者通过该函数取得他想要的类型库。
幸好,在 99% 的情况下,我们都不用关心这两个函数的实现,因为 MFC/ATL 都帮我们完成了默认的一个实现,如果是自己完成函数代码,甚至可以直接返回 E_NOTIMPL 表示没有实现。(注2)
HRESULT GetIDsOfNames(
    [in] REFIID riid,
    [in,size_is(cNames)] LPOLESTR * rgszNames,
    [
in] UINT cNames,
    [in] LCID lcid,
    [out,size_is(cNames)] DISPID * rgDispId)
根据函数名称取得函数序号,为调用 Invoke() 做准备。
所谓函数序号,大家去观察双接口 IDL 文件和 MFC 的 ODL 文件,每一个函数和属性都会有
[id(序号)....] 这样的描述。
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)
根据序号,执行函数。
使用 MFC/ATL 写的组件程序,我们也不必关心这个函数的实现。如果是自己写代码,则该函数类似如下实现:
switch(dispIdMember)
{
    case 1: .....; break;
    case 2: .....; break;
    ....
}
其实,就是根据序号进行分支调用啦。(注3)
 

    从 Invoke() 函数的实现就可以看出,使用 IDispatch 接口的程序,其执行效率是比较低的。ATL 从效率出发,实现了一种叫“双接口(dual)”的接口模式。下面我们来看看,到底什么是双接口:

comtut11pic1.jpg
图一、双接口
(dual) 结构示意图

    从上图中可以看出,所谓双接口,其实是在一个 VTAB 的虚函数表中容纳了三个接口(因为任何接口都是从
IUnknown 派生的,所以就不强调 IUnknown 了,叫做双接口)。我们如果从任意一个接口中调用 QueryInterface()得到另外的接口指针的话,其实,得到的指针地址都是同一个。双接口有什么好处那?答:好呀,多好呀,特别好呀......
 

使用方式因为所以
脚本语言使用组件解释器只认识 IDispatch 接口可以调用,但执行效率最低
编译型语言使用组件它认识 IDispatch 接口可以调用,执行效率比较低
编译型语言使用组件它装载类型库后,就认识了 Ixxx 接口可以直接调用 Ixxx 函数,效率最高啦

结论

双接口,既满足脚本语言的使用方便性,又满足编译型语言的使用高效性。
于是,我们写的所有的 COM 组件接口,都用双接口实现吗?
错!否!NO!
如果不是明确非要支持脚本的调用,则最好不要使用双接口,因为:

如果所有函数都放在一个双接口中,那么层次、结构、分类不清
如果使用多个双接口,则会产生其它问题(注4)
双接口、IDispatch接口只支持自动化的参数类型,使用受到限制,某些情况下很不方便喽
还有很多弊病呦,不过现在我想不起来喽......

三、使用方法
    如果你的开发环境是 vc6.0,那么我们使用第九回中的Simple6组件为例,快去下载呀......
    如果你的开发环境是 vc.net 2003,那么用第十回中的Simple8组件为例,快去下载呀......
    嘿嘿,其实不下载也没有关系,因为你只要下载本回的示例程序,里面已经包含了所需的组件。但使用前不要忘了去注册呀:regsvr32.exe simple6.dll regsvr32.exe simple8.dll (注意别忘了输入组件的安装目录)。注册成功后,就可以使用了,使用方法有:
 

示例程序自动化组件的使用方式简要说明
示例0在脚本中调用在第九回/第十回中,已经做了介绍
示例1使用 API 方式调用揭示 IDispatch 的调用原理,但傻子才去这么使用那,会累死了
示例2使用 CComDispatchDriver 的智能指针包装类比直接使用 API 方式要简单多啦,这个不错!
示例3使用 MFC 装载类型库的包装方式简单!好用!常用!但它本质上是使用 IDispatch 接口,所以执行效率稍差
示例4使用 #import 方式加载类型库方式#import 方式使用组件,咱们在第七回中讲过啦。常用!对双接口组件,直接调用自定义接口函数,不再经过 IDispatch,因此执行效率最高啦
示例xvbjavac#bcbdelphi.......反正我不会,自己去请教高人去吧 :-(

示例一、IDispatch 调用原理篇

示例二、CComDispatchDriver 智能指针包装类的使用方法
示例程序中使用了 Invoke2()函数,其实你根据不同的函数,还可以使用 Invoke0()Invoke1()InvokeN()PutProperty()GetProperty()......等等等,的确很方便。

示例三、加载类型库,产生包装类来使用
    这个方法使用更简单一些,如果你观察 MFC 帮你产生的包装类的实现,你就会发现,其实它调用的是 IDispatch 接口函数。使用 vc6.0 的朋友,步骤如下:
1、建立一个 MFC 的应用程序
2、开启 ClassWizard,执行 Add Class,选择 From a type library

comtut11pic2.jpg
图二、加载类型库

3、然后找到你要使用的组件文件 simple6.dll(tlb 文件也可以),选择接口后确认

comtut11pic3.jpg
图三、选择类型库中需要包装的接口

4、在适当的地方输入调用代码
使用 vc.net 的朋友,步骤如下:
1、建立一个 MFC 的应用程序
2、执行菜单“添加\添加类”,选择 MFC 分类中的“类型库中的MFC类”

comtut11pic4.jpg
图四、添加类型库中的MFC类

3、选择组件文件 simple8.dll(tlb 文件),并选择需要包装的接口

comtut11pic5.jpg
图五、选择文件和接口

4、在适当的位置输入调用代码
示例四、使用 #import 方式调用组件
    #import 方式在第七回中已经作过介绍,这里就不多罗嗦了。大家下载本回的示例程序后,自己去看吧。并且一定要掌握这个方法,因为它的运行效率是最快的呀。

四、小结
    留作业啦。在我们以前所实现的所有组件程序中,只添加了接口方法(函数),而没有添加接口属性(变量),你自己练习一下吧,很简单的,然后写个程序调用看看。其实对于 VC 来说,调用属性和调用方法没有太大的区别(vc 把属性包装为 GetXXX()/PutXXX()getXXX()/putXXX()的函数方式),但在另外一些语言中(比如脚本语言)则更方便,设置属性值是:对象.属性 = 变量或常量,获取属性值是:变量 = 对象.属性。
    本回书至此做一了断,更多组件设计和使用的知识,且听下回分解...... 注1:多个自动化接口的实现方法,我们以后再说。
注2:将来介绍 ITypeLib::GetTypeInfo
() 的时候,大家再回味 IDispatch::GetTypeInfo()吧。
注3:在后面介绍“事件”的时候,我们会自己真正去实现一个
IDispatch::Invoke() 函数。
注4:介绍多个双接口实现的时候,会谈到这个问题。

转载于:https://www.cnblogs.com/cdo/archive/2005/10/14/254638.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/424242.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

冒泡排序 和 归并排序

时间复杂度O&#xff08;nlog2n&#xff09; 归并排序&#xff1a; void Merge(int l,int mid,int r){ int il,jmid1,k0; while(i<mid && j<r) { if(a[i]>a[j]) { t[k]a[j]; cntmid-i1; } else …

39. Combination Sum

文章目录1题目理解2 回溯分析3 40. Combination Sum II3.1 延续39解题思路3.2 新思路3.3 递归计数的方式4 216. Combination Sum III1题目理解 Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of ca…

第九十五期:Python帮你识破双11的套路

一年一度的“双十一”又要来了&#xff0c;很多人已经开始摩拳擦掌&#xff0c;毕竟几天之后手还在不在就不好说了。 作者&#xff1a;清风小筑 各种社交软件也是跟着遭殃&#xff0c;整天就是“来帮我一起盖楼”&#xff0c;各种字体绕过屏蔽&#xff0c;什么奇葩的脑洞也出来…

客户端独立弹出详细的实现过程

拷贝粘贴以下代码段&#xff0c;保存为html文件&#xff0c;试试看效果如何吧。。。前几天贴子没写东西就搁在上面搁了几天&#xff0c;真不好意思。 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" ><HTML><HEAD></HEAD>&…

Unity3D性能优化之Draw Call Batching

在屏幕上渲染物体&#xff0c;引擎需要发出一个绘制调用来访问图形API&#xff08;iOS系统中为OpenGL ES&#xff09;。每个绘制调用需要进行大量的工作来访问图形API&#xff0c;从而导致了CPU方面显著的性能开销。Unity在运行时可以将一些物体进行合并&#xff0c;从而用一个…

第九十六期:JavaScript 中的 4 个相等比较算法的介绍

JavaScript 运算中&#xff0c;一共包含 4 个相等比较算法&#xff1a;抽象相等比较&#xff1b;严格相等比较&#xff1b;SameValueZero&#xff1b;SameValue。 作者&#xff1a;zhangbao90s JavaScript 运算中&#xff0c;一共包含 4 个相等比较算法&#xff1a; 抽象相等…

VC6下使用WebLink控件

这是今年6月7号我的一篇日志&#xff0c;好像还有些参考价值&#xff0c;誊到blog上来吧。 最终我在VC6下面搞定了WebLink&#xff0c;与以往一样&#xff0c;论坛和MSDN是我最大的帮手。在ESRI官方论坛那可怜的四五个关于VC6WebLink的帖子中&#xff0c;我找到了困扰我多天的问…

建行B2B支付回调参数乱码现象解析

建行B2B支付采用Java开发&#xff0c;页面回调采用POST提交方式&#xff0c;编码为GBK。而我们的系统为ASP.NET&#xff0c;编码UTF-8。通过Request获取的参数是乱码&#xff0c;无奈之下&#xff0c;只能从InputStream解析。解析代码如下&#xff1a;log.Debug("Request …

77. Combinations

文章目录1 题目理解2 回溯1 题目理解 Given two integers n and k, return all possible combinations of k numbers out of 1 … n. You may return the answer in any order. 输入&#xff1a;两个int n和k。 规则&#xff1a;从1到n&#xff0c;n个数选择k个数&#xff0…

第九十七期:新版Kite:实时补全代码,Python之父都发声力挺!

不久前&#xff0c;一个免费的专门针对 Python 的代码补全工具 Kite&#xff0c;有了新的动态。 作者&#xff1a;杨鲤萍 本文转自雷锋网&#xff0c;如需转载请至雷锋网官网申请授权。 不久前&#xff0c;一个免费的专门针对 Python 的代码补全工具 Kite&#xff0c;有了新…

svn 版本升级的问题

原创文章&#xff0c;转载请注明 svn本地版本由1.6升级到1.7后&#xff0c;再使用时遇到一些问题&#xff0c;这里记录一下以备忘。 升级后&#xff0c;使用任何命令 不能用了&#xff0c;提示的意思大致是本地的workcopy版本太低了&#xff08;之前用1.6版本&#xff0c;check…

[JavaME]手机申请移动分配的动态IP(3)?

获取IP后是否可以和它通讯呢&#xff1f;<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />Hi&#xff0c;继续上回的讨论《[JavaME]手机是否能够申请到动态IP[2]?》。 上回说到申请动态IP是可以了&#xff0c;并且准备好了一个线…

78. Subsets

文章目录1 题目理解2 回溯90 subset II方式一代码方式三代码1 题目理解 Given an integer array nums, return all possible subsets (the power set). The solution set must not contain duplicate subsets. 输入&#xff1a;int数组nums 输出&#xff1a;返回所有可能的子数…

第九十八期:TIOBE11月榜单:C、Swift、Go、D与Rust起起伏伏

TIOBE 指数并不代表语言的好坏&#xff0c;开发者可以使用该榜单检查自身的编程技能是否需要更新&#xff0c;或者在开始构建新软件时对某一语言做出选择。 作者&#xff1a;oschina TIOBE 公布了 11 月份编程语言排行榜。 本月前 20 名中有一些有趣的现象&#xff0c;先看看…

Vue 之 slot(插槽)

前言&#xff1a; vue中关于插槽的文档说明很短&#xff0c;语言又写的很凝练&#xff0c;再加上其和methods&#xff0c;data&#xff0c;computed等常用选项在使用频率、使用先后上的差别&#xff0c;这就有可能造成初次接触插槽的开发者容易产生“算了吧&#xff0c;回头再学…

sharepoint安装心得_过程

sharepoint安装心得_过程 我是新手,没有接触过sharepoint以前,所有在安装方面吃了一些亏 下面说一下正确的顺序: windows 2003 域服务器(ad) vs.net(如果需要的话,但不要装windows的frontpage的扩展,虽然.net需要,不装亦可) sqlserver 2000(sp3) sharepoint server 2003卸载顺序…

46. Permutations

文章目录1题目理解2 回溯3 47. Permutations II1题目理解 Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order. 输入&#xff1a;整数数组nums&#xff0c;所有元素不相同 输出&#xff1a;数组的所有…

第九十九期:可以编写代码的代码:代码生成的利与弊

代码生成的当前状态是无处不在的&#xff08;2019年春季&#xff09;。REST API的数量激增&#xff0c;导致在过去十年中针对各种编程语言和环境开发的API客户端生成器种类繁多。 作者&#xff1a;约翰麦克马洪 代码生成的当前状态 代码生成的当前状态是无处不在的&#xff0…

TD商用将迈重要一步 六大运营商年底建网试验

TD商用将迈重要一步 六大运营商年底建网试验 中国电信、中国网通、中国移动、中国联通、中国铁通和中国卫通同时开动 TD-SCDMA独立组网实验即将迈出重要一步。 昨天记者从知情人士处获悉&#xff0c;如无意外&#xff0c;参加信产部组织的TD-SCDMA外场第三阶段测试的系统厂商将…

天气预报的Ajax效果

最近在网站上看了很多显示实时天气预报的&#xff0c;挺实用而且用户体验也不错。对用户的帮助也比较大&#xff0c;用户可以通过你的网站了解到实时的天气信息。感觉比较有意思&#xff0c;于是自己钻研了一下其中的实现方法。于是决定把代码分享给大家&#xff0c;希望能对大…