Freigeben über


Debugger-Datenmodell-C++-Konzepte

In diesem Thema werden Konzepte im Debugger-C++-Datenmodell beschrieben.

Konzepte im Datenmodell

Synthetische Objekte im Datenmodell sind effektiv zwei Dinge:

  • Ein Wörterbuch mit Schlüssel-/Wert-/Metadaten-Tupeln.
  • Eine Reihe von Konzepten (Schnittstellen), die vom Datenmodell unterstützt werden. Konzepte sind Schnittstellen, die ein Client (im Gegensatz zum Datenmodell) implementiert, um einen bestimmten Satz semantischer Verhaltensweisen bereitzustellen. Die derzeit unterstützten Konzepte sind hier aufgeführt.
Konzeptschnittstelle Beschreibung
IDataModelConcept Das Konzept ist ein übergeordnetes Modell. Wenn dieses Modell über eine registrierte Typsignatur automatisch an einen nativen Typ angehängt ist, wird die Methode InitializeObject automatisch jedes Mal aufgerufen, wenn ein neues Objekt dieses Typs instanziiert wird.
IStringDisplayableConcept Das Objekt kann zu Anzeigezwecken in eine Zeichenfolge umgewandelt werden.
IIterableConcept Das Objekt ist ein Container und kann iteriert werden.
IIndexableConcept Das Objekt ist ein Container und kann in einer oder mehreren Dimensionen indiziert werden (Zugriff über wahlfreien Zugriff).
IPreferredRuntimeTypeConcept Das Objekt versteht mehr über die von ihm abgeleiteten Typen, als das zugrunde liegende Typsystem bereitstellen kann, und möchte seine eigenen Konvertierungen von statischen in Runtime-Typen vornehmen.
IDynamicKeyProviderConcept Das Objekt ist ein dynamischer Schlüsselanbieter und möchte alle Abfragen von Schlüsseln aus dem Core-Datenmodell übernehmen. Diese Schnittstelle wird normalerweise als Brücke zu dynamischen Sprachen wie JavaScript verwendet.
IDynamicConceptProviderConcept Das Objekt ist ein dynamischer Anbieter von Konzepten und möchte alle Konzeptabfragen aus dem Core-Datenmodell übernehmen. Diese Schnittstelle wird normalerweise als Brücke zu dynamischen Sprachen wie JavaScript verwendet.

Das Datenmodellkonzept: IDataModelConcept

Jedes Modellobjekt, das einem anderen Modellobjekt als übergeordnetes Modell zugeordnet ist, muss das Datenmodellkonzept direkt unterstützen. Das Datenmodellkonzept erfordert die Unterstützung einer Schnittstelle, IDataModelConcept definiert wie folgt.

DECLARE_INTERFACE_(IDataModelConcept, IUnknown)
{
    STDMETHOD(InitializeObject)(_In_ IModelObject* modelObject, _In_opt_ IDebugHostTypeSignature* matchingTypeSignature, _In_opt_ IDebugHostSymbolEnumerator* wildcardMatches) PURE;
    STDMETHOD(GetName)(_Out_ BSTR* modelName) PURE;
}

InitializeObject

Ein Datenmodell kann als kanonischer Visualizer oder als Erweiterung für einen bestimmten systemeigenen Typ über die Methoden RegisterModelForTypeSignature oder RegisterExtensionForTypeSignature registriert werden. Wenn ein Modell über eine dieser Methoden registriert wird, wird das Datenmodell automatisch als übergeordnetes Modell an jedes systemeigene Objekt angefügt, dessen Typ mit der in der Registrierung übergebenen Signatur übereinstimmt. An der Stelle, an der diese Anlage automatisch erstellt wird, wird die InitializeObject-Methode für das Datenmodell aufgerufen. Ihm werden das Instanzobjekt, die Typsignatur, die die Anfügung verursacht hat, und ein Enumerator übergeben, der die Typinstanzen (in linearer Reihenfolge) erzeugt, die mit allen Platzhaltern in der Typsignatur übereinstimmen. Die Datenmodellimplementierung kann diesen Methodenaufruf verwenden, um alle benötigten Caches zu initialisieren.

GetName

