Win32编程点滴 - 响应ActiveX控件的事件
2010-01-10 09:37:15 来源:WEB开发网当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的构造函数)。
代码下载:files.cnblogs.com/Greatest/TestActiveX2.zip
更多精彩
赞助商链接