STL ベースのコレクションの実装
ATL は、標準テンプレート ライブラリの (STL) のオブジェクト ベースのコレクションのインターフェイスを実装できるように ICollectionOnSTLImpl のインターフェイスを提供します。このクラスの機能を理解するには、読み取り専用コレクションによって目指されるオートメーション クライアントを実行するには、このクラスを使用する簡単な例の (以下) で動作します。
サンプル コードは ATLCollections sampleからです。
この手順を完了するには、:
新しい簡単なオブジェクトを生成します。。
生成されたインターフェイスのIDL ファイルを編集します。。
コレクション項目を格納、およびどのように、COM クライアントに公開する方法を記述 する5 個の typedef を作成します。 はインターフェイスです。
コピー ポリシー クラスの 2 種類の typedef を作成します。。
列挙子とコレクションの実装の typedef を作成します。。
コレクションの typedef を使用するためにウィザードで生成された C++ コードを編集します。。
コレクションを作成するコードを追加します。。
新しいシンプル オブジェクトの生成
新しいプロジェクトを、アプリケーション設定の下の属性ボックスがオフになっていることを確認して作成します。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);
};
これは、デザインされるところでオートメーション クライアントを持つ読み取り専用コレクション インターフェイスの標準形式です。このインターフェイス定義の番号が付けられるコメントは次のようにコメントに対応しています:
コレクションのインターフェイスは通常オートメーション クライアントが IDispatch::Invokeによって _NewEnum のプロパティにアクセスできるため、階層です。ただし、オートメーション クライアントは、vtable を使用して残りのメソッドにアクセスできます。つまり、デュアル インターフェイスは、ディスパッチ インターフェイスに必要です。
デュアル インターフェイスまたはディスパッチ インターフェイスが、実行時 (つまり、IDispatch::Invokeして、メソッドまたはプロパティを提供しません) に拡張であるか、または nonextensible の定義に属性を適用する必要があります。この属性は、コンパイル時に完全なコード検証を実行することをオートメーション クライアントができます。この場合、拡張インターフェイスは必要ではありません。
適切な DISPID は、オートメーション クライアントにこのプロパティを使用できるように重要です。DISPID_NEWENUMに 1 二つのアンダースコアがあることに注意してください)。
[アイテム] のプロパティの DISPID として値を指定できます。ただし、[アイテム] は、通常はコレクション、既定のプロパティに DISPID_VALUE を使用します。これは、オートメーション クライアントが明示的に表示せずにプロパティを示すことができます。
[アイテム] のプロパティの戻り値に使用するデータ型は、COM クライアントに関する限りでは、コレクションに格納されている項目の型です。インターフェイスは文字列を返すため、文字列型、BSTRを標準の COM を使用する必要があります。次に示すように別の形式のデータを内部的に格納できます。
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::string、.の std::vector としてデータを格納します。std::vector は、マネージ配列のようにして、STL コンテナー クラスです。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");
}
これで、任意のクライアントとのコードをテストできます。