這個類別提供方法來處理非匯總和匯總物件的對象參考計數管理。
語法
template<class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase
參數
ThreadModel
類別,其方法實作所需的線程模型。 您可以將 ThreadModel 設定為 CComSingleThreadModel、CComMultiThreadModel 或 CComMultiThreadModelNoCS,以明確選擇線程模型。 您可以將 ThreadModel 設定為 CComObjectThreadModel 或 CComGlobalsThreadModel,以接受伺服器的預設線程模型。
成員
方法
| 函式 | 描述 |
|---|---|
| CComObjectRootEx | 建構函式。 |
| InternalAddRef | 遞增非匯總對象的參考計數。 |
| InternalRelease | 遞減非匯總對象的參考計數。 |
| 鎖定 | 如果線程模型是多線程,請取得重要區段對象的擁有權。 |
| 開鎖 | 如果線程模型是多線程,則會釋放重要區段對象的擁有權。 |
CComObjectRootBase 方法
| 函式 | 描述 |
|---|---|
| FinalConstruct | 覆寫 類別中的 ,以執行物件所需的任何初始化。 |
| FinalRelease | 覆寫 類別中的 ,以執行物件所需的任何清除。 |
| OuterAddRef | 遞增匯總對象的參考計數。 |
| OuterQueryInterface | 委派給匯總物件的外部 IUnknown 。 |
| OuterRelease | 遞減匯總對象的參考計數。 |
靜態函式
| 函式 | 描述 |
|---|---|
| InternalQueryInterface | 委派給 IUnknown 非匯總物件的 。 |
| ObjectMain | 在對象對應中所列衍生類別的模組初始化和終止期間呼叫。 |
資料成員
| 數據成員 | 描述 |
|---|---|
| m_dwRef | 使用 m_pOuterUnknown時,屬於聯集的一部分。 當物件未匯總以保存 和Release的AddRef參考計數時使用。 |
| m_pOuterUnknown | 使用 m_dwRef時,屬於聯集的一部分。 當物件匯總以保存外部未知的指標時使用。 |
備註
CComObjectRootEx 會處理非匯總和匯總物件的物件參考計數管理。 如果您的物件未匯總,它會保留物件參考計數,並在物件正在匯總時保留外部未知的指標。 針對匯總物件, CComObjectRootEx 方法可用來處理內部物件的建構失敗,以及在釋放內部介面或刪除內部物件時保護外部物件免於刪除。
實作 COM 伺服器的類別必須繼承自 CComObjectRootEx 或 CComObjectRoot。
如果您的類別定義指定DECLARE_POLY_AGGREGATABLE巨集,ATL 會在呼叫 時IClassFactory::CreateInstance建立的CComPolyObject<CYourClass>實例。 在建立期間,會檢查外部未知的值。 如果是 NULL, IUnknown 則會針對非匯總物件實作。 如果外部未知不是 NULL, IUnknown 則會針對匯總物件實作。
如果您的類別未指定DECLARE_POLY_AGGREGATABLE巨集,ATL 會為匯總物件建立的實例 CAggComObject<CYourClass> ,或針對非匯總物件建立的實例 CComObject<CYourClass> 。
使用 CComPolyObject 的優點是,您避免在 CComAggObject 模組中有 和 CComObject 來處理匯總和非匯總案例。 單 CComPolyObject 一物件會處理這兩種情況。 因此,您的模組中只有一份 vtable 和一份函式複本。 如果您的 vtable 很大,這可能會大幅減少模組大小。 不過,如果您的 vtable 很小,使用 CComPolyObject 可能會導致模組大小略大,因為它未針對匯總或非匯總的對象進行優化,如同 CComAggObject 和 CComObject。
如果您的對象已匯總, 則 IUnknown 是由 CComAggObject 或 CComPolyObject實作。 這些類別會將、 AddRef和 Release 呼叫OuterQueryInterfaceCComObjectRootEx委派QueryInterface給 的、 OuterAddRef和 ,以OuterRelease轉送至外部未知。 一般而言,您會覆寫 CComObjectRootEx::FinalConstruct 類別中以建立任何匯總物件,並覆寫 CComObjectRootEx::FinalRelease 以釋放任何匯總物件。
如果您的物件未匯總, IUnknown 則 是由 CComObject 或 CComPolyObject實作。 在這裡情況下,對、 和的呼叫QueryInterface會委派給 CComObjectRootEx的InternalQueryInterface、 InternalAddRef和 ,並InternalRelease執行實際作業。Release AddRef
需求
標頭: atlcom.h
CComObjectRootEx::CComObjectRootEx
建構函式會將參考計數初始化為 0。
CComObjectRootEx();
CComObjectRootEx::FinalConstruct
您可以在衍生類別中覆寫此方法,以執行物件所需的任何初始化。
HRESULT FinalConstruct();
傳回值
傳回成功S_OK或其中一個標準錯誤 HRESULT 值。
備註
根據預設, CComObjectRootEx::FinalConstruct 只會傳回S_OK。
在 中 FinalConstruct 執行初始化,而不是類別的建構函式有其優點:
您無法從建構函式傳回狀態代碼,但您可以透過
FinalConstruct傳回值傳回 HRESULT。 當您的類別物件是使用 ATL 所提供的標準類別處理站建立時,這個傳回值會傳播回 COM 用戶端,讓您提供詳細的錯誤資訊。您無法透過類別建構函式的虛擬函式機制呼叫虛擬函式。 從類別的建構函式呼叫虛擬函式,會導致在繼承階層的該時間點定義函式時,靜態解析對函式的呼叫。 對純虛擬函式的呼叫會導致連結器錯誤。
您的類別不是繼承階層中最衍生的類別, 它依賴 ATL 提供的衍生類別來提供其部分功能。 您的初始化很有可能需要使用該類別所提供的功能(當類別的物件需要匯總其他物件時,這當然是正確的),但是類別中的建構函式無法存取這些功能。 在完整建構最衍生類別之前,會先執行類別的建構程序代碼。
不過,在大部分衍生類別完全建構之後立即呼叫 ,
FinalConstruct可讓您呼叫虛擬函式,並使用 ATL 所提供的參考計數實作。
範例
一般而言,覆寫衍生自 CComObjectRootEx 的類別中的這個方法,以建立任何匯總的物件。 例如:
class ATL_NO_VTABLE CMyAggObject :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyAggObject, &CLSID_MyAggObject>,
public IDispatchImpl<IMyAggObject, &IID_IMyAggObject, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
DECLARE_GET_CONTROLLING_UNKNOWN()
HRESULT FinalConstruct()
{
return CoCreateInstance(CLSID_MyCustomClass, GetControllingUnknown(),
CLSCTX_ALL, IID_IUnknown, (void**)&m_pMyCustomClass);
}
IMyCustomClass* m_pMyCustomClass;
// Remainder of class declaration omitted.
如果建構失敗,您可以傳回錯誤。 如果建立期間,內部匯總物件會遞增參考計數,然後遞減到 0,您也可以使用巨集 DECLARE_PROTECT_FINAL_CONSTRUCT 來保護外部物件免於遭到刪除。
以下是建立匯總的一般方式:
IUnknown將指標新增至類別物件,並將其初始化為建構函式中的NULL。覆寫
FinalConstruct以建立匯總。IUnknown使用您定義為 COM_INTERFACE_ENTRY_AGGREGATE 巨集參數的指標。覆寫
FinalRelease以釋放IUnknown指標。
CComObjectRootEx::FinalRelease
您可以在衍生類別中覆寫此方法,以執行物件所需的任何清除。
void FinalRelease();
備註
根據預設, CComObjectRootEx::FinalRelease 不會執行任何動作。
若要在 中 FinalRelease 執行清除,最好是將程式代碼新增至類別的解構函式,因為物件仍會在呼叫的點 FinalRelease 完全建構。 這可讓您安全地存取最衍生類別所提供的方法。 這在刪除之前釋放任何匯總物件特別重要。
CComObjectRootEx::InternalAddRef
將非匯總對象的參考計數遞增 1。
ULONG InternalAddRef();
傳回值
對於診斷和測試而言可能很有用的值。
備註
如果線程模型是多線程, InterlockedIncrement 則會用來防止多個線程同時變更參考計數。
CComObjectRootEx::InternalQueryInterface
擷取所要求介面的指標。
static HRESULT InternalQueryInterface(
void* pThis,
const _ATL_INTMAP_ENTRY* pEntries,
REFIID iid,
void** ppvObject);
參數
pThis
[in]物件的指標,其中包含公開至 QueryInterface之介面的 COM 對應。
pEntries
[in]存取可用介面對應之結構的指標 _ATL_INTMAP_ENTRY 。
iid
[in]所要求介面的 GUID。
ppvObject
[out]在 iid 中指定的介面指標指標,如果找不到介面,則為 NULL。
傳回值
其中一個標準 HRESULT 值。
備註
InternalQueryInterface 只處理 COM 對應表格中的介面。 如果您的對象已匯總, InternalQueryInterface 則不會委派給外部未知。 您可以使用巨集 COM_INTERFACE_ENTRY 或其其中一個變體,在 COM 對應數據表中輸入介面。
CComObjectRootEx::InternalRelease
將非匯總對象的參考計數遞減 1。
ULONG InternalRelease();
傳回值
在非偵錯和偵錯組建中,此函式會傳回值,這對於診斷或測試很有用。 傳回的確切值取決於許多因素,例如使用的操作系統,而且可能或可能不是參考計數。
備註
如果線程模型是多線程, InterlockedDecrement 則會用來防止多個線程同時變更參考計數。
CComObjectRootEx::Lock
如果線程模型是多線程,這個方法會呼叫 Win32 API 函 式 EnterCriticalSection,該函式會等到線程可以取得透過私人數據成員取得的重要區段對象的擁有權為止。
void Lock();
備註
當受保護的程式代碼完成執行時,線程必須呼叫 Unlock 以釋放重要區段的擁有權。
如果線程模型是單個線程,這個方法就不會執行任何動作。
CComObjectRootEx::m_dwRef
存取四個字節記憶體之等位的聯集部分。
long m_dwRef;
備註
使用 m_pOuterUnknown時,聯集的一部分:
union {
long m_dwRef;
IUnknown* m_pOuterUnknown;
};
如果未匯總物件,則 所 AddRef 存取的參考計數會 Release 儲存在 中 m_dwRef。 如果匯總物件,則外部未知的指標會儲存在 m_pOuterUnknown中。
CComObjectRootEx::m_pOuterUnknown
存取四個字節記憶體之等位的聯集部分。
IUnknown*
m_pOuterUnknown;
備註
使用 m_dwRef時,聯集的一部分:
union {
long m_dwRef;
IUnknown* m_pOuterUnknown;
};
如果匯總物件,外部未知的指標會儲存在 中 m_pOuterUnknown。 如果未匯總物件,則 由 AddRef 存取的 Release 參考計數會儲存在 m_dwRef中。
CComObjectRootEx::ObjectMain
針對對象對應中列出的每個類別,當模組初始化時,就會呼叫此函式一次,並在終止時再次呼叫此函式。
static void WINAPI ObjectMain(bool bStarting);
參數
bStarting
[out]如果類別正在初始化,則值為TRUE;否則為 FALSE。
備註
bStarting 參數的值會指出模組正在初始化或終止。 的預設實 ObjectMain 作不會執行任何動作,但您可以在 類別中覆寫此函式,以初始化或清除您想要為類別配置的資源。 請注意, ObjectMain 在要求類別的任何實體之前呼叫 。
ObjectMain 是從 DLL 的進入點呼叫,因此進入點函式可執行的作業類型會受到限制。 如需這些限制的詳細資訊,請參閱 DLL 和 Visual C++運行時間連結庫行為 和 DllMain。
範例
class ATL_NO_VTABLE CMyApp :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CMyApp, &CLSID_MyApp>,
public IMyApp
{
public:
CMyApp()
{
}
static void WINAPI ObjectMain(bool bStarting)
{
if (bStarting)
;// Perform custom initialization routines
else
;// Perform custom termination routines
}
// Remainder of class declaration omitted.
CComObjectRootEx::OuterAddRef
遞增匯總外部未知的參考計數。
ULONG OuterAddRef();
傳回值
對於診斷和測試而言可能很有用的值。
CComObjectRootEx::OuterQueryInterface
擷取所要求介面的間接指標。
HRESULT OuterQueryInterface(REFIID iid, void** ppvObject);
參數
iid
[in]所要求介面的 GUID。
ppvObject
[out]在 iid 中指定的介面指標指標,如果匯總不支援 介面,則為 NULL。
傳回值
其中一個標準 HRESULT 值。
CComObjectRootEx::OuterRelease
遞減匯總外部未知的參考計數。
ULONG OuterRelease();
傳回值
在非偵錯組建中,一律會傳回 0。 在偵錯組建中,傳回可能對診斷或測試很有用的值。
CComObjectRootEx::Unlock
如果線程模型是多線程,這個方法會呼叫 Win32 API 函 式 LeaveCriticalSection,此函式會釋放透過私人數據成員取得的重要區段對象的擁有權。
void Unlock();
備註
若要取得擁有權,線程必須呼叫 Lock。 對的每個呼叫 Lock 都需要對應的呼叫 Unlock ,才能釋放重要區段的擁有權。
如果線程模型是單個線程,這個方法就不會執行任何動作。