如下,定义了一个CHello组件类。
class ATL_NO_VTABLE CHello : 
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CHello, &CLSID_Hello>,
public IDispatchImpl<IHello, &IID_IHello, &LIBID_netfeesrvLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
CHello()
{
}.....CComObject<CHello> 提供了IUnknown方法的真正实现。我想知道的是:ATL是如何将IDispatch中的方法(如:GetTypeInfo ...)按循序排在IUnknown方法(如:QuteryInterface ...)之后的?

解决方案 »

  1.   

    另外,CComObject中的方法好像也不是按照QueryInterface,AddRef,ReleaseRef顺序排列的。如下:
     
    //Base is the user's class that derives from CComObjectRoot and whatever
    //interfaces the user wants to support on the object
    template <class Base>
    class CComObject : public Base
    {
    public:
    typedef Base _BaseClass;
    CComObject(void* = NULL) throw()
    {
    _pAtlModule->Lock();
    }
    // Set refcount to -(LONG_MAX/2) to protect destruction and 
    // also catch mismatched Release in debug builds
    ~CComObject() throw()
    {
    m_dwRef = -(LONG_MAX/2);
    FinalRelease();
    #ifdef _ATL_DEBUG_INTERFACES
    _AtlDebugInterfacesModule.DeleteNonAddRefThunk(_GetRawUnknown());
    #endif
    _pAtlModule->Unlock();
    }
    //If InternalAddRef or InternalRelease is undefined then your class
    //doesn't derive from CComObjectRoot
    STDMETHOD_(ULONG, AddRef)() throw() {return InternalAddRef();}
    STDMETHOD_(ULONG, Release)() throw()
    {
    ULONG l = InternalRelease();
    if (l == 0)
    delete this;
    return l;
    }
    //if _InternalQueryInterface is undefined then you forgot BEGIN_COM_MAP
    STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) throw()
    {return _InternalQueryInterface(iid, ppvObject);}
    template <class Q>
    HRESULT STDMETHODCALLTYPE QueryInterface(Q** pp) throw()
    {
    return QueryInterface(__uuidof(Q), (void**)pp);
    } static HRESULT WINAPI CreateInstance(CComObject<Base>** pp) throw();
    };
      

  2.   

    根据内存布局,就在IUnknown之后了
       IDispatch : public IUnknown
        {
        public:
            virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount( 
                /* [out] */ UINT *pctinfo) = 0;
            
            virtual HRESULT STDMETHODCALLTYPE GetTypeInfo( 
                /* [in] */ UINT iTInfo,
                /* [in] */ LCID lcid,
                /* [out] */ ITypeInfo **ppTInfo) = 0;
            
            virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames( 
                /* [in] */ REFIID riid,
                /* [size_is][in] */ LPOLESTR *rgszNames,
                /* [in] */ UINT cNames,
                /* [in] */ LCID lcid,
                /* [size_is][out] */ DISPID *rgDispId) = 0;
            
            virtual /* [local] */ HRESULT STDMETHODCALLTYPE Invoke( 
                /* [in] */ DISPID dispIdMember,
                /* [in] */ REFIID riid,
                /* [in] */ LCID lcid,
                /* [in] */ WORD wFlags,
                /* [out][in] */ DISPPARAMS *pDispParams,
                /* [out] */ VARIANT *pVarResult,
                /* [out] */ EXCEPINFO *pExcepInfo,
                /* [out] */ UINT *puArgErr) = 0;
            
        };
      

  3.   

    >> 见IDispatch的接口声明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)(UINT* pctinfo)
    {
    *pctinfo = 1;
    return S_OK;
    }
    STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
    {
    return _tih.GetTypeInfo(itinfo, lcid, pptinfo);
    }
    STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
    LCID lcid, DISPID* rgdispid)
    {
    return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
    }
    STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
    LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
    EXCEPINFO* pexcepinfo, 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 atl70.dll
    IDispatchImpl() : _tih(piid, plibid, wMajor, wMinor)
    {
    }protected:
    _tihclass _tih;
    HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
    {
    return _tih.GetTI(lcid, ppInfo);
    }#elseprotected:
    static _tihclass _tih;
    static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
    {
    return _tih.GetTI(lcid, ppInfo);
    }#endif};这里方法的顺序好像是对的,但我想知道,这些方法是如何按循序排在IUnknown方法(如:QuteryInterface ...)之后的?
      

  4.   

    >>根据内存布局,就在IUnknown之后了是否可以这样说:内存布局是由IDispatchImpl 决定的,而CComObject 只是提供了其中的IUnknown部分方法的实现。
      

  5.   

    因为 接口是这样继承的
    IDispatch : public IUnknown
    不是IDispatchImpl 决定的.
    而你的接口通常都会从IDispatch 继承.那么你的接口提供的方法都在IDispatch之后而IDispatchImpl 和CComObject什么的都是提供具体的实现
    接口的继承关系都在idl文件中定义
      

  6.   

    lz参考一下 深入探索C++ 对象模型这本书吧
      

  7.   

    是否可以这样认为:IDispatch决定内存布局。
    IDispatchImpl 实现IDisopatch方法.
    CComObject 实现IUnknown方法。
      

  8.   

    IDispatchImpl 实现IDisopatch方法.
    CComObject 实现IUnknown方法。
    呵呵,是这样的