腳本環境中訪問組件非默認的IDispatch接口

    腳本中訪問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>,
        ......
 
實現步驟如下:
 
一、實現中轉的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
            : public IDispatchImpl<T,piid,plibid,wMajor,wMinor,tihclass>
{
public:
    STDMETHOD(GetIDsOfNamesDummy)(REFIID riid,LPOLESTR* rgszNames,
            UINT cNames,LCID lcid,DISPID* rgdispid)
    {
        return IDispatchImpl<T,piid,plibid,wMajor,wMinor,tihclass>::GetIDsOfNames(
                     riid,rgszNames,cNames,lcid,rgdispid);
    }

    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,
              riid, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
    }

    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,
            DISPPARAMS* pdispparams, VARIANT* pvarResult,
            EXCEPINFO* pexcepinfo, UINT* puArgErr)
    {
        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<IOtherInterface1, &IID_IOtherInterface1, &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>,
        ......
{
        ......
 
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()
       
        ......
}
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章