ATL 核心COM继承类之IDispatchImpl及调用

实现

先看IDispatch接口,如同反射

interface IDispatch : IUnknown {                   
    HRESULT GetTypeInfoCount([out] UINT * pctinfo);

    HRESULT GetTypeInfo([in] UINT iTInfo,          
        [in] LCID lcid,                            
        [out] ITypeInfo ** ppTInfo);               

    HRESULT GetIDsOfNames([in] REFIID riid,        
        [in, size_is(cNames)] LPOLESTR * rgszNames,
        [in] UINT cNames,                          
        [in] LCID lcid,                            
        [out, size_is(cNames)] DISPID * rgDispId); 

    HRESULT Invoke([in] DISPID dispIdMember,       
        [in] REFIID riid,                          
        [in] LCID lcid,                            
        [in] WORD wFlags,                          
        [in, out] DISPPARAMS * pDispParams,        
        [out] VARIANT * pVarResult,                
        [out] EXCEPINFO * pExcepInfo,              
        [out] UINT * puArgErr);                    
}                

要实现IDispatch接口的动作是差不多的

class CPenguin :
    public CComObectRootEx<CComSingleThreadModel>,
    public IBird,
    public ISnappyDresser,
    public IPenguin {
public:
    CPenguin() : m_pTypeInfo(0) {
        IID*      pIID   = &IID_IPenguin;
        GUID*     pLIBID = &LIBID_BIRDSERVERLib;
        WORD      wMajor = 1;
        WORD      wMinor = 0;
        ITypeLib* ptl = 0;
        HRESULT hr = LoadRegTypeLib(*pLIBID, wMajor, wMinor,
            0, &ptl);
        if( SUCCEEDED(hr) ) {
            hr = ptl->GetTypeInfoOfGuid(*pIID, &m_pTypeInfo);
            ptl->Release();
        }
    }

    virtual ~Penguin() {
        if( m_pTypeInfo ) m_pTypeInfo->Release();
    }

    BEGIN_COM_MAP(CPenguin)
        COM_INTERFACE_ENTRY(IBird)
        COM_INTERFACE_ENTRY(ISnappyDresser)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(IPenguin)
    END_COM_MAP()

    // IDispatch methods
    STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) {
        return (*pctinfo = 1), S_OK;
    }
    STDMETHODIMP GetTypeInfo(UINT ctinfo, LCID lcid,
        ITypeInfo **ppti) {
            if( ctinfo != 0 ) return (*ppti = 0), DISP_E_BADINDEX;
            return (*ppti = m_pTypeInfo)->AddRef(), S_OK;
    }

    STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR **rgszNames,
        UINT cNames, LCID lcid, DISPID *rgdispid) {
            return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames,
                rgdispid);
    }

    STDMETHODIMP Invoke(DISPID dispidMember,
        REFIID riid,
        LCID lcid,
        WORD wFlags,
        DISPPARAMS *pdispparams,
        VARIANT *pvarResult,
        EXCEPINFO *pexcepinfo,
        UINT *puArgErr) {
            return m_pTypeInfo->Invoke(static_cast<IPenguin*>(this),
                dispidMember, wFlags,
                pdispparams, pvarResult,
                pexcepinfo, puArgErr);
    }
    // IBird, ISnappyDresser and IPenguin methods...
private:
    ITypeInfo* m_pTypeInfo;
};

以IDispatchImpl替代

class CPenguin :
    public CComObjectRootEx<CComMultiThreadModel>,
    public IBird,
    public ISnappyDresser,
    public IDispatchImpl<IPenguin, &IID_IPenguin> {
public:
    BEGIN_COM_MAP(CPenguin)
        COM_INTERFACE_ENTRY(IBird)
        COM_INTERFACE_ENTRY(ISnappyDresser)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(IPenguin)
    END_COM_MAP()
    // IBird, ISnappyDresser and IPenguin methods...
};

IDispatchImpl具体实现

