ATL是通过接口映射表来实现QueryInterface

ATL是通过接口映射表来实现QueryInterface的。

1.   从CComObject,   CComObjectCached,   CComAggObject   等中可以看出,QueryInterface都是_InternalQueryInterface实现的。

template    < class    Base >  
class    CComObject   :    public    Base 

public
    ... 

    
// if   _InternalQueryInterface   is   undefined   then   you   forgot   BEGIN_COM_MAP 
    STDMETHOD(QueryInterface)(REFIID   iid,    void     **    ppvObject)    throw () 
    {
return    _InternalQueryInterface(iid,   ppvObject);} 
    ... 
}; 


template    < class    contained >  
class    CComAggObject   : 
public    IUnknown, 
public    CComObjectRootEx  <    contained::_ThreadModel::ThreadModelNoCS    >  

public
    STDMETHOD(QueryInterface)(REFIID   iid,   
void     **    ppvObject) 
    { 
        ATLASSERT(ppvObject   
!=    NULL); 
        
if    (ppvObject    ==    NULL) 
            
return    E_POINTER; 
        
* ppvObject    =    NULL; 

        HRESULT   hRes   
=    S_OK; 
        
if    (InlineIsEqualUnknown(iid)) 
        { 
            
* ppvObject    =    ( void * )(IUnknown * ) this
            AddRef(); 
            #ifdef   _ATL_DEBUG_INTERFACES 
            _AtlDebugInterfacesModule.AddThunk((IUnknown
** )ppvObject,   (LPCTSTR) 

            contained::_GetEntries()[
- 1 ].dw,   iid); 
            
#endif     //    _ATL_DEBUG_INTERFACES 
        } 
        
else  
        hRes   
=    m_contained._InternalQueryInterface(iid,   ppvObject); 
        
return    hRes; 
    } 


2.   而_InternalQueryInterface   是定义于宏BEGIN_COM_MAP中的,并且调用了CComObjectRootBase中的InternalQueryInterface

。其中包含参数_GetEntries()   ---这是接口映射表、

#define    BEGIN_COM_MAP(x)   public:    
..... 
HRESULT   _InternalQueryInterface(REFIID   iid,   
void **    ppvObject)    throw ()    
{   
return    InternalQueryInterface( this ,   _GetEntries(),   iid,   ppvObject);   }    
const     static    ATL::_ATL_INTMAP_ENTRY *    WINAPI   _GetEntries()    throw ()   {    
static     const    ATL::_ATL_INTMAP_ENTRY   _entries[]    =    {   DEBUG_QI_ENTRY(x) 


3.   InternalQueryInterface由调用AtlInternalQueryInterface来遍历口映射表来查找接口,并获得接口指针


static    HRESULT   WINAPI   InternalQueryInterface( void *    pThis, 
const    _ATL_INTMAP_ENTRY *    pEntries,   REFIID   iid,    void **    ppvObject) 

//    Only   Assert   here.   AtlInternalQueryInterface   will   return   the   correct   HRESULT   if   ppvObject   ==   

NULL 
    #ifndef   _ATL_OLEDB_CONFORMANCE_TESTS 
    ATLASSERT(ppvObject   
!=    NULL); 
    
#endif  
    ATLASSERT(pThis   
!=    NULL); 
    
//    First   entry   in   the   com   map   should   be   a   simple   map   entry 
    ATLASSERT(pEntries ->  pFunc    ==    _ATL_SIMPLEMAPENTRY); 
    
#if    defined(_ATL_DEBUG_INTERFACES)   ¦ ¦   defined(_ATL_DEBUG_QI) 
    LPCTSTR   pszClassName   
=    (LPCTSTR)   pEntries[ - 1 ].dw; 
    
#endif     //    _ATL_DEBUG_INTERFACES 
    HRESULT   hRes   
=    AtlInternalQueryInterface(pThis,   pEntries,   iid,   ppvObject); 
    #ifdef   _ATL_DEBUG_INTERFACES 
    _AtlDebugInterfacesModule.AddThunk((IUnknown
** )ppvObject,   pszClassName,   iid); 
    
#endif     //    _ATL_DEBUG_INTERFACES 
    
return    _ATLDUMPIID(iid,   pszClassName,   hRes); 

4。而接口映射表是通过一组宏来实现的

BEGIN_COM_MAP(CClass) 
COM_INTERFACE_ENTRY(IA) 
COM_INTERFACE_ENTRY(IB) 
END_COM_MAP() 

 

//    BEGIN_COM_MAP 
#define    BEGIN_COM_MAP(x)   public:    
..... 
HRESULT   _InternalQueryInterface(REFIID   iid,   
void **    ppvObject)    throw ()    
{   
return    InternalQueryInterface( this ,   _GetEntries(),   iid,   ppvObject);   }    
const     static    ATL::_ATL_INTMAP_ENTRY *    WINAPI   _GetEntries()    throw ()   {    
static     const    ATL::_ATL_INTMAP_ENTRY   _entries[]    =    {   DEBUG_QI_ENTRY(x) 

//    COM_INTERFACE_ENTRY 
#define    COM_INTERFACE_ENTRY(x) 
{
& _ATL_IIDOF(x),    
offsetofclass(x,   _ComMapClass),    
_ATL_SIMPLEMAPENTRY}, 

//    END_COM_MAP 
#ifdef   _ATL_DEBUG 
#define    END_COM_MAP()    
__if_exists(_GetAttrEntries)   {{NULL,   (DWORD_PTR)_GetAttrEntries,   _ChainAttr   },   } 
{NULL,   
0 ,    0 }};    return     & _entries[ 1 ];}    
virtual    ULONG   STDMETHODCALLTYPE   AddRef(    void )    throw ()    =     0 ;    
virtual    ULONG   STDMETHODCALLTYPE   Release(    void )    throw ()    =     0 ;    
STDMETHOD(QueryInterface)(REFIID,   
void ** )    throw ()    =     0
#else  
#define    END_COM_MAP()    
__if_exists(_GetAttrEntries)   {{NULL,   (DWORD_PTR)_GetAttrEntries,   _ChainAttr   },   } 
{NULL,   
0 ,    0 }};    return    _entries;}    
virtual    ULONG   STDMETHODCALLTYPE   AddRef(    void )    throw ()    =     0 ;    
virtual    ULONG   STDMETHODCALLTYPE   Release(    void )    throw ()    =     0 ;    
STDMETHOD(QueryInterface)(REFIID,   
void ** )    throw ()    =     0
#endif     //    _ATL_DEBUG 


