實作 C++ 標準程式庫架構集合
ATL 提供 ICollectionOnSTLImpl
介面,可讓您在物件上快速實作標準連結庫型集合介面C++。 若要瞭解此類別的運作方式,您將透過使用這個類別實作以自動化客戶端為目標的唯讀集合的簡單範例(以下)。
範例程式代碼來自 ATLCollections 範例。
若要完成此程式,您將:
建立五個 typedefs ,描述如何儲存集合專案,以及如何透過 COM 介面向客戶端公開它們。
為複製原則類別建立兩個 typedefs。
建立列舉值和集合實作的 typedefs。
產生新的簡單物件
建立新的項目,確保清除 [應用程式設定] 底下的 [屬性] 方塊。 使用 [ATL 新增類別] 對話框和 [新增簡單物件精靈] 來產生名為 Words
的簡單物件。 請確定產生名為 IWords
的雙重介面。 產生的類別物件將用來表示單字集合(也就是字串)。
編輯IDL檔案
現在,開啟IDL檔案,並新增轉換成 IWords
只讀集合介面所需的三個屬性,如下所示:
[
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 存取其餘方法,因此最好使用雙重介面來散發介面。如果在運行時間不會擴充雙重介面或 dispinterface(也就是說,您不會透過
IDispatch::Invoke
提供額外的方法或屬性),您應該將 不可 延伸的屬性套用至您的定義。 此屬性可讓自動化客戶端在編譯時期執行完整程式代碼驗證。 在此情況下,不應該擴充 介面。如果您想要自動化客戶端能夠使用這個屬性,正確的 DISPID 很重要。 (請注意,DISPID_NEWENUM中只有一個底線。
您可以提供任何值做為 屬性的
Item
DISPID。 不過,Item
通常會使用 DISPID_VALUE,讓它成為集合的默認屬性。 這可讓自動化客戶端參考 屬性,而不明確命名。屬性傳
Item
回值所使用的數據類型是儲存在集合中的專案類型,就 COM 用戶端而言。 介面會傳回字串,因此您應該使用標準 COM 字串類型 BSTR。 您可以在內部以不同的格式儲存數據,因為很快就會看到。用於屬性 DISPID 的值是完全任意的
Count
。 這個屬性沒有標準 DISPID。
建立記憶體和曝光的 Typedefs
定義集合介面之後,您必須決定資料的儲存方式,以及如何透過列舉值公開數據。
這些問題的答案可透過數個 typedefs 的形式提供,您可以在新建立類別的頭檔頂端附近新增:
// 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::strings 的 std::vector。 std::vector 是C++標準連結庫容器類別,其行為就像Managed數位一樣。 std::string 是標準連結庫的字串類別C++。 這些類別可讓您輕鬆地使用字串集合。
由於 Visual Basic 支援對於這個介面的成功至關重要,因此 屬性所 _NewEnum
傳回的列舉值必須支援 IEnumVARIANT
介面。 這是 Visual Basic 唯一瞭解的列舉值介面。
建立複製原則類別的 Typedefs
到目前為止所建立的 typedefs 會提供您為列舉值和集合將使用之複製類別建立進一步 typedefs 所需的所有資訊:
// 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 複製原則類別。
建立列舉和集合的 Typedefs
現在已以 typedefs 的形式提供專門化 CComEnumOnSTL
和 ICollectionOnSTLImpl
類別所需的所有範本參數。 若要簡化特製化的使用,請建立兩個其他 typedefs,如下所示:
typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;
現在 CollectionType
與 特製化同義,這個特製化 ICollectionOnSTLImpl
會實 IWords
作稍早定義的介面,並提供支援 IEnumVARIANT
的列舉值。
編輯精靈產生的程序代碼
現在,您必須衍生 CWords
自 typedef 所代表的 CollectionType
介面實作,而不是 IWords
,如下所示:
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");
}
現在,您可以使用您選擇的客戶端來測試程式碼。