ATL介面映射宏詳解[7]

來源:互聯網
上載者:User
七、COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid) 參ATL常式COMMAP

先看看這個宏的定義:
#define COM_INTERFACE_ENTRY_AUTOAGGREGATE(iid, punk, clsid)/
{&iid,/
(DWORD)&_CComCacheData</ CComAggregateCreator<_ComMapClass, &clsid>,/
(DWORD)offsetof(_ComMapClass, punk)/
>::data,/
_Cache},
先看看它的典型用法:
class CAutoAgg :
public IDispatchImpl,
public ISupportErrorInfo,
public CComObjectRoot,
public CComCoClass
{
......
......
};
與一般的組件並無二樣。
class COuter :
public CChainBase,
public IDispatchImpl,
public CComCoClass
{
BEGIN_COM_MAP(COuter)
COM_INTERFACE_ENTRY_AUTOAGGREGATE(IID_IAutoAgg, m_pUnkAutoAgg.p,
CLSID_CAutoAgg)
END_COM_MAP()
CComPtr m_pUnkAutoAgg;
};
與宏COM_INTERFACE_ENTRY_AGGREGRATE(_)不同,COuter不用在FinalConstruct中建立聚
集組件。外部組件會自動建立聚集組件!!!
1。
template
_ATL_CACHEDATA _CComCacheData::data = {dwVar, Creator::Creat
eInstance};
2。
static HRESULT WINAPI _Cache(void* pv, REFIID iid, void** ppvObject, DWORD dw)
{
{
HRESULT hRes = E_NOINTERFACE;
_ATL_CACHEDATA* pcd = (_ATL_CACHEDATA*)dw;
IUnknown** pp = (IUnknown**)((DWORD)pv + pcd->dwOffsetVar);
if (*pp == NULL)
hRes = pcd->pFunc(pv, IID_IUnknown, (void**)pp);
if (*pp != NULL)
hRes = (*pp)->QueryInterface(iid, ppvObject);
return hRes;
}
3。
template
class CComAggregateCreator
{
public:
static HRESULT WINAPI CreateInstance(void* pv, REFIID/*riid*/, LPVOID* ppv
)
{
ATLASSERT(*ppv == NULL);
ATLASSERT(pv != NULL);
T* p = (T*) pv;
return CoCreateInstance(*pclsid, p->GetControllingUnknown(),
CLSCTX_INPROC, IID_IUnknown, ppv);
}
};
因為_Cache,_CComCacheData,CComAggregateCreator這幾個類和函數我們已經在前面見
過或者見過類似的,所以就不再多講了。總之我們可以看到,若m_pUnkAutoAgg.p不為空白
則直接查詢,否則建立聚集組件。
與宏COM_INTERFACE_ENTRY_AGGREGATE相比,這個宏似乎更好一些,僅當需要時才會建立
使用更簡單。

八、COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND( punk, clsid ) 參ATL常式COMMAP

看看它的定義:
#define COM_INTERFACE_ENTRY_AUTOAGGREGATE_BLIND(punk, clsid)/
{NULL,/
(DWORD)&_CComCacheData</ CComAggregateCreator<_ComMapClass, &clsid>,/
(DWORD)offsetof(_ComMapClass, punk)/
>::data,/
_Cache},
呵呵,這個宏綜合了COM_INTERFACE_ENTRY_AUTOAGGREGATE()和
COM_INTERFACE_ENTRY_AGGREGATE_BLIND()的特點,既可以自動建立也可以很方便地查詢
聚集組件中的多個介面。不再贅述!!

九、COM_INTERFACE_ENTRY_CHAIN(classname) 參ATL常式COMMAP

先看看它的定義:
#define COM_INTERFACE_ENTRY_CHAIN(classname)/
{NULL,/
(DWORD)&_CComChainData::data,/
_Chain},

典型用法:
class CChain :
public IDispatchImpl,
public ISupportErrorInfo,
public CComObjectRoot
public CComCoClass
{
........
};
它與一般的組件無異。
class COuter :
class COuter :
public CChain,
....
{
BEGIN_COM_MAP(COuter)
......
COM_INTERFACE_ENTRY_CHAIN(CChain)
END_COM_MAP()
};

我們對查詢的過程已經很熟悉了,可以直接來看看_Chain的功能。
_Chain()是CComObjectRootBase的成員函數:
static HRESULT WINAPI _Chain(void* pv, REFIID iid, void** ppvObject,DWORD dw)
{
_ATL_CHAINDATA* pcd = (_ATL_CHAINDATA*)dw;
void* p = (void*)((DWORD)pv + pcd->dwOffset);
return InternalQueryInterface(p, pcd->pFunc(), iid, ppvObject);
}
struct _ATL_CHAINDATA
{
DWORD dwOffset;
const _ATL_INTMAP_ENTRY* (WINAPI *pFunc)();
};
};
我們再看看宏定義中的dw部分:
template
_ATL_CHAINDATA _CComChainData::data =
{offsetofclass(base, derived), base::_GetEntries};
基本上我們已經看懂是怎麼回事了,void *p將得到基類的指標,InteralQueryInterface
我們已經很熟悉了,_Chain把基類的指標以及基類的介面映射宏傳給它,實際上是查詢
基類的介面!!!