Wenn ein angegebenes Datenmodell unter einem Standardnamen über die RegisterNamedModel-Methode registriert ist, muss die IDataModelConcept-Schnittstelle des registrierten Datenmodells diesen Namen von dieser Methode zurückgeben. Beachten Sie, dass es vollkommen legitim ist, dass ein Modell unter mehreren Namen registriert wird (der Standardwert oder die beste sollte hier zurückgegeben werden). Ein Modell kann vollständig unbenannt sein (solange es nicht unter einem Namen registriert ist). Unter solchen Umständen sollte die GetName-Methode E_NOTIMPL zurückgeben.

Das String Displayable-Konzept: IStringDisplayableConcept

Ein Objekt, das eine Zeichenfolgenkonvertierung für Anzeigezwecke bereitstellen möchte, kann das Zeichenfolgenanzeigekonzept durch Implementierung der IStringDisplayableConcept-Schnittstelle implementieren. Die Schnittstelle wird wie folgt definiert:

DECLARE_INTERFACE_(IStringDisplayableConcept, IUnknown)
{
    STDMETHOD(ToDisplayString)(_In_ IModelObject* contextObject, _In_opt_ IKeyStore* metadata, _Out_ BSTR* displayString) PURE;
}

ToDisplayString

Die ToDisplayString-Methode wird immer aufgerufen, wenn ein Client ein Objekt in eine anzuzeigende Zeichenfolge (in Konsole, in der Benutzeroberfläche usw.) konvertieren möchte. Eine solche Zeichenfolgenkonvertierung sollte nicht für die Grundlage zusätzlicher programmgesteuerter Manipulationen verwendet werden. Die Zeichenfolgenkonvertierung selbst kann durch die an den Aufruf übergebenen Metadaten tief beeinflusst werden. Bei einer Zeichenfolgenkonvertierung sollte jeder Versuch unternommen werden, die Schlüssel "PreferredRadix" und "PreferredFormat" zu berücksichtigen.

Das iterable Konzept: IIterableConcept und IModelIterator

Ein Objekt, das ein Container anderer Objekte ist und die Fähigkeit zum Durchlaufen dieser enthaltenen Objekte ausdrücken möchte, kann das iterierbare Konzept durch eine Implementierung der IIterableConcept- und IModelIterator-Schnittstellen unterstützen. Es gibt eine sehr wichtige Beziehung zwischen der Unterstützung des iterierbaren Konzepts und der Unterstützung des indizierbaren Konzepts. Ein Objekt, das den zufälligen Zugriff auf die enthaltenen Objekte unterstützt, kann das indizierbare Konzept zusätzlich zum iterierbaren Konzept unterstützen. In diesem Fall müssen die iterierten Elemente auch einen Standardindex erzeugen, der beim Übergeben an das indizierbare Konzept auf dasselbe Objekt verweist. Ein Fehler bei der Erfüllung dieser Invariante führt zum nicht definierten Verhalten im Debughost.

Das IIterableConcept wird wie folgt definiert:

DECLARE_INTERFACE_(IIterableConcept, IUnknown)
{
    STDMETHOD(GetDefaultIndexDimensionality)(_In_ IModelObject* contextObject, _Out_ ULONG64* dimensionality) PURE;
    STDMETHOD(GetIterator)(_In_ IModelObject* contextObject, _Out_ IModelIterator** iterator) PURE;
}

Das IModelIterator-Konzept ist wie folgt definiert:

