Debuggerdatenmodell-C++-Konzepte

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

Konzepte im Datenmodell

Synthetische Objekte im Datenmodell sind effektiv zwei Dinge:

  • Ein Wörterbuch mit Schlüssel-Wert-/Metadatentupeln.
  • Eine Reihe von Konzepten (Schnittstellen), die vom Datenmodell unterstützt werden. Konzepte sind Schnittstellen, die ein Client (im Gegensatz zum Datenmodell) implementiert, um einen angegebenen Satz semantischem Verhalten 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 angefügt wird, wird die InitializeObject-Methode automatisch aufgerufen, wenn ein neues Objekt dieses Typs instanziiert wird.
IStringDisplayableConcept Das Objekt kann zu Anzeigezwecken in eine Zeichenfolge konvertiert werden.
IIterableConcept Das Objekt ist ein Container und kann durchlaufen werden.
IIndexableConcept Das Objekt ist ein Container und kann in einer oder mehreren Dimensionen indiziert werden (zugriff per Zufallszugriff).
IPreferredRuntimeTypeConcept Das Objekt versteht mehr über typen, die von ihm abgeleitet werden, als das zugrunde liegende Typsystem bereitstellen kann und möchte seine eigenen Konvertierungen vom statischen in den Laufzeittyp verarbeiten.
IDynamicKeyProviderConcept Das Objekt ist ein dynamischer Anbieter von Schlüsseln und möchte alle Schlüsselabfragen aus dem Kerndatenmodell übernehmen. Diese Schnittstelle wird in der Regel 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 Kerndatenmodell übernehmen. Diese Schnittstelle wird in der Regel als Brücke zu dynamischen Sprachen wie JavaScript verwendet.

Das Datenmodellkonzept: IDataModelConcept

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

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 kanonische Schnellansicht oder als Erweiterung für einen bestimmten nativen Typ über die RegisterModelForTypeSignature- oder RegisterExtensionForTypeSignature-Methoden des Datenmodell-Managers registriert werden. Wenn ein Modell mit einer dieser Methoden registriert wird, wird das Datenmodell automatisch als übergeordnetes Modell an jedes native Objekt angefügt, dessen Typ mit der in der Registrierung übergebenen Signatur übereinstimmt. An dem Punkt, an dem diese Anlage automatisch erstellt wird, wird die InitializeObject-Methode für das Datenmodell aufgerufen. Es wird das instance-Objekt, die Typsignatur, die die Anlage verursacht hat, und ein Enumerator übergeben, der die Typinstanzen (in linearer Reihenfolge) erzeugt, die mit allen Feldhaltern in der Typsignatur übereinstimmen. Die Datenmodellimplementierung kann diesen Methodenaufruf verwenden, um alle benötigten Caches zu initialisieren.

GetName

Wenn ein bestimmtes Datenmodell über die RegisterNamedModel-Methode unter einem Standardnamen registriert wird, 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 (das Standardmodell oder das beste modell sollte hier zurückgegeben werden). Ein Modell kann vollständig unbenannt sein (solange es nicht unter einem Namen registriert ist). In solchen Fällen sollte die GetName-Methode E_NOTIMPL zurückgeben.

Das Konzept zur Anzeige von Zeichenfolgen: IStringDisplayableConcept

Ein Objekt, das eine Zeichenfolgenkonvertierung für Anzeigezwecke bereitstellen möchte, kann das konzept der Zeichenfolgenanzeige 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 dann aufgerufen, wenn ein Client ein Objekt in eine anzuzeigende Zeichenfolge konvertieren möchte (in der Konsole, auf der Benutzeroberfläche usw.). Eine solche Zeichenfolgenkonvertierung sollte nicht für die Grundlage zusätzlicher programmgesteuerter Manipulationen verwendet werden. Die Zeichenfolgenkonvertierung selbst kann stark von den Metadaten beeinflusst werden, die an den Aufruf übergeben werden. Eine Zeichenfolgenkonvertierung sollte jeden Versuch unternehmen, die Schlüssel PreferredRadix und PreferredFormat zu berücksichtigen.

Das Iterable-Konzept: IIterableConcept und IModelIterator

Ein Objekt, das ein Container mit anderen Objekten ist und die Fähigkeit zum Iterieren über diese enthaltenen Objekte ausdrücken möchte, kann das iterierbare Konzept durch eine Implementierung der Schnittstellen IIterableConcept und IModelIterator unterstützen. Es besteht ein sehr wichtiger Zusammenhang 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 bei Übergabe an das indizierbare Konzept auf dasselbe Objekt verweist. Ein Fehler bei der Erfüllung dieser Invariante führt zu einem nicht definierten Verhalten auf dem Debughost.

IIterableConcept ist 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;
}

