ATL Internals 2ed复习.chapter 6.Table driven QueryInterface

The Raw Interface Map

ATL实现QueryInterface的方法是调用CComObjectRootBase::InternalQueryInterface():

static HRESULT WINAPI                                         
CComObjectRootBase::InternalQueryInterface(                   
  void*                     pThis,                            
  const _ATL_INTMAP_ENTRY*  pEntries,                         
  REFIID                    iid,                              
  void**                    ppvObject)                        
{                                                             
    // First entry in the com map should be a simple map entry
    ATLASSERT(pEntries->pFunc == _ATL_SIMPLEMAPENTRY);        
    HRESULT hRes = AtlInternalQueryInterface(pThis, pEntries, 
        iid, ppvObject);                                      
    return hRes;                                              
}                                                             

ATL_INTMAP_ENTRY


其中涉及到ATL_INTMAP_ENTRY,作为数组传递给InternalQueryInterface():

struct _ATL_INTMAP_ENTRY {                                 
    const IID* piid;       // the interface id (IID)       
    DWORD_PTR dw;                                          
    _ATL_CREATORARGFUNC* pFunc; //NULL:end, 1:offset, n:ptr
};                                                         


其中_ATL_CREATORARGFUNC的定义为:

typedef HRESULT (WINAPI _ATL_CREATORARGFUNC)(                 
    void* pv,        // Object's this pointer                 
    REFIID riid,     // IID of requested interface            
    LPVOID* ppv,     // Storage for returned interface pointer
    DWORD_PTR dw);   // dw from the interface map entry       

AtlInternalQueryInterface

作为一个全局函数,AtlInternalQueryInterface()的作用是遍历interface map,找出匹配的iid,返回指针

ATLINLINE ATLAPI AtlInternalQueryInterface(                       
    void* pThis,                                                  
    const _ATL_INTMAP_ENTRY* pEntries,                            
    REFIID iid,                                                   
    void** ppvObject)                                             
{                                                                 
    ATLASSERT(pThis != NULL);                                     
    ATLASSERT(pEntries!= NULL);                                   
                                                                   
    if(pThis == NULL || pEntries == NULL)                         
        return E_INVALIDARG ;                                     
                                                                  
    // 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;                                         
}                                                                 


注意,interface map第一项一定要是_ATL_SIMPLEMAPENTRY类型,否则会assert。

如果查询IUnknown,该函数直接返回第一项

如果pEntries->piid==NULL,将会调用pFunc,在COM_INTERFACE_ENTRY_XXX_BLIND将会用到这一特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值