一般情況下把這個宏放在BEGIN_COM_MAP和END_COM_MAP之間的最後面,這表示只有在當
前類中查不到介面時才去查父類的介面。不過也經常把它放在第一位,這時就是先去查
父類介面,只有父類沒有實現這種介面時才查自己。在ATL中組件是以多重繼承的方式實
現的,ATL定義了很多類實現了一些常用的介面,這些類經常被做為組件的基類,所以這
個宏被大量使用。

所有重要的宏我們都已經講過了,剩下的都是些很簡單的宏了.呵呵,還是把它們都羅列一
下,善始善終嘛.

十、COM_INTERFACE_ENTRY_IID(iid, x)
#define COM_INTERFACE_ENTRY_IID(iid, x)/
{&iid,/
offsetofclass(x, _ComMapClass),/
_ATL_SIMPLEMAPENTRY},

十一、COM_INTERFACE_ENTRY2_IID(iid, x, x2)
#define COM_INTERFACE_ENTRY2_IID(iid, x, x2)/
{&iid,/
(DWORD)((x*)(x2*)((_ComMapClass*)8))-8,/
_ATL_SIMPLEMAPENTRY},
從定義上看這兩個宏與COM_INTERFACE_ENTRY()和COM_INTERFACE_ENTRY2()相比,都只是
多了一項"iid"。沒有別的好處,只不過由使用者明確指出介面IID,而不用系統根據介面
名字去轉換了。

十二、COM_INTERFACE_ENTRY_FUNC( iid, dw, func )
#define COM_INTERFACE_ENTRY_FUNC(iid, dw, func)/
{&iid, /
dw, /
func},
還記得AtlInternalQueryInterface()中的代碼嗎?如果在介面映射表中找到了我們
要找的介面,並且這個介面不是_ATL_SIMPLEENTRY型的,則執行宏定義中的指定的函數。
這個宏就給我們提供了自己編寫處理函數的功能。這個函數必須是如下定義:
HRESULT WINAPI func(void* pv, REFIID riid, LPVOID* ppv, DWORD dw);
當AtlInternalQueryInterface調用func時,會傳進相關的資訊。pv是類對象的指標,riid
是要查詢的介面,ppv是要返回查詢得到的介面指標,dw是在宏定義中指定的參數。
另外如果函數中不打算返回介面指標,則應把ppv賦為NULL,並返回S_FALSE或
E_NOINTERFACE。返回S_FALSE剛會繼續尋找下去,若返回E_NOINTERFACE則會終止查詢。
若返回介面指標,則應返回S_OK.

十三、COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)
#define COM_INTERFACE_ENTRY_FUNC_BLIND(dw, func)/
{NULL, /
dw, /
func},
至於_BLIND類型的特點可以看前面幾節。

十四、COM_INTERFACE_ENTRY_NOINTERFACE(x)
#define COM_INTERFACE_ENTRY_NOINTERFACE(x)/
{&_ATL_IIDOF(x), /
NULL, /
_NoInterface},
_NoInterface是CComObjectRootBase的成員函數,看看它的定義:
static HRESULT WINAPI _NoInterface(...)
{
return E_NOINTERFACE;
}
原來它只是返回E_NOINTERFACE,並且將終止查詢。
哈哈,看來是不想讓別人查到這個介面啊!!!

十五、COM_INTERFACE_ENTRY_BREAK(x)
#define COM_INTERFACE_ENTRY_BREAK(x)/
{&_ATL_IIDOF(x), /
NULL, /
_Break},
_Break也是CComObjectRootBase的成員函數,看看它的定義:
static HRESULT WINAPI _Break(...)
{
iid;
_ATLDUMPIID(iid, _T("Break due to QI for interface "), S_OK);
DebugBreak();
return S_FALSE;
}
如果查到這個介面將調用DebugBreak(),並返回S_FALSE,繼續查詢下去。
DebugBreak()是什麼效果大家自己試試吧,一定很熟悉的,呵呵。

至此全部十五個介面映射宏我們都已經講完了,唉,真是不容易,特別是前面幾個宏跟
蹤起來很麻煩。因為文本方式的限制,所以很多東西不容易表達清楚。有些叫法也是我
自己這麼叫的,可能與別人的習慣不同。沒辦法,大家將就將就了,呵呵。

---------------全文完------------

2000/3/31淩晨

補註:關於ATL中類廠的實現問題

1.當建立一個組件時,必須先建立它的類廠,再調用類廠的CreateInstance()來建立組件.
  在CComCoClass中定義了宏DECLARE_CLASSFACTORY(),包含了組件的類廠對象.
  _ClassFactoryCreatorClass,它的CreateInstance是用來建立組件的類廠的.也就是
  CComCreator< CCOMCLASSFACTORY>>::CreateInstance();
2.在CComCoClass中也定義了宏DECLARE_AGGREGATABLE(),包含了對象_CreatorClass,
  這個對象實際上就是我們要建立的組件對象(具體定義看詳解一),它也有一個
  CreateInstance,這個函數是用來建立這個組件的!!當建立組件的類廠時,會把這
  個函數的地址告訴給類廠。
3.當我們成功的獲得類廠對象後(此時類廠已經建立完畢),我們然後將調用類廠的
  CreateInstance(),在這個函數中,會調用組件的CreateInstance從而建立組件。
4.所以,可見這裡總共牽扯到三個CreateInstance:
  (1)_ClassFactoryCreatorClass::CreateInstance()//用於建立組件的類廠對象
  (2)CComClassFactory::CreateInstance()//用於調用_CreatorClass::CreateInstance
  (3)_CreatorClass::CreateInstance()//用於建立組件

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.