Partager via


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

Cette rubrique explique comment utiliser les objets C++ du modèle de données du débogueur et comment ils peuvent étendre les fonctionnalités de ce dernier.

Modèle objet du débogueur principal

L’un des principaux avantages, mais aussi le plus puissant, du modèle de données est qu’il normalise la définition de ce qu’est un objet et de la manière dont on interagit avec ce dernier. L’interface IModelObject encapsule la notion d’objet : qu’il s’agisse d’un entier, d’une valeur à virgule flottante, d’une chaîne, d’un type complexe dans l’espace d’adressage cible du débogueur ou d’un concept de débogueur comme la notion d’un processus ou d’un module.

Un IModelObject peut contenir (ou effectuer le boxing de) plusieurs choses :

  • Valeurs intrinsèques : un IModelObject peut être un conteneur pour un certain nombre de types de base : 8, 16, 32 ou 64 bits signés ou non signés, booléens, chaînes, erreurs ou notion de vide.

  • Objets natifs : un IModelObject peut représenter un type complexe (tel que défini par le système de type du débogueur) dans l’espace d’adressage de la cible du débogueur

  • Objets synthétiques : un IModelObject peut être un objet dynamique, un dictionnaire si vous voulez : une collection de tuples clé/valeur/métadonnées et un ensemble de concepts qui définissent des comportements qui ne sont pas simplement représentés par des paires clé/valeur.

  • Propriétés : un IModelObject peut représenter une propriété : une chose dont la valeur peut être récupérée ou modifiée avec un appel de méthode. Une propriété au sein d’un IModelObject est effectivement une interface IModelPropertyAccessor contenue dans un IModelObject

  • Méthodes : un IModelObject peut représenter une méthode : une chose que vous pouvez appeler avec un ensemble d’arguments et obtenir une valeur de retour. Une méthode au sein d’un IModelObject est effectivement une interface IModelMethod contenue dans un IModelObject

Extensibilité au sein du modèle objet

Un IModelObject n’est pas un objet isolé. Chaque objet représente non seulement l’un des types d’objets présentés ci-dessus, mais aussi une chaîne de modèles de données parents. Cette chaîne se comporte comme une chaîne de prototype JavaScript. Au lieu d’une chaîne linéaire de prototypes comme dans JavaScript, chaque objet de modèle de données définit une chaîne linéaire de modèles parents. Chacun de ces modèles parents possède à son tour une autre chaîne linéaire de son propre ensemble de parents. Par essence, chaque objet est une agrégation des fonctionnalités (propriétés, etc.) de lui-même et de tous les objets de cette arborescence. Lorsqu’une propriété spécifique est interrogée, si l’objet sur lequel elle est interrogée ne prend pas en charge cette propriété, la requête est transmise dans l’ordre linéaire à chaque parent à tour de rôle. Il en résulte un comportement où la recherche d’une propriété est résolue par une recherche en profondeur de l’arborescence agrégée.

L’extensibilité de ce modèle d’objet est très simple étant donné que chaque objet est un agrégat de lui-même et de l’arborescence des modèles parents. Une extension peut venir s’ajouter à la liste des modèles parents pour d’un autre objet. Ce faisant, l’objet est étendu. Il est ainsi possible d’ajouter des fonctionnalités à tout ce que l’on veut : une instance particulière d’un objet ou d’une valeur, un type natif, le concept de processus ou de thread du débogueur, ou même la notion de « tous les objets itérables ».

Contexte, contexte et contexte : le pointeur this, l’espace d’adressage et les données privées d’implémentation

Il existe trois notions de contexte nécessaires pour comprendre dans le contexte du modèle objet.

Contexte : le pointeur this

