读杨老师《COM设计与应用》18篇 下
9 IDispatch接口
IDispatch接口在MSDN中的定义This interface exposes objects, methods, and properties to
Automation programming tools and other applications.
我的理解是,实际上是将一个对象的接口暴暴露给脚本或IE
下面是IDispatch接口的四个函数
IDispatch::GetIDsOfNames Maps a single member name and an optional set of parameter names
to a corresponding set of integer dispatch identifiers (DISPIDs), which can then be used
on subsequent calls to IDispatch::Invoke.
IDispatch::GetTypeInfo Retrieves the type information for an object.
IDispatch::GetTypeInfoCount Retrieves the number of type information interfaces that an
object provides, either 0 or 1.
IDispatch::Invoke Provides access to properties and methods exposed by an object.
最重要的就是这个Invoke,通过设置IDipID,实现了一个接口函数调用多个功能,有点像窗口的消息
处理函数,根据不同的消息采用不同的处理方式,另外,GetIDsofNames提供将函数名转化为DispID的功
能。
杨老师举了两个例子,一个是利用MFC Automation生成组件,然后在VB Scrip中通过ProgID来进行调用
,另外一个是ATL 双接口, 在Word的快捷键宏之中来调用
10 9的.net版本,不赘述
11 IDispatch接口
11章进一步重点介绍了IDispatch接口,介绍了IDispatch接口的4个函数。另外提到了双接口的概念,
实际上就是接口继承接口,常出现的形式是Ixxx:IDispatch:IUnknown
提到了三种调用IDispatch接口的方式,都是在C++内调用IDispatch接口,觉得意义不大,因为
IDispatch接口本来主要的作用就是供脚本来调用。
a.通过原始的COM函数调用
CoInitialize->CoCreateInstance->QuerryInterface->GetIDofName->初始化DISPParam->invoke-
>release->CounInitialize
b.通过CComDispatchDriver智能指针类来调用
CComDispatchDriver的这种形式,初始化DISPParam简单,也不用调用>GetIDofName
c.MFC引入tlb库,生成相应的封装类
CreateDispatch后直接调用相应函数,这种方式无疑是最简单的
12 错误异常处理
介绍的是COM组件调用时,客户端如何获得服务端的错误,而并非C++的try catch
a. 服务端
继承一个IErrorSupportInfo接口
CComQIPtr< ICreateErrorInfo> spCEI,错误内容通过这个接口写入
CComQIPtr < IErrorInfo > spErrInfo = spCEI; SetErrorInfo();
b. 客户端
当发生错误时
CComQIPtr < ISupportErrorInfo > spSEI = spXXX
如果支持错误信息, 创建一个IErrorInfo接口
GetErrorInfo()
spErrInfo->GetDescription( &bstrDes)&
不过我觉得错误处理可能用的不多,毕竟有谁会花这么多功夫来给你提供异常信息啊
13 事件、通知
就是COM组件如何通知调用者。基本思路是这样的,调用方创建一个接口,然后通过Advise函数把该接
口指针传递给COM组件,这样,COM组件就能够在认为必要的时候通过这个接口调用调用方提供的相应函数
。
其实做工具条的时候一般要用到IObjectWithSite接口,浏览器回去调用setsite函数,把相关的接口
传过来,然后COM组件会调用Advise函数,将COM的IDispatch接口传回给IE,从这个角度考虑,IE成了服
务端,COM组件成了客户端。
客户端 服务端(COM组件端)
得到COM的接口IEvent(举例)
pEvent->Advise(&m_Sink) 得到ICallBack接口
IEvent->Add() Add函数被调用
在Add函数中,m_pCallBack->fireResult
fireResult函数被调用
14 .net版本
15 连接点事件
诚如杨老师所言,连接点方法确实要比事件、通知方法繁琐,而且具体的实现不好理解。
连接点和事件通知的不同在于一个COM组件处理多个链接时的方式不同,事件通知是通过数组和
Cookie机制,而连接点是通过设置多个连接点。
对于客户端来说,在Advise之前,需要得到IConnectPointContainer指针,然后通过
FindConnectPoint找到连接点接口指针,这样才能调用Advise,而且回调函数必须在IDispatch接口的
Invoke函数内实现
对于服务端来说,要增加一个Event接口,生成一个Event类,通过invoke通知调用方,也挺复杂。
17 持续性
由于调用者不清楚组件内部的数据结构,因此设计了一套组件读取和保存数据的接口。
调用者将IStream传递给组件,组件按照自己喜欢的方式进行读写操作
IPersistStreamInit是常用的持续性接口