Compartilhar via


Objetos do Modelo de Dados do Depurador C++

Este tópico descreve como usar Objetos do Modelo de Dados do Depurador C++ e como eles podem estender as funcionalidades do depurador.

O modelo de objeto do depurador principal

Uma das coisas mais básicas, mas poderosas, do modelo de dados é que ele padroniza a definição do que é um objeto e como ele interage com um objeto. A interface IModelObject encapsula a noção de um objeto, seja ele um inteiro, um valor de ponto flutuante, uma cadeia de caracteres, algum tipo complexo no espaço de endereço de destino do depurador ou algum conceito de depurador, como a noção de um processo ou um módulo.

Há várias pontos diferentes que podem ser mantidos (ou convertidos) em um IModelObject:

  • Valores Intrínsecos - Um IModelObject pode ser um contêiner para vários tipos básicos: inteiros assinados ou não assinados de 8, 16, 32 ou 64 bits, boolianos, cadeias de caracteres, erros ou a noção de vazio.

  • Objetos Nativos - Um IModelObject pode representar um tipo complexo (conforme definido pelo sistema de tipo do depurador) no espaço de endereço de qualquer destino do depurador.

  • Objetos Sintéticos - Um IModelObject pode ser um objeto dinâmico -- um dicionário, se quiser: uma coleção de tuplas de chave/valor/metadados e um conjunto de conceitos que definem comportamentos que não são simplesmente representados por pares chave/valor.

  • Propriedades - Um IModelObject pode representar uma propriedade: algo cujo valor pode ser recuperado ou alterado com uma chamada de método. Uma propriedade em um IModelObject é efetivamente uma interface IModelPropertyAccessor convertida em um IModelObject.

  • Métodos - Um IModelObject pode representar um método: algo que você pode chamar com um conjunto de argumentos e obter um valor de retorno. Um método em um IModelObject é efetivamente uma interface IModelMethod convertida em um IModelObject.

Extensibilidade no modelo de objeto

Isoladamente, um IModelObject não é um objeto. Além de representar um dos tipos de objetos mostrados acima, cada objeto tem a noção de uma cadeia de modelos de dados pai. Essa cadeia se comporta de uma maneira muito parecida com uma cadeia de protótipos JavaScript. Em vez de uma cadeia linear de protótipos, como o JavaScript, cada objeto de modelo de dados define uma cadeia linear de modelos pai. Por sua vez, cada um desses modelos pai tem outra cadeia linear de seu próprio conjunto de pais. Basicamente, cada objeto é uma agregação das funcionalidades (propriedades, etc...) de si mesmo e de cada objeto nesta árvore. Quando uma propriedade específica for consultada, se o objeto em que ela for consultada não oferecer suporte a essa propriedade, a consulta será passada em ordem linear para cada pai por sua vez. Isso cria um comportamento em que a pesquisa de uma propriedade é resolvida por uma pesquisa de balanceamento em profundidade da árvore agregada.

A extensibilidade nesse modelo de objeto é muito simples, considerando-se que cada objeto é um agregado de si mesmo e da árvore de modelos pai. Uma extensão pode entrar e se adicionar à lista de modelos pai de outro objeto. Fazer isso estende o objeto. Dessa forma, é possível adicionar funcionalidades a qualquer situação: uma instância específica de um objeto ou valor, um tipo nativo, o conceito do depurador do que é um processo ou thread, ou mesmo a noção de "todos os objetos iteráveis".

Contexto, contexto e contexto: o ponteiro this, o espaço de endereço e os dados privados de implementação

Há três noções de contexto que são necessárias compreender no contexto do modelo de objeto.

Contexto: o ponteiro this

