Freigeben über


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:

Generieren eines neuen einfachen Objekts

Erstellen Sie ein neues Projekt, und stellen Sie sicher, dass das Feld "Attribute" unter "Anwendung Einstellungen" deaktiviert ist. Verwenden Sie das Dialogfeld "KLASSE hinzufügen" und den Assistenten zum Hinzufügen eines einfachen Objekts, um ein einfaches Objekt zu Wordsgenerieren. 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:

  1. Sammlungsschnittstellen sind in der Regel dual, da Automatisierungsclients über IDispatch::Invokedie _NewEnum Eigenschaft zugreifen. Automatisierungsclients können jedoch über die vtable auf die Neu-Standard methoden zugreifen, sodass duale Schnittstellen bevorzugt werden, um Dispinterfaces zu erreichen.

  2. 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.

  3. 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.)

  4. 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.

  5. 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.

  6. 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 wieder Standard ist, 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