c语言事故,C语言梆定ActiveX事件

我的博客里写的关于C语言访问COM的一些文章帮助了一些朋友,感到非常高兴。最近有几个朋友发邮件问过我C梆定ActiveX事件的方式,解答后感觉好像也有段时间没有写文章了,所以就详细地来写一篇关于C梆定和监听ActiveX事件的文章。

对C访问COM不是很了解的朋友,可以看我博客里的这些文章:

本文链接: http://www.hoverlees.com/blog/?p=1793

上面的文章讲过COM,ActiveX,Ole自动化对象的一些东西,这里不再多说。关于ActiveX的事件,是由ActiveX内部产生的,如果ActiveX容器对这个事件感兴趣,就可以监听这个事件,当这个事件触发时,就会调用我们提供的实现IDispatch的监听器,从而实现ActiveX调用容器函数的效果,这样就可以扩展ActiveX的功能。

例如我们常用的IWebBrowser控件有很多的事件,如将要开始导航、页面加载完成等事件,当容器监听到这些事件,就可以做自己的处理;浏览器里javascript有个window.external对象,是提供给javascript脚本调用容器的方式,实现javascript调用C实现的容器所提供的功能。

同样,常用的Flash控制也有一些事件可供监听,如fscommand、ExternalInterface.call,都是脚本调用容器的方式,它们同样是靠触发ActiveX事件实现的。

进入正题,具有事件的ActiveX控件,都有实现IConnectionPointContainer接口,通过QueryInterface就可以获得这个接口,然后调用IConnectionPointContainer的FindConnectionPoint函数就可以得到具体事件的IConnectionPoint,然后使用IConnectionPoint的Advise函数即可注册该事件的一个监听器,UnAdvise取消监听。

关于QueryInterface和调用接口的函数,可以参考C访问COM组件的函数那篇文章里的代码,现在主要要解决的是C去实现一个IDispatch接口的对象。其实只要熟悉COM的结构,要实现一个IDispatch也是很简单的事,如下面的代码:

//注意需要#include "ccom.h", ccom.h在上面的文章中有提供

typedef struct _IDispatchVTable{

_QueryInterface QueryInterface;

_AddRef AddRef;

_Release Release;

_GetTypeInfoCount GetTypeInfoCount;

_GetTypeInfo GetTypeInfo;

_GetIDsOfNames GetIDsOfNames;

_Invoke Invoke;

}IDispatchVTable;

typedef struct _IDispatchClass{

IDispatchVTable* pv;

IDispatchVTable vtable;

int counter; //对象自己的引用计数,可以再加其他私有变量。

}IDispatchClass;

//实现IDispatch的vtable

static HRESULT __stdcall IDispatchClass_QueryInterface(LPVOID _this,REFIID iid,void ** ppvObject){

//不管Query什么接口,都返回该对象本身,如果要真自的自消毁,要注意在前三个函数中对引用计数进行正确的维护,我这儿为了简便就不做维护了,对象不会自消毁,需要手工free

*ppvObject=_this;

return S_OK;

}

static ULONG __stdcall IDispatchClass_AddRef(LPVOID _this){

return 1;

}

static ULONG __stdcall IDispatchClass_Release(LPVOID _this){

return 1;

}

static HRESULT __stdcall IDispatchClass_GetTypeInfoCount(LPVOID _this,unsigned int FAR* pctinfo){

*pctinfo=0;

return S_OK;

}

static HRESULT __stdcall IDispatchClass_GetTypeInfo(LPVOID _this,unsigned int iTInfo,LCID lcid,ITypeInfo FAR* FAR* ppTInfo){

return S_OK;

}

//自已只需要传入GetIdsOfNames和Invoke的实现,即可创建一个IDispatch,GetIdsOfNames就是通过名称获取ID的函数,例如你向ActiveX提供Hover函数,则可以通过这个函数为字符串Hover这个名称返回一个指定的ID,并在Invoke中判断,如果是这个ID,就调用Hover对应的函数。

