Partager via


Concepts C++ du modèle de données du débogueur

Cette rubrique décrit les concepts C++ du modèle de données du débogueur.

Concepts dans le modèle de données

Les objets synthétiques dans le modèle de données sont en fait deux choses :

  • Un dictionnaire de tuples clé/valeur/métadonnées.
  • Un ensemble de concepts (interfaces) pris en charge par le modèle de données. Les concepts sont des interfaces qu’un client (par opposition au modèle de données) implémente pour fournir un ensemble spécifié de comportements sémantiques. L’ensemble de concepts actuellement pris en charge est répertorié ici.
Interface de concept Description
IDataModelConcept Le concept est un modèle parent. Si ce modèle est automatiquement attaché à un type natif au moyen d’une signature de type inscrite, la méthode InitializeObject est appelée automatiquement chaque fois qu’un nouvel objet de ce type est instancié.
IStringDisplayableConcept L’objet peut être converti en chaîne à des fins d’affichage.
IIterableConcept L’objet est un conteneur et peut être itéré.
IIndexableConcept L’objet est un conteneur et peut être indexé (accessible par accès aléatoire) dans une ou plusieurs dimensions.
IPreferredRuntimeTypeConcept L’objet comprend mieux les types qui en sont dérivés que ce que le système de types sous-jacent est capable de fournir et souhaite gérer ses propres conversions de type statique en type runtime.
IDynamicKeyProviderConcept L’objet est un fournisseur dynamique de clés et souhaite prendre en charge toutes les requêtes clés à partir du modèle de données de base. Cette interface est généralement utilisée comme passerelle vers des langages dynamiques tels que JavaScript.
IDynamicConceptProviderConcept L’objet est un fournisseur dynamique de concepts et souhaite prendre en charge toutes les requêtes de concepts à partir du modèle de données de base. Cette interface est généralement utilisée comme passerelle vers des langages dynamiques tels que JavaScript.

Concept de modèle de données : IDataModelConcept

Tout objet de modèle attaché à un autre objet de modèle en tant que modèle parent doit prendre directement en charge le concept de modèle de données. Le concept de modèle de données nécessite la prise en charge d’une interface IDataModelConcept définie comme suit.

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

Un modèle de données peut être inscrit en tant que visualiseur canonique ou en tant qu’extension pour un type natif donné via les méthodes RegisterModelForTypeSignature ou RegisterExtensionForTypeSignature du gestionnaire de modèles de données. Lorsqu’un modèle est inscrit à l’aide de l’une de ces méthodes, le modèle de données est automatiquement attaché en tant que modèle parent à tout objet natif dont le type correspond à la signature transmise lors de l’inscription. Au moment où cet attachement est automatiquement effectué, la méthode InitializeObject est appelée sur le modèle de données. On lui transmet l’objet instance, la signature de type qui a provoqué l’attachement et un énumérateur qui produit les instances de type (dans l’ordre linéaire) qui correspondent aux caractères génériques de la signature de type. L’implémentation du modèle de données peut utiliser cet appel de méthode pour initialiser les caches dont elle a besoin.

GetName

Si un modèle de données est inscrit sous un nom par défaut à l’aide de la méthode RegisterNamedModel, l’interface IDataModelConcept du modèle de données inscrit doit renvoyer ce nom à partir de cette méthode. Il convient de noter qu’il est parfaitement légitime qu’un modèle soit inscrit sous plusieurs noms (le nom par défaut ou le meilleur nom doit être renvoyé ici). Un modèle peut être dépourvu de tout nom (tant qu’il n’est pas inscrit sous un nom). Dans ce cas, la méthode GetName doit renvoyer E_NOTIMPL.

Concept d’affichage de chaîne : IStringDisplayableConcept

Un objet qui souhaite fournir une conversion de chaîne à des fins d’affichage peut implémenter le concept d’affichage de chaîne via l’implémentation de l’interface IStringDisplayableConcept. L’interface se définit comme suit :

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

ToDisplayString

La méthode ToDisplayString est appelée chaque fois qu’un client souhaite convertir un objet en chaîne à afficher (dans la console, dans l’interface utilisateur, etc.). Cette conversion de chaîne ne doit pas être utilisée comme base pour une manipulation programmatique supplémentaire. La conversion de chaîne elle-même peut être profondément influencée par les métadonnées transmises à l’appel. Une conversion de chaîne doit s’efforcer de respecter les clés PreferredRadix et PreferredFormat.

