Win32编程点滴5 - 响应ActiveX控件的事件
在最近的一篇文章中说到了,如何创建ActiveX,这次我们来响应事件。这次,我们将创建一个类:CGeneralEventSink,它能够响应任何Dispatch事件(事件的接口继承与IDispatch)。
首先,我们来回顾一下ConnectionPoint的概念。任何支持事件的对象(比如,ActiveX控件),都支持IConnectionPointContainer接口,顾名思义就是一个IConnectionPoint的容器,包含了这个对象支持的全部事件。IConnectionPoint代表了一组事件,调用IConnectionPoint::Advise并传入我们想要接收事件的对象指针。而IConnectionPoint::GetConnectionInterface返回的IID,是此接收事件的对象必须实现的接口,否则Advise会失败。来看一下AxAdviseAll的代码:

- //枚举IConnectionPointContainer中的每个IConnectionPoint,
//对于每个IConnectionPoint新建一个支持iid接口的CGeneralEventSink对象,并Advise。
//pUnk是控件的指针- HRESULT AxAdviseAll(IUnknown * pUnk)
- {
- HRESULT hr;
- IConnectionPointContainer * pContainer = NULL;
- IConnectionPoint * pConnectionPoint=NULL;
- IEnumConnectionPoints * pEnum = NULL;
- hr = pUnk->QueryInterface(IID_IConnectionPointContainer,(void**)&pContainer);
- if (FAILED(hr)) goto error1;
- hr = pContainer->EnumConnectionPoints(&pEnum);
- if (FAILED(hr)) goto error1;
- ULONG uFetched;
- while(S_OK == (pEnum->Next(1,&pConnectionPoint,&uFetched)) && uFetched>=1)
- {
- DWORD dwCookie;
- IID iid;
- hr = pConnectionPoint->GetConnectionInterface(&iid);
- if (FAILED(hr)) iid = IID_NULL;
- //这里传入pUnk是为了通过pUnk得到iid的ITypeInfo,进而判断iid是否是Dispatch接口
- IUnknown * pSink = new CGeneralEventSink(iid,pUnk);
- hr = pConnectionPoint->Advise(pSink,&dwCookie);
- pSink->Release();
- pConnectionPoint->Release();
- pConnectionPoint = NULL;
- pSink = NULL;
- }
- hr = S_OK;
- error1:
- if (pEnum)pEnum->Release();
- if (pContainer) pContainer->Release();
- if (pConnectionPoint) pConnectionPoint->Release();
- return hr;
- }

