脚本中访问COM组件,是通过组件暴露的IDispatch接口来实现的。但是,正常情况下在脚本中,只能访问组件默认的IDispatch接口,一旦组件实现了多个IDispatc接口,则无法访问非默认的接口。通过重载默认IDispatch接口的默认实现,可以来达到向脚本暴露非默认的IDispatch接口。
以下面的CTestObject为例:
class ATL_NO_VTABLE CTestObject:
......
public IDispatchImpl<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface1, &IID_IOtherInterface1, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface2, &IID_IOtherInterface2, &LIBID_TestLib,1,0>,
......
......
public IDispatchImpl<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface1, &IID_IOtherInterface1, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface2, &IID_IOtherInterface2, &LIBID_TestLib,1,0>,
......
实现步骤如下:
一、实现中转的Dispatch Dummy类
由于组件实现了多个IDispatch,如果直接重载IDispatch的API,将会是对所有接口的功能重写,这并不是我们希望的。所以通过添加一个中转的Dummy类来实现。
Dummy类实现:
template<
class T,
const IID* piid= &__uuidof(T),
const GUID* plibid = &CAtlModule::m_libid,
WORD wMajor = 1,
WORD wMinor = 0,
class tihclass = CComTypeInfoHolder
>
class CDispatchDummy
class T,
const IID* piid= &__uuidof(T),
const GUID* plibid = &CAtlModule::m_libid,
WORD wMajor = 1,
WORD wMinor = 0,
class tihclass = CComTypeInfoHolder
>
class CDispatchDummy
:
public IDispatchImpl<T,piid,plibid,wMajor,wMinor,tihclass>
{
public:
STDMETHOD(GetIDsOfNamesDummy)(REFIID riid,LPOLESTR* rgszNames,
{
public:
STDMETHOD(GetIDsOfNamesDummy)(REFIID riid,LPOLESTR* rgszNames,
UINT cNames,LCID lcid,DISPID* rgdispid)
{
return IDispatchImpl<T,piid,plibid,wMajor,wMinor,tihclass>::GetIDsOfNames(
{
return IDispatchImpl<T,piid,plibid,wMajor,wMinor,tihclass>::GetIDsOfNames(
riid,rgszNames,cNames,lcid,rgdispid);
}
STDMETHOD(InvokeDummy)(DISPID dispidMember, REFIID riid, LCID lcid,
}
STDMETHOD(InvokeDummy)(DISPID dispidMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return IDispatchImpl<T,piid,plibid,wMajor,wMinor,tihclass>::Invoke(dispidMember,
{
return IDispatchImpl<T,piid,plibid,wMajor,wMinor,tihclass>::Invoke(dispidMember,
riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
}
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR* rgszNames,UINT cNames,
}
STDMETHOD(GetIDsOfNames)(REFIID riid,LPOLESTR* rgszNames,UINT cNames,
LCID lcid,DISPID* rgdispid)
{
return GetIDsOfNamesDummy(riid,rgszNames,cNames,lcid,rgdispid);
}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
{
return GetIDsOfNamesDummy(riid,rgszNames,cNames,lcid,rgdispid);
}
STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
DISPPARAMS* pdispparams, VARIANT* pvarResult,
EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
return InvokeDummy(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult,
{
return InvokeDummy(dispidMember, riid, lcid, wFlags, pdispparams, pvarResult,
pexcepinfo, puArgErr);
}
};
}
};
二、修改默认的IDispatch接口的继承方式
class ATL_NO_VTABLE CTestObject:
......
// public IDispatchImpl<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
public CDispatchDummy<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
......
// public IDispatchImpl<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
public CDispatchDummy<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface1, &IID_IOtherInterface1, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface2, &IID_IOtherInterface2, &LIBID_TestLib,1,0>,
......
public IDispatchImpl<IOtherInterface2, &IID_IOtherInterface2, &LIBID_TestLib,1,0>,
......
三、重载默认的IDispatch接口的实现
STDMETHOD(GetIDsOfNamesDummy)(REFIID riid,
LPOLESTR* rgszNames,UINT cNames,LCID lcid,DISPID* rgdispid)
{
// 先调用父类的实现,成功,直接返回
// 如果调用失败,在这里,遍历其他非默认Dispatch接口的实现
// 直到成功为止
return S_OK;
}
STDMETHOD(InvokeDummy)(DISPID dispidMember, REFIID riid,
LCID lcid, WORD wFlags, DISPPARAMS* pdispparams,
VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr)
{
// 先调用父类的实现,成功,直接返回
// 如果调用失败,在这里,遍历其他非默认Dispatch接口的实现
// 直到成功为止
return S_OK;
}
四、完成
这样,在脚本中,便能访问组件所有的IDispatch接口。对于组件来说,相当于把所有的IDispatch合并了!而在C++中,调用方式完全不变。
五、封装
为了使用上方便,所以把所有的细节都包装成几个宏,存放于附件的DispatchDummy.h中。
使用:
#include “DispatchDummy.h”
class ATL_NO_VTABLE CTestObject:
......
public CDispatchDummy<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface1, &IID_IOtherInterface1, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface2, &IID_IOtherInterface2, &LIBID_TestLib,1,0>,
......
......
public CDispatchDummy<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface1, &IID_IOtherInterface1, &LIBID_TestLib,1,0>,
public IDispatchImpl<IOtherInterface2, &IID_IOtherInterface2, &LIBID_TestLib,1,0>,
......
{
......
typedef CDispatchDummy<IDefaultInterface, &IID_IDefaultInterface, &LIBID_TestLib,1,0> DefaultDisp ;
BEGIN_DISPATCH_INTERFACE_MAP(DefaultDisp)
DISPATCH_INTERFACE_ENTRY(IOtherInterface1)
DISPATCH_INTERFACE_ENTRY(IOtherInterface2)
END_XMP_INTERFACE_MAP()
DISPATCH_INTERFACE_ENTRY(IOtherInterface1)
DISPATCH_INTERFACE_ENTRY(IOtherInterface2)
END_XMP_INTERFACE_MAP()
......
}
转载于:https://blog.51cto.com/pyhcx/323728