Implementace kolekce založené na standardní knihovně C++
ATL poskytuje ICollectionOnSTLImpl
rozhraní, které umožňuje rychle implementovat rozhraní kolekcí založené na standardní knihovně C++ na objekty. Abyste pochopili, jak tato třída funguje, budete pracovat pomocí jednoduchého příkladu (níže), který tuto třídu používá k implementaci kolekce jen pro čtení zaměřené na klienty Automation.
Vzorový kód pochází z ukázky ATLCollections.
Chcete-li provést tento postup, budete:
Upravte soubor IDL pro vygenerované rozhraní.
Vytvořte pět typedef popisujících, jak se položky kolekce ukládají a jak budou vystaveny klientům prostřednictvím rozhraní MODELU COM.
Vytvořte dva definice typedef pro třídy zásad kopírování.
Upravte kód C++ vygenerovaný průvodcem tak, aby používal typedef kolekce.
Generování nového jednoduchého objektu
Vytvořte nový projekt a ujistěte se, že pole Atributy v části Nastavení aplikace je nezaškrtnuto. Pomocí dialogového okna Přidat třídu ATL a Průvodce přidáním jednoduchého objektu vygenerujte jednoduchý objekt s názvem Words
. Ujistěte se, že je vygenerováno IWords
duální rozhraní. Objekty vygenerované třídy budou použity k reprezentaci kolekce slov (to znamená řetězce).
Úprava souboru IDL
Nyní otevřete soubor IDL a přidejte tři vlastnosti potřebné k převodu IWords
na rozhraní kolekce jen pro čtení, jak je znázorněno níže:
[
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);
};
Toto je standardní formulář pro rozhraní kolekce jen pro čtení navržené s ohledem na klienty Automation. Očíslované komentáře v této definici rozhraní odpovídají následujícím komentářům:
Rozhraní kolekce jsou obvykle duální, protože klienti Automation přistupují k
_NewEnum
vlastnosti prostřednictvímIDispatch::Invoke
. Klienti Automation ale můžou přistupovat ke zbývajícím metodám prostřednictvím tabulky vtable, takže duální rozhraní jsou vhodnější než dispinterfaces.Pokud duální rozhraní nebo dispinterface nebude rozšířeno za běhu (to znamená, že nebudete poskytovat další metody nebo vlastnosti prostřednictvím
IDispatch::Invoke
), měli byste použít nonextensible atribut pro vaši definici. Tento atribut umožňuje klientům Automation provádět úplné ověření kódu v době kompilace. V tomto případě by rozhraní nemělo být rozšířeno.Správné ID DISPID je důležité, pokud chcete, aby klienti Automation mohli tuto vlastnost používat. (Všimněte si, že v DISPID_NEWENUM je pouze jedno podtržítko.)
Jako IDENTIFIKÁTOR DISPID
Item
vlastnosti můžete zadat libovolnou hodnotu. Obvykle však používá DISPID_VALUE k tomu,Item
aby byla výchozí vlastností kolekce. To umožňuje klientům Automation odkazovat na vlastnost bez explicitního pojmenování.Datový typ použitý pro návratové
Item
hodnoty vlastnosti je typ položky uložené v kolekci, pokud jde o klienty MODELU COM. Rozhraní vrací řetězce, takže byste měli použít standardní typ řetězce MODELU COM BSTR. Data můžete ukládat interně v jiném formátu, jak uvidíte krátce.Hodnota použitá pro DISPID
Count
vlastnosti je zcela libovolná. Pro tuto vlastnost neexistuje standardní DISPID.
Vytváření typedef pro ukládání a vystavení
Jakmile je rozhraní kolekce definováno, musíte se rozhodnout, jak se budou data ukládat a jak budou data vystavena prostřednictvím enumerátoru.
Odpovědi na tyto otázky můžete poskytnout ve formě řady typedefs, které můžete přidat do horní části souboru záhlaví pro nově vytvořenou třídu:
// 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;
V tomto případě uložíte data jako std::vector std ::strings. std::vector je třída kontejneru standardní knihovny C++, která se chová jako spravované pole. std::string je třída řetězců standardní knihovny jazyka C++. Tyto třídy usnadňují práci s kolekcí řetězců.
Vzhledem k tomu, že podpora jazyka Visual Basic je nezbytná pro úspěch tohoto rozhraní, enumerátor vrácený _NewEnum
vlastností musí podporovat IEnumVARIANT
rozhraní. Toto je jediné rozhraní enumerátoru, kterému jazyk Visual Basic rozumí.
Vytváření typedefs pro třídy zásad kopírování
Typedefs, které jste zatím vytvořili, poskytují všechny informace, které potřebujete k vytvoření dalších typedefs pro třídy kopírování, které budou používány enumerátorem a kolekcí:
// Typedef the copy classes using existing typedefs
typedef VCUE::GenericCopy<EnumeratorExposedType, ContainerType::value_type> EnumeratorCopyType;
typedef VCUE::GenericCopy<CollectionExposedType, ContainerType::value_type> CollectionCopyType;
V tomto příkladu můžete použít vlastní GenericCopy
třídu definovanou v VCUE_Copy.h a VCUE_CopyString.h z ukázky ATLCollections . Tuto třídu můžete použít v jiném kódu, ale možná budete muset definovat další specializace pro podporu datových GenericCopy
typů používaných ve vlastních kolekcích. Další informace naleznete v tématu ATL Copy Policy Classes.
Vytváření typedefs pro výčet a kolekci
Nyní byly všechny parametry šablony nezbytné pro specializaci CComEnumOnSTL
a ICollectionOnSTLImpl
třídy pro tuto situaci poskytovány ve formě typedefs. Pokud chcete zjednodušit používání specializace, vytvořte další dva typydefy, jak je znázorněno níže:
typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;
Nyní CollectionType
je synonymem pro specializaci ICollectionOnSTLImpl
, která implementuje IWords
rozhraní definované dříve a poskytuje enumerátor, který podporuje IEnumVARIANT
.
Úprava kódu generovaného průvodcem
Nyní je nutné odvodit CWords
z implementace rozhraní reprezentované CollectionType
typedef místo IWords
, jak je znázorněno níže:
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.
Přidání kódu pro naplnění kolekce
Jedinou věcí, která zůstává, je naplnění vektoru daty. V tomto jednoduchém příkladu můžete do kolekce přidat několik slov v konstruktoru pro třídu:
CWords()
{
m_coll.push_back("this");
m_coll.push_back("is");
m_coll.push_back("a");
m_coll.push_back("test");
}
Teď můžete kód otestovat pomocí klienta podle vašeho výběru.
Viz také
Kolekce a výčty
Ukázka ATLCollections
Třídy zásady kopírování ATL