Le concept itérable : IIterableConcept et IModelIterator

Un objet qui est un conteneur d’autres objets et qui souhaite exprimer la possibilité d’itérer sur les objets qu’il contient peut prendre en charge le concept itérable par une implémentation des interfaces IIterableConcept et IModelIterator. Il existe une relation très importante entre la prise en charge du concept itérable et la prise en charge du concept indexable. Un objet qui prend en charge l’accès aléatoire aux objets contenus peut prendre en charge le concept indexable en plus du concept itérable. Dans ce cas, les éléments itérés doivent également produire un index par défaut qui, lorsqu’il est transmis au concept d’indexation, fait référence au même objet. Si cet invariant n’est pas respecté, le comportement de l’hôte de débogage sera indéfini.

L’IIterableConcept se définit comme suit :

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

Le concept IModelIterator est défini comme suit :

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

La méthode GetDefaultIndexDimensionality de l’IIterableConcept

La méthode GetDefaultIndexDimensionality renvoie le nombre de dimensions à l’index par défaut. Si un objet n’est pas indexable, cette méthode doit renvoyer 0 et réussir (S_OK). Tout objet qui retourne une valeur non nulle de cette méthode déclare la prise en charge d’un contrat de protocole qui indique :

  • L’objet prend en charge le concept indexable via la prise en charge de l’IIndexableConcept
  • La méthode GetNext de l’IModelIterator renvoyée à partir de la méthode GetIterator du concept itérable renvoie un index par défaut unique pour chaque élément produit. Ce type d’index aura le nombre de dimensions indiquées ici.
  • La transmission des index renvoyés par la méthode GetNext de l’IModelIterator à la méthode GetAt du concept indexable (IIndexableConcept) fera référence au même objet que celui produit par GetNext. La même valeur est renvoyée.

La méthode GetIterator de l’IIterableConcept

La méthode GetIterator sur le concept itérable renvoie une interface d’itérateur qui peut être utilisée pour itérer l’objet. L’itérateur renvoyé doit mémoriser l’objet de contexte transmis à la méthode GetIterator. Elle ne sera pas transmise aux méthodes sur l’itérateur lui-même.

La méthode Reset de l’ImodelIterator

La méthode Reset sur un itérateur renvoyé par le concept itérable rétablit la position de l’itérateur à l’endroit où il se trouvait lors de sa création (avant le premier élément). Bien qu’il soit fortement recommandé que l’itérateur prenne en charge la méthode Reset, ce n’est pas obligatoire. Un itérateur peut être l’équivalent d’un itérateur d’entrée C++ et autoriser uniquement une seule transmission d’itération vers l’avant. Dans ce cas, la méthode Reset peut échouer avec E_NOTIMPL.

La méthode GetNext d’IModelIterator

La méthode GetNext déplace l’itérateur vers l’avant et récupère l’élément itéré suivant. Si l’objet est indexable en plus d’être itérable et que cela est indiqué par l’argument GetDefaultIndexDimensionality qui renvoie une valeur non nulle, cette méthode peut éventuellement renvoyer les indices par défaut pour revenir à la valeur produite par l’indexeur. Il convient de noter qu’un appelant peut choisir de transmettre 0/nullptr et de ne pas récupérer d’index. Il est considéré comme illégal pour l’appelant de demander des indices partiels (par exemple : moins que le nombre produit par GetDefaultIndexDimensionality).

Si l’itérateur a été déplacé vers l’avant, mais qu’une erreur s’est produite lors de la lecture de la valeur de l’élément itéré, la méthode peut renvoyer une erreur ET remplir « object » avec un objet d’erreur. À la fin de l’itération des éléments contenus, l’itérateur renvoie E_BOUNDS à partir de la méthode GetNext. Tout appel ultérieur (à moins qu’il n’y ait eu un appel Reset intermédiaire) renverra également E_BOUNDS.

Le concept indexable : IIndexableConcept

Un objet qui souhaite fournir un accès aléatoire à un ensemble de contenus peut prendre en charge le concept indexable via l’interface IIndexableConcept. La plupart des objets qui sont indexables sont itérables, grâce à la prise en charge du concept itérable. Toutefois, cela n’est pas nécessaire. S’il est pris en charge, il existe une relation significative entre l’itérateur et l’indexeur. L’itérateur doit prendre en charge GetDefaultIndexDimensionality, renvoyer une valeur non nulle de cette méthode et prendre en charge le contrat documenté ici. L’interface concept d’indexeur est définie comme suit :

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