DECLARE_INTERFACE_(IModelIterator, IUnknown)
{
   STDMETHOD(Reset)() PURE;
   STDMETHOD(GetNext)(_COM_Errorptr_ IModelObject** object, _In_ ULONG64 dimensions, _Out_writes_opt_(dimensions) IModelObject** indexers, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
}

IIterableConcepts GetDefaultIndexDimensionality

Die GetDefaultIndexDimensionality-Methode gibt die Anzahl der Dimensionen an den Standardindex zurück. Wenn ein Objekt nicht indiziert werden kann, sollte diese Methode 0 zurückgeben und erfolgreich (S_OK). Jedes Objekt, das einen Wert ungleich Null aus dieser Methode zurückgibt, deklariert die Unterstützung für einen Protokollvertrag, der folgendes angibt:

  • Das Objekt unterstützt das indizierbare Konzept durch Unterstützung von IIndexableConcept.
  • Die GetNext-Methode des von der GetIterator-Methode des iterablen Konzepts zurückgegebenen IModelIterator-Methode gibt einen eindeutigen Standardindex für jedes produzierte Element zurück. Dieser Index hat die Anzahl der Dimensionen, wie hier angegeben.
  • Wenn die von der GetNext-Methode des IModelIterator zurückgegebenen Indizes an die GetAt-Methode für das indizierbare Konzept (IIndexableConcept) übergeben werden, wird auf dasselbe Objekt verwiesen, das von GetNext erzeugt wurde. Der leiche Wert von wird zurückgegeben.

IIterableConcept GetIterator

Die GetIterator-Methode für das iterierbare Konzept gibt eine Iteratorschnittstelle zurück, die zum Durchlaufen des Objekts verwendet werden kann. Der zurückgegebene Iterator muss sich an das Kontextobjekt erinnern, das an die GetIterator-Methode übergeben wurde. Sie wird nicht an Methoden für den Iterator selbst übergeben.

IModelIterator zurücksetzen

Die Reset-Methode für einen Iterator, der vom iterierbaren Konzept zurückgegeben wird, stellt die Position des Iterators wieder her, an der es war, als der Iterator zum ersten Mal erstellt wurde (vor dem ersten Element). Es wird zwar dringend empfohlen, die Reset-Methode von Iterator zu unterstützen, es ist jedoch nicht erforderlich. Ein Iterator kann das Äquivalent eines C++-Eingabe-Iterators sein und nur einen einzelnen Durchlauf der Vorwärtsiteration zulassen. In diesem Fall kann die Reset-Methode mit E_NOTIMPL fehlschlagen.

IModelIterator GetNext

Die GetNext-Methode verschiebt den Iterator vorwärts und ruft das nächste iterierte Element ab. Wenn das Objekt nicht nur iterierbar, sondern auch indizierbar ist und dies durch das Argument GetDefaultIndexDimensionality angezeigt wird, das einen Wert ungleich Null zurückgibt, kann diese Methode optional die Standardindizes zurückgeben, um zum vom Indexer erzeugten Wert zurückzukehren. Beachten Sie, dass ein Aufrufer wählen kann, 0/nullptr zu übergeben und keine Indizes abzurufen. Es gilt als illegal, dass der Aufrufer Teilindizes anfordert (z. B.: kleiner als die von GetDefaultIndexDimensionality erzeugte Zahl).

Wenn der Iterator erfolgreich vorwärts verschoben wurde, aber beim Lesen des Werts des iterierten Elements ein Fehler aufgetreten ist, gibt die Methode möglicherweise einen Fehler UND das Füllzeichen "Objekt" mit einem Fehlerobjekt zurück. Am Ende der Iteration der enthaltenen Elemente gibt der Iterator E_BOUNDS aus der GetNext-Methode zurück. Jeder nachfolgende Aufruf (sofern nicht zuvor ein Reset-Aufruf erfolgt ist) gibt ebenfalls E_BOUNDS zurück.

Das indizierbare Konzept: IIndexableConcept

Ein Objekt, das zufälligen Zugriff auf eine Gruppe von Inhalten ermöglichen möchte, kann das indizierbare Konzept über die Unterstützung der IIndexableConcept-Schnittstelle unterstützen. Die meisten Objekte, die indiziert werden können, werden auch durch Unterstützung des iterierbaren Konzepts iterierbar sein. Dies ist jedoch nicht erforderlich. Wenn dies unterstützt wird, gibt es eine wichtige Beziehung zwischen iterator und Indexer. Der Iterator muss die GetDefaultIndexDimensionality unterstützen, einen Wert ungleich Null aus dieser Methode zurückgeben und den dort dokumentierten Vertrag unterstützen. Die Indexer-Konzeptschnittstelle ist wie folgt definiert:

DECLARE_INTERFACE_(IIndexableConcept, IUnknown)
{
    STDMETHOD(GetDimensionality)(_In_ IModelObject* contextObject, _Out_ ULONG64* dimensionality) PURE;
    STDMETHOD(GetAt)(_In_ IModelObject* contextObject, _In_ ULONG64 indexerCount, _In_reads_(indexerCount) IModelObject** indexers, _COM_Errorptr_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(SetAt)(_In_ IModelObject* contextObject, _In_ ULONG64 indexerCount, _In_reads_(indexerCount) IModelObject** indexers, _In_ IModelObject *value) PURE;
}

Nachfolgend sehen Sie ein Beispiel für die Verwendung des Indexers (und dessen Zusammenspiel mit dem Iterator). In diesem Beispiel wird der Inhalt eines indizierbaren Containers durchlaufen und der Indexer verwendet, um zum soeben zurückgegebenen Wert zurückzukehren. Während dieser Vorgang funktionell nutzlos wie geschrieben ist, wird gezeigt, wie diese Schnittstellen interagieren. Beachten Sie, dass im folgenden Beispiel kein Speicherzuweisungsfehler auftritt. Dabei wird ein „Throwing new“ angenommen (was je nach Umgebung, in der der Code existiert, eine falsche Annahme sein kann – die COM-Methoden des Datenmodells können nicht durch C++-Ausnahmen entkommen):

ComPtr<IModelObject> spObject;

//
// Assume we have gotten some object in spObject that is iterable (e.g.: an object which represents a std::vector<SOMESTRUCT>)
//
ComPtr<IIterableConcept> spIterable;
ComPtr<IIndexableConcept> spIndexer;
if (SUCCEEDED(spObject->GetConcept(__uuidof(IIterableConcept), &spIterable, nullptr)) &&
    SUCCEEDED(spObject->GetConcept(__uuidof(IIndexableConcept), &spIndexable, nullptr)))
{
    ComPtr<IModelIterator> spIterator;

    //
    // Determine how many dimensions the default indexer is and allocate the requisite buffer.
    //
    ULONG64 dimensions;
    if (SUCCEEDED(spIterable->GetDefaultIndexDimensionality(spObject.Get(), &dimensions)) && dimensions > 0 &&
        SUCCEEDED(spIterable->GetIterator(spObject.Get(), &spIterator)))
    {
        std::unique_ptr<ComPtr<IModelObject>[]> spIndexers(new ComPtr<IModelObject>[dimensions]);

        //
        // We have an iterator.  Error codes have semantic meaning here.  E_BOUNDS indicates the end of iteration.  E_ABORT indicates that
        // the debugger host or application is trying to abort whatever operation is occurring.  Anything else indicates
        // some other error (e.g.: memory read failure) where the iterator MIGHT still produce values.
        //
        for(;;)
        {
            ComPtr<IModelObject> spContainedStruct;
            ComPtr<IKeyStore> spContainedMetadata;

            //
            // When we fetch the value from the iterator, it will pass back the default indices.
            //
            HRESULT hr = spIterable->GetNext(&spContainedStruct, dimensions, reinterpret_cast<IModelObject **>(spIndexers.get()), &spContainedMetadata);
            if (hr == E_BOUNDS || hr == E_ABORT)
            {
                break;
            }

            if (FAILED(hr))
            {
                //
                // Decide how to deal with failure to fetch an element.  Note that spContainedStruct *MAY* contain an error object
                // which has detailed information about why the failure occurred (e.g.: failure to read memory at address X).
                //
            }

            //
            // Use the indexer to get back to the same value.  We already have them, so there isn't much functional point to this.  It simply
            // highlights the interplay between iterator and indexer.
            //
            ComPtr<IModelObject> spIndexedStruct;
            ComPtr<IKeyStore> spIndexedMetadata;

            if (SUCCEEDED(spIndexer->GetAt(spObject.Get(), dimensions, reinterpret_cast<IModelObject **>(spIndexers.get()), &spIndexedStruct, &spIndexedMetadata)))
            {
                //
                // spContainedStruct and spIndexedStruct refer to the same object.  They may not have interface equality.
                // spContainedMetadata and spIndexedMetadata refer to the same metadata store with the same contents.  They may not have interface equality.
                //
            }
        }
    }
}

GetDimensionality

Die GetDimensionality-Methode gibt die Anzahl der Dimensionen zurück, in denen das Objekt indiziert ist. Beachten Sie, dass, wenn das Objekt sowohl iterierbar als auch indizierbar ist, die Implementierung von GetDefaultIndexDimensionality hinsichtlich der Anzahl der Dimensionen des Indexers mit der Implementierung von GetDimensionality übereinstimmen muss.

GetAt

Die GetAt-Methode ruft den Wert bei einem bestimmten N-dimensionalen Index aus dem indizierten Objekt ab. Ein Indexer von N-Dimensionen, wobei N der von GetDimensionality zurückgegebene Wert ist, muss unterstützt werden. Beachten Sie, dass ein Objekt in verschiedenen Domänen durch unterschiedliche Typen indiziert werden kann (z. B. sowohl über Ordinalzahlen als auch über Zeichenfolgen indiziert werden kann). Wenn sich der Index außerhalb des Bereichs befindet (oder nicht darauf zugegriffen werden konnte), gibt die Methode einen Fehler zurück. In solchen Fällen kann das Ausgabeobjekt jedoch weiterhin auf ein Fehlerobjekt festgelegt werden.

SetAt

Die SetAt-Methode versucht, den Wert auf einen bestimmten N-dimensionalen Index innerhalb des indizierten Objekts festzulegen. Ein Indexer von N-Dimensionen, wobei N der von GetDimensionality zurückgegebene Wert ist, muss unterstützt werden. Beachten Sie, dass ein Objekt in verschiedenen Domänen durch unterschiedliche Typen indiziert werden kann (z. B. sowohl über Ordinalzahlen als auch über Zeichenfolgen indiziert werden kann). Einige Indexer sind schreibgeschützt. In solchen Fällen wird E_NOTIMPL von jedem Aufruf der SetAt-Methode zurückgegeben.

Das bevorzugte Laufzeittypkonzept: IPreferredRuntimeTypeConcept

Ein Debughost kann abgefragt werden, um zu versuchen, den realen Laufzeittyp eines Objekts aus einem statischen Typ zu ermitteln, der in symbolischen Informationen enthalten ist. Diese Konvertierung kann auf vollständig genauen Informationen (z. B. C++ RTTI) basieren oder auf starken Heuristiken wie der Form aller virtuellen Funktionstabellen innerhalb des Objekts basieren. Einige Objekte können jedoch nicht von einer statischen in einen Laufzeittyp konvertiert werden, da sie nicht in die Heuristik des Debughosts passen (z. B.: sie haben keine RTTI- oder virtuellen Funktionstabellen). In solchen Fällen kann ein Datenmodell für ein Objekt das Standardverhalten überschreiben und erklären, dass es mehr über den „Laufzeittyp“ eines Objekts weiß, als der Debug-Host verstehen kann. Dies erfolgt über das bevorzugte Laufzeittypkonzept und die Unterstützung der IPreferredRuntimeTypeConcept-Schnittstelle.

Die IPreferredRuntimeTypeConcept-Schnittstelle wird wie folgt deklariert:

DECLARE_INTERFACE_(IPreferredRuntimeTypeConcept, IUnknown)
{
    STDMETHOD(CastToPreferredRuntimeType)(_In_ IModelObject* contextObject, _COM_Errorptr_ IModelObject** object) PURE;
}

CastToPreferredRuntimeType

Die CastToPreferredRuntimeType-Methode wird immer aufgerufen, wenn ein Client versuchen möchte, von einer statischen Typinstanz in den Laufzeittyp dieser Instanz zu konvertieren. Wenn das betreffende Objekt (über eines seiner angefügten übergeordneten Modelle) das bevorzugte Laufzeittypkonzept unterstützt, wird diese Methode aufgerufen, um die Konvertierung auszuführen. Diese Methode kann entweder das Originalobjekt zurückgeben (es gibt keine Konvertierung oder es konnte nicht analysiert werden), eine neue Instanz des Laufzeittyps zurückgeben, aus nicht semantischen Gründen fehlschlagen (z. B.: nicht genügend Arbeitsspeicher) oder E_NOT_SET zurückgeben. Der Fehlercode E_NOT_SET ist ein ganz spezieller Fehlercode, der dem Datenmodell anzeigt, dass die Implementierung das Standardverhalten nicht überschreiben möchte und dass das Datenmodell auf die vom Debug-Host durchgeführte Analyse zurückgreifen soll (z. B. RTTI-Analyse, Prüfung der Form der virtuellen Funktionstabellen usw.).

Die dynamischen Providerkonzepte: IDynamicKeyProviderConcept und IDynamicConceptProviderConcept

Während das Datenmodell selbst normalerweise die Schlüssel- und Konzeptverwaltung für Objekte übernimmt, gibt es Fälle, in denen diese Vorgehensweise nicht optimal ist. Insbesondere, wenn ein Kunde eine Brücke zwischen dem Datenmodell und etwas anderes erstellen möchte, das wirklich dynamisch ist (z. B. JavaScript), kann es hilfreich sein, die Schlüssel- und Konzeptverwaltung von der Implementierung im Datenmodell zu übernehmen. Da das Kerndatenmodell die einzige Implementierung von IModelObject ist, erfolgt dies stattdessen über eine Kombination aus zwei Konzepten: dem dynamischen Schlüsselanbieter-Konzept und dem dynamischen Konzeptanbieter-Konzept. Obwohl es typisch wäre, beide oder keines zu implementieren, besteht keine Anforderung dafür.

Wenn beide implementiert sind, muss das dynamische Schlüsselanbieter-Konzept vor dem dynamischen Konzeptanbieter-Konzept hinzugefügt werden. Beide Konzepte sind besonders. Sie kippen effektiv einen Schalter auf dem Objekt, der ihn von "statisch verwaltet" in "dynamisch verwaltet" ändert. Diese Konzepte können nur festgelegt werden, wenn es keine Schlüssel/Konzepte gibt, die vom Datenmodell für das Objekt verwaltet werden. Sobald diese Konzepte einem Objekt hinzugefügt wurden, ist diese Aktion unwiderruflich.

Es gibt einen weiteren semantischen Unterschied hinsichtlich der Erweiterbarkeit zwischen einem IModelObject, das ein dynamischer Konzeptanbieter ist, und einem, das dies nicht ist. Diese Konzepte sollen es Clients ermöglichen, Brücken zwischen dem Datenmodell und dynamischen Sprachsystemen wie JavaScript zu schlagen. Das Datenmodell hat ein Konzept der Erweiterbarkeit, das sich grundlegend von Systemen wie JavaScript unterscheidet, da es eine Struktur von übergeordneten Modellen anstelle einer linearen Kette wie der JavaScript-Prototypkette gibt. Um eine bessere Beziehung zu solchen Systemen zu ermöglichen, verfügt ein IModelObject, das ein dynamischer Konzeptanbieter ist, über ein einzelnes übergeordnetes Datenmodell. Dieses übergeordnete Einzelne Datenmodell ist ein normales IModelObject, das eine beliebige Anzahl von übergeordneten Modellen aufweisen kann, wie für das Datenmodell typisch ist. Alle Anfragen an den dynamischen Konzeptanbieter zum Hinzufügen oder Entfernen von Übergeordneten werden automatisch an den einzelnen Übergeordneten weitergeleitet. Von außen betrachtet sieht es so aus, als ob der dynamische Konzeptanbieter über eine normale baumartige Kette von übergeordneten Modellen verfügt. Der Implementierer des Konzepts des dynamischen Konzeptanbieters ist das einzige Objekt (außerhalb des Kerndatenmodells), das sich der übergeordneten Zwischenstufe bewusst ist. Dieses einzelne übergeordnete Element kann mit dem dynamischen Sprachsystem verknüpft werden, um eine Brücke bereitzustellen (z. B. in die JavaScript-Prototypkette platziert).

Das Konzept des dynamischen Schlüsselanbieters wird wie folgt definiert:

DECLARE_INTERFACE_(IDynamicKeyProviderConcept, IUnknown)
{
    STDMETHOD(GetKey)(_In_ IModelObject *contextObject, _In_ PCWSTR key, _COM_Outptr_opt_result_maybenull_ IModelObject** keyValue, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata, _Out_opt_ bool *hasKey) PURE;
    STDMETHOD(SetKey)(_In_ IModelObject *contextObject, _In_ PCWSTR key, _In_ IModelObject *keyValue, _In_ IKeyStore *metadata) PURE;
    STDMETHOD(EnumerateKeys)(_In_ IModelObject *contextObject, _COM_Outptr_ IKeyEnumerator **ppEnumerator) PURE;
}

Das Konzept des dynamischen Konzeptanbieters wird wie folgt definiert:

DECLARE_INTERFACE_(IDynamicConceptProviderConcept, IUnknown)
{
    STDMETHOD(GetConcept)(_In_ IModelObject *contextObject, _In_ REFIID conceptId, _COM_Outptr_result_maybenull_ IUnknown **conceptInterface, _COM_Outptr_opt_result_maybenull_ IKeyStore **conceptMetadata, _Out_ bool *hasConcept) PURE;
    STDMETHOD(SetConcept)(_In_ IModelObject *contextObject, _In_ REFIID conceptId, _In_ IUnknown *conceptInterface, _In_opt_ IKeyStore *conceptMetadata) PURE;
    STDMETHOD(NotifyParent)(_In_ IModelObject *parentModel) PURE;
    STDMETHOD(NotifyParentChange)(_In_ IModelObject *parentModel) PURE;
    STDMETHOD(NotifyDestruct)() PURE;
}

IDynamicKeyProviderConcept's GetKey

Die GetKey-Methode für einen dynamischen Schlüsselanbieter ist weitgehend eine Außerkraftsetzung der GetKey-Methode für IModelObject. Vom dynamischen Schlüsselanbieter wird erwartet, dass er den Wert des Schlüssels und alle mit diesem Schlüssel verknüpften Metadaten zurückgibt. Wenn der Schlüssel nicht vorhanden ist (aber kein anderer Fehler auftritt), muss der Anbieter "false" im hasKey-Parameter zurückgeben und mit S_OK erfolgreich sein. Wenn dieser Aufruf fehlschlägt, wird ein Fehler beim Abrufen eines Schlüssels betrachtet und die Suche nach dem Schlüssel über die übergeordnete Modellkette explizit angehalten. Wenn "false" in hasKey zurückgegeben wird, wird die Suche nach dem Schlüssel fortgesetzt. Beachten Sie, dass es für GetKey völlig zulässig ist, einen Boxed-Property-Accessor als Schlüssel zurückzugeben. Dies wäre semantisch identisch mit der GetKey-Methode von IModelObject, die einen Eigenschaftenaccessor zurückgibt.

IDynamicKeyProviderConcept's SetKey

Die SetKey-Methode für einen dynamischen Schlüsselanbieter ist effektiv eine Außerkraftsetzung der SetKey-Methode für IModelObject. Dadurch wird ein Schlüssel im dynamischen Anbieter festgelegt. Es ist effektiv die Schaffung einer neuen Eigenschaft auf dem Anbieter. Beachten Sie, dass ein Anbieter, der keine Vorstellung von etwas wie der Erstellung von expando-Eigenschaften unterstützt, hier E_NOTIMPL zurückgeben sollte.

IDynamicKeyProviderConcept's EnumerateKeys

Die EnumerateKeys-Methode für einen dynamischen Schlüsselanbieter ist effektiv eine Außerkraftsetzung der EnumerateKeys-Methode auf IModelObject. Dadurch werden alle Schlüssel im dynamischen Anbieter aufgelistet. Der zurückgegebene Enumerator hat mehrere Einschränkungen, die von der Implementierung berücksichtigt werden müssen:

  • Er muss sich als Aufruf von EnumerateKeys und nicht als EnumerateKeyValues oder EnumerateKeyReferences verhalten. Er muss die Schlüsselwerte zurückgeben, die keine zugrunde liegenden Eigenschaftsaccessoren auflösen (sofern ein solches Konzept im Anbieter vorhanden ist).
  • Aus Sicht eines einzelnen dynamischen Schlüsselanbieters ist es unzulässig, mehrere Schlüssel mit demselben Namen aufzählen zu können, die physisch voneinander getrennt sind. Dies kann bei verschiedenen Anbietern geschehen, die über die übergeordnete Modellkette angefügt sind, aber nicht aus Sicht eines einzelnen Anbieters geschehen.

IDynamicConceptProviderConcept's GetConcept

Die GetConcept-Methode für einen dynamischen Konzeptanbieter ist effektiv eine Außerkraftsetzung der GetConcept-Methode auf IModelObject. Der dynamische Konzeptanbieter muss eine Schnittstelle für das abgefragte Konzept zurückgeben, sofern es vorhanden ist, sowie alle Metadaten, die diesem Konzept zugeordnet sind. Wenn das Konzept für den Anbieter nicht vorhanden ist, muss dies über einen falsch zurückgegebenen Wert im hasConcept-Argument und einer erfolgreichen Rückgabe angegeben werden. Fehler dieser Methode ist ein Fehler beim Abrufen des Konzepts und wird die Suche nach dem Konzept explizit anhalten. Wenn für hasConcept „false“ zurückgegeben wird und der Code erfolgreich ist, wird die Suche nach dem Konzept im übergeordneten Modellbaum fortgesetzt.

IDynamicConceptProviderConcept's SetConcept

Die SetConcept-Methode für einen dynamischen Konzeptanbieter ist effektiv eine Außerkraftsetzung der SetConcept-Methode auf IModelObject. Der dynamische Anbieter weist das Konzept zu. Dies kann dazu führen, dass das Objekt iterierbar, indiziert, Zeichenfolge konvertierbar usw. wird... Beachten Sie, dass ein Anbieter, der die Erstellung von Konzepten nicht zulässt, hier E_NOPTIMPL zurückgeben sollte.

IDynamicConceptProviderConcept's NotifyParent

Der Aufruf „NotifyParent“ eines dynamischen Konzeptanbieters wird vom Kerndatenmodell verwendet, um den dynamischen Anbieter über das einzelne übergeordnete Modell zu informieren, das erstellt wird, um eine Überbrückung des Paradigmas der „mehreren übergeordneten Modelle“ des Datenmodells mit dynamischeren Sprachen zu ermöglichen. Jede Manipulation dieses einzelnen übergeordneten Modells führt zu weiteren Benachrichtigungen an den dynamischen Anbieter. Beachten Sie, dass dieser Rückruf unmittelbar nach Zuweisung des Konzepts des dynamischen Konzeptanbieters erfolgt.

IDynamicConceptProviderConcept's NotifyParentChange

Die NotifyParent-Methode für einen dynamischen Konzeptanbieter ist ein Rückruf des Kerndatenmodells, wenn eine statische Manipulation des einzelnen übergeordneten Modells des Objekts vorgenommen wird. Für jedes hinzugefügte übergeordnete Modell wird diese Methode zum ersten Mal aufgerufen, wenn das übergeordnete Modell hinzugefügt wird, und ein zweites Mal, wenn/wann das übergeordnete Modell entfernt wird.

IDynamicConceptProviderConcept's NotifyDestruct

Die NotifyDestruct-Methode eines dynamischen Konzeptanbieters ist ein Rückruf des Kerndatenmodells zu Beginn der Zerstörung des Objekts, das ein dynamischer Konzeptanbieter ist. Sie bietet zusätzliche sauber Möglichkeiten für Kunden, die sie erfordern.

--

Weitere Informationen

Dieses Thema ist Teil einer Serie, in der die Schnittstellen beschrieben werden, auf die von C++ aus zugegriffen werden kann, und wie man sie verwendet, um eine C++ basierte Debugger-Erweiterung zu erstellen, und wie man andere Datenmodellkonstrukte (z. B. JavaScript oder NatVis) von einer C++ -Datenmodellerweiterung aus nutzen kann.

Debugger Datenmodell C++ – Übersicht

Debugger Datenmodell C++ – Schnittstellen

Debugger-Datenmodell-C++-Objekte

Debugger Datenmodell C++ – Zusätzliche Schnittstellen

Debugger-Datenmodell C++ – Konzepte

Debugger-Datenmodell C++ – Scripting