GetDefaultIndexDimensionality von IIterableConcept

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

  • Das Objekt unterstützt das indizierbare Konzept über die Unterstützung von IIndexableConcept.
  • Die GetNext-Methode des IModelIterators, die von der GetIterator-Methode des iterierbaren Konzepts zurückgegeben wird, gibt einen eindeutigen Standardindex für jedes produzierte Element zurück. Ein solcher Index weist die hier angegebene Anzahl von Dimensionen auf.
  • Wenn Sie die Von der GetNext-Methode des IModelIterator zurückgegebenen Indicies an die GetAt-Methode für das indexierbare Konzept (IIndexableConcept) übergeben, wird auf dasselbe Objekt verwiesen, das Von GetNext erstellt wurde. Der gleiche Wert wird zurückgegeben.

GetIterableConcepts 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 im Iterator selbst übergeben.

Zurücksetzen von IModelIterator

Die Reset-Methode für einen Iterator, der vom Iterable-Konzept zurückgegeben wird, stellt die Position des Iterators an der Stelle wieder her, an der er sich befand, als der Iterator zum ersten Mal erstellt wurde (vor dem ersten Element). Es wird zwar dringend empfohlen, dass der Iterator die Reset-Methode unterstützt, 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 schlägt die Reset-Methode möglicherweise mit E_NOTIMPL fehl.

GetNext von IModelIterator

Die GetNext-Methode verschiebt den Iterator nach vorne und ruft das nächste iterierte Element ab. Wenn das Objekt zusätzlich zu seiner Iterbarkeit indiziert werden kann und dies durch das GetDefaultIndexDimensionality-Argument angegeben wird, das einen Wert ungleich null zurückgibt, kann diese Methode optional die Standardindikationen zurückgeben, um zum erzeugten Wert aus dem Indexer zurückzukehren. Beachten Sie, dass ein Aufrufer auswählen kann, 0/nullptr zu übergeben und keine Indicies abzurufen. Es gilt als illegal, dass der Aufrufer Teilindikationen anzufordern (z. B. kleiner als die von GetDefaultIndexDimensionality erzeugte Zahl).

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

Das indizierbare Konzept: IIndexableConcept

Ein Objekt, das zufälligen Zugriff auf einen Satz von Inhalten ermöglichen möchte, kann das indizierbare Konzept über die Unterstützung der IIndexableConcept-Schnittstelle unterstützen. Die meisten Objekte, die indizierbar sind, sind auch durch die Unterstützung des iterierbaren Konzepts iterierbar. Dies ist jedoch nicht erforderlich. Falls unterstützt, besteht eine wichtige Beziehung zwischen dem Iterator und dem Indexer. Der Iterator muss die GetDefaultIndexDimensionality unterstützen, einen Wert ungleich Null von dieser Methode zurückgeben und den dort dokumentierten Vertrag unterstützen. Die Indexerkonzeptschnittstelle 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;
}

Ein Beispiel für die Verwendung des Indexers (und dessen Zusammenspiel mit dem Iterator) finden Sie unten. In diesem Beispiel wird der Inhalt eines indizierbaren Containers durchlaufen und der Indexer verwendet, um zum soeben zurückgegebenen Wert zurückzukehren. Dieser Vorgang ist zwar wie geschrieben funktional nutzlos, zeigt aber, wie diese Schnittstellen interagieren. Beachten Sie, dass das folgende Beispiel keinen Speicherbelegungsfehler behandelt. Es wird davon ausgegangen, dass ein neues Ausgelöst wird (was abhängig von der Umgebung, in der der Code vorhanden ist, eine schlechte Annahme sein kann - die COM-Methoden des Datenmodells können keine C++-Ausnahmen escape aufweisen):

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 indicies.
            //
            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 die Implementierung von GetDefaultIndexDimensionality mit der Implementierung von GetDimensionality übereinstimmen muss, wenn das Objekt sowohl iterierbar als auch indexierbar ist.

GetAt