template <class T, const IID* piid = &__uuidof(T), const GUID* plibid = &CAtlModule::m_libid, WORD wMajor = 1,
WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
class ATL_NO_VTABLE IDispatchImpl : 
    public T
{
public:
    typedef tihclass _tihclass;
// IDispatch
    STDMETHOD(GetTypeInfoCount)(_Out_ UINT* pctinfo)
    {
        if (pctinfo == NULL) 
            return E_POINTER; 
        *pctinfo = 1;
        return S_OK;
    }
    STDMETHOD(GetTypeInfo)(
        _In_ UINT itinfo, 
        _In_ LCID lcid, 
        _Deref_out_ ITypeInfo** pptinfo)
    {
        return _tih.GetTypeInfo(itinfo, lcid, pptinfo);
    }
    STDMETHOD(GetIDsOfNames)(
        _In_ REFIID riid, 
        _In_count_(cNames) _Deref_pre_z_ LPOLESTR* rgszNames, 
        _In_ UINT cNames,
        _In_ LCID lcid, 
        _Out_ DISPID* rgdispid)
    {
        return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
    }
    STDMETHOD(Invoke)(
        _In_ DISPID dispidMember, 
        _In_ REFIID riid,
        _In_ LCID lcid, 
        _In_ WORD wFlags, 
        _In_ DISPPARAMS* pdispparams, 
        _Out_opt_ VARIANT* pvarResult,
        _Out_opt_ EXCEPINFO* pexcepinfo, 
        _Out_opt_ UINT* puArgErr)
    {
        return _tih.Invoke((IDispatch*)this, dispidMember, riid, lcid,
        wFlags, pdispparams, pvarResult, pexcepinfo, puArgErr);
    }

#ifdef _ATL_DLL_IMPL
    // Do not cache type info if it is used in the ATL dll
    IDispatchImpl() : _tih(piid, plibid, wMajor, wMinor)
    {
    }
    virtual ~IDispatchImpl()
    {
    }

protected:
    _tihclass _tih;
    HRESULT GetTI(
        _In_ LCID lcid, 
        _Deref_out_ ITypeInfo** ppInfo)
    {
        return _tih.GetTI(lcid, ppInfo);
    }

#else

protected:
    static _tihclass _tih;
    static HRESULT GetTI(
        _In_ LCID lcid, 
        _Deref_out_ ITypeInfo** ppInfo)
    {
        return _tih.GetTI(lcid, ppInfo);
    }

#endif
};

调用IDispatch接口

很麻烦的一个过程,如下动态调用Add方法

// component IDL file
[
    object,
    uuid(2F6C88D7-C2BF-4933-81FA-3FBAFC3FC34B),
    dual,
]
interface ICalc : IDispatch {
    [id(1)] HRESULT Add([in] DOUBLE Op1,
        [in] DOUBLE Op2, [out,retval] DOUBLE* Result);
};

// client.cpp
HRESULT CallAdd(IDispatch* pdisp) {
    // Get the DISPID
    LPOLESTR pszMethod = OLESTR("Add");
    DISPID dispid;
    hr = pdisp->GetIDsOfNames(IID_NULL,
        &pszMethod,
        1,
        LOCALE_SYSTEM_DEFAULT,
        &dispid);

    if (FAILED(hr))
        return hr;

    // Set up the parameters
    DISPPARAMS dispparms;
    memset(&dispparms, 0, sizeof(DISPPARAMS));
    dispparms.cArgs = 2;

    // Parameters are passed right to left
    VARIANTARG rgvarg[2];
    rgvarg[0].vt = VT_R8;
    rgvarg[0].dblVal = 6;
    rgvarg[1].vt = VT_R8;
    rgvarg[1].dblVal = 7;

    dispparms.rgvarg = &rgvarg[0];

    // Set up variable to hold method return value
    VARIANTARG vaResult;
    ::VariantInit(&vaResult);

    // Invoke the method
    hr = pdisp->Invoke(dispid,
        IID_NULL,
        LOCALE_SYSTEM_DEFAULT,
        DISPATCH_METHOD,
        &dispparms,
        &vaResult,
        NULL,
        NULL);

    // vaResult now holds sum of 6 and 7
}

CComPtr<IDispatch>提供了很多的便利方法

image

调用如下:

HRESULT TheEasyWay( IDispatch *spCalcDisp ) {
    CComPtr< IDispatch > spCalcDisp( pCalcDisp );

    CComVariant varOp1( 6.0 );
    CComVariant varOp2( 7.0 );
    CComVariant varResult;
    HRESULT hr = spCalcDisp.Invoke2( OLESTR( "Add" ),
        &varOp1, &varOp2, &varResult );
    // varResult now holds sum of 6 and 7
}
原文地址:https://www.cnblogs.com/Clingingboy/p/2674935.html