5.   AtlInternalQueryInterface实现

ATLINLINE   ATLAPI   AtlInternalQueryInterface( void *    pThis, 
const    _ATL_INTMAP_ENTRY *    pEntries,   REFIID   iid,    void **    ppvObject) 

    ATLASSERT(pThis   
!=    NULL); 
    
//    First   entry   in   the   com   map   should   be   a   simple   map   entry 
    ATLASSERT(pEntries ->  pFunc    ==    _ATL_SIMPLEMAPENTRY); 
    
if    (ppvObject    ==    NULL) 
        
return    E_POINTER; 
    
* ppvObject    =    NULL; 
    
if    (InlineIsEqualUnknown(iid))    //    use   first   interface 
    { 
        IUnknown
*    pUnk    =    (IUnknown * )((INT_PTR)pThis + pEntries ->  dw); 
        pUnk
->  AddRef(); 
        
* ppvObject    =    pUnk; 
        
return    S_OK; 
    } 
    
while    (pEntries ->  pFunc    !=    NULL) 
    { 
        BOOL   bBlind   
=    (pEntries ->  piid    ==    NULL); 
        
if    (bBlind   ¦ ¦   InlineIsEqualGUID( * (pEntries ->  piid),   iid)) 
        { 
            
if    (pEntries ->  pFunc    ==    _ATL_SIMPLEMAPENTRY)    // offset 
            { 
                ATLASSERT(
! bBlind); 
                IUnknown
*    pUnk    =    (IUnknown * )((INT_PTR)pThis + pEntries ->  dw); 
                pUnk
->  AddRef(); 
                
* ppvObject    =    pUnk; 
                
return    S_OK; 
            } 
            
else     // actual   function   call 
            { 
                HRESULT   hRes   
=    pEntries ->  pFunc(pThis, 
                iid,   ppvObject,   pEntries
->  dw); 
                
if    (hRes    ==    S_OK   ¦ ¦   ( ! bBlind    &&    FAILED(hRes))) 
                
return    hRes; 
            } 
        } 
        pEntries
++
    } 
    
return    E_NOINTERFACE; 


ATL实际是通过计算指针偏移量来获得指针的。
IUnknown*   pUnk   =   (IUnknown*)((INT_PTR)pThis+pEntries-> dw); 

你可能感兴趣的:(ATL是通过接口映射表来实现QueryInterface)