Die GetAt-Methode ruft den Wert an 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 nach verschiedenen Typen indiziert werden kann (z. B. über Ordinale und Zeichenfolgen indizierbar). Wenn sich der Index außerhalb des Bereichs befindet (oder nicht 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 nach verschiedenen Typen indiziert werden kann (z. B. über Ordinale und Zeichenfolgen indizierbar). Einige Indexer sind schreibgeschützt. In solchen Fällen wird E_NOTIMPL von jedem Aufruf der SetAt-Methode zurückgegeben.

Das Konzept des bevorzugten Laufzeittyps: IPreferredRuntimeTypeConcept

Ein Debughost kann abgefragt werden, um den tatsächlichen Laufzeittyp eines Objekts anhand eines statischen Typs in symbolischen Informationen zu ermitteln. Diese Konvertierung kann auf vollständig genauen Informationen (z.B. C++ RTTI) basieren oder auf starken Heuristiken wie der Form von virtuellen Funktionstabellen innerhalb des Objekts basieren. Einige Objekte können jedoch nicht von einem statischen in einen Laufzeittyp konvertiert werden, da sie nicht in die Heuristik des Debughosts passen (z. B. keine RTTI- oder virtuellen Funktionstabellen). In solchen Fällen kann ein Datenmodell für ein Objekt das Standardverhalten außer Kraft setzen und deklarieren, dass es mehr über den "Laufzeittyp" eines Objekts weiß, als der Debughost 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 dann aufgerufen, wenn ein Client versuchen möchte, von einem statischen Typ instance in den Laufzeittyp dieses instance 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 durchzuführen. Diese Methode kann entweder das ursprüngliche Objekt zurückgeben (es gibt keine Konvertierung oder es konnte nicht analysiert werden), eine neue instance des Laufzeittyps zurückgeben, aus nicht semantischen Gründen (z. B. nicht genügend Arbeitsspeicher) fehlschlagen oder E_NOT_SET zurückgeben. Der E_NOT_SET Fehlercode ist ein sehr spezieller Fehlercode, der dem Datenmodell angibt, dass die Implementierung das Standardverhalten nicht überschreiben möchte und dass das Datenmodell auf die vom Debughost durchgeführte Analyse zurückgreifen sollte (z. B. RTTI-Analyse, Untersuchung der Form der virtuellen Funktionstabellen, etc...)

Die Konzepte für dynamische Anbieter: IDynamicKeyProviderConcept und IDynamicConceptProviderConcept

Während das Datenmodell selbst normalerweise die Schlüssel- und Konzeptverwaltung für Objekte übernimmt, gibt es Zeiten, in denen dieser Begriff nicht ideal ist. Insbesondere wenn ein Kunde eine Brücke zwischen dem Datenmodell und etwas anderem schaffen 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üsselanbieterkonzept und dem dynamischen Konzeptanbieterkonzept. Es wäre zwar üblich, beides oder keines zu implementieren, aber es gibt keine Anforderung dafür.

Wenn beide implementiert sind, muss das Konzept des dynamischen Schlüsselanbieters vor dem Konzept des dynamischen Konzeptanbieters hinzugefügt werden. Beide Konzepte sind besonders. Sie kippen effektiv einen Schalter auf dem Objekt, um es von "statisch verwaltet" in "dynamisch verwaltet" zu ändern. Diese Konzepte können nur festgelegt werden, wenn keine Schlüssel/Konzepte vorhanden sind, die vom Datenmodell für das Objekt verwaltet werden. Sobald diese Konzepte zu einem Objekt hinzugefügt wurden, ist die Aktion, die dies bewirkt, unwiderruflich.

Es gibt einen zusätzlichen semantischen Unterschied in Bezug auf die Erweiterbarkeit zwischen einem IModelObject, das ein dynamischer Konzeptanbieter ist, und einem, das nicht ist. Diese Konzepte sollen es Clients ermöglichen, Brücken zwischen dem Datenmodell und dynamischen Sprachsystemen wie JavaScript zu erstellen. Das Datenmodell verfügt über ein Konzept der Erweiterbarkeit, das sich etwas grundlegend von Systemen wie JavaScript unterscheidet, da eine Struktur übergeordneter Modelle anstelle einer linearen Kette wie die JavaScript-Prototypkette vorhanden ist. 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 übergeordneter Modelle aufweisen kann, wie es typisch für das Datenmodell ist. Alle Anforderungen an den dynamischen Konzeptanbieter, übergeordnete Elemente hinzuzufügen oder zu entfernen, werden automatisch an das einzelne übergeordnete Element umgeleitet. Aus Sicht eines Außenseiters sieht es so aus, als ob der dynamische Konzeptanbieter über eine normale Strukturstilkette von übergeordneten Modellen verfügt. Der Implementierer des dynamischen Konzeptanbieterkonzepts ist das einzige Objekt (außerhalb des Kerndatenmodells), das sich des zwischengeschalteten übergeordneten Elements bewusst ist. Dieses einzelne übergeordnete Element kann mit dem dynamischen Sprachsystem verknüpft werden, um eine Brücke zu schaffen (z. B. in die JavaScript-Prototypkette platziert).

Das Konzept des dynamischen Schlüsselanbieters ist 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;
}

GetKey von IDynamicKeyProviderConcept

