次の方法で共有


C++ 標準ライブラリに基づくコレクションの実装

ATL には、C++ 標準ライブラリベースのコレクション インターフェイスをオブジェクトにすばやく実装できるようにするための ICollectionOnSTLImpl インターフェイスが用意されています。 このクラスがどのように動作するかを理解するために、このクラスを使用して、オートメーション クライアントを対象とする読み取り専用コレクションを実装する (下記の) 簡単な例を使用します。

サンプル コードは、ATLCollections サンプルからのものです。

この手順を完了するには、次のようにします。

新しい単純なオブジェクトの生成

新しいプロジェクトを作成し、[アプリケーション設定] の [属性] ボックスがオフになっていることを確かめます。 ATL の [クラスの追加] ダイアログ ボックスと [単純なオブジェクトの追加] ウィザードを使用して、Words という単純なオブジェクトを生成します。 IWords というデュアル インターフェイスが生成されていることを確認します。 生成されたクラスのオブジェクトは、単語のコレクション (つまり、文字列) を表すために使用されます。

IDL ファイルの編集

ここで、次に示すように、IDL ファイルを開き、IWords を読み取り専用コレクション インターフェイスにするために必要な 3 つのプロパティを追加します。

[
   object,
   uuid(7B3AC376-509F-4068-87BA-03B73ADC359B),
   dual,                                                    // (1)
   nonextensible,                                           // (2)
   pointer_default(unique)
]
interface IWords : IDispatch
{
   [id(DISPID_NEWENUM), propget]                            // (3)
   HRESULT _NewEnum([out, retval] IUnknown** ppUnk);

   [id(DISPID_VALUE), propget]                              // (4)
   HRESULT Item([in] long Index, [out, retval] BSTR* pVal); // (5)

   [id(0x00000001), propget]                                // (6)
   HRESULT Count([out, retval] long* pVal);

};

これは、オートメーション クライアントを考慮して設計された読み取り専用コレクション インターフェイスの標準形式です。 このインターフェイス定義の番号付きコメントは、以下のコメントに対応しています。

  1. コレクション インターフェイスは通常、デュアルになります。これは、オートメーション クライアントから IDispatch::Invoke を介して _NewEnum プロパティにアクセスするためです。 しかし、オートメーション クライアントでは vtable 経由で残りのメソッドにアクセスできるため、デュアル インターフェイスはディスパッチインターフェイスよりも適しています。

  2. デュアル インターフェイスまたはディスパッチインターフェイスが実行時に拡張されない (つまり、IDispatch::Invoke を介して追加のメソッドやプロパティを指定しない) 場合は、nonextensible 属性を定義に適用する必要があります。 この属性を使用すると、コンパイル時にオートメーション クライアントで完全なコードの検証を実行できます。 この場合、インターフェイスを拡張することはできません。

  3. オートメーション クライアントでこのプロパティを使用できるようにするには、正しい DISPID が重要です (DISPID_NEWENUM にはアンダースコアが 1 つだけあることに注意してください)。

  4. Item プロパティの DISPID として任意の値を指定できます。 しかし、Item では通常、DISPID_VALUE を使用して、コレクションの既定のプロパティにします。 これにより、オートメーション クライアントでは、明示的に名前を付けずにプロパティを参照できます。

  5. Item プロパティの戻り値に使用されるデータ型は、COM クライアントに関する限り、コレクションに格納される項目の型です。 インターフェイスからは文字列が返されます。したがって、標準の COM 文字列型である BSTR を使用する必要があります。 データは、後述のとおり、内部で異なる形式で格納することができます。

  6. Count プロパティの DISPID に使用される値はまったく任意です。 このプロパティには標準の DISPID がありません。

格納および公開用の typedef を作成する

コレクション インターフェイスを定義したら、データを格納する方法と、列挙子を使用してデータを公開する方法を決定する必要があります。

これらの質問に対する答えは、多数の typedef の形式で提供できます。これは、新しく作成されたクラスのヘッダー ファイルの先頭付近に追加できます。

// Store the data in a vector of std::strings
typedef std::vector< std::string >         ContainerType;

// The collection interface exposes the data as BSTRs
typedef BSTR                               CollectionExposedType;
typedef IWords                             CollectionInterface;

// Use IEnumVARIANT as the enumerator for VB compatibility
typedef VARIANT                            EnumeratorExposedType;
typedef IEnumVARIANT                       EnumeratorInterface;

この場合は、std::stringstd::vector としてデータを格納します。 std::vector は、マネージド配列のように動作する C++ 標準ライブラリのコンテナー クラスです。 std::string は、C++ 標準ライブラリの文字列クラスです。 これらのクラスを使用すると、文字列のコレクションを簡単に操作できます。

このインターフェイスを成功させるには Visual Basic サポートが不可欠であるため、_NewEnum プロパティによって返される列挙子で IEnumVARIANT インターフェイスをサポートする必要があります。 これは、Visual Basic によって認識される唯一の列挙子インターフェイスです。

コピー ポリシー クラス用の typedef の作成

これまでに作成した typedef では、列挙子とコレクションによって使用されるコピー クラス用に、さらに typedef を作成するために必要なすべての情報が提供されます。

// Typedef the copy classes using existing typedefs
typedef VCUE::GenericCopy<EnumeratorExposedType, ContainerType::value_type> EnumeratorCopyType;
typedef VCUE::GenericCopy<CollectionExposedType, ContainerType::value_type> CollectionCopyType;

この例では、ATLCollections サンプルの VCUE_Copy.h と VCUE_CopyString.h で定義されているカスタム GenericCopy クラスを使用できます。 他のコードでもこのクラスを使用できますが、独自のコレクションで使用されるデータ型をサポートするために、GenericCopy の特殊化をさらに定義することが必要になる場合があります。 詳細については、「ATL コピー ポリシー クラス」を参照してください。

列挙およびコレクション用の typedef の作成

現在、この状況で CComEnumOnSTL および ICollectionOnSTLImpl クラスを特殊化するために必要なすべてのテンプレート パラメーターが、typedef の形式で提供されています。 特殊化の使用を簡単にするために、次のようにさらに 2 つの typedef を作成します。

typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;

CollectionType は、前に定義された IWords インターフェイスを実装し、IEnumVARIANT をサポートする列挙子を提供する ICollectionOnSTLImpl の特殊化のシノニムです。

ウィザードで生成されたコードの編集

ここで、次に示すように、IWords ではなく、CollectionType typedef によって表されるインターフェイスの実装から CWords を派生する必要があります。

class ATL_NO_VTABLE CWords :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CWords, &CLSID_Words>,
   // 'CollectionType' replaces 'IWords' in next line
   public IDispatchImpl<CollectionType, &IID_IWords, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
DECLARE_REGISTRY_RESOURCEID(IDR_WORDS)


BEGIN_COM_MAP(CWords)
   COM_INTERFACE_ENTRY(IWords)
   COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()

// Remainder of class declaration omitted.

コレクションに読み込むコードの追加

あとはベクターにデータを設定するだけです。 この簡単な例では、クラスのコンストラクターのコレクションにいくつかの単語を追加できます。

CWords()
{
    m_coll.push_back("this");
    m_coll.push_back("is");
    m_coll.push_back("a");
    m_coll.push_back("test");
}

ここで、任意のクライアントを使用してコードをテストできます。

関連項目

コレクションと列挙子
ATLCollections サンプル
ATL コピー ポリシー クラス