Un exemple d’utilisation de l’indexeur (et de son interaction avec l’itérateur) est présenté ci-dessous. Cet exemple itère le contenu d’un conteneur indexable et utilise l’indexeur pour revenir à la valeur qui vient d’être renvoyée. Bien que cette opération soit fonctionnellement inutile telle qu’elle est écrite, elle montre comment ces interfaces interagissent. Il convient de noter que l’exemple ci-dessous ne traite pas de l’échec d’allocation de mémoire. Il suppose qu’une nouvelle exception est levée (ce qui peut être une mauvaise hypothèse en fonction de l’environnement dans lequel le code existe, les méthodes COM du modèle de données ne peuvent pas avoir d’échappement d’exceptions C++) :

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

La méthode GetDimensionality renvoie le nombre de dimensions dans lesquelles l’objet est indexé. Il convient de noter que si l’objet est à la fois itérable et indexable, l’implémentation de GetDefaultIndexDimensionality doit être en accord avec l’implémentation de GetDimensionality quant au nombre de dimensions de l’indexeur.

GetAt

La méthode GetAt permet de récupérer la valeur à un indice N-dimensionnel particulier à l’intérieur de l’objet indexé. Un indexeur de N dimensions où N est la valeur renvoyée par GetDimensionality doit être pris en charge. Il convient de noter qu’un objet peut être indexable dans différents domaines par différents types (par exemple, indexable via des ordinaux et des chaînes). Si l’index est hors plage (ou s’il n’est pas possible d’y accéder), la méthode renvoie un message d’échec ; dans ce cas, l’objet de sortie peut toutefois être défini comme un objet d’erreur.

SetAt

La méthode SetAt tente de définir la valeur à un index à N dimensions particulier à partir de l’objet indexé. Un indexeur de N dimensions où N est la valeur renvoyée par GetDimensionality doit être pris en charge. Il convient de noter qu’un objet peut être indexable dans différents domaines par différents types (par exemple, indexable via des ordinaux et des chaînes). Certains indexeurs sont en lecture seule. Dans ce cas, E_NOTIMPL est renvoyé à partir d’un appel à la méthode SetAt.

Concept de type d’exécution préféré : IPreferredRuntimeTypeConcept

Un hôte de débogage peut être interrogé pour tenter de déterminer le type d’exécution réel d’un objet à partir d’un type statique trouvé dans des informations symboliques. Cette conversion peut être basée sur des informations totalement précises (par exemple : C++ RTTI) ou sur des heuristiques fortes telles que la forme des tables de fonctions virtuelles au sein de l’objet. Certains objets ne peuvent toutefois pas être convertis d’un type statique en un type d’exécution parce qu’ils ne correspondent pas à l’heuristique de l’hôte de débogage (par exemple : ils n’ont pas de RTTI ou de tables de fonctions virtuelles). Dans ce cas, un modèle de données pour un objet peut choisir de remplacer le comportement par défaut et déclarer qu’il en sait plus sur le « type d’exécution » d’un objet que ce que l’hôte de débogage est capable de comprendre. Cela est possible grâce au concept de type d’exécution préféré et à la prise en charge de l’interface IPreferredRuntimeTypeConcept.

L’interface IPreferredRuntimeTypeConcept est déclarée comme suit :

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

CastToPreferredRuntimeType

La méthode CastToPreferredRuntimeType est appelée chaque fois qu’un client souhaite tenter de convertir une instance de type statique en type d’exécution de cette instance. Si l’objet en question prend en charge (via l’un de ses modèles parents attachés) le concept de type d’exécution préféré, cette méthode est appelée pour effectuer la conversion. Cette méthode peut renvoyer l’objet d’origine (il n’y a pas de conversion ou il n’a pas pu être analysé), renvoyer une nouvelle instance du type d’exécution, échouer pour des raisons non sémantiques (par exemple : absence de mémoire) ou renvoyer E_NOT_SET. Le code d’erreur E_NOT_SET est un code d’erreur très spécial qui indique au modèle de données que l’implémentation ne veut pas remplacer le comportement par défaut et que le modèle de données doit revenir à l’analyse effectuée par l’hôte de débogage (par exemple : analyse RTTI, examen de la forme des tables de fonctions virtuelles, etc.)