Die GetKey-Methode für einen dynamischen Schlüsselanbieter ist weitgehend eine Außerkraftsetzung der GetKey-Methode auf IModelObject. Vom Anbieter dynamischer Schlüssel wird erwartet, dass er den Wert des Schlüssels und alle Metadaten zurückgibt, die diesem Schlüssel zugeordnet sind. Für den Fall, dass 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 nicht ausgeführt wird, wird als 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 legal ist, einen boxed property accessor als Schlüssel zurückzugeben. Dies wäre semantisch identisch mit der GetKey-Methode auf IModelObject, die einen Eigenschaftsaccessor zurückgibt.

SetKey von IDynamicKeyProviderConcept

Die SetKey-Methode für einen dynamischen Schlüsselanbieter ist effektiv eine Außerkraftsetzung der SetKey-Methode auf IModelObject. Dadurch wird ein Schlüssel im dynamischen Anbieter festgelegt. Es handelt sich effektiv um die Erstellung einer neuen Eigenschaft für den Anbieter. Beachten Sie, dass ein Anbieter, der kein Konzept wie die Erstellung von Expando-Eigenschaften unterstützt, E_NOTIMPL hier zurückgeben sollte.

EnumerateKeys von IDynamicKeyProviderConcept

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

  • Sie muss sich als Aufruf von EnumerateKeys und nicht als EnumerateKeyValues oder EnumerateKeyReferences verhalten. Es muss die Schlüsselwerte zurückgeben, die keine zugrunde liegenden Eigenschaftsaccessoren auflösen (wenn ein solches Konzept im Anbieter vorhanden ist).
  • Aus Der Perspektive eines einzelnen dynamischen Schlüsselanbieters ist es unzulässig, mehrere Schlüssel desselben Namens aufzuzählen, die physisch unterschiedliche Schlüssel sind. Dies kann bei verschiedenen Anbietern geschehen, die über die übergeordnete Modellkette angefügt sind, aber nicht aus der Perspektive eines einzelnen Anbieters.

GetConcept von IDynamicConceptProviderConcept

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 vorhanden, sowie alle Metadaten, die diesem Konzept zugeordnet sind. Wenn das Konzept auf dem Anbieter nicht vorhanden ist, muss dies durch einen false-Wert angegeben werden, der im hasConcept-Argument zurückgegeben wird, und eine erfolgreiche Rückgabe. Der Fehler dieser Methode ist ein Fehler beim Abrufen des Konzepts und beendet explizit die Suche nach dem Konzept. Wenn false für hasConcept und ein erfolgreicher Code zurückgegeben wird, wird die Suche nach dem Konzept über die übergeordnete Modellstruktur fortgesetzt.

SetConcept von IDynamicConceptProviderConcept

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. Dadurch kann das Objekt iterierbar, indizierbar, Zeichenfolgen konvertierbar usw. werden... Beachten Sie, dass ein Anbieter, der die Erstellung von Konzepten nicht zulässt, hier E_NOPTIMPL zurückgeben sollte.

NotifyParent von IDynamicConceptProviderConcept

Der NotifyParent-Aufruf für einen dynamischen Konzeptanbieter wird vom Kerndatenmodell verwendet, um den dynamischen Anbieter über das einzelne übergeordnete Modell zu informieren, das erstellt wird, um das Paradigma "mehrere übergeordnete Modelle" des Datenmodells mit dynamischeren Sprachen zu überbrücken. Jede Manipulation dieses allein übergeordneten Modells führt zu weiteren Benachrichtigungen an den dynamischen Anbieter. Beachten Sie, dass dieser Rückruf sofort nach Zuweisung des dynamischen Konzeptanbieterkonzepts erfolgt.

NotifyParentChange von IDynamicConceptProviderConcept

Die NotifyParent-Methode für einen dynamischen Konzeptanbieter ist ein Rückruf des Kerndatenmodells, wenn eine statische Bearbeitung 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 das übergeordnete Modell entfernt wird.

NotifyDestruct von IDynamicConceptProviderConcept

Die NotifyDestruct-Methode für einen dynamischen Konzeptanbieter ist ein Rückruf des Kerndatenmodells zu Beginn der Zerstörung des Objekts, das ein dynamischer Konzeptanbieter ist. Es bietet zusätzliche sauber Möglichkeiten für Clients, die dies benötigen.

--

Siehe auch

Dieses Thema ist Teil einer Reihe, die die Schnittstellen beschreibt, auf die über C++ zugegriffen werden kann, wie sie zum Erstellen einer C++-basierten Debuggererweiterung verwendet werden und wie Sie andere Datenmodellkonstrukte (z. B. JavaScript oder NatVis) aus einer C++-Datenmodellerweiterung verwenden.

Übersicht über das Debuggerdatenmodell in C++

Debuggerdatenmodell-C++-Schnittstellen

Debuggerdatenmodell-C++-Objekte

Debuggerdatenmodell C++-Zusätzliche Schnittstellen

Debuggerdatenmodell C++-Konzepte

Debuggerdatenmodell C++-Skripterstellung