Como uma determinada propriedade ou método pode ser implementado em qualquer nível da árvore de modelo de dados, é necessário que a implementação do método ou da propriedade possa acessar o objeto original (o que você pode chamar de ponteiro this em C++ ou objeto this em JavaScript. Esse objeto de instância é passado para uma variedade de métodos, como o primeiro argumento chamado contexto nos métodos descritos.

Contexto: O espaço de endereço

É importante observar que, ao contrário dos modelos de extensão anteriores, em que o contexto (o destino, o processo, o thread que você está procurando) é um conceito de interface do usuário com todas as APIs relativas ao estado atual da interface do usuário, as interfaces de modelo de dados geralmente usam esse contexto explícita ou implicitamente como uma interface IDebugHostContext. Cada IModelObject no modelo de dados carrega esse tipo de informação de contexto junto com ele e pode propagar esse contexto para objetos que ele retorna. Isso significa que, quando você ler um valor nativo ou um valor de chave de um IModelObject, ele será lido do destino e processo de onde o objeto foi originalmente obtido.

Há um valor constante explícito, USE_CURRENT_HOST_CONTEXT, que pode ser passado para os métodos que usam um argumento IDebugHostContext. Esse valor indica que o contexto deve realmente ser o estado atual da interface do usuário do depurador. Essa noção, no entanto, precisa ser explícita.

Contexto: Dados privados de implementação

Lembre-se de que cada objeto no modelo de dados é, na verdade, uma agregação da instância do objeto e da árvore de modelos pai anexados. Cada um desses modelos pai (que podem ser vinculados nas cadeias de muitos objetos diferentes) pode associar dados privados de implementação a qualquer objeto de instância. Cada IModelObject que é criado conceitualmente tem uma tabela de hash que mapeia de um modelo pai específico para dados de instância privada definidos por uma interface IUnknown. Isso permite que um modelo pai armazene em cache informações sobre cada instância ou tenha dados arbitrários associados.

Esse tipo de contexto é acessado por meio dos métodos GetContextForDataModel e SetContextForDataModel em IModelObject.

A interface de objeto do depurador principal: IModelObject


A interface IModelObject é definida da seguinte forma:

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étodos Básicos

A seguir estão métodos gerais aplicáveis a qualquer tipo de objeto representado por um 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

O método GetKind retorna que tipo de objeto é convertido dentro do IModelObject.

GetContext

O método GetContext retorna o contexto de host que está associado ao objeto.

GetIntrinsicValue

O método GetIntrinsicValue retorna o item que é convertido dentro de um IModelObject. Esse método só pode ser legalmente chamado em interfaces IModelObject que representam uma interface intrínseca convertida ou uma interface específica que está convertida. Ele não pode ser chamado em objetos nativos, objetos sem valor, objetos sintéticos e objetos de referência. O método GetIntrinsicValueAs se comporta muito mais como o método GetIntrinsicValue, exceto que ele converte o valor para o tipo de variante especificado. Se a conversão não puder ser executada, o método retornará um erro.

IsEqualTo

O método IsEqualTo compara dois objetos de modelo e retorna se eles são iguais em valor. Para objetos que têm uma ordem, esse método que retorna true é equivalente ao método Compare que retorna 0. Para objetos que não têm ordenação, mas são equitativos, o método Compare falhará, mas isso não acontecerá. O significado de uma comparação baseada em valores é definido pelo tipo de objeto. No momento, isso é definido apenas para tipos intrínsecos e objetos de erro. Não há um conceito atual de modelo de dados para equabilidade.

Desreferenciar

O método Dereference desreferencia um objeto. Esse método pode ser usado para desreferenciar uma referência baseada em modelo de dados (ObjectTargetObjectReference, ObjectKeyReference) ou uma referência de idioma nativo (um ponteiro ou uma referência de idioma). É importante observar que esse método remove um único nível de semântica de referência no objeto. É totalmente possível, por exemplo, ter uma referência de modelo de dados a uma referência de linguagem. Nesse caso, chamar o método Dereference pela primeira vez removeria a referência do modelo de dados e deixaria a referência de linguagem. Chamar Dereference nesse objeto resultante removerá subsequentemente a referência de linguagem e retornará o valor nativo sob essa referência.

Principais métodos de manipulação

Qualquer objeto sintético que seja um dicionário de tuplas de chave, valor e metadados tem uma série de métodos para manipular essas chaves, valores e os metadados associados a eles.

Os formulários baseados em valor das APIs são:

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;

Os formulários baseados em referência das APIs são:

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

O método GetKeyValue é o primeiro método ao qual um cliente recorrerá para obter o valor de (e os metadados associados a) uma determinada chave por nome. Se a chave for um acessador de propriedade, ou seja, seu valor como um IModelObject que é um IModelPropertyAccessor convertido, o método GetKeyValue chamará automaticamente o método GetValue do acessador de propriedade para recuperar o valor real.

SetKeyValue

O método SetKeyValue é o primeiro método ao qual um cliente recorrerá para definir o valor de uma chave. Esse método não pode ser usado para criar uma nova chave em um objeto. Ele só definirá o valor de uma chave existente. Muitas chaves são somente leitura (por exemplo: elas são implementadas por um acessador de propriedade que retorna E_NOT_IMPL de seu método SetValue). Esse método falhará quando chamado em uma chave somente leitura.

EnumerateKeyValues

O método EnumerateKeyValues é o primeiro método ao qual um cliente recorrerá para enumerar todas as chaves em um objeto (isso inclui todas as chaves implementadas em qualquer lugar na árvore de modelos pai). É importante observar que EnumerateKeyValues enumerará as chaves definidas por nomes duplicados na árvore de objetos. No entanto, métodos como GetKeyValue e SetKeyValue só manipularão a primeira instância de uma chave com o nome fornecido conforme descoberto pela passagem de balanceamento em profundidade.

GetKey

O método GetKey obterá o valor de (e os metadados associados a) uma determinada chave por nome. A maioria dos clientes deve utilizar o método GetKeyValue. Se a chave for um acessador de propriedade, chamar esse método retornará o acessador de propriedade (uma interface IModelPropertyAccessor) convertido em um IModelObject. Ao contrário de GetKeyValue, esse método não resolverá automaticamente o valor subjacente da chave chamando o método GetValue. Essa responsabilidade é do chamador.

SetKey

O método SetKey é o método ao qual um cliente recorrerá para criar uma chave em um objeto (e, potencialmente, associar metadados à chave criada). Se um determinado objeto já tiver uma chave com o nome fornecido, ocorrerá um dos dois comportamentos. Se a chave estiver na instância fornecida por isso, o valor dessa chave será substituído como se a chave original não existisse. Por outro lado, se a chave estiver na cadeia de modelos de dados pai da instância fornecida por isso, uma nova chave com o nome fornecido será criada na instância fornecida por isso. Na verdade, isso faria com que o objeto tivesse duas chaves do mesmo nome (semelhante a uma classe derivada que acompanha um membro do mesmo nome que uma classe base).

EnumerateKeys

O método EnumerateKeys se comporta de forma semelhante ao método EnumerateKeyValues, exceto que ele não resolve automaticamente os acessadores de propriedade no objeto. Isso significa que, se o valor de uma chave for um acessador de propriedade, o método EnumerateKeys retornará o acessador de propriedade (um IModelPropertyAccessorInterface) convertido em um IModelObject, em vez de chamar automaticamente o método GetValue. Isso é semelhante à diferença entre GetKey e GetKeyValue.

ClearKeys

O método ClearKeys remove todas as chaves e seus valores e metadados associados da instância do objeto especificado por esse método. Esse método não tem efeito em modelos pai anexados à instância de objeto específico.

GetKeyReference

O método GetKeyReference procurará uma chave do nome fornecido no objeto (ou sua cadeia de modelo pai) e retornará uma referência a essa chave considerando uma interface IModelKeyReference convertida em um IModelObject. Essa referência pode ser usada posteriormente para obter ou definir o valor da chave.

EnumerateKeyReferences

O método EnumerateKeyReferences se comporta de forma semelhante ao método EnumerateKeyValues, exceto que ele retorna as referências às chaves que enumera (fornecidas por uma interface IModelKeyReference convertida em um IModelObject), em vez do valor da chave. Essas referências podem ser usadas para obter ou definir o valor subjacente das chaves.

Métodos de manipulação de conceitos

Além de um objeto de modelo ser um dicionário de tuplas de chave/valor/metadados, ele também é um contêiner de conceitos. Um conceito é algo abstrato que pode ser realizado em um objeto ou por meio dele. Basicamente, os conceitos são um repositório dinâmico de interfaces ao qual um objeto tem suporte. Vários conceitos são definidos pelo modelo de dados atualmente:

Interface de conceito Descrição
IDataModelConcept O conceito é um modelo pai. Se esse modelo for anexado automaticamente a um tipo nativo por meio de uma assinatura de tipo registrado, o método InitializeObject será automaticamente chamado sempre que um novo objeto desse tipo for instanciado.
IStringDisplayableConcept O objeto pode ser convertido em uma cadeia de caracteres para fins de exibição.
IIterableConcept O objeto é um contêiner e pode ser iterado.
IIndexableConcept O objeto é um contêiner e pode ser indexado (acessado via acesso aleatório) em uma ou mais dimensões.
IPreferredRuntimeTypeConcept O objeto entende mais sobre os tipos derivados dele do que o sistema de tipos subjacente é capaz de fornecer e gostaria de lidar com suas próprias conversões do tipo estático no tipo de runtime.
IDynamicKeyProviderConcept O objeto é um provedor dinâmico de chaves e deseja assumir todas as consultas de chave do modelo de dados principal. Essa interface geralmente é usada como uma ponte para linguagens dinâmicas, como JavaScript.
IDynamicConceptProviderConcept O objeto é um provedor dinâmico de conceitos e deseja assumir todas as consultas de conceito do modelo de dados principal. Essa interface geralmente é usada como uma ponte para linguagens dinâmicas, como JavaScript.

Os métodos a seguir em IModelObject são utilizados para manipular os conceitos aos quais um objeto tem suporte.

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

O método GetConcept procurará um conceito no objeto (ou sua cadeia de modelo pai) e retornará um ponteiro de interface para a interface de conceito. O comportamento e os métodos em uma interface de conceito são específicos para cada conceito. No entanto, é importante observar que muitas das interfaces de conceito requerem que o chamador passe explicitamente o objeto de contexto (ou o que se pode chamar tradicionalmente de ponteiro this). É importante garantir que o objeto de contexto correto seja passado para cada interface de conceito.

SetConcept

O método SetConcept inserirá um conceito especificado na instância do objeto especificada pelo ponteiro this. Se um modelo pai anexado à instância de objeto especificada por this também oferecer suporte ao conceito, a implementação na instância substituirá esta no modelo pai.

ClearConcepts

O método ClearConcepts removerá todos os conceitos da instância do objeto especificado por this.

Métodos de objetos nativos

Embora muitos objetos de modelo façam referência a construções intrínsecas (por exemplo: inteiros, cadeias de caracteres) ou sintéticas (um dicionário de tuplas e conceitos de chave/valor/metadados), um objeto de modelo também pode se referir a uma construção nativa (por exemplo: um tipo definido pelo usuário no espaço de endereço do destino de depuração). A interface IModelObject tem uma série de métodos que acessam informações sobre esses objetos nativos. Os métodos são:

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

O método GetRawValue localiza uma construção nativa dentro do objeto fornecido. Tal construção pode ser um campo, uma classe base, um campo em uma classe base, uma função de membro, etc.

EnumerateRawValues

O método EnumerateRawValues enumera todos os filhos nativos (por exemplo: campos, classes base, etc.) do objeto fornecido.

TryCastToRuntimeType

O método TryCastToRuntimeType solicitará ao host de depuração para executar uma análise e determinar o tipo de runtime real (por exemplo: classe mais derivada) do objeto fornecido. A análise exata utilizada é específica para o host de depuração e pode incluir RTTI (informações de tipo de runtime C++), exame da estrutura V-Table (tabela de função virtual) do objeto ou qualquer outro meio que o host possa usar para determinar de forma confiável o tipo dinâmico/de tempo de execução a partir do tipo estático. Não converter um tipo de runtime não significa que essa chamada de método falhará. Nesses casos, o método retornará o objeto fornecido (o ponteiro this) no argumento de saída.

GetLocation

O método GetLocation retornará a localização do objeto nativo. Embora esse local geralmente seja um endereço virtual dentro do espaço de endereço do destino de depuração, não é necessariamente assim. O local retornado por esse método é um local abstrato que pode ser um endereço virtual, pode indicar a colocação em um registro ou sub-registro, ou pode indicar algum outro espaço de endereço arbitrário, conforme definido pelo host de depuração. Se o campo HostDefined do objeto Location resultante for 0, indicará que o local é realmente um endereço virtual. Esse endereço virtual pode ser recuperado examinando o campo Deslocamento do local resultante. Qualquer valor diferente de zero do campo HostDefined indica um espaço de endereço alternativo em que o campo Deslocamento é o deslocamento dentro desse espaço de endereço. O significado exato de valores HostDefined diferentes de zero aqui são privados para o host de depuração.

GetTypeInfo

O método GetTypeInfo retornará o tipo nativo do objeto fornecido. Se o objeto não tiver informações de tipo nativo associadas a ele (por exemplo: é um intrínseco, etc.), a chamada ainda será bem-sucedida, mas retornará null.

GetTargetInfo

O método GetTargetInfo é efetivamente uma combinação dos métodos GetLocation e GetTypeInfo retornando o local abstrato, bem como o tipo nativo do objeto fornecido.

GetRawReference

O método GetRawReference localiza uma construção nativa dentro do objeto fornecido e retorna uma referência a ele. Tal construção pode ser um campo, uma classe base, um campo em uma classe base, uma função de membro. É importante distinguir a referência retornada aqui (um objeto do tipo ObjectTargetObjectReference) de uma referência de linguagem (por exemplo: uma referência de estilo C++ & ou && ).

EnumerateRawReferences

O método EnumerateRawReferences enumera referências a todos os filhos nativos (por exemplo: campos, classes base, etc.) do objeto fornecido.

Métodos de extensibilidade

Conforme descrito anteriormente, um objeto de modelo se comporta de forma muito semelhante a um objeto JavaScript e sua cadeia de protótipos. Além da instância representada por uma determinada interface IModelObject, pode haver um número arbitrário de modelos pai anexados ao objeto (cada um dos quais pode, por sua vez, ter um número arbitrário de modelos pai anexados a eles). Esse é o principal meio de extensibilidade no modelo de dados. Se uma determinada propriedade ou conceito não puder ser localizado em uma determinada instância, uma pesquisa de balanceamento em profundidade da árvore de objetos (definida por modelos pai) enraizada na instância será executada.

Os métodos a seguir manipulam a cadeia de modelos pai associados a uma determinada instância IModelObject:

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

O método GetNumberOfParentModels retorna o número de modelos pai que são anexados à instância de objeto fornecida. Os modelos pai são pesquisados pelo balanceamento em profundidade das propriedades na ordenação linear da cadeia de modelos pai.

GetParentModel

O método GetParentModel retorna o iº modelo pai na cadeia de modelos pai do objeto fornecido. Os modelos pai são pesquisados por uma propriedade ou conceito na ordem linear em que são adicionados ou enumerados. O modelo pai com índice i de zero é pesquisado (hierarquicamente) antes do modelo pai com índice i + 1.

AddParentModel

O método AddParentModel adiciona um novo modelo pai ao objeto fornecido. Esse modelo pode ser adicionado no final da cadeia de pesquisa (o argumento de substituição é especificado como falso) ou na frente da cadeia de pesquisa (o argumento de substituição é especificado como verdadeiro). Além disso, cada modelo pai pode, opcionalmente, ajustar o contexto (o ponteiro semântico this) para qualquer propriedade ou conceito no pai fornecido (ou qualquer pessoa em sua hierarquia pai). O ajuste de contexto raramente é usado, mas permite alguns conceitos poderosos, como incorporação de objetos, construção de namespaces, etc.

RemoveParentModel

O método RemoveParentModel removerá um modelo pai especificado da cadeia de pesquisa pai do objeto fornecido.

SetContextForDataModel

O método SetContextForDataModel é usado pela implementação de um modelo de dados para inserir dados de implementação em objetos de instância. Conceitualmente, cada IModelObject (chame isso de instância para simplificar) contém uma tabela de hash de estado. A tabela de hash é indexada por outro IModelObject (chame isso de modelo de dados para simplificar) que está na hierarquia de modelo pai da instância. O valor contido nesse hash é um conjunto de informações de estado contadas como referência representadas por uma instância IUnknown. Depois que o modelo de dados define esse estado na instância, ele pode armazenar dados de implementação arbitrários que podem ser recuperados durante coisas como getters de propriedade.

GetContextForDataModel

O método GetContextForDataModel é usado para recuperar informações de contexto que foram configuradas com uma chamada anterior para SetContextForDataModel. Isso recupera informações de estado que foram definidas em um objeto de instância por um modelo de dados mais acima na hierarquia do modelo pai do objeto de instância. Para obter mais detalhes sobre esse contexto/estado e seu significado, confira a documentação de SetContextForDataModel.

Tipos de objeto principal do modelo de dados do depurador

Um objeto no modelo de dados é semelhante à noção de Objeto no .NET. É o contêiner genérico no qual a construção que o modelo de dados entende pode ser convertida. Além de objetos nativos e objetos sintéticos (dinâmicos), há uma série de tipos de objetos principais que podem ser inseridos (ou convertidos) no contêiner de um IModelObject. O contêiner no qual a maioria desses valores é inserida é uma COM/OLE VARIANT padrão com diversas restrições adicionais inseridas no que essa VARIANT pode conter. Os tipos mais básicos são:

  • Valores não assinados e assinados de 8 bits (VT_UI1, VT_I1)
  • Valores não assinados e assinados de 16 bits (VT_UI2, VT_UI2)
  • Valores não assinados e assinados de 32 bits (VT_UI4, VT_I4)
  • Valores não assinados e assinados de 64 bits (VT_UI8, VT_I8)
  • Valores de ponto flutuante de precisão simples e dupla (VT_R4, VT_R8)
  • Cadeias de caracteres (VT_BSTR)
  • Boolianos (VT_BOOL)

Além desses tipos básicos, vários objetos de modelo de dados principais são inseridos no IModelObject definido por VT_UNKNOWN, em que o IUnknown armazenado tem a garantia de implementar uma interface específica. Esses tipos são:

  • Acessadores de propriedade (IModelPropertyAccessor)
  • Objetos de método (IModelMethod)
  • Principais objetos de referência (IModelKeyReference ou IModelKeyReference2)
  • Objetos de contexto (IDebugModelHostContext)

Acessadores de propriedade: IModelPropertyAccessor

Um acessador de propriedade no modelo de dados é uma implementação da interface IModelPropertyAccessor que é convertida em um IModelObject. O objeto de modelo retornará um tipo de ObjectPropertyAccessor quando consultado e o valor intrínseco será um VT_UNKNOWN que é garantido para ser passível de consulta para IModelPropertyAccessor. No processo, é garantido que ele seja transmitido estaticamente para IModelPropertyAccessor.

Um acessador de propriedade é uma maneira indireta de obter uma chamada de método para obter e definir um valor de chave no modelo de dados. Se o valor de determinada chave for um acessador de propriedade, os métodos GetKeyValue e SetKeyValue notarão isso automaticamente e chamarão os métodos subjacentes GetValue ou SetValue do acessador de propriedade, conforme apropriado.

A interface IModelPropertyAccessor é definida da seguinte maneira:

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

O método GetValue é o getter para o acessador de propriedade. Ele é chamado sempre que um cliente deseja buscar o valor subjacente da propriedade. Qualquer chamador que obtém diretamente um acessador de propriedade é responsável por passar o nome da chave e o objeto de instância preciso (ponteiro this) para o método GetValue do acessador de propriedade.

SetValue

O método SetValue é o setter para o acessador de propriedade. Ele é chamado sempre que um cliente deseja atribuir um valor à propriedade subjacente. Muitas propriedades são somente para leitura. Nesses casos, chamar o método SetValue retornará E_NOTIMPL. Qualquer chamador que obtém diretamente um acessador de propriedade é responsável por passar o nome da chave e o objeto de instância preciso (ponteiro this) para o método SetValue do acessador de propriedade.

Métodos: IModelMethod

Um método no modelo de dados é uma implementação da interface IModelMethod que é convertida em um IModelObject. O objeto de modelo retornará um tipo de ObjectMethod quando consultado e o valor intrínseco será um VT_UNKNOWN que é garantido para ser passível de consulta para IModelMethod. No processo, é garantido que ele seja transmitido estaticamente para IModelMethod. Todos os métodos no modelo de dados são dinâmicos por natureza. Eles tomam como entrada um conjunto de 0 ou mais argumentos e retornam um único valor de saída. Não há resolução de sobrecarga nem metadados sobre nomes, tipos ou expectativas de parâmetros.

A interface IModelMethod é definida da seguinte forma:

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

Chamar

O método Call é a maneira pela qual qualquer método definido no modelo de dados é chamado. O chamador é responsável por passar um objeto de instância preciso (ponteiro this) e um conjunto arbitrário de argumentos. O resultado do método e os metadados opcionais associados a esse resultado são retornados. Métodos que não retornam logicamente um valor ainda devem retornar um IModelObject válido. Nesse caso, o IModelObject é nenhum valor convertido. Se um método falhar, poderá retornar informações de erro estendidas opcionais no argumento de entrada (mesmo se o HRESULT retornado for uma falha). É imprescindível que os chamadores verifiquem isso.

Referências de chave: IModelKeyReference ou IModelKeyReference2

Uma referência de chave é, basicamente, um identificador para uma chave em um objeto específico. Um cliente pode recuperar esse identificador por meio de métodos, como GetKeyReference, e usar o identificador posteriormente para obter ou definir o valor da chave sem necessariamente manter o objeto original. Esse tipo de objeto é uma implementação da interface IModelKeyReference ou IModelKeyReference2 que é convertida em um IModelObject. O objeto de modelo retornará um tipo de ObjectKeyReference quando consultado e o valor intrínseco será um VT_UNKNOWN que é garantido para ser passível de consulta para IModelKeyReference. No processo, é garantido que ele seja transmitido estaticamente para IModelKeyReference.

A interface de referência de chave é definida da seguinte forma:

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

O método GetKeyName retorna o nome da chave para a qual essa referência de chave é um identificador. A cadeia de caracteres retornada é um BSTR padrão e deve ser liberada por meio de uma chamada para SysFreeString.

GetOriginalObject

O método GetOriginalObject retorna o objeto de instância a partir do qual a referência de chave foi criada. Observe que a própria chave pode estar em um modelo pai do objeto de instância.

GetContextObject

O método GetContextObject retorna o contexto (ponteiro this) que será passado para o método GetValue ou SetValue de um acessador de propriedade se a chave em questão se referir a um acessador de propriedade. O objeto de contexto retornado aqui pode ou não ser o mesmo que o objeto original obtido de GetOriginalObject. Se uma chave estiver em um modelo pai e houver um ajustador de contexto associado a esse modelo pai, o objeto original será o objeto de instância no qual GetKeyReference ou EnumerateKeyReferences foi chamado. O objeto de contexto será o que sai do ajustador de contexto final entre o objeto original e o modelo pai que contém a chave para a qual essa referência de chave é um identificador. Se não houver ajustadores de contexto, o objeto original e o objeto de contexto serão idênticos.

GetKey

O método GetKey em uma referência de chave se comporta da mesma maneira que o método GetKey em IModelObject se comportaria. Ele retorna o valor da chave subjacente e quaisquer metadados associados à chave. Se o valor da chave for um acessador de propriedade, será retornado o acessador de propriedade (IModelPropertyAccessor) convertido em um IModelObject. Esse método não chamará os métodos GetValue ou SetValue subjacentes no acessador de propriedade.

GetKeyValue

O método GetKeyValue em uma referência de chave se comporta como o método GetKeyValue em IModelObject se comportaria. Ele retorna o valor da chave subjacente e quaisquer metadados associados à chave. Se o valor da chave for um acessador de propriedade, o método GetValue subjacente no acessador de propriedade será chamado automaticamente.

SetKey

O método SetKey em uma referência de chave se comporta da mesma maneira que o método SetKey em IModelObject se comportaria. Ele atribuirá o valor da chave. Se a chave original era um acessador de propriedade, isso substituirá o acessador de propriedade. Ele não chamará o método SetValue no acessador de propriedade.

SetKeyValue

O método SetKeyValue em uma referência de chave se comporta como o método SetKeyValue em IModelObject se comportaria. Ele atribuirá o valor da chave. Se a chave original era um acessador de propriedade, isso chamará o método SetValue subjacente no acessador de propriedade, em vez de substituir o próprio acessador de propriedade.

OverrideContextObject

O método OverrideContextObject (presente somente em IModelKeyReference2) é um método avançado que é usado para alterar permanentemente o objeto de contexto que essa referência de chave passará para os métodos GetValue ou SetValue de qualquer acessador de propriedade subjacente. O objeto passado para esse método também será retornado de uma chamada para GetContextObject. Esse método pode ser usado por provedores de script para replicar certos comportamentos de linguagem dinâmica. A maioria dos clientes não deve chamar esse método.

Objetos de contexto: IDebugHostContext

Os objetos de contexto são blobs opacos de informações que o host de depuração (em cooperação com o modelo de dados) associa a cada objeto. Pode incluir itens como o contexto do processo ou o espaço de endereço de onde as informações são fornecidas, etc. Um objeto de contexto é uma implementação de IDebugHostContext convertida em um IModelObject. Observe que IDebugHostContext é uma interface definida pelo host. Um cliente nunca implementará essa interface.

Para obter mais informações sobre objetos de contexto, confira Interfaces do Host do Modelo de Dados do Depurador C++ em Interfaces do Modelo de Dados do Depurador C++.

O Gerenciador do Modelo de Dados

A interface principal para o gerenciador de modelo de dados, IDataModelManager2 (ou o IDataModelManager anterior), é definida da seguinte maneira:

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étodos de gerenciamento

O seguinte conjunto de métodos é utilizado pelo aplicativo (por exemplo: depurador) que hospeda o modelo de dados.

STDMETHOD(Close)() PURE;

Fechar

O método Close é chamado no gerenciador de modelo de dados por um aplicativo (por exemplo: depurador) que hospeda o modelo de dados para iniciar o processo de desligamento do gerenciador de modelo de dados. Um host do modelo de dados que não usa o método Close antes de liberar sua referência final no gerenciador de modelo de dados pode causar um comportamento indefinido, incluindo, mas não se limitando a, vazamentos significativos da infraestrutura de gerenciamento para o modelo de dados.

Métodos de criação/conversão boxing de objetos

O conjunto de métodos a seguir é usado para criar novos objetos ou para fazer a conversão boxing dos valores em um IModelObject, a interface principal do modelo de dados.

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

O método CreateNoValue cria um objeto "no value", faz a sua conversão boxing em um IModelObject e o retorna. O objeto de modelo retornado tem um tipo de ObjectNoValue.

Um objeto "no value" tem vários significados semânticos:

  • (Dependendo da linguagem), pode ser considerado o equivalente semântico de void, null ou undefined
  • O método GetValue de qualquer acessador de propriedade que retorna êxito e um objeto "no value" resultante está indicando que a propriedade específica não tem valor para a instância fornecida e deve ser tratada como se a propriedade não existisse para essa instância específica.
  • Os métodos de modelo de dados que não têm semanticamente um valor de retorno usam isso como um sentinel para indicar isso (como um método deve retornar um IModelObject válido).

CreateErrorObject

O método CreateErrorObject cria um "objeto de erro". O modelo de dados não tem a noção de exceções e o fluxo de exceções. A falha resulta de uma propriedade/método de duas maneiras:

  • Um único HRESULT com falha sem informações de erro estendidas. Ou não há mais informações que possam ser fornecidas para o erro ou o erro em si é autoexplicativo do HRESULT retornado.
  • Um único HRESULT com falha juntamente com informações de erro estendidas. As informações de erro estendidas são um objeto de erro retornado no argumento de saída da propriedade/método.

CreateTypedObject

O método CreateTypedObject é o método que permite que um cliente crie uma representação de um objeto nativo/de linguagem no espaço de endereço de um destino de depuração. Se o tipo do objeto recém-criado (conforme indicado pelo argumento objectType) corresponder a uma ou mais assinaturas de tipo registradas no gerenciador de modelo de dados como visualizadores canônicos ou extensões, esses modelos de dados correspondentes serão automaticamente anexados ao objeto de instância criado antes que ele seja retornado ao chamador.

CreateTypedObjectReference

O método CreateTypedObjectReference é semanticamente semelhante ao método CreateTypedObject, exceto que ele cria uma referência à construção nativa/de linguagem subjacente. A referência criada é um objeto que tem um tipo de ObjectTargetObjectReference. Não é uma referência nativa, pois a linguagem subjacente pode oferecer suporte (por exemplo: C++ & ou &&). É totalmente possível ter um ObjectTargetObjectReference para uma referência C++. Um objeto do tipo ObjectTargetObjectReference pode ser convertido no valor subjacente por meio do uso do método Dereference em IModelObject. A referência também pode ser passada para o avaliador de expressão do host subjacente para ser atribuída de volta ao valor de uma maneira apropriada para a linguagem.

CreateSyntheticObject

O método CreateSyntheticObject cria um objeto de modelo de dados vazio -- um dicionário de tuplas e conceitos de chave/valor/metadados. No momento da criação, não há chaves nem conceitos no objeto. É uma imagem fixa limpa para o chamador utilizar.

CreateDataModelObject

O método CreateDataModelObject é um wrapper auxiliar simples para criar objetos que são modelos de dados , ou seja, objetos que serão anexados como modelos pai a outros objetos. Todos esses objetos devem oferecer suporte ao conceito de modelo de dados via IDataModelConcept. Esse método cria um novo objeto sintético em branco sem contexto explícito e adiciona o IDataModelConcept inserido como a implementação do objeto recém-criado do conceito de modelo de dados. Isso também pode ser realizado com chamadas para CreateSyntheticObject e SetConcept.

CreateIntrinsicObject

O método CreateIntrinsicObject é o método que converte valores intrínsecos em IModelObject. O chamador coloca o valor em COM VARIANT e chama esse método. O gerenciador de modelo de dados retorna um IModelObject que representa o objeto. Observe que esse método também é usado para converter tipos fundamentais baseados em IUnknown: acessadores de propriedade, métodos, contextos, etc. Nesses casos, o método objectKind indica qual tipo de construção baseada em IUnknown o objeto representa e o campo punkVal da variante passada é o tipo derivado IUnknown. O tipo deve ser transmitido estaticamente para a interface de modelo apropriada (por exemplo: IModelPropertyAccessor, IModelMethod, IDebugHostContext, etc.) em processo. Os tipos de VARIANT compatíveis com esse método são VT_UI1, VT_I1, VT_UI2, VT_I2, VT_UI4, VT_I4, VT_UI8, VT_I8, VT_R4, VT_R8, VT_BOOL, VT_BSTR e VT_UNKNOWN (para um conjunto especializado de tipos derivados de IUnknown, conforme indicado pela enumeração ModelObjectKind).

CreateTypedIntrinsicObject

O método CreateTypedintrinsicObject é semelhante ao método CreateIntrinsicObject, exceto que ele permite que um tipo nativo/de linguagem seja associado aos dados e transportado junto com o valor convertido. Isso permite que o modelo de dados represente construções, como tipos de enumeração nativos (que são simplesmente os valores VT_UI* ou VT_I*). Tipos de ponteiro também são criados com esse método. Um ponteiro nativo no modelo de dados é uma quantidade estendida zero de 64 bits que representa um deslocamento no espaço de endereço virtual do destino de depuração. Ele é convertido dentro de uma VT_UI8 e é criado com esse método e um tipo que indica um ponteiro nativo/de linguagem.

CreateMetadataStore

O método CreateMetadataStore cria um repositório de chaves -- um contêiner simplificado de tuplas de chave/valor/metadados -- que é usado para reter os metadados que podem ser associados a propriedades e a vários outros valores. Um repositório de metadados pode ter um único pai (que, por sua vez, pode ter um único pai). Se uma determinada chave de metadados não estiver localizada em um determinado repositório, seus pais serão verificados. A maioria dos repositórios de metadados não tem pais. No entanto, ele fornece uma maneira de compartilhar metadados comuns facilmente.

CreateTypedIntrinsicObjectEx

O método CreateTypedIntrinsicObjectEx é semanticamente semelhante ao método CreateTypedIntrinsicObject. A única diferença entre os dois é que esse método permite que o chamador especifique o contexto no qual os dados intrínsecos são válidos. Se nenhum contexto for passado, os dados serão considerados válidos em qualquer contexto herdado do argumento type (como CreateTypedIntrinsicObject se comporta). Isso permite criar valores de ponteiro digitados no destino de depuração que requeiram um contexto mais específico do que pode ser herdado do tipo.

Métodos de extensibilidade/registro O conjunto de métodos a seguir gerencia o mecanismo de extensibilidade do modelo de dados, permitindo que um cliente estenda ou registre modelos existentes ou peça ao modelo de dados para anexar automaticamente um determinado modelo pai em tipos nativos que correspondam a um determinado critério.

    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

O método GetModelForTypeSignature retorna o modelo de dados que foi registrado em uma assinatura de tipo específico por meio de uma chamada anterior para o método RegisterModelForTypeSignature. O modelo de dados retornado desse método é considerado o visualizador canônico para qualquer tipo que corresponda à assinatura de tipo passada. Como um visualizador canônico, esse modelo de dados assume a exibição do tipo. Os mecanismos de exibição ocultarão, por padrão, construções nativas/de linguagem do objeto em favor da exibição do objeto apresentado pelo modelo de dados.

GetModelForType

O método GetModelForType retorna o modelo de dados que é o visualizador canônico para uma determinada instância de tipo. Na verdade, esse método localiza a melhor assinatura de tipo correspondente que foi registrada com uma chamada anterior para o método RegisterModelForTypeSignature e retorna o modelo de dados associado.

RegisterModelForTypeSignature

O método RegisterModelForTypeSignature é o método principal que um chamador utiliza para registrar um visualizador canônico para um determinado tipo (ou conjunto de tipos). Um visualizador canônico é um modelo de dados que, na verdade, assume a exibição de um determinado tipo (ou conjunto de tipos). Em vez da exibição nativa/de linguagem do tipo ser exibida em qualquer interface do usuário do depurador, a exibição do tipo como apresentada pelo modelo de dados registrado é exibida (juntamente com um meio de voltar à exibição nativa/de linguagem para um usuário que a deseje).

UnregisterModelForTypeSignature

O método UnregisterModelForTypeSignature desfaz uma chamada anterior para o método RegisterModelForTypeSignature. Esse método pode remover determinado modelo de dados como o visualizador canônico para tipos que correspondam a uma assinatura de tipo específico ou pode remover determinado modelo de dados como o visualizador canônico para cada assinatura de tipo sob a qual esse modelo de dados é registrado.

RegisterExtensionForTypeSignature

O método RegisterExtensionForTypeSignature é semelhante ao método RegisterModelForTypeSignature com uma diferença de chave. O modelo de dados que é passado para esse método não é o visualizador canônico para nenhum tipo e ele não assumirá a exibição da visualização nativa/de linguagem desse tipo. O modelo de dados que é passado para esse método será automaticamente adicionado como um pai a qualquer tipo concreto que corresponda à assinatura de tipo fornecida. Ao contrário do método RegisterModelForTypeSignature, não há limite para assinaturas de tipo idênticas ou ambíguas sendo registradas como extensões para um determinado tipo (ou conjunto de tipos). Cada extensão cuja assinatura de tipo corresponde a uma determinada instância de tipo concreto fará com que o modelo de dados registrado por meio desse método seja automaticamente anexado a objetos recém-criados como modelos pai. Isso, na verdade, permite que um número arbitrário de clientes estenda um tipo (ou conjunto de tipos) com novos campos ou funcionalidades.

UnregisterExtensionForTypeSignature

O método UnregisterExtensionForTypeSignature desfaz uma chamada anterior para RegisterExtensionForTypeSignature. Ele cancela o registro de um modelo de dados específico como uma extensão para uma assinatura de tipo específica ou como uma extensão para todas as assinaturas de tipo nas quais o modelo de dados foi registrado.

GetRootNamespace

O método GetRootNamespace retorna o namespace raiz do modelo de dados. Este é um objeto que o modelo de dados gerencia e no qual o host de depuração coloca determinados objetos.

RegisterNamedModel

O método RegisterNamedModel registra determinado modelo de dados sob um nome bem conhecido para que ele possa ser encontrado por clientes que desejam estendê-lo. Esse é o objetivo principal da API, publicar um modelo de dados como algo que possa ser estendido recuperando o modelo registrado sob esse nome conhecido e adicionando um modelo pai a ele.

UnregisterNamedModel

O método UnregisterNamedModel desfaz uma chamada anterior para RegisterNamedModel. Ele remove a associação entre um modelo de dados e um nome sob o qual ele pode ser pesquisado.

AcquireNamedModel

Um chamador que deseja estender um modelo de dados registrado sob um nome específico chama o método AcquireNamedModel para recuperar o objeto do modelo de dados que deseja estender. Esse método retornará qualquer modelo de dados que foi registrado por meio de uma chamada anterior para o método RegisterNamedModel. Como o objetivo principal do método AcquireNamedModel é estender o modelo, esse método terá um comportamento especial se nenhum modelo tiver sido registrado ainda com o nome fornecido. Se nenhum modelo tiver sido registrado ainda com o nome fornecido, um objeto stub será criado, temporariamente registrado com o nome fornecido e retornado ao chamador. Quando o modelo de dados real é registrado por meio de uma chamada para o método RegisterNamedModel, as alterações que foram feitas no objeto stub são, na verdade, feitas no modelo real. Isso remove muitos problemas de dependência de ordem de carga de componentes que se estendem uns aos outros.

Métodos auxiliares

Os métodos a seguir são métodos auxiliares gerais que auxiliam na execução de operações complexas em objetos no modelo de dados. Embora seja possível executar essas ações por meio de outros métodos no modelo de dados ou em seus objetos, estes métodos de conveniência facilitam significativamente:

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

AcquireSubNamespace

O método AcquireSubNamespace ajuda na construção de algo que pode mais tradicionalmente se parecer com um namespace de linguagem do que um novo objeto em uma linguagem dinâmica. Se, por exemplo, um chamador desejar categorizar propriedades em um objeto de processo para tornar o objeto de processo mais organizado e as propriedades mais fáceis de descobrir, um método de fazer isso é criar um subobjeto para cada categoria no objeto de processo e colocar essas propriedades dentro desse objeto.

Consulte também

Este tópico faz parte de uma série que descreve as interfaces acessíveis a partir de C++, como usá-las para criar uma extensão de depurador baseada em C++ e como fazer uso de outras construções de modelo de dados (por exemplo: JavaScript ou NatVis) a partir de uma extensão de modelo de dados C++.

Visão geral do Modelo de Dados do Depurador C++

Interfaces do Modelo de Dados do Depurador C++

Interfaces adicionais do Modelo de Dados do Depurador C++

Conceitos do Modelo de Dados do Depurador C++

Script do Modelo de Dados do Depurador C++