Concepts de fournisseur dynamique : IDynamicKeyProviderConcept et IDynamicConceptProviderConcept

Bien que le modèle de données lui-même assure normalement la gestion des clés et des concepts pour les objets, il arrive que cette notion soit loin d’être idéale. En particulier, lorsqu’un client souhaite créer un pont entre le modèle de données et un autre élément véritablement dynamique (par exemple, JavaScript), il peut être utile de prendre en charge la gestion des clés et des concepts à partir de l’implémentation dans le modèle de données. Comme le modèle de données principal est la seule et unique implémentation d’IModelObject, cela se fait par le biais d’une combinaison de deux concepts : le concept de fournisseur de clé dynamique et le concept de fournisseur de concept dynamique. Bien qu’il soit normal de mettre en œuvre les deux ou aucun des deux, il n’y a pas d’obligation en la matière.

Si les deux sont mis en œuvre, le concept de fournisseur de clé dynamique doit être ajouté avant celui de fournisseur de concept dynamique. Ces deux concepts sont spéciaux. Ils actionnent en fait un commutateur sur l’objet, le faisant passer de « géré de manière statique » à « géré de manière dynamique ». Ces concepts peuvent uniquement être définis s’il n’y a pas de clés/concepts gérés par le modèle de données sur l’objet. Une fois que ces concepts sont ajoutés à un objet, cette action est irrévocable.

Il existe une différence sémantique supplémentaire en matière d’extensibilité entre un IModelObject qui est un fournisseur de concepts dynamique et un autre qui ne l’est pas. Ces concepts sont destinés à permettre aux clients de créer des ponts entre le modèle de données et les systèmes de langage dynamique tels que JavaScript. Le modèle de données possède un concept d’extensibilité qui diffère fondamentalement de systèmes tels que JavaScript en ce sens qu’il existe un arbre de modèles parents plutôt qu’une chaîne linéaire comme la chaîne de prototypes JavaScript. Pour faciliter la relation avec de tels systèmes, un IModelObject qui est un fournisseur de concepts dynamiques a un seul parent de modèle de données. Ce parent unique du modèle de données est un IModelObject normal qui peut avoir un nombre arbitraire de modèles parents, comme c’est le cas pour le modèle de données. Toutes les demandes adressées au fournisseur de concepts dynamiques pour ajouter ou supprimer des parents sont automatiquement redirigées vers le parent unique. D’un point de vue extérieur, il semble que le fournisseur de concepts dynamiques dispose d’une chaîne de modèles parents normale de type arborescent. L’implémenteur du concept de fournisseur de concepts dynamiques est le seul objet (en dehors du modèle de données principal) qui est conscient de l’existence du parent unique intermédiaire. Ce dernier peut être lié au système de langage dynamique pour fournir un pont (par exemple, placé dans la chaîne de prototype JavaScript).

Le concept de fournisseur de clés dynamiques est défini comme suit :

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

Le concept de fournisseur de concepts dynamiques est défini comme suit :

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

La méthode GetKey d’IDynamicKeyProviderConcept

La méthode GetKey sur un fournisseur de clés dynamiques est en grande partie un remplacement de la méthode GetKey sur IModelObject. Le fournisseur de clés dynamiques est censé renvoyer la valeur de la clé et toutes les métadonnées associées à cette dernière. Si la clé n’est pas présente (mais qu’aucune autre erreur ne se produit), le fournisseur doit renvoyer false dans le paramètre hasKey et réussir avec S_OK. L’échec de cet appel est considéré comme un échec de la recherche d’une clé et interrompt expressément la recherche de la clé dans la chaîne du modèle parent. En renvoyant false dans hasKey et en cas de succès, la recherche de la clé se poursuit. Il convient de noter qu’il est parfaitement légal pour GetKey de renvoyer un accesseur de propriété boxed comme clé. Cela serait sémantiquement identique à la méthode GetKey sur IModelObject renvoyant un accesseur de propriété.

La méthode SetKey d’IDynamicKeyProviderConcept

La méthode SetKey sur un fournisseur de clés dynamiques est en fait un remplacement de la méthode SetKey sur IModelObject. Cela définit une clé dans le fournisseur dynamique. Il s’agit en fait de la création d’une nouvelle propriété sur le fournisseur. Il convient de noter qu’un fournisseur qui ne prend pas en charge une notion telle que la création de propriétés expando doit renvoyer E_NOTIMPL ici.

