科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件COM编程技术基础之四

COM编程技术基础之四

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

所谓自动化对象,指的是实现了IDispatch接口的COM对象,IDispatch接口是自动化对象的一个重要标志

作者:中国电波传播研究所青岛分所郎锐 来源:yesky 2007年10月20日

关键字: COM 编程技术

  • 评论
  • 分享微博
  • 分享邮件
所谓自动化对象,指的是实现了IDispatch接口的COM对象,IDispatch接口是自动化对象的一个重要标志。使用自动化技术的一个主要目的就是对COM的一些底层操作进行简化。包括自动化组件和自动化客户两方面的内容,分别用来定义和使用自动化对象。 自动化对象包含有属性和方法这两种重要的组成。属性类似于类中的数据成员,方法则类似于类成员函数,只不过这里的属性只能被读取而不允许被写入。自动化组件除了定义自动化对象外,还将内部可编程对象展现给自动化客户,而自动化客户则对这些暴露的自动化对象进行操作。具体的操作包括:创建一个新的自动化对象,获取、设置自动化对象的属性,以及调用自动化对象的方法等。IDispatch接口作为自动化对象的重要特征,可以通过QuereyInterface()函数查询此接口来确定组件是否是自动化对象。IDispatch接口直接从IUnknown接口派生,接口定义如下:

interface IDispatch : IUnknown
{
 virtual HRESULT GetTypeInfoCount(UINT* pctinfo) = 0;
 virtual HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) = 0;
 virtual HRESULT GetIDsOfNames (REFIID riid, LPOLESTR* rgszNames, UINT cNames, LCID lcid, DISPID* rgdispid) = 0;
 virtual HRESULT Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr ) = 0;
}

  其中,接口成员函数GetTypeInfoCount()用于获取自动化组件支持的ITypeInfo接口的数目。GetTypeInfo()用于获取指针ITypeInfo接口的指针,通过该指针将能够判断自动化服务程序所提供的自动化支持。剩下的这两个函数是比较重要的,其中GetIDsOfNames()将读取一个函数的名称并返回其调度ID(DISPID),DISPID只是一个long类型的数据,对于IDispatch的一个特定实现,此DISPID值应该是唯一的。其参数riid为保留参数,必须设置为IID_NULL,在rgszNames中指定了成员的函数名及其参数,由cNames标识了名字的个数,lcid参数用于指定本地化标识,得到的DISPID 将保存到rgdispid中。Invoke()提供了访问自动化对象暴露出来的方法和属性的方法。可以将DISPID作为函数指针数组的索引传入dispidMember参数,Invoke()将实现一组按此索引来访问的函数。riid和lcid的含义与在GetIDsOfNames()中的定义相同,分别为保留参数和本地化标识。WFlags参数指定了要访问的是接口的属性还是方法,pdispparams参数包括了方法和属性调用的参数数组、DISPID数组以及数组中参数个数等信息。pvarResult参数保存有返回值信息。pexcepinfo指向一个有效的异常信息结构,puArgErr参数包含了第一个产生错误的参数指针。通过GetIDsOfNames()和Invoke()的结合使用,将可以根据函数名称对方法和属性进行调用。这样,函数地址、AddRef()、Release()以及接口指针等细节问题将无需考虑。下面结合一段实例代码来说明对IDispatch接口的使用:

// 从ProgID得到CLSID
wchar_t progid[] = L"MSCAL.Calendar.7";
CLSID clsid;
if (FAILED(::CLSIDFromProgID(progid, &clsid)))
 return;
 // 得到IDispatch接口指针
IDispatch* pIDispatch = NULL;
if (FAILED(::CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IDispatch, (void**)&pIDispatch)))
 return;
// 得到DISPID
DISPID dispid;
OLECHAR* func = L"Today";
if (FAILED(pIDispatch->GetIDsOfNames(IID_NULL, &func, 1, GetUserDefaultLCID(), &dispid)))
 return;
// 通过DISPID使用Today方法
DISPPARAMS dispparams = {NULL};
if (FAILED(pIDispatch->Invoke(dispid, IID_NULL, GetUserDefaultLCID(), DISPATCH_METHOD, &dispparams, NULL, NULL, NULL)))
 return;
// 将日期移动到今天
AfxMessageBox("日期成功移动到今天");

  这段代码使用的是Calendar组件,并通过IDispatch接口完成对Today()方法的调用。CLSIDFromProgID()将Calendar组件的ProgID转换为CLSID,并以此CLSID和IID_IDispatch作为参数去调用CoCreateInstance()以得到IDispatch接口指针。通过其成员函数GetIDsOfNames()得到将要调用的Today方法的DISPID,最后使用

查看本文来源

Invoke()成员函数执行此方法。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章