Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
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 du débogueur.
le modèle objet du débogueur principal
L’une des choses les plus fondamentales mais puissantes sur le modèle de données est qu’elle normalise la définition de ce qu’est un objet et comment l’on interagit avec un objet. 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.
Il existe plusieurs choses différentes qui peuvent être conservées dans (ou boxées) dans une IModelObject:
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.
Native Objects - 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 ce que le débogueur cible
Objets synthétiques - Un IModelObject peut être un objet dynamique - un dictionnaire si vous le souhaitez : 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é : quelque 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 boxée dans un IModelObject
Methods - Un IModelObject peut représenter une méthode : quelque 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 boxée dans un IModelObject
Extensibilité dans le modèle objet
Un IModelObject n’est pas un objet isolé. En plus de représenter l’un des types d’objets indiqués ci-dessus, chaque objet a la notion d’une chaîne de modèles de données parents. Cette chaîne se comporte beaucoup comme une chaîne de prototype JavaScript . Au lieu d’une chaîne linéaire de prototypes comme 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 a à son tour une autre chaîne linéaire de son propre ensemble de parents. En essence, chaque objet est une agrégation des fonctionnalités (propriétés, etc.) de lui-même et de chaque objet dans cette arborescence. Lorsqu’une propriété spécifique est interrogée, si l’objet sur lequel il est interrogé ne prend pas en charge cette propriété, la requête est transmise de façon linéaire à chaque parent à son tour. Cela crée un comportement dans lequel la recherche d’une propriété est résolue par une recherche approfondie de l’arborescence d’agrégation.
L’extensibilité dans ce modèle objet est très simple étant donné cette notion que chaque objet est un agrégat de lui-même et l’arborescence des modèles parents. Une extension peut entrer et s’ajouter à la liste des modèles parents pour un autre objet. Cette étend l’objet. De cette façon, il est possible d’ajouter des fonctionnalités à tout : une instance particulière d’un objet ou d’une valeur, un type natif, le concept du débogueur de ce qu’est un processus ou un thread, ou même la notion de « tous les objets itérables ».
Contexte, contexte et contexte : le ce pointeur, l’espace d’adressage et les données privées d’implémentation
Il existe trois notions de contexte qui sont nécessaires pour comprendre dans le contexte du modèle objet.
Contexte : ce pointeur
É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 est nécessaire 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 ce pointeur en C++ ou le cet objet en JavaScript. Cet objet d’instance est passé à une variété de méthodes comme premier argument appelé contexte dans les méthodes décrites.
Contexte : Espace d’adressage
Il est important de noter que contrairement aux modèles d’extension précédents où 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 l’interface utilisateur, les interfaces de modèle de données prennent généralement ce contexte explicitement ou implicitement en tant qu’interface IDebugHostContext. Chaque IModelObject au sein du modèle de données porte ce type d’informations de contexte avec elle et peut propager ce contexte aux objets qu’il retourne. Cela signifie que lorsque vous lisez une valeur native ou une valeur clé à partir d’un IModelObject, il lit la cible et traite l’emplacement à partir duquel l’objet a été acquis à l’origine.
Il existe une valeur constante explicite, USE_CURRENT_HOST_CONTEXT, qui peut être passée à 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 : Implémentation de données privées
N’oubliez pas que chaque objet du modèle de données est en fait un agrégat de l’instance d’objet et 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 d’implémentation privées à n’importe quel objet d’instance. Chaque IModelObject créé a conceptuellement une table de hachage qui mappe d’un modèle parent particulier aux données d’instance privée définies par une interface IUnknown. Cela permet à un modèle parent de mettre en cache des informations sur chaque instance ou d’avoir des données arbitraires associées.
Ce type de contexte est accessible via les méthodes GetContextForDataModel et SetContextForDataModel sur IModelObject.
l’interface 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
Voici les méthodes générales applicables à n’importe quel 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;
La méthode GetKind retourne le type d’objet qui est boxé à l’intérieur du IModelObject.
La méthode GetContext retourne le contexte hôte associé à l’objet.
La méthode GetIntrinsicValue retourne la chose qui est boxée à l’intérieur d’un IModelObject. Cette méthode peut uniquement être appelée légalement sur les interfaces IModelObject qui représentent une interface intrinsèque boxée ou une interface particulière qui est boxée. Il ne peut pas être appelé sur des objets natifs, aucun objet valeur, objets synthétiques et objets de référence. La méthode GetIntrinsicValueAs se comporte autant que la méthode GetIntrinsicValue, sauf qu’elle convertit la valeur en type variant spécifié. Si la conversion ne peut pas être effectuée, la méthode retourne une erreur.
La méthode IsEqualTo compare deux objets de modèle et retourne s’ils sont égaux en valeur. Pour les objets qui ont un ordre, cette méthode retournant true équivaut à la méthode Compare qui retourne 0. Pour les objets qui n’ont pas d’ordre mais qui sont comparables, la méthode Compare échoue, mais ce n’est pas le cas. La signification d’une comparaison basée sur des valeurs est définie par le type d’objet. À l’heure actuelle, cela est défini uniquement pour les types intrinsèques et les objets d’erreur. Il n’existe aucun concept de modèle de données actuel pour l’équatabilité.
La méthode Dereference déréférence un objet. Cette méthode peut être utilisée pour déréférer une référence basée sur un modèle de données (ObjectTargetObjectReference, ObjectKeyReference) ou une référence de langage natif (pointeur ou référence de langage). Il est important de noter que cette méthode supprime un seul niveau de sémantique de référence sur l’objet. Par exemple, il est tout à fait possible d’avoir une référence de modèle de données à une référence de langage. Dans ce cas, l’appel de la méthode Dereference la première fois supprimerait la référence du modèle de données et laisserait la référence de langue. L’appel de dereference sur cet objet résultant supprime par la suite la référence de langue et retourne la valeur native sous cette référence.
méthodes de manipulation de 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, valeurs et métadonnées associées.
Les formes basées sur les valeurs des API sont les suivantes :
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 formes de référence des API sont les suivantes :
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;
La méthode GetKeyValue est la première méthode à laquelle un client va se tourner pour obtenir la valeur (et les métadonnées associées) une clé donnée par nom. Si la clé est un accesseur de propriété , c’est-à-dire qu’il s’agit d’une valeur IModelObject qui est un IModelPropertyAccessor boxed, la méthode GetKeyValue appelle automatiquement la méthode GetValue de l’accesseur de propriété pour récupérer la valeur réelle.
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é. Cette méthode ne peut pas être utilisée pour créer une clé sur un objet. Elle définit uniquement la valeur d’une clé existante. Notez que de nombreuses clés sont en lecture seule (par exemple, elles sont implémentées par un accesseur de propriété qui retourne E_NOT_IMPL à partir de sa méthode SetValue). Cette méthode échoue lorsqu’elle est appelée sur une clé en lecture seule.
La méthode EnumerateKeyValues est la première méthode qu’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 noter que EnumerateKeyValues énumère les clés définies par des noms en double dans l’arborescence d’objets ; toutefois, les méthodes telles que GetKeyValue et SetKeyValue manipulent uniquement la première instance d’une clé avec le nom donné tel que découvert par la profondeur-first-traversal.
La méthode GetKey obtient la valeur (et les métadonnées associées) une clé donnée par nom. La plupart des clients doivent utiliser la méthode GetKeyValue à la place. Si la clé est un accesseur de propriété, l’appel de cette méthode renvoie l’accesseur de propriété (interface IModelPropertyAccessor) boxé dans un IModelObject. Contrairement à GetKeyValue, cette méthode ne résout pas automatiquement la valeur sous-jacente de la clé en appelant la méthode GetValue. Cette responsabilité est celle de l’appelant.
La méthode SetKey est la méthode 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é a déjà une clé portant le nom donné, l’un des deux comportements se produit. Si la clé se trouve sur l’instance donnée par cela, la valeur de cette clé est remplacée comme si la clé d’origine n’existait pas. Si, d’autre part, la clé se trouve dans la chaîne de modèles de données parents de l’instance donnée par cela, une nouvelle clé portant le nom donné est créée sur l’instance donnée. Cela entraînerait, en effet, que l’objet ait deux clés du même nom (similaire à une classe dérivée ombrant un membre du même nom qu’une classe de base).
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 retourne l’accesseur de propriété (un IModelPropertyAccessorInterface) boxé dans un IModelObject plutôt que d’appeler automatiquement la méthode GetValue. Ceci est similaire à la différence entre GetKey et GetKeyValue.
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 ce paramètre. Cette méthode n’a aucun effet sur les modèles parents attachés à l’instance d’objet particulière.
La méthode GetKeyReference recherche une clé du nom donné sur l’objet (ou sa chaîne de modèle parent) et retourne une référence à cette clé donnée par une interface IModelKeyReference boxée dans un IModelObject. Cette référence peut ensuite être utilisée pour obtenir ou définir la valeur de la clé.
La méthode EnumerateKeyReferences se comporte comme la méthode EnumerateKeyValues, sauf qu’elle retourne des références aux clés qu’elle énumère (donnée par une interface IModelKeyReference boxée 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 concept
En plus d’un objet modèle étant 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 effectué sur ou par un objet. Les concepts sont, en essence, un magasin dynamique d’interfaces pris en charge par un objet. Un certain nombre de concepts sont définis par le modèle de données aujourd’hui :
Concept Interface | Description |
---|---|
IDataModelConcept | Le concept est un modèle parent. Si ce modèle est automatiquement attaché à un type natif via 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 via un accès aléatoire) dans une ou plusieurs dimensions. |
IPreferredRuntimeTypeConcept | L’objet comprend plus sur les types dérivés de celui-ci que le système de type sous-jacent est capable de fournir et souhaite gérer ses propres conversions de type statique en type d’exécution. |
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 pont 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 concept à partir du modèle de données de base. Cette interface est généralement utilisée comme pont 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;
La méthode GetConcept recherche un concept sur l’objet (ou sa chaîne de modèle parent) et retourne 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 passe explicitement l’objet de contexte (ou ce qu’on peut appeler traditionnellement ce pointeur). Il est important de s’assurer que l’objet de contexte approprié est passé à chaque interface de concept.
La méthode SetConcept place un concept spécifié sur l’instance d’objet spécifiée par le pointeur. Si un modèle parent attaché à l’instance d’objet spécifiée par cela prend également en charge le concept, l’implémentation dans l’instance remplace celle-ci dans le modèle parent.
La méthode ClearConcepts supprime tous les concepts de l’instance de l’objet spécifié par ce paramètre.
méthodes d’objet natives
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 (dictionnaire de tuples de clé/valeur/métadonnées/concepts), un objet 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 a une série de méthodes sur celle-ci qui accèdent aux informations sur 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;
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.
La méthode EnumerateRawValues énumère tous les enfants natifs (par exemple, champs, classes de base, etc.) de l’objet donné.
La méthode TryCastToRuntimeType demande à l’hôte de débogage d’effectuer une analyse et de déterminer le type d’exécution 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 informations de type de temps d’exécution C++ (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 d’exécution ne signifie pas que cet appel de méthode échoue. Dans ce cas, la méthode retourne l’objet donné (ce pointeur) dans l’argument de sortie.
La méthode GetLocation retourne 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 retourné par cette méthode est un emplacement abstrait qui peut être une adresse virtuelle, peut indiquer le placement 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 Location résultant est 0, il 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 du 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 pour l’hôte de débogage.
La méthode GetTypeInfo retourne le type natif de l’objet donné. Si l’objet n’a pas d’informations de type natif associées (par exemple, il s’agit d’une intrinsèque, etc.), l’appel réussit toujours, mais retourne null.
La méthode GetTargetInfo est effectivement une combinaison des méthodes GetLocation et GetTypeInfo qui retournent à la fois l’emplacement abstrait et le type natif de l’objet donné.
La méthode GetRawReference recherche une construction native dans l’objet donné et retourne une référence à cet objet. Une telle 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 retournée ici (objet du type ObjectTargetObjectReference) d’une référence de langage (par exemple, une référence de style C+&+ ou &&).
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 modèle se comporte très similaire à un objet JavaScript et à sa chaîne prototype. En plus de 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 pouvant, à son tour, avoir un nombre arbitraire de modèles parents attachés à eux). Il s’agit du principal moyen d’extensibilité dans le modèle de données. Si une propriété ou un concept donné ne peut pas se trouver dans une instance donnée, une recherche approfondie de l’arborescence d’objets (définie par les modèles parents) enracinée à 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;
La méthode GetNumberOfParentModels retourne le nombre de modèles parents qui sont attachés à l’instance d’objet donnée. Les modèles parents sont recherchés en premier dans l’ordre linéaire de la chaîne de modèle parent.
La méthode GetParentModel retourne le modèle parent i-ième dans la chaîne de modèle parent de l’objet donné. Les modèles parents sont recherchés pour une propriété ou un concept dans l’ordre linéaire, 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.
La méthode AddParentModel ajoute un nouveau modèle parent à l’objet donné. Un tel modèle peut être ajouté à la fin de la chaîne de recherche (l’argument de remplacement est spécifié comme false) ou à l’avant de la chaîne de recherche (l’argument de remplacement est spécifié comme vrai). En outre, chaque modèle parent peut éventuellement ajuster le contexte (le pointeur sémantique de ce pointeur) pour toute propriété ou concept sur le parent donné (ou toute personne dans sa hiérarchie parente). L’ajustement du contexte est rarement utilisé, mais permet des concepts puissants tels que l’incorporation d’objets, la construction d’espaces de noms, etc.
RemoveParentModel supprime un modèle parent spécifié de la chaîne de recherche parente de l’objet donné.
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 cette instance par souci de simplicité) contient une table de hachage d’état. La table de hachage est indexée par un autre IModelObject (appelez-le pour plus de simplicité) 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 comptées de référence représentées par une instance IUnknown. Une fois que le modèle de données définit cet état sur l’instance, il peut stocker des données d’implémentation arbitraires qui peuvent être récupérées pendant des éléments tels que les getters de propriété.
La méthode GetContextForDataModel est utilisée pour récupérer des informations de contexte qui ont été configurées avec un appel antérieur à SetContextForDataModel. Cela récupère les informations d’état qui ont été 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 plus d’informations sur ce contexte/état et sa signification, consultez la documentation de SetContextForDataModel.
types d’objets principaux 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 la construction que le modèle de données comprend peut être boxée. Outre les objets natifs et les objets synthétiques (dynamiques), il existe une série de types d’objets principaux qui peuvent être placés (ou boxés) 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 variant peut contenir. Les types les plus basiques sont les suivants :
- Valeurs non signées et non signées 8 bits (VT_UI1, VT_I1)
- Valeurs non signées et non signées 16 bits (VT_UI2, VT_UI2)
- Valeurs non signées et signées 32 bits (VT_UI4, VT_I4)
- Valeurs non signées et signées 64 bits (VT_UI8, VT_I8)
- Valeurs à virgule flottante simple et double précision (VT_R4, VT_R8)
- Chaînes (VT_BSTR)
- Booleans (VT_BOOL)
En plus de ces types de base, un certain nombre d’objets de modèle de données de base sont placés dans IModelObject défini par VT_UNKNOWN où l’IUnknown stocké est garanti pour implémenter une interface spécifique. Ces types sont les suivants :
- Accesseurs de propriété (IModelPropertyAccessor)
- Objets de méthode (IModelMethod)
- Objets de référence de clé (IModelKeyReference ou IModelKeyReference2)
- Objets de contexte (IDebugModelHostContext)
Accesseurs de propriétés : IModelPropertyAccessor
Un accesseur de propriété dans le modèle de données est une implémentation de l’interface IModelPropertyAccessor qui est boxée dans un IModelObject. L’objet de modèle retourne un type d’ObjectPropertyAccessor lorsque la requête est interrogée et que la valeur intrinsèque est une VT_UNKNOWN qui est garantie d’être interrogeable pour IModelPropertyAccessor. En cours de traitement, il est garanti qu’il soit statiquement castable 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 remarquent automatiquement cette valeur et appellent les méthodes GetValue ou SetValue sous-jacentes de l’accesseur de propriété selon les besoins.
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;
}
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é. Notez 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 (ce pointeur) à la méthode GetValue de l’accesseur de propriété.
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 retourne E_NOTIMPL. Notez 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 (ce pointeur) à 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 boxée dans un IModelObject. L’objet de modèle retourne un type d’ObjectMethod lorsqu’il est interrogé et que la valeur intrinsèque est une VT_UNKNOWN qui est garantie d’être interrogeable pour IModelMethod. En cours de traitement, il est garanti qu’il soit statiquement castable dans IModelMethod. Toutes les méthodes du modèle de données sont dynamiques par nature. Ils prennent comme entrée un ensemble de 0 arguments ou plus et retournent une valeur de sortie unique. Il n’existe aucune résolution de surcharge et aucune métadonnées sur les noms de paramètres, les types ou les attentes.
L’interface IModelMethod est définie 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;
}
La méthode Call est la façon dont n’importe quelle méthode définie dans le modèle de données est appelée. L’appelant est responsable du passage d’un objet d’instance précis (ce pointeur) et d’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 retournées. Les méthodes qui ne retournent pas logiquement une valeur doivent toujours retourner un IModelObject valide. Dans ce cas, iModelObject est une valeur sans boxe. En cas d’échec d’une méthode, elle peut retourner des informations d’erreur étendues facultatives dans l’argument d’entrée (même si le HRESULT retourné est un échec). Il est impératif que les appelants vérifient cela.
références de clé : IModelKeyReference ou IModelKeyReference2
Une référence clé est, en essence, un handle à une clé sur un objet particulier. Un client peut récupérer ce handle via des méthodes telles que GetKeyReference et utiliser le handle ultérieurement pour obtenir ou définir la valeur de la clé sans nécessairement tenir sur l’objet d’origine. Ce type d’objet est une implémentation de l’interface IModelKeyReference ou IModelKeyReference2 qui est boxée dans un IModelObject. L’objet de modèle retourne un type d’ObjectKeyReference lors de la requête, puis une valeur intrinsèque est une VT_UNKNOWN qui est garantie d’être interrogeable pour IModelKeyReference. En cours de traitement, il est garanti qu’il soit statiquement castable dans IModelKeyReference.
L’interface de référence de 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;
}
La méthode GetKeyName retourne le nom de la clé à laquelle cette référence de clé est un handle. La chaîne retournée est une BSTR standard et doit être libérée via un appel à SysFreeString.
La méthode GetOriginalObject retourne l’objet d’instance à partir duquel la référence de clé a été créée. Notez que la clé peut elle-même se trouver sur un modèle parent de l’objet d’instance.
La méthode GetContextObject retourne le contexte (ce pointeur) 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 retourné ici peut ou non être identique à l’objet d’origine extrait de GetOriginalObject. Si une clé se trouve sur un modèle parent et qu’il existe un ajusteur de contexte associé à ce modèle parent, 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é à laquelle cette référence de clé est un handle. S’il n’existe aucun ajusteurs de contexte, l’objet d’origine et l’objet de contexte sont identiques.
La méthode GetKey sur une référence de clé se comporte comme la méthode GetKey sur IModelObject. Elle retourne la valeur de la clé sous-jacente et toutes les métadonnées associées à la clé. Si la valeur de la clé est un accesseur de propriété, elle renvoie l’accesseur de propriété (IModelPropertyAccessor) boxé dans un IModelObject. Cette méthode n’appelle pas les méthodes GetValue ou SetValue sous-jacentes sur l’accesseur de propriété.
La méthode GetKeyValue sur une référence de clé se comporte comme la méthode GetKeyValue sur IModelObject. Elle retourne la valeur de la clé sous-jacente et toutes les métadonnées associées à la clé. 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é.
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é, cela remplacera l’accesseur de propriété. Il n’appelle pas la méthode SetValue sur l’accesseur de propriété.
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.
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 de l’accesseur de propriété sous-jacente. L’objet passé à cette méthode est également retourné à partir d’un appel à GetContextObject. Cette méthode peut être utilisée par les fournisseurs de script 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 objets blob opaques d’informations que l’hôte de débogage (en coopération avec le modèle de données) associe à chaque objet. Il peut inclure des éléments tels que le contexte du processus ou l’espace d’adressage dont proviennent les informations, etc. Un objet de contexte est une implémentation d’IDebugHostContext boxed dans un IModelObject. Notez que IDebugHostContext est une interface définie par l’hôte. Un client n’implémentera jamais cette interface.
Pour plus d’informations 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.
Le Gestionnaire de modèles de données
L’interface principale du gestionnaire de modèles de données, IDataModelManager2 (ou IDataModelManager précédent) 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;
La méthode Close est appelée sur le gestionnaire de modèles de données par une application (par exemple : débogueur) hébergeant le modèle de données afin de démarrer le processus d’arrêt du gestionnaire de modèles de données. Un hôte du modèle de données qui ne fait pas partie de la méthode Close avant de publier sa référence finale sur le gestionnaire de modèles de données peut entraîner un comportement non défini, y compris, mais pas limité à des fuites significatives de l’infrastructure de gestion pour le modèle de données.
méthodes de création d’objets /Boxing
L’ensemble de méthodes suivant est utilisé pour créer de nouveaux objets ou pour boxer 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;
La méthode CreateNoValue crée un objet « no value », le place dans un IModelObject et le retourne. L’objet de modèle retourné a un type ObjectNoValue.
Un objet « no value » a plusieurs significations sémantiques :
- (Selon le langage), il peut être considéré comme l’équivalent sémantique de void, null ou undefined
- Toute méthode GetValue de l’accesseur de propriété qui retourne la réussite et un objet « aucune valeur » résultant 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 de valeur de retour utilisent cette valeur comme sentinelle pour indiquer ce type (comme une méthode doit retourner un IModelObject valide).
La méthode CreateErrorObject crée un « objet d’erreur ». Le modèle de données n’a pas la notion d’exceptions et de flux d’exceptions. L’échec sort d’une propriété/méthode de deux façons :
- Un seul HRESULT défaillant sans informations d’erreur étendues. Il n’y a plus d’informations qui peuvent être fournies pour l’erreur ou l’erreur elle-même est explicite à partir du HRESULT retourné.
- UN SEUL HRESULT défaillant associé à des informations d’erreur étendues. Les informations d’erreur étendues sont un objet d’erreur retourné dans l’argument de sortie de la propriété/méthode.
La méthode CreateTypedObject est la méthode qui permet à un client de créer une représentation d’un objet natif/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 canoniques ou extensions, ces modèles de données correspondants sont automatiquement attachés à l’objet d’instance créé avant qu’il ne soit retourné à l’appelant.
La méthode CreateTypedObjectReference est sémantiquement similaire à la méthode CreateTypedObject, sauf qu’elle crée une référence à la construction native/linguistique sous-jacente. La référence créée est un objet qui a un type ObjectTargetObjectReference. Il n’est pas une référence native, car le langage sous-jacent peut prendre en charge (par exemple, un & C++ ou &&). Il est tout à fait possible d’avoir une référence 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 revenir à la valeur d’une manière appropriée.
La méthode CreateSyntheticObject crée un objet de modèle de données vide : dictionnaire de tuples et de concepts de clé/valeur/métadonnées. 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 propre pour que l’appelant utilise.
La méthode CreateDataModelObject est un wrapper d’assistance simple pour créer des objets qui sont des modèles de données , c’est-à-dire des objets qui vont être attachés en tant que modèles parents à d’autres objets. 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 inpassé 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.
La méthode CreateIntrinsicObject est la méthode qui place les 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 retourne un IModelObject représentant l’objet. Notez que cette méthode est également utilisée pour boxer des types IUnknown fondamentaux : accesseurs de propriétés, méthodes, 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 castable à l’interface de modèle appropriée (par exemple : IModelPropertyAccessor, IModelMethod, IDebugHostContext, etc.) en cours. 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.
La méthode CreateTypedintrinsicObject est similaire à la méthode CreateIntrinsicObject, à l’exception du fait qu’elle permet à un type natif/de langue d’être associé aux données et porté avec la valeur boxed. Cela permet au modèle de données de représenter des constructions telles que des types d’énumération natifs (qui sont simplement VT_UI* ou des valeurs VT_I*). Les types de pointeur sont également créés avec cette méthode. Un pointeur natif dans le modèle de données est une quantité 64 bits étendue zéro représentant un décalage dans l’espace d’adressage virtuel de la cible de débogage. Il est boxé à l’intérieur d’un VT_UI8 et est créé avec cette méthode et un type qui indique un pointeur natif/langage.
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 à son tour peut avoir un seul parent). Si une clé de métadonnées donnée n’est pas située dans un magasin donné, ses parents sont vérifiés. La plupart des magasins de métadonnées n’ont pas de parents. Toutefois, cela permet de partager facilement les métadonnées communes.
La méthode CreateTypedIntrinsicObjectEx est sémantiquement similaire à la méthode CreateTypedIntrinsicObject. La seule différence entre les deux est que cette méthode permet à l’appelant de spécifier le contexte dans lequel les données intrinsèques sont valides. Si aucun contexte n’est passé, les données sont considérées comme valides dans quel contexte est 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.
extensibilité /Méthodes 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 des 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;
La méthode GetModelForTypeSignature retourne le modèle de données inscrit sur une signature de type particulière via un appel antérieur à la méthode RegisterModelForTypeSignature. Le modèle de données retourné par cette méthode est considéré comme le visualiseur canonique pour n’importe quel type qui correspond à la signature de type passée. En tant que visualiseur canonique, ce modèle de données prend le contrôle de l’affichage du type. Les moteurs d’affichage masquent par défaut les constructions natives/linguistiques de l’objet en faveur de la vue de l’objet présenté par le modèle de données.
La méthode GetModelForType retourne 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 antérieur à la méthode RegisterModelForTypeSignature et retourne le modèle de données associé.
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 vigueur, prend en charge l’affichage d’un type donné (ou ensemble de types). Au lieu de l’affichage natif/linguistique du type affiché dans n’importe quelle interface utilisateur du débogueur, l’affichage du type tel que présenté par le modèle de données inscrit s’affiche (ainsi qu’un moyen de revenir à la vue native/langue pour un utilisateur qui le souhaite).
UnregisterModelForTypeSignature
La méthode UnregisterModelForTypeSignature annule un appel antérieur à 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é comme 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 passé à 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/langue de ce type. Le modèle de données passé à 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 sur 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 en effet à 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 antérieur à RegisterExtensionForTypeSignature. Il 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.
La méthode GetRootNamespace retourne 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.
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. Il s’agit de l’objectif principal 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 connu et en y ajoutant un modèle parent.
La méthode UnregisterNamedModel annule un appel antérieur à RegisterNamedModel. Il supprime l’association entre un modèle de données et un nom sous lequel il peut être recherché.
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 retourne le modèle de données inscrit via un appel antérieur à la méthode RegisterNamedModel. Comme l’objectif principal de la méthode AcquireNamedModel est d’étendre le modèle, cette méthode 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éé, enregistré temporairement sous le nom donné et retourné à 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, en effet, apportées au modèle réel. Cela supprime de nombreux problèmes de dépendance de l’ordre de charge 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 via d’autres méthodes sur le modèle de données ou ses objets, ces méthodes pratiques facilitent considérablement les opérations suivantes :
STDMETHOD(AcquireSubNamespace)(_In_ PCWSTR modelName, _In_ PCWSTR subNamespaceModelName, _In_ PCWSTR accessName, _In_opt_ IKeyStore *metadata, _COM_Outptr_ IModelObject **namespaceModelObject) PURE;
La méthode AcquireSubNamespace permet de construire quelque chose qui peut ressembler plus traditionnellement à un espace de noms de langage qu’à un nouvel objet dans un langage dynamique. Si, par exemple, un appelant souhaite classer les propriétés sur un objet de processus afin de rendre l’objet de processus plus organisé et les propriétés plus faciles à découvrir, une méthode consiste à créer un sous-objet pour chaque catégorie sur l’objet de processus et à placer ces 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
modèle de données du débogueur C++ interfaces supplémentaires