CComObjectRootEx クラス

このクラスは、非集計オブジェクトと集計オブジェクトの両方のオブジェクト参照カウント管理を処理するメソッドを提供します。

構文

template<class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase

パラメーター

ThreadModel
メソッドが目的のスレッド モデルを実装するクラス。 ThreadModelCComSingleThreadModelCComMultiThreadModel、またはCComMultiThreadModelNoCS に設定すると、スレッド モデルを明示的に選択できます。 ThreadModelCComObjectThreadModel または CComGlobalsThreadModel に設定すると、サーバーの既定のスレッド モデルを受け入れることができます。

メンバー

メソッド

機能 説明
CComObjectRootEx コンストラクターです。
InternalAddRef 非集計オブジェクトの参照カウントをインクリメントします。
InternalRelease 非集計オブジェクトの参照カウントをデクリメントします。
ロック スレッド モデルがマルチスレッドの場合、クリティカル セクション オブジェクトの所有権を取得します。
ロック 解除 スレッド モデルがマルチスレッドの場合、クリティカル セクション オブジェクトの所有権を解放します。

CComObjectRootBase メソッド

機能 説明
FinalConstruct クラスで、オブジェクトに必要な初期化を実行するようにオーバーライドします。
FinalRelease クラスで、オブジェクトに必要なクリーンアップを実行するようにオーバーライドします。
OuterAddRef 集計オブジェクトの参照カウントをインクリメントします。
OuterQueryInterface 集計オブジェクトの外部の IUnknown にデリゲートします。
OuterRelease 集計オブジェクトの参照カウントをデクリメントします。

静的関数

機能 説明
InternalQueryInterface 非集計オブジェクトの IUnknown にデリゲートします。
ObjectMain オブジェクト マップにリストされている派生クラスに対して、モジュールの初期化および終了時に呼び出されます。

データ メンバー

データ メンバー 説明
m_dwRef m_pOuterUnknown と共に、共用体に含まれます。 オブジェクトが AddRefRelease の参照カウントを保持するために集計されていない場合に使用されます。
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 を使用する利点は、集計されるケースと集計されないケースを処理するために CComAggObjectCComObject の両方をモジュールに含める必要がないことです。 1 つの CComPolyObject オブジェクトで両方のケースが処理されます。 従って、作成するモジュールには、vtable の 1 つのコピーと関数の 1 つのコピーだけが存在します。 vtable が大きい場合、これにより、モジュールのサイズが大幅に縮小される可能性があります。 一方、vtable が小さい場合は、CComPolyObject を使用すると、CComAggObjectCComObject のように、集計オブジェクトまたは非集計オブジェクトに合わせて最適化されないため、モジュールのサイズが若干大きくなります。

オブジェクトが集計される場合、IUnknownCComAggObject またはCComPolyObject によって実装されます。 これらのクラスによって、QueryInterfaceAddRef、および Release の呼び出しが CComObjectRootExOuterQueryInterfaceOuterAddRef、および OuterRelease にデリケートされ、外部不明に転送されます。 通常は、クラスで、CComObjectRootEx::FinalConstruct を集計オブジェクトを作成するようにオーバーライドし、CComObjectRootEx::FinalRelease を集計オブジェクトを解放するようにオーバーライドします。

オブジェクトが集計されない場合、IUnknown は、CComObject または CComPolyObject によって実装されます。 この場合、QueryInterfaceAddRef、および Release への呼び出しは、実際の操作を実行するために CComObjectRootExInternalQueryInterfaceInternalAddRef、および 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;
};

オブジェクトが集計されていない場合、AddRefRelease からアクセスされる参照カウントが m_dwRef に格納されます。 オブジェクトが集計されている場合、外部不明へのポインターは、m_pOuterUnknown に格納されます。

CComObjectRootEx::m_pOuterUnknown

4 バイトのメモリにアクセスする共用体に含まれます。

IUnknown*
    m_pOuterUnknown;

解説

m_dwRef と共に、共用体に含まれます。

union {
    long m_dwRef;
    IUnknown* m_pOuterUnknown;
};

オブジェクトが集計されている場合、外部不明へのポインターは、m_pOuterUnknown に格納されます。 オブジェクトが集計されていない場合、AddRefRelease からアクセスされる参照カウントが 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 を呼び出してクリティカル セクションの所有権を解放する必要があります。

スレッド モデルがシングル スレッドの場合、このメソッドで何も行われません。

関連項目

CComAggObject クラス
CComObject クラス
CComPolyObject クラス
クラスの概要