La méthode EnumerateKey d’IDynamicKeyProviderConcept

La méthode EnumerateKeys sur un fournisseur de clés dynamiques est en fait un remplacement de la méthode EnumerateKeys sur IModelObject. Elle énumère toutes les clés du fournisseur dynamique. L’énumérateur renvoyé présente plusieurs restrictions qui doivent être respectées par l’implémentation :

  • Il doit se comporter comme un appel à EnumerateKeys et non à EnumerateKeyValues ou à EnumerateKeyReferences. Il doit renvoyer les valeurs des clés sans résoudre les accès aux propriétés sous-jacentes (si un tel concept existe dans le fournisseur).
  • Du point de vue d’un fournisseur de clés dynamiques unique, il est illégal d’énumérer plusieurs clés du même nom qui sont des clés physiquement distinctes. Cela peut se produire sur différents fournisseurs qui sont attachés à travers la chaîne du modèle parent, mais cela ne peut pas se produire du point de vue d’un seul fournisseur.

La méthode GetConcept d’IDynamicConceptProviderConcept

La méthode GetConcept sur un fournisseur de concepts dynamiques est en fait un remplacement de la méthode GetConcept sur IModelObject. Le fournisseur de concepts dynamiques doit renvoyer une interface pour le concept interrogé s’il existe ainsi que les métadonnées associées à ce dernier. Si le concept n’existe pas sur le fournisseur, cela doit être indiqué via une valeur fausse renvoyée dans l’argument hasConcept et un renvoi réussi. L’échec de cette méthode signifie que le concept n’a pas été récupéré et interrompt explicitement sa recherche. Le renvoi de la valeur false pour hasConcept et d’un code réussi permet de poursuivre la recherche du concept dans l’arborescence du modèle parent.

La méthode SetConcept d’IDynamicConceptProviderConcept

La méthode SetConcept sur un fournisseur de concepts dynamiques est en fait un remplacement de la méthode SetConcept sur IModelObject. Le fournisseur dynamique attribue le concept. Cela peut rendre l’objet itérable, indexable, convertible en chaîne, etc. Il convient de noter qu’un fournisseur qui n’autorise pas la création de concepts sur lui doit renvoyer E_NOPTIMPL ici.

La méthode NotifyParent d’IDynamicConceptProviderConcept

L’appel NotifyParent sur un fournisseur de concepts dynamiques est utilisé par le modèle de données principal pour informer le fournisseur dynamique du modèle parent unique qui est créé pour permettre de faire le lien entre le paradigme des « plusieurs modèles parents » du modèle de données et des langages plus dynamiques. Toute manipulation de ce modèle parent unique entraîne d’autres notifications au fournisseur dynamique. Il convient de noter que ce rappel est effectué immédiatement lors de l’affectation du concept de fournisseur de concepts dynamiques.

La méthode NotifyParentChange d’IDynamicConceptProviderConcept

La méthode NotifyParent sur un fournisseur de concepts dynamiques est un rappel effectué par le modèle de données principal en cas de manipulation statique du modèle parent unique de l’objet. Pour tout modèle parent ajouté, cette méthode est appelée une première fois lorsque le modèle parent est ajouté et une deuxième fois si/quand le modèle parent est supprimé.

La méthode NotifyDestruct d’IDynamicConceptProviderConcept

La méthode NotifyDestruct sur un fournisseur de concepts dynamiques est un rappel effectué par le modèle de données principal au début de la destruction de l’objet, qui est un fournisseur de concepts dynamiques. Il offre des possibilités de nettoyage supplémentaires aux clients qui en ont besoin.

--

Voir aussi

Cette rubrique fait partie d’une série qui décrit les interfaces accessibles à partir de C++, comment les utiliser pour générer une extension de débogueur C++ et comment utiliser d’autres constructions de modèle de données (par exemple, JavaScript ou NatVis) à partir d’une extension de modèle de données C++.

Vue d’ensemble du modèle de données du débogueur C++

Interfaces C++ du modèle de données du débogueur

Objets C++ du modèle de données du débogueur

Interfaces supplémentaires C++ du modèle de données du débogueur

Concepts C++ du modèle de données du débogueur

Génération de scripts C++ du modèle de données du débogueur