int CComCreateDispatchObject(_GetIDsOfNames getIDsOfNames,_Invoke invoke,LPVOID* ppdispatch){

IDispatchClass* pthis=(IDispatchClass*) malloc(sizeof(IDispatchClass));

if(pthis==NULL) return 0;

pthis->pv=&pthis->vtable;

pthis->vtable.QueryInterface=IDispatchClass_QueryInterface;

pthis->vtable.AddRef=IDispatchClass_AddRef;

pthis->vtable.Release=IDispatchClass_Release;

pthis->vtable.GetTypeInfoCount=IDispatchClass_GetTypeInfoCount;

pthis->vtable.GetTypeInfo=IDispatchClass_GetTypeInfo;

pthis->vtable.GetIDsOfNames=getIDsOfNames;

pthis->vtable.Invoke=invoke;

pthis->vtable.counter=1;

*ppdispatch=pthis;

return 1;

}

//下面是向ActiveX注册事件监听器的函数

//调用COM组件的Release函数

void CComRelease(LPVOID ppv){

_Release* vtable=*(_Release**) ppv;

vtable[2](ppv);

}

typedef HRESULT (__stdcall *_FindConnectionPoint)(LPVOID _this,REFIID riid,LPVOID* ppv);

typedef HRESULT (__stdcall *_Advise)(LPVOID _this,IUnknown *pUnkSink,DWORD* cookie);

//向psrc对象注册eventIID事件监听器listenerDispatch,当有事件触发时,会自动调用listenerDispatch的Invoke

int CComBindEvent(LPVOID psrc,REFIID eventIID,LPVOID listenerDispatch,DWORD* pDWCookie){

_FindConnectionPoint* vtable;

_Advise* vtable2;

LPVOID pIConnectionPointContainer;

LPVOID pIConnectionPoint;

pIConnectionPointContainer=CComQueryInterface(psrc,L"{B196B284-BAB4-101A-B69C-00AA00341D07}",CCOM_IID_TYPE_WSTRINGID);

if(pIConnectionPointContainer==NULL){

return 0;

}

vtable=*(_FindConnectionPoint**)pIConnectionPointContainer;

//vtable[4]即是FindConnectionPoint函数。

if(S_OK!=vtable[4](pIConnectionPointContainer,eventIID,&pIConnectionPoint)){

CComRelease(pIConnectionPointContainer);

return 0;

}

vtable2=*(_Advise**)pIConnectionPoint;

//vtable2[5]即是Advise函数。

if(S_OK!=vtable2[5](pIConnectionPoint,(IUnknown*)listenerDispatch,pDWCookie)){

CComRelease(pIConnectionPointContainer);

CComRelease(pIConnectionPoint);

return 0;

}

CComRelease(pIConnectionPointContainer);

CComRelease(pIConnectionPoint);

return 1;

}

下面是一个监听IShockwaveFlash控件事件的示例,实现ExternalInterface调用C容器

static LPVOID pFlashListener;

static IID IID_IShockwaveFlashEvents = {0xD27CDB6D, 0xAE6D, 0x11CF, {0x96, 0xB8, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00}};

HRESULT __stdcall Flash_GetIDsOfNames(LPVOID _this,REFIID riid,OLECHAR FAR* FAR* rgszNames,unsigned int cNames,LCID lcid,DISPID FAR* rgDispId){

return S_OK;

}

HRESULT __stdcall Flash_Invoke(LPVOID _this,DISPID dispIdMember,REFIID riid,LCID lcid,WORD wFlags,DISPPARAMS FAR* pDispParams,VARIANT FAR* pVarResult,EXCEPINFO FAR* pExcepInfo,unsigned int FAR* puArgErr){

char buffer[1024];

switch(dispIdMember){

case 197://ExternalInterface.call

if(pDispParams->cArgs>0){

WideCharToMultiByte(0,0,pDispParams->rgvarg->bstrVal,-1,buffer,1024,0,0);

MessageBox(0,buffer,0,0);

}

break;

}

return S_OK;

}

//创建监听器Dispatch对象

CComCreateDispatchObject(Flash_GetIDsOfNames,Flash_Invoke,&pFlashListener);

//梆定Flash事件,梆定完成后,在Flash中调用ExternalInterface.call,会调用Flash_Invoke函数,并得到一串调用的具体信息,是以XML形式组织的数据。

CComBindEvent(pFlash,&IID_IShockwaveFlashEvents,pFlashListener,&dwCookie);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值