Implementieren einer auf der C++-Standardbibliothek basierten Auflistung
ATL bietet die Schnittstelle, mit der ICollectionOnSTLImpl
Sie schnell C++-Standardbibliotheksbasierte Sammlungsschnittstellen für Ihre Objekte implementieren können. Um zu verstehen, wie diese Klasse funktioniert, werden Sie ein einfaches Beispiel (unten) durcharbeiten, das diese Klasse verwendet, um eine schreibgeschützte Auflistung für Automatisierungsclients zu implementieren.
Der Beispielcode stammt aus dem ATLCollections-Beispiel.
Um dieses Verfahren abzuschließen, gehen Sie wie folgt vor:
Bearbeiten Sie die IDL-Datei für die generierte Schnittstelle.
Erstellen Sie fünf Typedefs , die beschreiben, wie die Sammlungselemente gespeichert werden und wie sie über COM-Schnittstellen für Clients verfügbar gemacht werden.
Erstellen Sie Typedefs für die Enumerations- und Sammlungsimplementierungen.
Bearbeiten Sie den vom Assistenten generierten C++-Code, um den Sammlungstyp zu verwenden.
Generieren eines neuen einfachen Objekts
Erstellen Sie ein neues Projekt, und stellen Sie sicher, dass das Feld "Attribute" unter "Anwendungseinstellungen" deaktiviert ist. Verwenden Sie das Dialogfeld "KLASSE hinzufügen" und den Assistenten zum Hinzufügen eines einfachen Objekts, um ein einfaches Objekt zu Words
generieren. Stellen Sie sicher, dass eine aufgerufene duale Schnittstelle IWords
generiert wird. Objekte der generierten Klasse werden verwendet, um eine Auflistung von Wörtern (d. b. Zeichenfolgen) darzustellen.
Bearbeiten der IDL-Datei
Öffnen Sie nun die IDL-Datei, und fügen Sie die drei Eigenschaften hinzu, die erforderlich sind, um eine schreibgeschützte Sammlungsschnittstelle zu erstellen IWords
, wie unten dargestellt:
[
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);
};
Dies ist das Standardformular für eine schreibgeschützte Sammlungsschnittstelle, die mit Automatisierungsclients entworfen wurde. Die nummerierten Kommentare in dieser Schnittstellendefinition entsprechen den kommentaren unten:
Sammlungsschnittstellen sind in der Regel dual, da Automatisierungsclients über
IDispatch::Invoke
die_NewEnum
Eigenschaft zugreifen. Automatisierungsclients können jedoch über die vtable auf die übrigen Methoden zugreifen, sodass duale Schnittstellen den Dispinterfaces vorzuziehen sind.Wenn eine duale Schnittstelle oder dispinterface zur Laufzeit nicht erweitert wird (d. h., Sie stellen keine zusätzlichen Methoden oder Eigenschaften über
IDispatch::Invoke
), sollten Sie das nonextensible Attribut auf Ihre Definition anwenden. Mit diesem Attribut können Automatisierungsclients zur Kompilierungszeit die vollständige Codeüberprüfung durchführen. In diesem Fall sollte die Schnittstelle nicht erweitert werden.Die richtige DISPID ist wichtig, wenn Sie möchten, dass Automatisierungsclients diese Eigenschaft verwenden können. (Beachten Sie, dass in DISPID_NEWENUM nur ein Unterstrich vorhanden ist.)
Sie können einen beliebigen Wert als DISPID der
Item
Eigenschaft angeben. Verwendet in der Regel jedoch DISPID_VALUE,Item
um sie zur Standardeigenschaft der Auflistung zu machen. Dadurch können Automatisierungsclients auf die Eigenschaft verweisen, ohne sie explizit zu benennen.Der datentyp, der für den Rückgabewert der
Item
Eigenschaft verwendet wird, ist der Typ des elements, das in der Sammlung gespeichert ist, soweit COM-Clients betroffen sind. Die Schnittstelle gibt Zeichenfolgen zurück, daher sollten Sie den standardmäßigen COM-Zeichenfolgentyp BSTR verwenden. Sie können die Daten intern in einem anderen Format speichern, da sie in Kürze angezeigt werden.Der für die DISPID der
Count
Eigenschaft verwendete Wert ist völlig willkürlich. Für diese Eigenschaft gibt es keine Standard-DISPID.
Erstellen von Typedefs für Speicher und Belichtung
Nachdem die Sammlungsschnittstelle definiert wurde, müssen Sie entscheiden, wie die Daten gespeichert werden sollen und wie die Daten über den Enumerator verfügbar gemacht werden.
Die Antworten auf diese Fragen können in Form einer Reihe von Typedefs bereitgestellt werden, die Sie am oberen Rand der Headerdatei für Ihre neu erstellte Klasse hinzufügen können:
// 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;
In diesem Fall speichern Sie die Daten als std::vector von std::strings. std::vector ist eine C++-Standardbibliothek-Containerklasse, die sich wie ein verwaltetes Array verhält. std::string ist die Zeichenfolgenklasse der C++-Standardbibliothek. Diese Klassen erleichtern das Arbeiten mit einer Sammlung von Zeichenfolgen.
Da die Visual Basic-Unterstützung für den Erfolg dieser Schnittstelle von entscheidender Bedeutung ist, muss der von der _NewEnum
Eigenschaft zurückgegebene Enumerator die IEnumVARIANT
Schnittstelle unterstützen. Dies ist die einzige Enumeratorschnittstelle, die von Visual Basic verstanden wird.
Erstellen von Typedefs für Kopierrichtlinienklassen
Die typedefs, die Sie bisher erstellt haben, stellen alle Informationen bereit, die Sie zum Erstellen weiterer Typedefs für die Kopierklassen benötigen, die von der Enumeration und Sammlung verwendet werden:
// Typedef the copy classes using existing typedefs
typedef VCUE::GenericCopy<EnumeratorExposedType, ContainerType::value_type> EnumeratorCopyType;
typedef VCUE::GenericCopy<CollectionExposedType, ContainerType::value_type> CollectionCopyType;
In diesem Beispiel können Sie die in VCUE_Copy.h und VCUE_CopyString.h definierte benutzerdefinierte GenericCopy
Klasse aus dem ATLCollections-Beispiel verwenden. Sie können diese Klasse in einem anderen Code verwenden, aber Möglicherweise müssen Sie weitere Spezialisierungen definieren, um Datentypen GenericCopy
zu unterstützen, die in Ihren eigenen Sammlungen verwendet werden. Weitere Informationen finden Sie unter ATL Copy Policy Classes.
Erstellen von Typedefs für Enumeration und Sammlung
Nun wurden alle Vorlagenparameter bereitgestellt, die erforderlich sind, um die CComEnumOnSTL
Klassen ICollectionOnSTLImpl
für diese Situation in Form von Typedefs zu spezialisieren. Um die Verwendung der Spezialisierungen zu vereinfachen, erstellen Sie zwei weitere Typedefs wie unten dargestellt:
typedef CComEnumOnSTL< EnumeratorInterface, &__uuidof(EnumeratorInterface), EnumeratorExposedType, EnumeratorCopyType, ContainerType > EnumeratorType;
typedef ICollectionOnSTLImpl< CollectionInterface, ContainerType, CollectionExposedType, CollectionCopyType, EnumeratorType > CollectionType;
Jetzt CollectionType
ist ein Synonym für eine Spezialisierung, die ICollectionOnSTLImpl
die IWords
zuvor definierte Schnittstelle implementiert und einen Enumerator bereitstellt, der unterstützt IEnumVARIANT
.
Bearbeiten des vom Assistenten generierten Codes
Jetzt müssen Sie von der Schnittstellenimplementierung abgeleitet werden CWords
, die durch den CollectionType
Typedef dargestellt wird, anstatt IWords
, wie unten dargestellt:
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.
Hinzufügen von Code zum Auffüllen der Auflistung
Das einzige, was übrig bleibt, besteht darin, den Vektor mit Daten aufzufüllen. In diesem einfachen Beispiel können Sie der Auflistung im Konstruktor für die Klasse ein paar Wörter hinzufügen:
CWords()
{
m_coll.push_back("this");
m_coll.push_back("is");
m_coll.push_back("a");
m_coll.push_back("test");
}
Jetzt können Sie den Code mit dem Client Ihrer Wahl testen.
Siehe auch
Sammlungen und Enumeratoren
ATLCollections-Beispiel
ATL-Kopierrichtlinienklasse