Étant donné qu’une propriété ou une méthode donnée peut être implémentée à n’importe quel niveau de l’arborescence du modèle de données, il faut que l’implémentation de la méthode ou de la propriété puisse accéder à l’objet d’origine (ce que vous pouvez appeler le pointeur this en C++ ou l’objet this en JavaScript. Cet objet d’instance est transmis à diverses méthodes en tant que premier argument appelé contexte dans les méthodes décrites.

Contexte : l’espace d’adressage

Il est important de noter que contrairement aux modèles d’extension précédents où le contexte (la cible, le processus, le thread que vous examinez) est un concept d’interface utilisateur avec toutes les API relatives à l’état actuel de cette dernière, les interfaces de modèle de données prennent généralement ce contexte soit explicitement, soit implicitement en tant qu’interface IDebugHostContext . Chaque IModelObject du modèle de données porte ce type d’informations de contexte et peut propager ce contexte aux objets qu’il renvoie. Cela signifie que lorsque vous lisez une valeur native ou une valeur clé à partir d’un IModelObject, celui-ci lira la cible et le processus à partir desquels l’objet a été acquis à l’origine.

Il existe une valeur constante explicite, USE_CURRENT_HOST_CONTEXT, qui peut être transmise à des méthodes qui prennent un argument IDebugHostContext . Cette valeur indique que le contexte doit effectivement être l’état actuel de l’interface utilisateur du débogueur. Toutefois, cette notion doit être explicite.

Contexte : données privées d’implémentation

N’oubliez pas que chaque objet du modèle de données est en fait un agrégat de l’instance d’objet et de l’arborescence des modèles parents qui sont attachés. Chacun de ces modèles parents (qui peuvent être liés dans les chaînes de nombreux objets différents) peut associer des données privées d’implémentation à n’importe quel objet d’instance. Chaque IModelObject créé de manière conceptuelle possède une table de hachage qui établit une correspondance entre un modèle parent particulier et des données d’instance privées définies par une interface IUnknown. Cela permet à un modèle parent de mettre en cache des informations sur chaque instance ou des données arbitraires associées.

Ce type de contexte est accessible via les méthodes GetContextForDataModel et SetContextForDataModel sur IModelObject.

L’interface d’objet du débogueur principal : IModelObject


L’interface IModelObject est définie comme suit :

DECLARE_INTERFACE_(IModelObject, IUnknown)
{
    STDMETHOD(QueryInterface)(_In_ REFIID iid, _COM_Outptr_ PVOID* iface);
    STDMETHOD_(ULONG, AddRef)();
    STDMETHOD_(ULONG, Release)() PURE;
    STDMETHOD(GetContext)(_COM_Outptr_result_maybenull_ IDebugHostContext** context) PURE;
    STDMETHOD(GetKind)(_Out_ ModelObjectKind *kind) PURE;
    STDMETHOD(GetIntrinsicValue)(_Out_ VARIANT* intrinsicData);
    STDMETHOD(GetIntrinsicValueAs)(_In_ VARTYPE vt, _Out_ VARIANT* intrinsicData) PURE;
    STDMETHOD(GetKeyValue)(_In_ PCWSTR key, _COM_Errorptr_opt_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(SetKeyValue)(_In_ PCWSTR key, _In_opt_ IModelObject* object) PURE;
    STDMETHOD(EnumerateKeyValues)(_COM_Outptr_ IKeyEnumerator** enumerator) PURE;
    STDMETHOD(GetRawValue)(_In_ SymbolKind kind, _In_ PCWSTR name, _In_ ULONG searchFlags, _COM_Errorptr_ IModelObject** object) PURE;
    STDMETHOD(EnumerateRawValues)(_In_ SymbolKind kind, _In_ ULONG searchFlags, _COM_Outptr_ IRawEnumerator** enumerator) PURE;
    STDMETHOD(Dereference)(_COM_Errorptr_ IModelObject** object) PURE;
    STDMETHOD(TryCastToRuntimeType)(_COM_Errorptr_ IModelObject** runtimeTypedObject) PURE;
    STDMETHOD(GetConcept)(_In_ REFIID conceptId, _COM_Outptr_ IUnknown** conceptInterface, _COM_Outptr_opt_result_maybenull_ IKeyStore** conceptMetadata) PURE;
    STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
    STDMETHOD(GetTypeInfo)(_Out_ IDebugHostType** type) PURE;
    STDMETHOD(GetTargetInfo)(_Out_ Location* location, _Out_ IDebugHostType** type) PURE;
    STDMETHOD(GetNumberOfParentModels)(_Out_ ULONG64* numModels) PURE;
    STDMETHOD(GetParentModel)(_In_ ULONG64 i, _COM_Outptr_ IModelObject **model, _COM_Outptr_result_maybenull_ IModelObject **contextObject) PURE;
    STDMETHOD(AddParentModel)(_In_ IModelObject* model, _In_opt_ IModelObject* contextObject, _In_ bool override) PURE;
    STDMETHOD(RemoveParentModel)(_In_ IModelObject* model) PURE;
    STDMETHOD(GetKey)(_In_ PCWSTR key, _COM_Errorptr_opt_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(GetKeyReference)(_In_ PCWSTR key, _COM_Errorptr_opt_ IModelObject** objectReference, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(SetKey)(_In_ PCWSTR key, _In_opt_ IModelObject* object, _In_opt_ IKeyStore* metadata) PURE;
    STDMETHOD(ClearKeys)() PURE;
    STDMETHOD(EnumerateKeys)(_COM_Outptr_ IKeyEnumerator** enumerator) PURE;
    STDMETHOD(EnumerateKeyReferences)(_COM_Outptr_ IKeyEnumerator** enumerator) PURE;
    STDMETHOD(SetConcept)(_In_ REFIID conceptId, _In_ IUnknown* conceptInterface, _In_opt_ IKeyStore* conceptMetadata) PURE;
    STDMETHOD(ClearConcepts)() PURE;
    STDMETHOD(GetRawReference)(_In_ SymbolKind kind, _In_ PCWSTR name, _In_ ULONG searchFlags, _COM_Errorptr_ IModelObject** object) PURE;
    STDMETHOD(EnumerateRawReferences)(_In_ SymbolKind kind, _In_ ULONG searchFlags, _COM_Outptr_ IRawEnumerator** enumerator) PURE;
    STDMETHOD(SetContextForDataModel)(_In_ IModelObject* dataModelObject, _In_ IUnknown* context) PURE;
    STDMETHOD(GetContextForDataModel)(_In_ IModelObject* dataModelObject, _Out_ IUnknown** context) PURE;
    STDMETHOD(Compare)(_In_ IModelObject* other, _COM_Outptr_opt_result_maybenull_ IModelObject **ppResult) PURE;
    STDMETHOD(IsEqualTo)(_In_ IModelObject* other, _Out_ bool* equal) PURE;
}

Méthodes de base

Les méthodes suivantes sont des méthodes générales applicables à tout type d’objet représenté par un IModelObject.

STDMETHOD(GetKind)(_Out_ ModelObjectKind *kind) PURE;
STDMETHOD(GetContext)(_COM_Outptr_result_maybenull_ IDebugHostContext** context) PURE;
STDMETHOD(GetIntrinsicValue)(_Out_ VARIANT* intrinsicData);
STDMETHOD(GetIntrinsicValueAs)(_In_ VARTYPE vt, _Out_ VARIANT* intrinsicData) PURE;
STDMETHOD(Compare)(_In_ IModelObject* other, _COM_Outptr_opt_result_maybenull_ IModelObject **ppResult) PURE;
STDMETHOD(IsEqualTo)(_In_ IModelObject* other, _Out_ bool* equal) PURE;
STDMETHOD(Dereference)(_COM_Errorptr_ IModelObject** object) PURE;

GetKind

La méthode GetKind renvoie le type d’objet contenu dans l’IModelObject.

GetContext

La méthode GetContext renvoie le contexte hôte associé à l’objet.

GetIntrinsicValue

La méthode GetIntrinsicValue renvoie la chose qui est boxed à l’intérieur d’un IModelObject. Cette méthode peut uniquement être appelée légalement sur des interfaces IModelObject qui représentent un intrinsèque boxed ou une interface particulière qui est boxed. Elle ne peut pas être appelée sur des objets natifs, les objets sans valeur, les objets synthétiques et les objets de référence. Le comportement de la méthode GetIntrinsicValueAs ressemble beaucoup à celui de la méthode GetIntrinsicValue, sauf qu’elle convertit la valeur dans le type de variant spécifié. Si la conversion ne peut pas être effectuée, la méthode renvoie une erreur.

IsEqualTo

La méthode IsEqualTo compare deux objets de modèle et indique s’ils ont la même valeur. Pour les objets qui ont un ordre, cette méthode qui renvoie true est équivalente à la méthode Compare qui renvoie 0. Pour les objets qui n’ont pas d’ordre mais qui sont équivalents, la méthode Compare échoue, mais pas celle-ci. La signification d’une comparaison basée sur la valeur est définie par le type d’objet. À l’heure actuelle, elle n’est définie que pour les types intrinsèques et les objets d’erreur. Il n’existe actuellement aucun concept de modèle de données pour déterminer l’égalité.

Dereference

La méthode Dereference déréférence un objet. Cette méthode peut être utilisée pour déréférencer une référence basée sur un modèle de données (ObjectTargetObjectReference, ObjectKeyReference) ou une référence en langage natif (pointeur ou référence de langage). Il est important de signaler que cette méthode supprime un seul niveau de sémantique de référence sur l’objet. Il est par exemple tout à fait possible d’avoir une référence de modèle de données à une référence de langue. Dans ce cas, le premier appel à la méthode Dereference supprimerait la référence au modèle de données et laisserait la référence au langage. L’appel de la méthode Dereference sur l’objet résultant supprimerait ensuite la référence au langage et renverrait la valeur native sous cette référence.

Méthodes de manipulation des clés

Tout objet synthétique qui est un dictionnaire de tuples de clé, de valeur et de métadonnées a une série de méthodes pour manipuler ces clés, ces valeurs et les métadonnées qui leur sont associées.

Les formulaires basés sur des valeurs des API sont les suivants :

STDMETHOD(GetKeyValue)(_In_ PCWSTR key, _COM_Errorptr_opt_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
STDMETHOD(SetKeyValue)(_In_ PCWSTR key, _In_opt_ IModelObject* object) PURE;
STDMETHOD(EnumerateKeyValues)(_COM_Outptr_ IKeyEnumerator** enumerator) PURE;
The key based forms of the APIs (including those used for key creation) are: 
STDMETHOD(GetKey)(_In_ PCWSTR key, _COM_Errorptr_opt_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
STDMETHOD(SetKey)(_In_ PCWSTR key, _In_opt_ IModelObject* object, _In_opt_ IKeyStore* metadata) PURE;
STDMETHOD(EnumerateKeys)(_COM_Outptr_ IKeyEnumerator** enumerator) PURE;
STDMETHOD(ClearKeys)() PURE;

Les formulaires basés sur des références des API sont les suivants :

STDMETHOD(GetKeyReference)(_In_ PCWSTR key, _COM_Errorptr_opt_ IModelObject** objectReference, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
STDMETHOD(EnumerateKeyReferences)(_COM_Outptr_ IKeyEnumerator** enumerator) PURE;

GetKeyValue

La méthode GetKeyValue est la première vers laquelle un client se tournera pour obtenir la valeur (et les métadonnées associées) d’une clé donnée par nom. Si la clé est un accesseur de propriété, c’est-à-dire sa valeur en tant qu’IModelObject qui est un IModelPropertyAccessor boxed, la méthode GetKeyValue appellera automatiquement la méthode GetValue de l’accesseur de propriété afin de récupérer la valeur réelle.

SetKeyValue

La méthode SetKeyValue est la première méthode vers laquelle un client va se tourner pour définir la valeur d’une clé. Elle ne peut pas être utilisée pour créer une nouvelle clé sur un objet. Elle définit uniquement la valeur d’une clé existante. Il convient de noter que de nombreuses clés sont en lecture seule (par exemple, elles sont implémentées par un accesseur de propriété qui renvoie E_NOT_IMPL à partir de sa méthode SetValue). Cette méthode échoue lorsqu’elle est appelée sur une clé en lecture seule.

EnumerateKeyValues

La méthode EnumerateKeyValues est la première méthode vers laquelle un client va se tourner pour énumérer toutes les clés d’un objet (cela inclut toutes les clés implémentées n’importe où dans l’arborescence des modèles parents). Il est important de signaler que la méthode EnumerateKeyValues énumère les clés définies par des noms dupliqués dans l’arborescence d’objets. Toutefois, les méthodes comme GetKeyValue et SetKeyValue manipulent uniquement la première instance d’une clé avec le nom donné tel que découverte par le parcours à profondeur prioritaire.

GetKey

La méthode GetKey obtient la valeur (et les métadonnées associées) d’une clé donnée par nom. La plupart des clients devraient plutôt utiliser la méthode GetKeyValue. Si la clé est un accesseur de propriété, l’appel de cette méthode renvoie l’accesseur de propriété (interface IModelPropertyAccessor) boxed dans un IModelObject. Contrairement à GetKeyValue, cette méthode ne résoudra pas automatiquement la valeur sous-jacente de la clé en appelant la méthode GetValue. Cette responsabilité est celle de l’appelant.

SetKey

La méthode SetKey est celle vers laquelle un client va se tourner pour créer une clé sur un objet (et éventuellement associer des métadonnées à la clé créée). Si un objet donné possède déjà une clé portant le nom donné, deux comportements sont possibles. Si la clé se trouve sur l’instance donnée par this, la valeur de cette clé sera remplacée comme si la clé originale n’existait pas. Si, en revanche, la clé se trouve dans la chaîne des modèles de données parents de l’instance donnée par this, une nouvelle clé portant le nom donné sera créée sur l’instance donnée par this. L’objet aurait alors deux clés portant le même nom (comme une classe dérivée qui utilise un membre portant le même nom qu’une classe de base).

EnumerateKeys

La méthode EnumerateKeys se comporte comme la méthode EnumerateKeyValues, sauf qu’elle ne résout pas automatiquement les accesseurs de propriété sur l’objet. Cela signifie que si la valeur d’une clé est un accesseur de propriété, la méthode EnumerateKeys renvoie l’accesseur de propriété (un IModelPropertyAccessorInterface) boxed dans un IModelObject plutôt que d’appeler automatiquement la méthode GetValue. Ceci est similaire à la différence entre GetKey et GetKeyValue.

ClearKeys

La méthode ClearKeys supprime toutes les clés et leurs valeurs et métadonnées associées de l’instance de l’objet spécifié par this. Cette méthode n’a aucun impact sur les modèles parents attachés à l’instance d’objet particulière.

GetKeyReference

La méthode GetKeyReference recherche une clé du nom donné sur l’objet (ou sa chaîne de modèles parents) et renvoie une référence à cette même clé donnée par une interface IModelKeyReference boxed dans un IModelObject. Cette référence peut ensuite être utilisée pour obtenir ou définir la valeur de la clé.

EnumerateKeyReferences

La méthode EnumerateKeyReferences se comporte comme la méthode EnumerateKeyValues, sauf qu’elle renvoie des références aux clés qu’elle énumère (données par une interface IModelKeyReference boxed dans un IModelObject) au lieu de la valeur de la clé. Ces références peuvent être utilisées pour obtenir ou définir la valeur sous-jacente des clés.

Méthodes de manipulation de concepts

Outre le fait qu’un objet de modèle est un dictionnaire de tuples clé/valeur/métadonnées, il s’agit également d’un conteneur de concepts. Un concept est quelque chose d’abstrait qui peut être exécuté sur ou par un objet. Les concepts sont, par essence, un magasin dynamique d’interfaces qu’un objet prend en charge. Un certain nombre de concepts sont définis par le modèle de données aujourd’hui :

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.

Les méthodes suivantes sur IModelObject sont utilisées pour manipuler les concepts pris en charge par un objet.

STDMETHOD(GetConcept)(_In_ REFIID conceptId, _COM_Outptr_ IUnknown** conceptInterface, _COM_Outptr_opt_result_maybenull_ IKeyStore** conceptMetadata) PURE;
STDMETHOD(SetConcept)(_In_ REFIID conceptId, _In_ IUnknown* conceptInterface, _In_opt_ IKeyStore* conceptMetadata) PURE;
STDMETHOD(ClearConcepts)() PURE;

GetConcept

La méthode GetConcept recherche un concept sur l’objet (ou sa chaîne de modèles parents) et renvoie un pointeur d’interface vers l’interface de concept. Le comportement et les méthodes d’une interface de concept sont spécifiques à chaque concept. Toutefois, il est important de noter que de nombreuses interfaces de concept nécessitent que l’appelant transmette explicitement l’objet de contexte (ou ce qu’on peut appeler traditionnellement le pointeur this). Il est important de s’assurer que l’objet de contexte approprié est transmis à chaque interface de concept.

SetConcept

La méthode SetConcept place un concept spécifié sur l’instance d’objet spécifiée par le pointeur this. Si un modèle parent attaché à l’instance d’objet spécifiée par this prend également en charge le concept, l’implémentation dans l’instance remplace celui-ci dans le modèle parent.

ClearConcepts

La méthode ClearConcepts supprime tous les concepts de l’instance de l’objet spécifié par this.

Méthodes d’objet natifs

Bien que de nombreux objets de modèle font référence à des intrinsèques (par exemple, des entiers, des chaînes) ou à des constructions synthétiques (un dictionnaire de tuples de clé/valeur/métadonnées et de concepts), un objet de modèle peut également faire référence à une construction native (par exemple, un type défini par l’utilisateur dans l’espace d’adressage de la cible de débogage). L’interface IModelObject comprend une série de méthodes permettant d’accéder aux informations relatives à ces objets natifs. Ces méthodes sont les suivantes :

STDMETHOD(GetRawValue)(_In_ SymbolKind kind, _In_ PCWSTR name, _In_ ULONG searchFlags, _COM_Errorptr_ IModelObject** object) PURE;
STDMETHOD(EnumerateRawValues)(_In_ SymbolKind kind, _In_ ULONG searchFlags, _COM_Outptr_ IRawEnumerator** enumerator) PURE;
STDMETHOD(TryCastToRuntimeType)(_COM_Errorptr_ IModelObject** runtimeTypedObject) PURE;
STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
STDMETHOD(GetTypeInfo)(_Out_ IDebugHostType** type) PURE;
STDMETHOD(GetTargetInfo)(_Out_ Location* location, _Out_ IDebugHostType** type) PURE;
STDMETHOD(GetRawReference)(_In_ SymbolKind kind, _In_ PCWSTR name, _In_ ULONG searchFlags, _COM_Errorptr_ IModelObject** object) PURE;
STDMETHOD(EnumerateRawReferences)(_In_ SymbolKind kind, _In_ ULONG searchFlags, _COM_Outptr_ IRawEnumerator** enumerator) PURE;

GetRawValue

La méthode GetRawValue recherche une construction native dans l’objet donné. Une telle construction peut être un champ, une classe de base, un champ dans une classe de base, une fonction membre, etc.

EnumerateRawValues

La méthode EnumerateRawValues énumère tous les enfants natifs (par exemple, champs, classes de base, etc.) de l’objet donné.

TryCastToRuntimeType

La méthode TryCastToRuntimeType demande à l’hôte de débogage d’effectuer une analyse et de déterminer le type de runtime réel (par exemple, la classe la plus dérivée) de l’objet donné. L’analyse exacte utilisée est spécifique à l’hôte de débogage et peut inclure des RTTI (informations de type au moment de l’exécution C++), l’examen de la structure V-Table (table de fonction virtuelle) de l’objet, ou tout autre moyen que l’hôte peut utiliser pour déterminer de manière fiable le type dynamique/runtime à partir du type statique. L’échec de la conversion en type de runtime ne signifie pas que cet appel de méthode échouera. Dans ce cas, la méthode renvoie l’objet donné (le pointeur this) dans l’argument de sortie.

GetLocation

La méthode GetLocation renvoie l’emplacement de l’objet natif. Bien qu’un tel emplacement soit généralement une adresse virtuelle dans l’espace d’adressage de la cible de débogage, ce n’est pas nécessairement le cas. L’emplacement renvoyé par cette méthode est un emplacement abstrait qui peut être une adresse virtuelle, peut indiquer le positionnement dans un registre ou un sous-registre, ou peut indiquer un autre espace d’adressage arbitraire tel que défini par l’hôte de débogage. Si le champ HostDefined de l’objet Emplacement résultant est 0, cela indique que l’emplacement est en fait une adresse virtuelle. Cette adresse virtuelle peut être récupérée en examinant le champ Offset de l’emplacement résultant. Toute valeur différente de zéro dans le champ HostDefined indique un autre espace d’adressage où le champ Offset est le décalage dans cet espace d’adressage. La signification exacte des valeurs HostDefined non nulles ici est privée à l’hôte de débogage.

GetTypeInfo

La méthode GetTypeInfo renvoie le type natif de l’objet donné. Si aucune information de type natif n’est associée à l’objet (par exemple, s’il s’agit d’un intrinsèque, etc...), l’appel réussit quand même, mais renvoie une valeur null.

GetTargetInfo

La méthode GetTargetInfo est en fait une combinaison des méthodes GetLocation et GetTypeInfo qui renvoie à la fois l’emplacement abstrait et le type natif de l’objet donné.

GetRawReference

La méthode GetRawReference recherche une construction native dans l’objet donné et renvoie une référence à cet objet. Cette construction peut être un champ, une classe de base, un champ dans une classe de base, une fonction membre, etc. Il est important de distinguer la référence renvoyée ici (un objet du type ObjectTargetObjectReference) d’une référence de langage (par exemple, une référence de style & ou && C++).

EnumerateRawReferences

La méthode EnumerateRawReferences énumère les références à tous les enfants natifs (par exemple, champs, classes de base, etc.) de l’objet donné.

Méthodes d’extensibilité

Comme décrit précédemment, un objet de modèle se comporte de manière très similaire à un objet JavaScript et à sa chaîne prototype. Outre l’instance représentée par une interface IModelObject donnée, il peut y avoir un nombre arbitraire de modèles parents attachés à l’objet (chacun d’entre eux pouvant, à tour de rôle, posséder un nombre arbitraire de modèles parents qui lui sont attachés). Il s’agit du principal moyen d’extension dans le modèle de données. Si une propriété ou un concept donné ne peut pas être localisé dans une instance donnée, une recherche en profondeur de l’arborescence d’objets (définie par les modèles parents) dont la racine est l’instance est effectuée.

Les méthodes suivantes manipulent la chaîne de modèles parents associés à une instance IModelObject donnée :

STDMETHOD(GetNumberOfParentModels)(_Out_ ULONG64* numModels) PURE;
STDMETHOD(GetParentModel)(_In_ ULONG64 i, _COM_Outptr_ IModelObject **model, _COM_Outptr_result_maybenull_ IModelObject **contextObject) PURE;
STDMETHOD(AddParentModel)(_In_ IModelObject* model, _In_opt_ IModelObject* contextObject, _In_ bool override) PURE;
STDMETHOD(RemoveParentModel)(_In_ IModelObject* model) PURE;
STDMETHOD(SetContextForDataModel)(_In_ IModelObject* dataModelObject, _In_ IUnknown* context) PURE;
STDMETHOD(GetContextForDataModel)(_In_ IModelObject* dataModelObject, _Out_ IUnknown** context) PURE;

GetNumberOfParentModels

La méthode GetNumberOfParentModels renvoie le nombre de modèles parents qui sont attachés à l’instance d’objet donnée. Les propriétés des modèles parents sont recherchées à profondeur prioritaire dans l’ordre linéaire de la chaîne des modèles parents.

GetParentModel

La méthode GetParentModel renvoie l’i-ième modèle parent dans la chaîne de modèles parents de l’objet donné. Les modèles parents sont recherchés pour une propriété ou un concept dans l’ordre linéaire dans lequel ils sont ajoutés ou énumérés. Le modèle parent avec l’index i de zéro est recherché (hiérarchiquement) avant le modèle parent avec l’index i + 1.

AddParentModel

La méthode AddParentModel ajoute un nouveau modèle parent à l’objet donné. Ledit modèle peut être ajouté à la fin de la chaîne de recherche (l’argument de substitution est spécifié comme faux) ou au début de la chaîne de recherche (l’argument de substitution est spécifié comme vrai). En outre, chaque modèle parent peut éventuellement ajuster le contexte (le pointeur sémantique this) pour toute propriété ou concept sur le parent donné (ou tout élément de sa hiérarchie parente). L’ajustement du contexte est rarement utilisé, mais il autorise des concepts puissants tels que l’intégration d’objets, la construction d’espaces de noms, etc.

RemoveParentModel

La fonction RemoveParentModel supprime un modèle parent spécifié de la chaîne de recherche parente de l’objet donné.

SetContextForDataModel

La méthode SetContextForDataModel est utilisée par l’implémentation d’un modèle de données pour placer des données d’implémentation sur des objets d’instance. Conceptuellement, chaque IModelObject (appelez this l’instance pour simplifier) contient une table de hachage d’état. La table de hachage est indexée par un autre IModelObject (appelez this le modèle de données pour simplifier) qui se trouve dans la hiérarchie du modèle parent de l’instance. La valeur contenue dans ce hachage est un ensemble d’informations d’état comptabilisées de référence et représentées par une instance IUnknown. Une fois que le modèle de données a défini cet état sur l’instance, il peut stocker des données d’implémentation arbitraires qui peuvent être récupérées au moyen d’éléments tels que les getters de propriété.

GetContextForDataModel

La méthode GetContextForDataModel est utilisée pour récupérer des informations de contexte qui ont été définies lors d’un appel antérieur à SetContextForDataModel. On récupère ainsi les informations d’état définies sur un objet d’instance par un modèle de données plus haut dans la hiérarchie du modèle parent de l’objet d’instance. Pour en savoir plus sur ce contexte/cet état et sa signification, consultez la documentation relative à SetContextForDataModel.

Types d’objets centraux du modèle de données du débogueur

Un objet dans le modèle de données est similaire à la notion d’objet dans .NET. Il s’agit du conteneur générique dans lequel les constructions comprises par le modèle de données peuvent être placées. Outre les objets natifs et les objets synthétiques (dynamiques), il existe une série de types d’objets centraux qui peuvent être placés (ou boxed) dans le conteneur d’un IModelObject. Le conteneur dans lequel la plupart de ces valeurs sont placées est une VARIANTE COM/OLE standard avec un certain nombre de restrictions supplémentaires placées sur ce que ce VARIANT peut contenir. Les types les plus basiques sont les suivants :

  • Valeurs signées et non signées 8 bits (VT_UI1, VT_I1)
  • Valeurs signées et non signées 16 bits (VT_UI2, VT_UI2)
  • Valeurs signées et non signées 32 bits (VT_UI4, VT_I4)
  • Valeurs signées et non signées 64 bits (VT_UI8, VT_I8)
  • Valeurs à virgule flottante simple et double précision (VT_R4, VT_R8)
  • Chaînes (VT_BSTR)
  • Valeurs booléennes (VT_BOOL)

Outre ces types de base, un certain nombre d’objets du modèle de données central sont placés dans IModelObject défini par VT_UNKNOWN, où l’IUnknown stocké est garanti pour mettre en œuvre une interface spécifique.nter une interface spécifique. Ces types sont les suivants :

  • Accesseurs de propriété (IModelPropertyAccessor)
  • Objets de méthode (IModelMethod)
  • Objets de référence clés (IModelKeyReference ou IModelKeyReference2)
  • Objets de contexte (IDebugModelHostContext)

Accesseurs de propriété : IModelPropertyAccessor

Un accesseur de propriété dans le modèle de données est une implémentation de l’interface IModelPropertyAccessor qui est boxed dans un IModelObject. L’objet de modèle renvoie un type d’ObjectPropertyAccessor lorsqu’il est interrogé et la valeur intrinsèque est une VT_UNKNOWN qui est garantie comme pouvant être interrogée pour IModelPropertyAccessor. En cours de traitement, il est garanti qu’elle peut être convertie statiquement en IModelPropertyAccessor.

Un accesseur de propriété est un moyen indirect d’obtenir un appel de méthode pour obtenir et définir une valeur clé dans le modèle de données. Si la valeur d’une clé donnée est un accesseur de propriété, les méthodes GetKeyValue et SetKeyValue le signalent automatiquement et appellent les méthodes GetValue ou SetValue sous-jacentes de l’accesseur de propriété, selon le cas.

L’interface IModelPropertyAccessor est définie comme suit :

DECLARE_INTERFACE_(IModelPropertyAccessor, IUnknown)
{
    STDMETHOD(GetValue)(_In_ PCWSTR key, _In_opt_ IModelObject* contextObject, _COM_Outptr_ IModelObject** value) PURE;
    STDMETHOD(SetValue)(_In_ PCWSTR key, _In_opt_ IModelObject* contextObject, _In_ IModelObject* value) PURE; 
}

GetValue

La méthode GetValue est le getter de l’accesseur de propriété. Elle est appelée chaque fois qu’un client souhaite récupérer la valeur sous-jacente de la propriété. Il convient de noter que tout appelant qui obtient directement un accesseur de propriété est chargé de transmettre le nom de clé et l’objet d’instance précis (pointeur this) à la méthode GetValue de l’accesseur de propriété.

SetValue

La méthode SetValue est le setter de l’accesseur de propriété. Elle est appelée chaque fois qu’un client souhaite affecter une valeur à la propriété sous-jacente. De nombreuses propriétés sont en lecture seule. Dans ce cas, l’appel de la méthode SetValue renvoie E_NOTIMPL. Il convient de noter que tout appelant qui obtient directement un accesseur de propriété est chargé de transmettre le nom de clé et l’objet d’instance précis (pointeur this) à la méthode SetValue de l’accesseur de propriété.

Méthodes : IModelMethod

Une méthode dans le modèle de données est une implémentation de l’interface IModelMethod qui est boxed dans un IModelObject. L’objet de modèle renvoie un type d’ObjectMethod lorsqu’il est interrogé et la valeur intrinsèque est une VT_UNKNOWN qui est garantie comme pouvant être interrogée pour IModelMethod. En cours de traitement, il est garanti qu’elle peut être convertie statiquement en IModelMethod. Toutes les méthodes du modèle de données sont dynamiques par nature. Elles prennent comme entrée un ensemble de 0 arguments ou plus et renvoient une seule valeur en sortie. Il n’y a pas de résolution de surcharge ni de métadonnées sur les noms des paramètres, les types ou les attentes.

L’interface IModelMethod se définit comme suit :

DECLARE_INTERFACE_(IModelMethod, IUnknown)
{
    STDMETHOD(Call)(_In_opt_ IModelObject *pContextObject, _In_ ULONG64 argCount, _In_reads_(argCount) IModelObject **ppArguments, _COM_Errorptr_ IModelObject **ppResult, _COM_Outptr_opt_result_maybenull_ IKeyStore **ppMetadata) PURE;
}

Appeler

La méthode Call est le moyen par lequel une méthode définie dans le modèle de données est appelée. L’appelant est chargé de transmettre un objet d’instance précis (pointeur this) et un ensemble arbitraire d’arguments. Le résultat de la méthode et toutes les métadonnées facultatives associées à ce résultat sont renvoyées. Les méthodes qui ne renvoient pas logiquement de valeur doivent néanmoins renvoyer un IModelObject valide. Dans ce cas, l’iModelObject est une valeur non intégrée. En cas d’échec d’une méthode, cette dernière peut renvoyer des informations d’erreur étendues facultatives dans l’argument d’entrée (même si le HRESULT renvoyé est un échec). Il est impératif que les appelants vérifient cela.

Références clés : IModelKeyReference ou IModelKeyReference2

Une référence de clé est, par essence, le descripteur d’une clé d’un objet particulier. Un client peut récupérer ce descripteur avec des méthodes telles que GetKeyReference et utiliser l’utiliser ultérieurement pour obtenir ou définir la valeur de la clé sans nécessairement conserver l’objet d’origine. Ce type d’objet est une implémentation de l’interface IModelKeyReference ou IModelKeyReference2 qui est boxed dans un IModelObject. L’objet de modèle renvoie un type d’ObjectKeyReference lorsqu’il est interrogé et la valeur intrinsèque est une VT_UNKNOWN qui est garantie comme pouvant être interrogée pour IModelKeyReference. En cours de traitement, il est garanti qu’elle peut être convertie statiquement en IModelKeyReference.

L’interface de référence clé est définie comme suit :

DECLARE_INTERFACE_(IModelKeyReference2, IModelKeyReference)
{
    STDMETHOD(GetKeyName)(_Out_ BSTR* keyName) PURE;
    STDMETHOD(GetOriginalObject)(_COM_Outptr_ IModelObject** originalObject) PURE;
    STDMETHOD(GetContextObject)(_COM_Outptr_ IModelObject** containingObject) PURE;
    STDMETHOD(GetKey)(_COM_Errorptr_opt_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(GetKeyValue)(_COM_Errorptr_opt_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(SetKey)(_In_opt_ IModelObject* object, _In_opt_ IKeyStore* metadata) PURE;
    STDMETHOD(SetKeyValue)(_In_ IModelObject* object) PURE;
    STDMETHOD(OverrideContextObject)(_In_ IModelObject* newContextObject) PURE;
}

GetKeyName

La méthode GetKeyName renvoie le nom de la clé pour laquelle cette référence de clé est un descripteur. La chaîne renvoyée est une BSTR standard et doit être libérée via un appel à SysFreeString.

GetOriginalObject

La méthode GetOriginalObject renvoie l’objet d’instance à partir duquel la référence de clé a été créée. Il convient de noter que la clé peut elle-même se trouver sur un modèle parent de l’objet d’instance.

GetContextObject

La méthode GetContextObject renvoie le contexte (pointeur this) qui sera transmis à la méthode GetValue ou SetValue d’un accesseur de propriété si la clé en question fait référence à un accesseur de propriété. L’objet de contexte renvoyé ici peut ou non être identique à l’objet d’origine récupéré à partir de GetOriginalObject. Si une clé se trouve sur un modèle parent et qu’il existe un ajusteur de contexte associé à ce dernier, l’objet d’origine est l’objet d’instance sur lequel GetKeyReference ou EnumerateKeyReferences a été appelé. L’objet de contexte serait tout ce qui sort de l’ajusteur de contexte final entre l’objet d’origine et le modèle parent contenant la clé pour laquelle cette référence de clé est un descripteur. En l’absence d’un ajusteur de contexte, l’objet d’origine et l’objet de contexte sont identiques.

GetKey

La méthode GetKey sur une référence de clé se comporte comme la méthode GetKey sur IModelObject. Elle renvoie la valeur de la clé sous-jacente et toutes les métadonnées associées à cette dernière. Si la valeur de la clé est un accesseur de propriété, elle renvoie l’accesseur de propriété (IModelPropertyAccessor) boxed dans un IModelObject. Cette méthode n’appelle pas les méthodes GetValue ou SetValue sous-jacentes sur l’accesseur de propriété.

GetKeyValue

La méthode GetKeyValue sur une référence de clé se comporte comme la méthode GetKeyValue sur IModelObject. Elle renvoie la valeur de la clé sous-jacente et toutes les métadonnées associées à cette dernière. Si la valeur de la clé est un accesseur de propriété, elle appelle automatiquement la méthode GetValue sous-jacente sur l’accesseur de propriété.

SetKey

La méthode SetKey sur une référence de clé se comporte comme la méthode SetKey sur IModelObject. Elle affecte la valeur de la clé. Si la clé d’origine était un accesseur de propriété, celle-ci remplace ce dernier. Elle n’appelle pas la méthode SetValue sur l’accesseur de propriété.

SetKeyValue

La méthode SetKeyValue sur une référence de clé se comporte comme la méthode SetKeyValue sur IModelObject. Elle affecte la valeur de la clé. Si la clé d’origine était un accesseur de propriété, cela appelle la méthode SetValue sous-jacente sur l’accesseur de propriété plutôt que de remplacer l’accesseur de propriété lui-même.

OverrideContextObject

La méthode OverrideContextObject (présente uniquement sur IModelKeyReference2) est une méthode avancée utilisée pour modifier définitivement l’objet de contexte que cette référence de clé transmet à toutes les méthodes GetValue ou SetValue sous-jacentes de l’accesseur de propriété. L’objet transmis à cette méthode est également renvoyé à partir d’un appel à GetContextObject. Cette méthode peut être utilisée par les fournisseurs de scripts pour répliquer certains comportements de langage dynamique. La plupart des clients ne doivent pas appeler cette méthode.

Objets de contexte : IDebugHostContext

Les objets de contexte sont des blobs opaques d’informations que l’hôte de débogage (en coopération avec le modèle de données) associe à chaque objet. Ils peuvent inclure des éléments tels que le contexte de processus ou l’espace d’adressage d’où proviennent les informations, etc. Un objet de contexte est une implémentation de IDebugHostContext dans un IModelObject. Il convient de noter que IDebugHostContext est une interface définie par l’hôte. Un client n’implémentera jamais cette interface.

Pour en savoir plus sur les objets de contexte, consultez Interfaces hôtes C++ du modèle de données du débogueur dans les interfaces C++ du modèle de données du débogueur.

Gestionnaire du modèle de données

L’interface principale du gestionnaire du modèles de données, IDataModelManager2 (ou IDataModelManager précédente) est définie comme suit :

DECLARE_INTERFACE_(IDataModelManager2, IDataModelManager)
{
    //
    // IDataModelManager:
    //
    STDMETHOD(Close)() PURE;
    STDMETHOD(CreateNoValue)(_Out_ IModelObject** object) PURE;
    STDMETHOD(CreateErrorObject)(_In_ HRESULT hrError, _In_opt_ PCWSTR pwszMessage, _COM_Outptr_ IModelObject** object) PURE;
    STDMETHOD(CreateTypedObject)(_In_opt_ IDebugHostContext* context, _In_ Location objectLocation, _In_ IDebugHostType* objectType, _COM_Errorptr_ IModelObject** object) PURE;
    STDMETHOD(CreateTypedObjectReference)(_In_opt_ IDebugHostContext* context, _In_ Location objectLocation, _In_ IDebugHostType* objectType, _COM_Errorptr_ IModelObject** object) PURE;
    STDMETHOD(CreateSyntheticObject)(_In_opt_ IDebugHostContext* context, _COM_Outptr_ IModelObject** object) PURE;
    STDMETHOD(CreateDataModelObject)(_In_ IDataModelConcept* dataModel, _COM_Outptr_ IModelObject** object) PURE;
    STDMETHOD(CreateIntrinsicObject)(_In_ ModelObjectKind objectKind, _In_ VARIANT* intrinsicData, _COM_Outptr_ IModelObject** object) PURE;
    STDMETHOD(CreateTypedIntrinsicObject)(_In_ VARIANT* intrinsicData, _In_ IDebugHostType* type, _COM_Outptr_ IModelObject** object) PURE;
    STDMETHOD(GetModelForTypeSignature)(_In_ IDebugHostTypeSignature* typeSignature, _Out_ IModelObject** dataModel) PURE;
    STDMETHOD(GetModelForType)(_In_ IDebugHostType* type, _COM_Outptr_ IModelObject** dataModel, _COM_Outptr_opt_ IDebugHostTypeSignature** typeSignature, _COM_Outptr_opt_ IDebugHostSymbolEnumerator** wildcardMatches) PURE;
    STDMETHOD(RegisterModelForTypeSignature)(_In_ IDebugHostTypeSignature* typeSignature, _In_ IModelObject* dataModel) PURE;
    STDMETHOD(UnregisterModelForTypeSignature)(_In_ IModelObject* dataModel, _In_opt_ IDebugHostTypeSignature* typeSignature) PURE;
    STDMETHOD(RegisterExtensionForTypeSignature)(_In_ IDebugHostTypeSignature* typeSignature, _In_ IModelObject* dataModel) PURE;
    STDMETHOD(UnregisterExtensionForTypeSignature)(_In_ IModelObject* dataModel, _In_opt_ IDebugHostTypeSignature* typeSignature) PURE;
    STDMETHOD(CreateMetadataStore)(_In_opt_ IKeyStore* parentStore, _COM_Outptr_ IKeyStore** metadataStore) PURE;
    STDMETHOD(GetRootNamespace)(_COM_Outptr_ IModelObject** rootNamespace) PURE;
    STDMETHOD(RegisterNamedModel)(_In_ PCWSTR modelName, _In_ IModelObject *modeObject) PURE;
    STDMETHOD(UnregisterNamedModel)(_In_ PCWSTR modelName) PURE;
    STDMETHOD(AcquireNamedModel)(_In_ PCWSTR modelName, _COM_Outptr_ IModelObject **modelObject) PURE;
    //
    // IDataModelManager2:
    //
    STDMETHOD(AcquireSubNamespace)(_In_ PCWSTR modelName, _In_ PCWSTR subNamespaceModelName, _In_ PCWSTR accessName, _In_opt_ IKeyStore *metadata, _COM_Outptr_ IModelObject **namespaceModelObject) PURE;
    STDMETHOD(CreateTypedIntrinsicObjectEx)(_In_opt_ IDebugHostContext* context, _In_ VARIANT* intrinsicData, _In_ IDebugHostType* type, _COM_Outptr_ IModelObject** object) PURE;
}

Méthodes de gestion

L’ensemble de méthodes suivant est utilisé par l’application (par exemple, débogueur) hébergeant le modèle de données.

STDMETHOD(Close)() PURE;

Close

La méthode Close est appelée sur le gestionnaire de modèles de données par une application (par exemple, le débogueur) hébergeant ce dernier afin de démarrer le processus d’arrêt du gestionnaire de celui-ci. Un hôte du modèle de données qui n’appelle pas la méthode Close avant de publier sa référence finale sur le gestionnaire de modèle de données peut provoquer un comportement indéfini, y compris, mais sans s’y limiter, des fuites importantes de l’infrastructure de gestion du modèle de données.

Méthodes de création/boxing d’objets

L’ensemble de méthodes ci-dessous est utilisé pour créer de nouveaux objets ou pour le boxing des valeurs dans un IModelObject, l’interface principale du modèle de données.

STDMETHOD(CreateNoValue)(_Out_ IModelObject** object) PURE;
STDMETHOD(CreateErrorObject)(_In_ HRESULT hrError, _In_opt_ PCWSTR pwszMessage, _COM_Outptr_ IModelObject** object) PURE;
STDMETHOD(CreateTypedObject)(_In_opt_ IDebugHostContext* context, _In_ Location objectLocation, _In_ IDebugHostType* objectType, _COM_Errorptr_ IModelObject** object) PURE;
STDMETHOD(CreateTypedObjectReference)(_In_opt_ IDebugHostContext* context, _In_ Location objectLocation, _In_ IDebugHostType* objectType, _COM_Errorptr_ IModelObject** object) PURE;
STDMETHOD(CreateSyntheticObject)(_In_opt_ IDebugHostContext* context, _COM_Outptr_ IModelObject** object) PURE;
STDMETHOD(CreateDataModelObject)(_In_ IDataModelConcept* dataModel, _COM_Outptr_ IModelObject** object) PURE;
STDMETHOD(CreateIntrinsicObject)(_In_ ModelObjectKind objectKind, _In_ VARIANT* intrinsicData, _COM_Outptr_ IModelObject** object) PURE;
STDMETHOD(CreateTypedIntrinsicObject)(_In_ VARIANT* intrinsicData, _In_ IDebugHostType* type, _COM_Outptr_ IModelObject** object) PURE;
STDMETHOD(CreateMetadataStore)(_In_opt_ IKeyStore* parentStore, _COM_Outptr_ IKeyStore** metadataStore) PURE;
STDMETHOD(CreateTypedIntrinsicObjectEx)(_In_opt_ IDebugHostContext* context, _In_ VARIANT* intrinsicData, _In_ IDebugHostType* type, _COM_Outptr_ IModelObject** object) PURE;

CreateNoValue

La méthode CreateNoValue crée un objet « sans valeur », effectue un boxing de ce dernier dans un IModelObject et le renvoie. L’objet de modèle renvoyé a un genre d’ObjectNoValue.

Un objet « sans valeur » a plusieurs significations sémantiques :

  • (Selon le langage), il peut être considéré comme l’équivalent sémantique de vide, null ou indéfini
  • Toute méthode GetValue d’un accesseur de propriété qui renvoie un succès et un objet « sans valeur » indique que la propriété particulière n’a pas de valeur pour l’instance donnée et doit être traitée comme si la propriété n’existait pas pour cette instance particulière.
  • Les méthodes de modèle de données qui n’ont pas sémantiquement de valeur de retour l’utilisent comme sentinelle pour l’indiquer (car une méthode doit renvoyer un IModelObject valide).

CreateErrorObject

La méthode CreateErrorObject crée un « objet d’erreur ». Le modèle de données ne connaît pas la notion d’exceptions et de flux d’exceptions. L’échec d’une propriété/méthode peut se manifester de deux manières :

  • Un seul HRESULT défaillant sans informations d’erreur étendues. Soit il n’y a pas d’autres informations à fournir pour l’erreur, soit l’erreur elle-même est explicite dans le HRESULT renvoyé.
  • Un seul HRESULT défaillant couplé à des informations d’erreur étendues. Les informations d’erreur étendues sont un objet d’erreur renvoyé dans l’argument de sortie de la propriété/méthode.

CreateTypedObject

La méthode CreateTypedObject est la méthode qui permet à un client de créer une représentation d’un objet natif/de langage dans l’espace d’adressage d’une cible de débogage. Si le type de l’objet nouvellement créé (comme indiqué par l’argument objectType) correspond à une ou plusieurs signatures de type inscrites auprès du gestionnaire de modèles de données en tant que visualiseurs ou extensions canoniques, ces modèles de données correspondants sont automatiquement attachés à l’objet d’instance créé avant qu’il ne soit renvoyé à l’appelant.

CreateTypedObjectReference

La méthode CreateTypedObjectReference est sémantiquement similaire à la méthode CreateTypedObject, sauf qu’elle crée une référence à la construction native/de langage sous-jacente. La référence créée est un objet qui a un type d’ObjectTargetObjectReference. Il ne s’agit pas d’une référence native que le langage sous-jacent pourrait prendre en charge (par exemple, un C++ & ou &&). Il est tout à fait possible d’avoir un ObjectTargetObjectReference à une référence C++. Un objet de type ObjectTargetObjectReference peut être converti en valeur sous-jacente à l’aide de la méthode Dereference sur IModelObject. La référence peut également être transmise à l’évaluateur d’expression de l’hôte sous-jacent afin de réassigner la valeur d’une manière adaptée au langage.

CreateSyntheticObject

La méthode CreateSyntheticObject crée un objet de modèle de données vide : dictionnaire de tuples et de clé/valeur/métadonnées et de concepts. Au moment de la création, il n’existe pas de clés ni de concepts sur l’objet. Il s’agit d’une ardoise vierge que l’appelant peut utiliser.

CreateDataModelObject

La méthode CreateDataModelObject est un simple wrapper d’aide à la création d’objets qui sont des modèles de données, c’est-à-dire des objets qui vont être attachés à d’autres objets en tant que modèles parents. Tous ces objets doivent prendre en charge le concept de modèle de données via IDataModelConcept. Cette méthode crée un objet synthétique vide sans contexte explicite et ajoute l’IDataModelConcept intégré comme implémentation de l’objet nouvellement créé du concept de modèle de données. Cela peut également être effectué avec des appels à CreateSyntheticObject et SetConcept.

CreateIntrinsicObject

La méthode CreateIntrinsicObject est la méthode qui effectue un boxing des valeurs intrinsèques dans IModelObject. L’appelant place la valeur dans un VARIANT COM et appelle cette méthode. Le gestionnaire de modèles de données renvoie un IModelObject représentant l’objet. Il convient de noter que cette méthode est également utilisée pour effectuer le boxing des types fondamentaux basés sur IUnknown   les accesseurs de propriété, les méthodes, les contextes, etc. Dans ce cas, la méthode objectKind indique quel type de construction basée sur IUnknown l’objet représente et le champ punkVal de la variante passée est le type dérivé IUnknown. Le type doit être statiquement adaptable à l’interface de modèle appropriée (par exemple, IModelPropertyAccessor, IModelMethod, IDebugHostContext, etc.) en cours de traitement. Les types VARIANT pris en charge par cette méthode sont VT_UI1, VT_I1, VT_UI2, VT_I2, VT_UI4, VT_I4, VT_UI8, VT_I8, VT_R4, VT_R8, VT_BOOL, VT_BSTR et VT_UNKNOWN (pour un ensemble spécialisé de types dérivés IUnknown, comme indiqué par l’énumération ModelObjectKind.

CreateTypedIntrinsicObject

La méthode CreateTypedintrinsicObject est similaire à la méthode CreateIntrinsicObject, si ce n’est qu’elle permet à un type natif/de langue d’être associé aux données et porté avec la valeur boxed. Ainsi, le modèle de données peut représenter des constructions telles que des types d’énumération natifs (qui sont simplement des valeurs VT_UI* ou VT_I*). Les types de pointeurs sont également créés avec cette méthode. Dans le modèle de données, un pointeur natif est une quantité de 64 bits étendue à zéro qui représente un décalage dans l’espace d’adressage virtuel de la cible de débogage. Il est boxed à l’intérieur d’un VT_UI8 et est créé avec cette méthode et un type qui indique un pointeur natif/de langage.

CreateMetadataStore

La méthode CreateMetadataStore crée un magasin de clés, un conteneur simplifié de tuples de clé/valeur/métadonnées, qui est utilisé pour contenir les métadonnées qui peuvent être associées aux propriétés et une variété d’autres valeurs. Un magasin de métadonnées peut avoir un parent unique (qui peut avoir un seul parent). Si une clé de métadonnées donnée ne se trouve pas dans un magasin donné, on vérifie ses parents. La plupart des magasins de métadonnées n’ont pas de parents. Toutefois, cela permet de partager facilement des métadonnées communes.

CreateTypedIntrinsicObjectEx

La méthode CreateTypedIntrinsicObjectEx est sémantiquement similaire à la méthode CreateTypedIntrinsicObject. La seule différence entre les deux est que celle-ci permet à l’appelant de spécifier le contexte dans lequel les données intrinsèques sont valides. Si aucun contexte n’est transmis, les données sont considérées comme valides quel que soit le contexte hérité de l’argument de type (comportement de CreateTypedIntrinsicObject). Cela permet de créer des valeurs de pointeur typées dans la cible de débogage qui nécessitent un contexte plus spécifique que celui qui peut être hérité du type.

Méthodes d’extension/d’inscription L’ensemble de méthodes suivant gère le mécanisme d’extensibilité du modèle de données, ce qui permet à un client d’étendre ou d’inscrire des modèles existants, ou de demander au modèle de données d’attacher automatiquement un modèle parent donné sur les types natifs qui correspondent à un critère donné.

    STDMETHOD(GetModelForTypeSignature)(_In_ IDebugHostTypeSignature* typeSignature, _Out_ IModelObject** dataModel) PURE;
    STDMETHOD(GetModelForType)(_In_ IDebugHostType* type, _COM_Outptr_ IModelObject** dataModel, _COM_Outptr_opt_ IDebugHostTypeSignature** typeSignature, _COM_Outptr_opt_ IDebugHostSymbolEnumerator** wildcardMatches) PURE;
    STDMETHOD(RegisterModelForTypeSignature)(_In_ IDebugHostTypeSignature* typeSignature, _In_ IModelObject* dataModel) PURE;
    STDMETHOD(UnregisterModelForTypeSignature)(_In_ IModelObject* dataModel, _In_opt_ IDebugHostTypeSignature* typeSignature) PURE;
    STDMETHOD(RegisterExtensionForTypeSignature)(_In_ IDebugHostTypeSignature* typeSignature, _In_ IModelObject* dataModel) PURE;
    STDMETHOD(UnregisterExtensionForTypeSignature)(_In_ IModelObject* dataModel, _In_opt_ IDebugHostTypeSignature* typeSignature) PURE;
    STDMETHOD(GetRootNamespace)(_COM_Outptr_ IModelObject** rootNamespace) PURE;
    STDMETHOD(RegisterNamedModel)(_In_ PCWSTR modelName, _In_ IModelObject *modeObject) PURE;
    STDMETHOD(UnregisterNamedModel)(_In_ PCWSTR modelName) PURE;
    STDMETHOD(AcquireNamedModel)(_In_ PCWSTR modelName, _COM_Outptr_ IModelObject **modelObject) PURE;

GetModelForTypeSignature

La méthode GetModelForTypeSignature renvoie le modèle de données qui a été inscrit pour une signature de type particulière via un appel préalable à la méthode RegisterModelForTypeSignature. Le modèle de données renvoyé par cette méthode est considéré comme le visualiseur canonique pour n’importe quel type qui correspond à la signature de type transmise. En tant que visualiseur canonique, ce modèle de données prend en charge l’affichage du type. Les moteurs d’affichage masquent par défaut les constructions natives/de langage de l’objet en faveur de la vue de l’objet présenté par le modèle de données.

GetModelForType

La méthode GetModelForType renvoie le modèle de données qui est le visualiseur canonique pour une instance de type donnée. En effet, cette méthode recherche la meilleure signature de type correspondante qui a été inscrite avec un appel préalable à la méthode RegisterModelForTypeSignature et renvoie le modèle de données associé.

RegisterModelForTypeSignature

La méthode RegisterModelForTypeSignature est la méthode principale utilisée par un appelant pour inscrire un visualiseur canonique pour un type donné (ou ensemble de types). Un visualiseur canonique est un modèle de données qui, en fait, prend en charge l’affichage d’un type donné (ou d’un ensemble de types). Au lieu de l’affichage natif/de langage du type affiché dans n’importe quelle interface utilisateur du débogueur, c’est la vue du type présentée par le modèle de données inscrit qui est affichée (ainsi qu’un moyen de revenir à la vue native/de langage pour l’utilisateur qui le souhaite).

UnregisterModelForTypeSignature

La méthode UnregisterModelForTypeSignature annule un appel préalable à la méthode RegisterModelForTypeSignature. Cette méthode peut soit supprimer un modèle de données donné en tant que visualiseur canonique pour les types correspondant à une signature de type particulière, soit supprimer un modèle de données donné en tant que visualiseur canonique pour chaque signature de type sous laquelle ce modèle de données est inscrit.

RegisterExtensionForTypeSignature

La méthode RegisterExtensionForTypeSignature est similaire à la méthode RegisterModelForTypeSignature avec une différence clé. Le modèle de données qui est transmis à cette méthode n’est pas le visualiseur canonique pour n’importe quel type et il ne prend pas en charge l’affichage de la vue native/de langage de ce type. Le modèle de données qui est transmis à cette méthode est automatiquement ajouté en tant que parent à n’importe quel type concret qui correspond à la signature de type fournie. Contrairement à la méthode RegisterModelForTypeSignature, il n’existe aucune limite concernant les signatures de type identiques ou ambiguës inscrites en tant qu’extensions d’un type donné (ou ensemble de types). Chaque extension dont la signature de type correspond à une instance de type concrète donnée entraîne l’attachement automatique du modèle de données inscrit via cette méthode aux objets nouvellement créés en tant que modèles parents. Cela permet à un nombre arbitraire de clients d’étendre un type (ou ensemble de types) avec de nouveaux champs ou fonctionnalités.

UnregisterExtensionForTypeSignature

La méthode UnregisterExtensionForTypeSignature annule un appel préalable à la méthode RegisterExtensionForTypeSignature. Elle annule l’inscription d’un modèle de données particulier en tant qu’extension pour une signature de type particulière ou comme extension pour toutes les signatures de type sur lesquelles le modèle de données a été inscrit.

GetRootNamespace

La méthode GetRootNamespace renvoie l’espace de noms racine du modèle de données. Il s’agit d’un objet que le modèle de données gère et dans lequel l’hôte de débogage place certains objets.

RegisterNamedModel

La méthode RegisterNamedModel inscrit un modèle de données donné sous un nom bien connu afin qu’il soit trouvé par les clients souhaitant l’étendre. C’est l’objectif premier de l’API : publier un modèle de données comme quelque chose qui peut être étendu en récupérant le modèle inscrit sous ce nom bien connu et en lui ajoutant un modèle parent.

UnregisterNamedModel

La méthode UnregisterNamedModel annule un appel préalable à la méthode RegisterNamedModel. Elle supprime l’association entre un modèle de données et un nom sous lequel il peut être recherché.

AcquireNamedModel

Un appelant qui souhaite étendre un modèle de données inscrit sous un nom donné appelle la méthode AcquireNamedModel afin de récupérer l’objet pour le modèle de données qu’il souhaite étendre. Cette méthode renvoie le modèle de données inscrit via un appel préalable à la méthode RegisterNamedModel. Comme l’objectif principal de la méthode AcquireNamedModel est d’étendre le modèle, elle a un comportement spécial si aucun modèle n’a encore été inscrit sous le nom donné. Si aucun modèle n’a encore été inscrit sous le nom donné, un objet stub est créé, inscrit temporairement sous le nom donné et renvoyé à l’appelant. Lorsque le modèle de données réel est inscrit via un appel à la méthode RegisterNamedModel, toutes les modifications apportées à l’objet stub sont apportées au modèle réel. Cela permet d’éliminer de nombreux problèmes de dépendance liés à l’ordre de chargement des composants qui s’étendent les uns les autres.

Méthodes d’assistance

Les méthodes suivantes sont des méthodes d’assistance générales qui aident à effectuer des opérations complexes sur des objets dans le modèle de données. Bien qu’il soit possible d’effectuer ces actions au moyen d’autres méthodes sur le modèle de données ou ses objets, ces méthodes pratiques facilitent grandement les choses :

STDMETHOD(AcquireSubNamespace)(_In_ PCWSTR modelName, _In_ PCWSTR subNamespaceModelName, _In_ PCWSTR accessName, _In_opt_ IKeyStore *metadata, _COM_Outptr_ IModelObject **namespaceModelObject) PURE;

AcquireSubNamespace

La méthode AcquireSubNamespace facilite la construction d’une chose qui pourrait ressembler davantage à un espace de noms de langage qu’à un nouvel objet dans un langage dynamique. Si un appelant souhaite, par exemple, classer les propriétés d’un objet de processus par catégories afin de mieux organiser ce dernier et de faciliter la découverte des propriétés, il peut créer un sous-objet pour chaque catégorie de l’objet de processus et placer les propriétés à l’intérieur de cet objet.

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

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