腳本中訪問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()
......
}