然后,来说一下Dispath事件。如果IConnectionPoint::GetConnectionInterface返回的IID代表的接口是继承于IDispatch的话,这个事件就是一个Dispath事件。当事件发生时,产生事件的对象不会直接调用pObj->OnEvent(),而会调用pObj->Invoke(…)。例如,Flash控件的事件对象:(通过vc的#import指令生成的)

- struct __declspec(uuid("d27cdb6d-ae6d-11cf-96b8-444553540000"))
_IShockwaveFlashEvents : IDispatch
{
//
// Wrapper methods for error-handling
//- // Methods:
HRESULT OnReadyStateChange (
long newState );
HRESULT OnProgress (
long percentDone );
HRESULT FSCommand (
_bstr_t command,
_bstr_t args );
HRESULT FlashCall (
_bstr_t request );
};

当Flash控件产生事件时,它会调用IDispath::Invoke而不是,OnReadyStateChange等方法。只有在vc,atl等框架里面,这些框架会自动生成Invoke函数,在Invoke函数中根据参数的不同(第一个参数memid代表代表哪个方法被调用),再调用OnReadyStateChange等方法。
所以,虽然IConnectionPoint要求实现的接口是_IShockwaveFlashEvents,但是我们的虚表中,只要存在IDispath的方法即可,虚表中之后_IShockwaveFlashEvents的方法不会被直接调用(如果我们自己实现Invoke,也不会去调用的)。我们告诉Flash控件,这是一个_IShockwaveFlashEvents接口,虽然它只实现了IDispath。就像CGeneralEventSink中的代码:

- STDMETHOD(QueryInterface(REFIID riid,void **ppvObject))
{
*ppvObject = NULL;
if ( IID_IUnknown == riid)
{
*ppvObject = (IUnknown*)this;
}
else if (IID_IDispatch == riid || m_iid == riid)
{
*ppvObject = (IDispatch*)this;
}
else
{
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}

其中m_iid是IConnectionPoint要求实现的接口,通过CGeneralEventSink构造函数参数传入的。当然,m_iid一定要是一个dispatch接口(继承于IDispatch)。如果IConnectionPoint要求的接口不是继承于IDispatch的,则m_iid会被设置为IID_NULL,然后IConnectionPoint便得不到所要求的接口,Advise就会失败,否则的话控件就会调用一个虚表中不存在的方法(不是IDispatch事件的话,控件只能直接调用接口的方法,而不是Invoke),产生错误。
那么,如何判断m_iid是Dispatch接口呢?首先,得到代表此接口的ITypeInfo指针,这个请参考代码中的:
- HRESULT CGeneralEventSink::GetIIDTypeInfo(IID iid,ITypeInfo ** ppInfo,IUnknown * pRelateObj);
简单的说,就是控件的接口pRelateObj会实现IProvideClassInfo接口,来提供它本身的ITypeInfo。再通过ITypeInfo::GetRefTypeInfo可以得到相关事件的ITypeInfo。
接着,此ITypeInfo的TYPEATTR结构中的typekind表明了,此ITypeInfo是否的Dispatch接口,代码如下:

- TYPEATTR *attr;
if (SUCCEEDED(pInfo->GetTypeAttr(&attr)))
{
if (attr->typekind == TKIND_DISPATCH) isDispatch = true;
pInfo->ReleaseTypeAttr(attr);
}

最后,CGeneralEventSink的IDispatch方法全部返回E_NOTIMPLE就可以了,毕竟控件只是通知我们事件发生了,而不关心我们有什么反应。当然,为了让提供的示例更有趣,代码里面的Invoke做了详细的log(在得到接口的ITypeInfo的同时,也枚举了MEMID/DISPID对应的名字。还从注册表中把iid变成了接口的名字,所有这一切参考CGeneralEventSink的构造函数)。
Win32编程点滴5 - 响应ActiveX控件的事件的更多相关文章
- Win32编程点滴3 - 简单ActiveX控件的使用
虽然这里一片的.net气氛,到处充斥着像MVC.WPF.WorkFlow.LINQ等各种niubility的术语.但我们使用的Windows还是由COM技术主宰着:我们在选择日常使用的软件时,也会避免 ...
- 如何给ActiveX控件添加“事件”“属性”“标准事件”“自定义事件”等一些相关操作
上一篇小编带大家熟悉了一下ActiveX的建立以及相关的概念,(http://blog.csdn.net/u014028070/article/details/38424611) 本文介绍下如何给控件 ...
- c# 开发ActiveX控件,添加事件,QT调用事件
c# 开发 ActiveX 的过程参考我的另一篇文章 : https://www.cnblogs.com/baqifanye/p/10414004.html 本篇讲如何 在C# 开发的ActiveX ...
- 用ATL和MFC来创建ActiveX控件
摘要:目前MFC和ATL代表了两种框架,分别面向不同类型的基于Windows的开发.MFC代表了创建独立的Windows应用的一种简单.一致的方法:ATL提供了一种框架来实现创建COM客户机和服务器所 ...
- MFC-[转]基于MFC的ActiveX控件开发
作者:lidan | 出处:博客园 | 2012/3/13 16:10:34 | 阅读22次 ActiveX 控件是基于组件对象模型 (COM) 的可重用软件组件,广泛应用于桌面及Web应用中.在VC ...
- 【转载】基于MFC的ActiveX控件开发(3)
原文:http://iysm.net/?p=122 3.事件 ActiveX 控件使用事件通知容器控件上发生了某些事情.事件的常见示例包括单击控件.使用键盘输入数据和控件状态更改.当发生这些操作时,控 ...
- 以编程方式使用 Microsoft Office Visio 2003 ActiveX 控件
以编程方式使用 Microsoft Office Visio 2003 ActiveX 控件 2007/10/29 Mark BukovecEmpire Down Development 适用于:Mi ...
- Qt 环境下的activex控件编程-------1
本人第一次接触这种activeX控件的东西,参考了网上很多的教程,终于耗时三个多小时初步理解并编写了一个小demo,现在分享给大家,希望大家少走弯路.步骤如下: 1>像平常创建项目一样创建一个d ...
- 让动态创建的ActiveX控件响应Windows消息
当我们通过 CWnd::CreateControl() 动态创建 ActiveX 控件时, Windows 消息并不会被发送给我 们的由 CWnd 派生得控件类.例如,即使我们为 WM_KIL ...
随机推荐
- 使用CCriticalSection类的注意事项
在类中使用CCriticalSection变量时,必需要将CCriticalSection变量定义为全局变量和静态变量,否则将出现没有定义的错误. 如: // a.h 文件 class A:publi ...
- windows 平台 ffmeg h264 硬编码
本文讲述windows 平台下ffmpeg如何利用intel media SDK 进行 h264硬编码(测试版本为3.2.2). ffmeg硬编编码的流程与软件编码流程相同,唯一不同的地方在初始化en ...
- 照猫画虎学gnuplot之折线图
本节重点:怎样利用已知数据来画折线图. 首先说明:gunplot文件的后缀名为*.plt.本节讲述怎样利用已知数据来画折线图,顾名思义必定涉及到两个文件:一个是须要的数据文件,即*.dat文件.还有一 ...
- 杭电 HDU 1279 验证角谷猜想
验证角谷猜想 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- kubernetes容器探针检测
系列目录 kubernetes提供了livenessProbe(可用性探针)和readinessProbe(就绪性探针)对容器的健康性进行检测,当然这仅仅简单的关于可用性方面的探测,实际上我们不仅仅要 ...
- Linux 下编译安装OpenCV(zhuanzai)
http://www.cnblogs.com/emouse/archive/2013/02/22/2922940.html Cmake的安装 OpenCV 2.2以后版本需要使用Cmake生成make ...
- java操作redis学习(一):安装及连接
文章参考自:http://www.cnblogs.com/edisonfeng/p/3571870.html,在此基础上进行了修改. 一.下载安装Redis redis官网显示暂时不支持Windows ...
- Oracle操作笔记
1.查询Oracle版本,数据库的SID select * from v$version; select name from v$database; 2.查询Oracle数据库所支持的功能 SELEC ...
- android handler looper
http://www.cnblogs.com/plokmju/p/android_Handler.html
- 【BZOJ2521】[Shoi2010]最小生成树 最小割
[BZOJ2521][Shoi2010]最小生成树 Description Secsa最近对最小生成树问题特别感兴趣.他已经知道如果要去求出一个n个点.m条边的无向图的最小生成树有一个Krustal算 ...