CComObjectRootEx クラス
このクラスは、非集計オブジェクトと集計オブジェクトの両方のオブジェクト参照カウント管理を処理するメソッドを提供します。
構文
template<class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase
パラメーター
ThreadModel
メソッドが目的のスレッド モデルを実装するクラス。 ThreadModel を CComSingleThreadModel、CComMultiThreadModel、またはCComMultiThreadModelNoCS に設定すると、スレッド モデルを明示的に選択できます。 ThreadModel を CComObjectThreadModel または CComGlobalsThreadModel に設定すると、サーバーの既定のスレッド モデルを受け入れることができます。
メンバー
メソッド
関数 | 説明 |
---|---|
CComObjectRootEx | コンストラクターです。 |
InternalAddRef | 非集計オブジェクトの参照カウントをインクリメントします。 |
InternalRelease | 非集計オブジェクトの参照カウントをデクリメントします。 |
ロック | スレッド モデルがマルチスレッドの場合、クリティカル セクション オブジェクトの所有権を取得します。 |
Unlock | スレッド モデルがマルチスレッドの場合、クリティカル セクション オブジェクトの所有権を解放します。 |
CComObjectRootBase メソッド
関数 | 説明 |
---|---|
FinalConstruct | クラスで、オブジェクトに必要な初期化を実行するようにオーバーライドします。 |
FinalRelease | クラスで、オブジェクトに必要なクリーンアップを実行するようにオーバーライドします。 |
OuterAddRef | 集計オブジェクトの参照カウントをインクリメントします。 |
OuterQueryInterface | 集計オブジェクトの外部の IUnknown にデリゲートします。 |
OuterRelease | 集計オブジェクトの参照カウントをデクリメントします。 |
静的関数
関数 | 説明 |
---|---|
InternalQueryInterface | 非集計オブジェクトの IUnknown にデリゲートします。 |
ObjectMain | オブジェクト マップにリストされている派生クラスに対して、モジュールの初期化および終了時に呼び出されます。 |
データ メンバー
データ メンバー | 説明 |
---|---|
m_dwRef | m_pOuterUnknown と共に、共用体に含まれます。 オブジェクトが AddRef と Release の参照カウントを保持するために集計されていない場合に使用されます。 |
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
の両方をモジュールに含める必要がないことです。 1 つの CComPolyObject
オブジェクトで両方のケースが処理されます。 従って、作成するモジュールには、vtable の 1 つのコピーと関数の 1 つのコピーだけが存在します。 vtable が大きい場合、これにより、モジュールのサイズが大幅に縮小される可能性があります。 一方、vtable が小さい場合は、CComPolyObject
を使用すると、CComAggObject
や CComObject
のように、集計オブジェクトまたは非集計オブジェクトに合わせて最適化されないため、モジュールのサイズが若干大きくなります。
オブジェクトが集計される場合、IUnknown は CComAggObject
またはCComPolyObject
によって実装されます。 これらのクラスによって、QueryInterface
、AddRef
、および Release
の呼び出しが CComObjectRootEx
の OuterQueryInterface
、OuterAddRef
、および OuterRelease
にデリケートされ、外部不明に転送されます。 通常は、クラスで、CComObjectRootEx::FinalConstruct
を集計オブジェクトを作成するようにオーバーライドし、CComObjectRootEx::FinalRelease
を集計オブジェクトを解放するようにオーバーライドします。
オブジェクトが集計されない場合、IUnknown
は、CComObject
または CComPolyObject
によって実装されます。 この場合、QueryInterface
、AddRef
、および Release
への呼び出しは、実際の操作を実行するために CComObjectRootEx
の InternalQueryInterface
、InternalAddRef
、および InternalRelease
にデリケートされます。
要件
ヘッダー: atlcom.h
CComObjectRootEx::CComObjectRootEx
このコンストラクターによって、参照カウントが 0 に初期化されます。
CComObjectRootEx();
CComObjectRootEx::FinalConstruct
派生クラスのこのメソッドを、オブジェクトに必要な初期化を実行するようにオーバーライドできます。
HRESULT FinalConstruct();
戻り値
成功時は S_OK、エラー時は標準の HRESULT 値の 1 つが返されます。
解説
既定では、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.
構築に失敗した場合は、エラーを返すことができます。 また、マクロ DECLARE_PROTECT_FINAL_CONSTRUCT を使用して、作成中に、内部集計オブジェクトによって参照カウントがインクリメントされた後にカウントが 0 にデクリメントされる場合に外部オブジェクトが削除されないように保護することもできます。
集計を作成する一般的な方法を次に示します。
IUnknown
ポインターをクラス オブジェクトに追加し、それをコンストラクターで NULL に初期化します。FinalConstruct
を、集計を作成するようにオーバーライドします。COM_INTERFACE_ENTRY_AGGREGATE マクロのパラメーターとして定義した
IUnknown
ポインターを使用します。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
[入力] QueryInterface
に公開されるインターフェイスの COM マップを含むオブジェクトへのポインター。
pEntries
[入力] 使用可能なインターフェイスのマップにアクセスする _ATL_INTMAP_ENTRY
構造体へのポインター。
iid
[入力] 要求されているインターフェイスの GUID。
ppvObject
[出力] iid に指定するインターフェイス ポインターへのポインター。インターフェイスが見つからない場合は NULL。
戻り値
標準 HRESULT 値のいずれか。
解説
InternalQueryInterface
が処理するのは、COM マップ テーブル内のインターフェイスのみです。 オブジェクトが集計されている場合、InternalQueryInterface
によって、外部不明にデリゲートされません。 マクロ COM_INTERFACE_ENTRY またはそのバリアントの 1 つを使用して、COM マップ テーブルにインターフェイスを入力できます。
CComObjectRootEx::InternalRelease
非集計オブジェクトの参照カウントを 1 デクリメントします。
ULONG InternalRelease();
戻り値
デバッグなしのビルドとデバッグ ビルドの両方で、この関数から、診断またはテストに役立つ可能性がある値が返されます。 返される正確な値は、使用されているオペレーティング システムなど、多くの要因によって異なり、参照カウントである場合と、そうでない場合があります。
解説
スレッド モデルがマルチスレッドの場合、InterlockedDecrement
を使用して、参照カウントが複数のスレッドによって同時に変更されないようにします。
CComObjectRootEx::Lock
スレッド モデルがマルチスレッドの場合、このメソッドから、Win32 API 関数 EnterCriticalSection が呼び出され、スレッドがプライベート データ メンバーを通じて取得したクリティカル セクション オブジェクトの所有権を取得できるまで待機します。
void Lock();
解説
保護されたコードの実行が完了したら、Unlock
を呼び出してクリティカル セクションの所有権を解放する必要があります。
スレッド モデルがシングル スレッドの場合、このメソッドで何も行われません。
CComObjectRootEx::m_dwRef
4 バイトのメモリにアクセスする共用体に含まれます。
long m_dwRef;
解説
m_pOuterUnknown
と共に、共用体に含まれます。
union {
long m_dwRef;
IUnknown* m_pOuterUnknown;
};
オブジェクトが集計されていない場合、AddRef
と Release
からアクセスされる参照カウントが m_dwRef
に格納されます。 オブジェクトが集計されている場合、外部不明へのポインターは、m_pOuterUnknown に格納されます。
CComObjectRootEx::m_pOuterUnknown
4 バイトのメモリにアクセスする共用体に含まれます。
IUnknown*
m_pOuterUnknown;
解説
m_dwRef
と共に、共用体に含まれます。
union {
long m_dwRef;
IUnknown* m_pOuterUnknown;
};
オブジェクトが集計されている場合、外部不明へのポインターは、m_pOuterUnknown
に格納されます。 オブジェクトが集計されていない場合、AddRef
と Release
からアクセスされる参照カウントが m_dwRef に格納されます。
CComObjectRootEx::ObjectMain
オブジェクト マップにリストされているクラスごとに、この関数はモジュールが初期化されると 1 回呼び出され、終了すると再度呼び出されます。
static void WINAPI ObjectMain(bool bStarting);
パラメーター
bStarting
[出力] クラスが初期化されている場合、値は 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
[入力] 要求されているインターフェイスの GUID。
ppvObject
[出力] iid に指定するインターフェイス ポインターへのポインター。集計がインターフェイスをサポートしていない場合は NULL。
戻り値
標準 HRESULT 値のいずれか。
CComObjectRootEx::OuterRelease
集計の外部不明の参照カウントをデクリメントします。
ULONG OuterRelease();
戻り値
デバッグなしのビルドでは、常に 0 が返されます。 デバッグ ビルドでは、診断またはテストに役立つ可能性のある値が返されます。
CComObjectRootEx::Unlock
スレッド モデルがマルチスレッドの場合、このメソッドから、Win32 API 関数 LeaveCriticalSection が呼び出され、プライベート データ メンバーを通じて取得されたクリティカル セクション オブジェクトの所有権が解放されます。
void Unlock();
解説
所有権を取得するには、スレッドで Lock
を呼び出す必要があります。 Lock
を呼び出すたびに、対応する Unlock
を呼び出してクリティカル セクションの所有権を解放する必要があります。
スレッド モデルがシングル スレッドの場合、このメソッドで何も行われません。