Interfaces C++ do modelo de dados do depurador

Este tópico fornece uma visão geral de como usar interfaces C++ do Modelo de Dados do Depurador para estender e personalizar os recursos do depurador.

Interfaces de host C++ do modelo de dados do depurador

O host do modelo de dados do depurador

O Modelo de Dados do Depurador foi projetado para ser um sistema com componentes que pode ser hospedado em uma variedade de contextos diferentes. Normalmente, o Modelo de Dados é hospedado no contexto de um aplicativo de depurador. Para ser um host do modelo de dados, várias interfaces precisam ser implementadas para expor os principais aspectos do depurador: seu direcionamento, seus espaços de memória, seu avaliador, seu sistema simbólico e de tipos etc... Embora essas interfaces sejam implementadas por qualquer aplicativo que deseje hospedar o modelo de dados, elas são consumidas pelo modelo de dados principal, bem como por qualquer extensão que interopere com o modelo de dados.

O conjunto de interfaces principais é:

Nome da Interface Descrição
IDebugHost A interface principal para o host de depuração.
IDebugHostStatus Uma interface que permite que um cliente consulte o status do host.
IDebugHostContext Uma abstração de um contexto dentro do host (por exemplo: um destino específico, um processo específico, um espaço de endereço específico etc...)
IDebugHostErrorSink Uma interface implementada pelos chamadores para receber erros de determinadas partes do host e do modelo de dados
IDebugHostEvaluator / IDebugHostEvaluator2 O avaliador de expressão do host de depuração.
IDebugHostExtensibility Uma interface para estender os recursos do host ou partes dele (como o avaliador de expressão).

O sistema de tipos e as interfaces simbólicas são:

InterfaceName Descrição
IDebugHostSymbols Interface principal que fornece acesso e resolução de símbolos
IDebugHostSymbol / IDebugHostSymbol2 Representa um único símbolo de qualquer tipo. O símbolo específico é uma derivação dessa interface.
IDebugHostModule Representa um módulo carregado em um processo. Este é um tipo de símbolo.
IDebugHostType / IDebugHostType2 Representa um tipo nativo/de idioma.
IDebugHostConstant Representa uma constante dentro de informações simbólicas (por exemplo: um argumento de modelo não tipo em C++)
IDebugHostField Representa um campo dentro de uma estrutura ou classe.
IDebugHostData Representa dados dentro de um módulo (se isso estivesse dentro de uma estrutura ou classe, seria um IDebugHostField)
IDebugHostBaseClass Representa uma classe base.
IDebugHostPublic Representa um símbolo dentro da tabela publics de um PDB. Isso não tem informações de tipo associadas a ela. É um nome e endereço.
IDebugHostModuleSignature Representa uma assinatura de módulo – uma definição que corresponderá a um conjunto de módulos por nome e/ou versão
IDebugHostTypeSignature Representa uma assinatura de tipo – uma definição que corresponderá a um conjunto de tipos por módulo e/ou nome

A interface de host principal: IDebugHost

A interface IDebugHost é a interface principal de qualquer host de modelo de dados. Ela é definida da seguinte maneira:

DECLARE_INTERFACE_(IDebugHost, IUnknown)
{
    STDMETHOD(GetHostDefinedInterface)(_COM_Outptr_ IUnknown** hostUnk) PURE;
    STDMETHOD(GetCurrentContext)(_COM_Outptr_ IDebugHostContext** context) PURE;
    STDMETHOD(GetDefaultMetadata)(_COM_Outptr_ IKeyStore** defaultMetadataStore) PURE;
}

GetHostDefinedInterface

O método GetHostDefinedInterface retornará a interface privada main do host, se existir para o host fornecido. Para Ferramentas de Depuração para Windows, a interface retornada aqui é um IDebugClient (convertido em IUnknown).

GetCurrentContext

O método GetCurrentContext retorna uma interface que representa o estado atual do host do depurador. O significado exato disso é deixado para o host, mas normalmente inclui itens como a sessão, o processo e o espaço de endereço que está ativo na interface do usuário do host de depuração. O objeto de contexto retornado é amplamente opaco para o chamador, mas é um objeto importante para passar entre chamadas para o host de depuração. Quando um chamador está, por exemplo, lendo memória, é importante saber de qual processo e espaço de endereço a memória está sendo lida. Essa noção é encapsulada na noção do objeto de contexto que é retornado desse método.

GetDefaultMetadata

O método GetDefaultMetadata retorna um repositório de metadados padrão que pode ser usado para determinadas operações (por exemplo, conversão de cadeia de caracteres) quando nenhum metadado explícito foi passado. Isso permite que o host de depuração tenha algum controle sobre a maneira como alguns dados são apresentados. Por exemplo, os metadados padrão podem incluir uma chave PreferredRadix, permitindo que o host indique se ordinais devem ser exibidos em decimal ou hexadecimal se não for especificado de outra forma.

Observe que os valores de propriedade no repositório de metadados padrão devem ser resolvidos manualmente e devem passar o objeto para o qual os metadados padrão estão sendo consultados. O método GetKey deve ser usado em vez de GetKeyValue.

A interface status: IDebugHostStatus

A interface IDebugHostStatus permite que um cliente do modelo de dados ou do host de depuração indague sobre determinados aspectos do status do host de depuração. A interface é definida assim:

DECLARE_INTERFACE_(IDebugHostStatus, IUnknown)
{
    STDMETHOD(PollUserInterrupt)(_Out_ bool* interruptRequested) PURE;
}

PollUserInterrupt

O método PollUserInterrupt é usado para perguntar se o usuário do host de depuração solicitou uma interrupção da operação atual. Um acessador de propriedade no modelo de dados pode, por exemplo, chamar em código arbitrário (por exemplo: um método JavaScript). Esse código pode levar um tempo arbitrário. Para manter o host de depuração responsivo, qualquer código desse tipo que possa levar um período arbitrário deve marcar para uma solicitação de interrupção por meio da chamada desse método. Se o valor interruptRequested voltar como true, o chamador deverá anular imediatamente e retornar um resultado de E_ABORT.

A interface de contexto: IDebugHostContext

O contexto é um dos aspectos mais importantes do modelo de dados e do host de depuração subjacente. Quando você mantém um objeto, é importante saber de onde veio um objeto – em qual processo ele está, com qual espaço de endereço ele está associado. Saber essas informações permite a interpretação correta de coisas como valores de ponteiro. Um objeto do tipo IDebugHostContext deve ser passado para muitos métodos no host de depuração. Essa interface pode ser adquirida de várias maneiras:

  • Obtendo o contexto atual do depurador: chamando o método GetCurrentContext de IDebugHost
  • Obtendo o contexto de um objeto: chamando o método GetContext de IModelObject
  • Obtendo o contexto de um símbolo: chamando o método GetContext de IDebugHostSymbol

Além disso, há dois valores que têm um significado especial no contexto de uma interface IDebugHostContext que é retornada ou passada para um modelo de dados ou método de host de depuração:

nullptr: uma indicação de que não há contexto. É perfeitamente válido que alguns objetos não tenham contexto. O objeto Depurador no namespace raiz do modelo de dados não se refere a nada dentro de um processo ou espaço de endereço específico. Ele não tem contexto.

USE_CURRENT_HOST_CONTEXT: um valor sentinela que indica que se deve usar o contexto de interface do usuário atual do host de depuração. Esse valor nunca será retornado do host de depuração. No entanto, ele pode ser passado para qualquer método de host de depuração que usa uma entrada IDebugHostContext em vez de chamar explicitamente o método GetCurrentContext de IDebugHost. Observe que passar explicitamente USE_CURRENT_HOST_CONTEXT geralmente é mais eficaz do que obter explicitamente o contexto atual.

Os contextos de um contexto de host são amplamente opacos para o chamador. A única operação que um chamador fora do host de depuração principal pode fazer com um contexto de host é compará-lo com outro contexto de host.

A interface IDebugHostContext é definida da seguinte maneira:

DECLARE_INTERFACE_(IDebugHostContext, IUnknown)
{
    STDMETHOD(IsEqualTo)(_In_ IDebugHostContext *pContext, _Out_ bool *pIsEqual) PURE;
}

IsEqualTo

O método IsEqualTo compara um contexto de host com outro contexto de host. Se os dois contextos forem equivalentes, uma indicação disso será retornada. Observe que essa comparação não é equivalência de interface. Isso compara o conteúdo opaco subjacente do próprio contexto.

O coletor de erros: IDebugHostErrorSink

O IDebugHostErrorSink é um meio pelo qual um cliente pode receber notificações de erros que ocorrem durante determinadas operações e rotear esses erros quando necessário. A interface é definida assim:

enum ErrorClass
{
    ErrorClassWarning,
    ErrorClassError
}
DECLARE_INTERFACE_(IDebugHostErrorSink, IUnknown)
{
    STDMETHOD(ReportError)(_In_ ErrorClass errClass, _In_ HRESULT hrError, _In_ PCWSTR message) PURE;
}

ReportError

O método ReportError é um retorno de chamada no coletor de erros para notificá-lo de que ocorreu um erro e permitir que o coletor encaminhe o erro para qualquer interface do usuário ou mecanismo apropriado.

O avaliador de host: IDebugHostEvaluator / IDebugHostEvaluator2

Uma das partes mais importantes da funcionalidade que o host de depuração fornece aos clientes é o acesso ao seu avaliador de expressão baseado em linguagem. As interfaces IDebugHostEvaluator e IDebugHostEvaluator2 são os meios para acessar essa funcionalidade do host de depuração.

As interfaces são definidas da seguinte maneira:

DECLARE_INTERFACE_(IDebugHostEvaluator2, IDebugHostEvaluator)
{
    //
    // IDebugHostEvaluator:
    //
    STDMETHOD(EvaluateExpression)(_In_ IDebugHostContext* context, _In_ PCWSTR expression, _In_opt_ IModelObject* bindingContext, _COM_Errorptr_ IModelObject** result, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(EvaluateExtendedExpression)(_In_ IDebugHostContext* context, _In_ PCWSTR expression, _In_opt_ IModelObject* bindingContext, _COM_Errorptr_ IModelObject** result, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    //
    // IDebugHostEvaluator2:
    //
    STDMETHOD(AssignTo)(_In_ IModelObject* assignmentReference, _In_ IModelObject* assignmentValue, _COM_Errorptr_ IModelObject** assignmentResult, _COM_Outptr_opt_result_maybenull_ IKeyStore** assignmentMetadata) PURE;
}

Evaluateexpression

O método EvaluateExpression permite que o host de depuração avalie uma expressão de linguagem (por exemplo: C++) e retorne o valor resultante dessa avaliação de expressão em caixa como um IModelObject. Essa variante específica do método permite apenas constructos de linguagem. Qualquer funcionalidade adicional apresentada no avaliador de expressão do host de depuração que não está presente na linguagem (por exemplo: métodos de consulta LINQ) está desativada para a avaliação.

EvaluateExtendedExpression

O método EvaluateExtendedExpression é semelhante ao método EvaluateExpression, exceto pelo fato de que ele ativa novamente a funcionalidade adicional que um host de depuração específico escolhe adicionar ao seu avaliador de expressão. Para Ferramentas de Depuração para Windows, por exemplo, isso permite tipos anônimos, consultas LINQ, qualificadores de módulo, especificadores de formato e outras funcionalidades não C/C++.

IDebugHostEvaluator2

AssignTo

O método AssignTo executa a atribuição de acordo com a semântica do idioma que está sendo depurado.

A interface de extensibilidade do host: IDebugHostExtensibility

Algumas funcionalidades do host de depuração estão opcionalmente sujeitas à extensibilidade. Isso pode, por exemplo, incluir o avaliador de expressão. A interface IDebugHostExtensibility é o meio pelo qual esses pontos de extensibilidade são acessados. A interface é definida assim:

DECLARE_INTERFACE_(IDebugHostExtensibility, IUnknown)
{
    STDMETHOD(CreateFunctionAlias)(_In_ PCWSTR aliasName, _In_ IModelObject *functionObject) PURE;
    STDMETHOD(DestroyFunctionAlias)(_In_ PCWSTR aliasName) PURE;
}

CreateFunctionAlias

O método CreateFunctionAlias cria um "alias de função", um "alias rápido" para um método implementado em alguma extensão. O significado desse alias é específico do host. Ele pode estender o avaliador de expressão do host com a função ou pode fazer algo totalmente diferente.

DestroyFunctionAlias

O método DestroyFunctionAlias desfaz uma chamada anterior ao método CreateFunctionAlias. A função não estará mais disponível sob o nome do alias rápido.

Acessando o modelo de dados

Em primeiro lugar, as APIs de extensibilidade do modelo de dados foram projetadas para serem neutras para o aplicativo (normalmente um depurador) que atua como um host do modelo de dados. Em teoria, qualquer aplicativo pode hospedar o modelo de dados fornecendo um conjunto de APIs de host que expõem o sistema de tipos dos destinos de depuração do aplicativo e um conjunto de objetos projetados no namespace do modelo de dados sobre quais destinos, processos, threads etc... estão nesses destinos de depuração.

Embora as APIs do modelo de dados – aquelas que iniciam IDataModel, IDebugHost e os desdobramentos de IModelObject – sejam projetadas para serem portáteis, elas não definem o que é uma "extensão do depurador". Hoje, um componente que deseja estender as Ferramentas de Depuração para Windows e o mecanismo que ele fornece deve gravar uma extensão de mecanismo para obter acesso ao modelo de dados. Essa extensão do mecanismo só precisa ser uma extensão de mecanismo, tanto quanto o mecanismo de carregamento e inicialização para a extensão. Dessa forma, uma implementação mínima forneceria:

  • DebugExtensionInitialize: um método que utiliza um IDebugClient criado para obter acesso ao modelo de dados e configura manipulações de modelo de objeto.
  • DebugExtensionUninitialize: um método que desfaz as manipulações do modelo de objeto que foram executadas em DebugExtensionInitialize.
  • DebugExtensionCanUnload: um método que retorna se a extensão pode descarregar. Se ainda houver objetos COM ativos na extensão, ele deverá indicar isso. Esse é o equivalente do depurador de DllCanUnloadNow do COM. Se isso retornar a indicação S_FALSE de incapacidade de descarregar, o depurador poderá consultar isso mais tarde para ver se um descarregamento é seguro ou pode reinicializar a extensão chamando DebugExtensionInitialize novamente. A extensão deve estar preparada para lidar com os dois caminhos.
  • DebugExtensionUnload: um método que faz qualquer limpeza final necessária antes do descarregamento da DLL

A interface bridge: IHostDataModelAccess

Conforme mencionado, quando DebugExtensionInitialize é chamado, ele cria um cliente de depuração e obtém acesso ao modelo de dados. Esse acesso é fornecido por uma interface de ponte entre as interfaces IDebug* herdadas das Ferramentas de Depuração para Windows e o modelo de dados. Essa interface de ponte é 'IHostDataModelAccess e é definida da seguinte maneira:

DECLARE_INTERFACE_(IHostDataModelAccess, IUnknown)
{
   STDMETHOD(GetDataModel)(_COM_Outptr_ IDataModelManager** manager, _COM_Outptr_ IDebugHost** host) PURE;
}

GetDataModel

O método GetDataModel é o método na interface de ponte que fornece acesso a ambos os lados do modelo de dados: o host de depuração (a borda inferior do depurador) é expresso pela interface IDebugHost retornada O componente main do modelo de dados – o gerenciador de modelos de dados é expresso pela interface IDataModelManager retornada

Interfaces do sistema do modelo de dados do depurador

O host do modelo de dados

O Modelo de Dados do Depurador foi projetado para ser um sistema com componentes que pode ser hospedado em uma variedade de contextos diferentes. Normalmente, o Modelo de Dados é hospedado no contexto de um aplicativo de depurador. Para ser um host do modelo de dados, várias interfaces precisam ser implementadas para expor os principais aspectos do depurador: seu direcionamento, seus espaços de memória, seu avaliador, seu sistema simbólico e de tipos etc... Embora essas interfaces sejam implementadas por qualquer aplicativo que deseje hospedar o modelo de dados, elas são consumidas pelo modelo de dados principal, bem como por qualquer extensão que interopere com o modelo de dados.

O sistema de tipos e as interfaces simbólicas são:

Nome da Interface Descrição
IDebugHostSymbols Interface principal que fornece acesso e resolução de símbolos
IDebugHostSymbol / IDebugHostSymbol2 Representa um único símbolo de qualquer tipo. O símbolo específico é uma derivação dessa interface.
IDebugHostModule Representa um módulo carregado em um processo. Este é um tipo de símbolo.
IDebugHostType / IDebugHostType2 Representa um tipo nativo/de idioma.
IDebugHostConstant Representa uma constante dentro de informações simbólicas (por exemplo: um argumento de modelo não tipo em C++)
IDebugHostField Representa um campo dentro de uma estrutura ou classe.
IDebugHostData Representa dados dentro de um módulo (se isso estivesse dentro de uma estrutura ou classe, seria um IDebugHostField)
IDebugHostBaseClass Representa uma classe base.
IDebugHostPublic Representa um símbolo dentro da tabela publics de um PDB. Isso não tem informações de tipo associadas a ela. É um nome e endereço.
IDebugHostModuleSignature Representa uma assinatura de módulo – uma definição que corresponderá a um conjunto de módulos por nome e/ou versão
IDebugHostTypeSignature Representa uma assinatura de tipo – uma definição que corresponderá a um conjunto de tipos por módulo e/ou nome

As outras interfaces principais são:

Nome da Interface Descrição
IDebugHost A interface principal para o host de depuração.
IDebugHostStatus Uma interface que permite que um cliente consulte o status do host.
IDebugHostContext Uma abstração de um contexto dentro do host (por exemplo: um destino específico, um processo específico, um espaço de endereço específico etc...)
IDebugHostErrorSink Uma interface implementada pelos chamadores para receber erros de determinadas partes do host e do modelo de dados
IDebugHostEvaluator / IDebugHostEvaluator2 O avaliador de expressão do host de depuração.
IDebugHostExtensibility Uma interface para estender os recursos do host ou partes dele (como o avaliador de expressão).

A interface simbólica principal: IDebugHostSymbols

A interface IDebugHostSymbols é o ponto de partida main para acessar símbolos no destino de depuração. Essa interface pode ser consultada de uma instância do IDebugHost e é definida da seguinte maneira:

DECLARE_INTERFACE_(IDebugHostSymbols, IUnknown)
{
    STDMETHOD(CreateModuleSignature)(_In_z_ PCWSTR pwszModuleName, _In_opt_z_ PCWSTR pwszMinVersion, _In_opt_z_ PCWSTR pwszMaxVersion, _Out_ IDebugHostModuleSignature** ppModuleSignature) PURE;
    STDMETHOD(CreateTypeSignature)(_In_z_ PCWSTR signatureSpecification, _In_opt_ IDebugHostModule* module, _Out_ IDebugHostTypeSignature** typeSignature) PURE;
    STDMETHOD(CreateTypeSignatureForModuleRange)(_In_z_ PCWSTR signatureSpecification, _In_z_ PCWSTR moduleName, _In_opt_z_ PCWSTR minVersion, _In_opt_z_ PCWSTR maxVersion, _Out_ IDebugHostTypeSignature** typeSignature) PURE;
    STDMETHOD(EnumerateModules)(_In_ IDebugHostContext* context, _COM_Outptr_ IDebugHostSymbolEnumerator** moduleEnum) PURE;
    STDMETHOD(FindModuleByName)(_In_ IDebugHostContext* context, _In_z_ PCWSTR moduleName, _COM_Outptr_ IDebugHostModule **module) PURE;
    STDMETHOD(FindModuleByLocation)(_In_ IDebugHostContext* context, _In_ Location moduleLocation, _COM_Outptr_ IDebugHostModule **module) PURE;
    STDMETHOD(GetMostDerivedObject)(_In_opt_ IDebugHostContext *pContext, _In_ Location location, _In_ IDebugHostType* objectType, _Out_ Location* derivedLocation, _Out_ IDebugHostType** derivedType) PURE;
}

CreateModuleSignature

O método CreateModuleSignature cria uma assinatura que pode ser usada para corresponder a um conjunto de módulos específicos por nome e, opcionalmente, por versão. Há três componentes para uma assinatura de módulo:

  • Um nome: um módulo correspondente deve ter um nome que seja uma correspondência não diferenciada de maiúsculas e minúsculas com relação ao nome na assinatura
  • Uma versão mínima: se especificado, um módulo correspondente deve ter uma versão mínima que seja pelo menos tão alta quanto esta versão. As versões são especificadas no formato "A.B.C.D", com cada parte subsequente sendo menos importante do que a anterior. Somente o primeiro segmento é obrigatório.
  • Uma versão máxima: se especificado, um módulo correspondente deve ter uma versão máxima que não seja superior a esta versão. As versões são especificadas no formato "A.B.C.D", com cada parte subsequente sendo menos importante do que a anterior. Somente o primeiro segmento é obrigatório.

CreateTypeSignature

O método CreateTypeSignature cria uma assinatura que pode ser usada para corresponder a um conjunto de tipos concretos contendo o nome do módulo e do tipo. O formato da cadeia de caracteres de assinatura de nome de tipo é específico para o idioma que está sendo depurado (e o host de depuração). Para C/C++, a cadeia de caracteres de assinatura é equivalente a uma Especificação de Tipo natVis. Ou seja, a cadeia de caracteres de assinatura é um nome de tipo em que curingas (especificados como *) são permitidos para argumentos de modelo.

CreateTypeSignatureForModuleRange

O método CreateTypeSignatureForModuleRange cria uma assinatura que pode ser usada para corresponder a um conjunto de tipos concretos por assinatura de módulo e nome de tipo. Isso é semelhante ao método CreateTypeSignature, exceto que, em vez de passar um módulo específico para corresponder à assinatura, o chamador passa os argumentos necessários para criar uma assinatura de módulo (como se a assinatura do módulo fosse criada com o método CreateModuleSignature).

EnumerateModules

O método EnumerateModules cria um enumerador que enumerará todos os módulos disponíveis em um contexto de host específico. Esse contexto de host pode encapsular um contexto de processo ou encapsular algo como o kernel do Windows.

FindModuleByName

O método FindModuleByName analisará o contexto de host fornecido e localizará um módulo que tem o nome especificado e retornará uma interface a ele. É legal pesquisar o módulo pelo nome com ou sem a extensão de arquivo.

FindModuleByLocation

O método FindModuleByLocation analisará o contexto de host especificado e determinará qual módulo contém o endereço fornecido pelo local especificado. Em seguida, ele retornará uma interface para esse módulo.

GetMostDerivedObject

O GetMostDerivedObject usará o sistema de tipos do depurador para determinar o tipo de runtime de um objeto de seu tipo estático. Esse método usará apenas informações simbólicas e heurísticas disponíveis na camada do sistema de tipos para executar essa análise. Essas informações podem incluir RTTI do C++ (informações de tipo de tempo de execução) ou análise da forma das tabelas de funções virtuais do objeto. Ele não inclui coisas como o conceito de tipo de runtime preferido em um IModelObject. Se a análise não puder encontrar um tipo de runtime ou não encontrar um tipo de runtime diferente do tipo estático passado para o método , o local e o tipo de entrada poderão ser passados para fora. O método não falhará por esses motivos.

A interface de símbolo individual principal: IDebugHostSymbol

Todos os símbolos que podem ser retornados do host do modelo de dados derivarão de alguma forma de IDebugHostSymbol. Essa é a interface principal que cada símbolo implementa, independentemente do tipo de símbolo. Dependendo do tipo de símbolo, um determinado símbolo pode implementar um conjunto de outras interfaces que retornam atributos mais exclusivos para o tipo específico de símbolo representado por essa interface. A interface IDebugHostSymbol2 / IDebugHostSymbol é definida da seguinte maneira:

DECLARE_INTERFACE_(IDebugHostSymbol2, IDebugHostSymbol)
{
    // 
    // IDebugHostSymbol:
    //
    STDMETHOD(GetContext)(_COM_Outptr_ IDebugHostContext** context) PURE;
    STDMETHOD(EnumerateChildren)(_In_ SymbolKind kind, _In_opt_z_ PCWSTR name, _Out_ IDebugHostSymbolEnumerator **ppEnum) PURE;
    STDMETHOD(GetSymbolKind)(_Out_ SymbolKind *kind) PURE;
    STDMETHOD(GetName)(_Out_ BSTR* symbolName) PURE;
    STDMETHOD(GetType)(_Out_ IDebugHostType** type) PURE;
    STDMETHOD(GetContainingModule)(_Out_ IDebugHostModule **containingModule) PURE;
    STDMETHOD(CompareAgainst)(_In_ IDebugHostSymbol *pComparisonSymbol, _In_ ULONG comparisonFlags, _Out_ bool *pMatches) PURE;
    //
    // IDebugHostSymbol2
    //
    STDMETHOD(EnumerateChildrenEx)(_In_ SymbolKind kind, _In_opt_z_ PCWSTR name, _In_opt_ SymbolSearchInfo* searchInfo, _Out_ IDebugHostSymbolEnumerator **ppEnum) PURE;
}

É muito importante observar que essa interface representa muitos tipos de símbolos , delineados pela enumeração SymbolKind que tem valores da seguinte maneira:

Enumarant Significado
Símbolo Tipo de símbolo não especificado
SymbolModule O símbolo é um módulo e pode ser consultado para IDebugHostModule
SymbolType O símbolo é um tipo e pode ser consultado para IDebugHostType
SymbolField O símbolo é um campo (um membro de dados dentro de uma estrutura ou classe) e pode ser consultado para IDebugHostField
SymbolConstant O símbolo é um valor constante e pode ser consultado para IDebugHostConstant
SymbolData O símbolo são dados que não são membros de uma estrutura ou classe e podem ser consultados para IDebugHostData
SymbolBaseClass O símbolo é uma classe base e pode ser consultado para IDebugHostBaseClass
SymbolPublic O símbolo é uma entrada na tabela pública de um módulo (sem informações de tipo) e é consultável para IDebugHostPublic
SymbolFunction O símbolo é uma função e pode ser consultado para IDebugHostData

Getcontext

O método GetContext retorna o contexto em que o símbolo é válido. Embora isso represente coisas como o destino de depuração e o espaço de processo/endereço no qual o símbolo existe, ele pode não ser tão específico quanto um contexto recuperado de outros meios (por exemplo: de um IModelObject).

EnumerarChildren

O método EnumerateChildren retorna um enumerador que enumerará todos os filhos de um determinado símbolo. Para um tipo C++, por exemplo, as classes base, campos, funções membro e similares são considerados filhos do símbolo de tipo.

A interface do módulo: IDebugHostModule

A noção do depurador de um módulo carregado em algum espaço de endereço é representada de duas maneiras distintas no modelo de dados: no nível do sistema de tipos por meio da interface IDebugHostModule. Aqui, um módulo é um símbolo e os atributos principais do módulo são chamadas de método de interface Projetadas no nível do modelo de dados por meio do modelo de dados Debugger.Models.Module. Esse é um encapsulamento extensível da representação IDebugHostModule do sistema de tipo de um módulo.

A interface IDebugHostModule é definida da seguinte maneira (ignorando métodos genéricos para IDebugHostSymbol):

DECLARE_INTERFACE_(IDebugHostModule, IDebugHostSymbol)
{
    //
    // IDebugHostModule:
    //
    STDMETHOD(GetImageName)(_In_ bool allowPath, _Out_ BSTR* imageName) PURE;
    STDMETHOD(GetBaseLocation)(_Out_ Location* moduleBaseLocation) PURE;
    STDMETHOD(GetVersion)(_Out_opt_ ULONG64* fileVersion, _Out_opt_ ULONG64* productVersion) PURE;
    STDMETHOD(FindTypeByName)(_In_z_ PCWSTR typeName, _Out_ IDebugHostType** type) PURE;
    STDMETHOD(FindSymbolByRVA)(_In_ ULONG64 rva, _Out_ IDebugHostSymbol** symbol) PURE;
    STDMETHOD(FindSymbolByName)(_In_z_ PCWSTR symbolName, _Out_ IDebugHostSymbol** symbol) PURE;
}

GetImageName

O método GetImageName retorna o nome da imagem do módulo. Dependendo do valor do argumento allowPath, o nome da imagem retornado pode ou não incluir o caminho completo para a imagem.

GetBaseLocation

O método GetBaseLocation retorna o endereço de carga base do módulo como uma estrutura de localização. A estrutura de localização retornada para um módulo normalmente se referirá a um endereço virtual.

GetVersion

O método GetVersion retorna informações de versão sobre o módulo (supondo que essas informações possam ser lidas com êxito dos cabeçalhos). Se uma determinada versão for solicitada (por meio de um ponteiro de saída não nullptr) e não puder ser lida, um código de erro apropriado será retornado da chamada de método.

FindTypeByName

O método FindTypeByName localiza um tipo definido dentro do módulo pelo nome do tipo e retorna um símbolo de tipo para ele. Esse método pode retornar um IDebugHostType válido que nunca seria retornado por meio de recursão explícita de filhos do módulo. O host de depuração pode permitir a criação de tipos derivados – tipos que nunca foram usados dentro do próprio módulo, mas derivados de tipos que são. Por exemplo, se a estrutura MyStruct for definida nos símbolos do módulo, mas o tipo MyStruct ** nunca for usado, o método FindTypeByName poderá retornar legitimamente um símbolo de tipo para MyStruct ** apesar desse nome de tipo nunca aparecer explicitamente nos símbolos do módulo.

FindSymbolByRVA

O método FindSymbolByRVA encontrará um único símbolo correspondente no endereço virtual relativo fornecido dentro do módulo. Se não houver um único símbolo no RVA fornecido (por exemplo: há várias correspondências), um erro será retornado por esse método. Observe que esse método preferirá retornar um símbolo privado em vez de um símbolo na tabela publics.

FindSymbolByName

O método FindSymbolByName encontrará um único símbolo global do nome fornecido dentro do módulo. Se não houver um único símbolo correspondente ao nome fornecido, um erro será retornado por esse método. Observe que esse método preferirá retornar um símbolo privado em vez de um símbolo na tabela publics.

Acesso ao Sistema de Tipos: IDebugHostType2 / IDebugHostType

Um determinado idioma/tipo nativo é descrito pelas interfaces IDebugHostType2 ou IDebugHostType. Observe que alguns dos métodos nessas interfaces se aplicam apenas a tipos específicos de tipos. Um determinado símbolo de tipo pode se referir a um dos seguintes tipos, conforme descrito pela enumeração TypeKind:

Tipo de Tipo Descrição
TypeUDT Um tipo definido pelo usuário (struct, classe, união etc.). Um objeto de modelo que tem um tipo nativo cujo tipo é TypeUDT tem uma representação canônica de ObjectTargetObject em que o tipo é sempre mantido dentro do IModelObject correspondente.
TypePointer Um ponteiro. Um objeto de modelo que tem um tipo nativo cujo tipo é TypePointer tem uma representação canônica de ObjectIntrinsic em que o valor do ponteiro é zero estendido para VT_UI8 e mantido como dados intrínsecos nesta forma de 64 bits. Qualquer símbolo de tipo do TypePointer tem um tipo base (conforme retornado pelo método GetBaseType) do tipo para o qual o ponteiro aponta.
TypeMemberPointer Um ponteiro para o membro da classe. Um objeto de modelo que tem um tipo nativo cujo tipo é TypeMemberPointer tem uma representação canônica intrínseca (o valor é o mesmo que o valor do ponteiro). O significado exato desse valor é específico do host do compilador/depuração.
TypeArray Uma matriz . Um objeto de modelo que tem um tipo nativo cujo tipo é TypeArray tem uma representação canônica de ObjectTargetObject. O endereço base da matriz é o local do objeto (recuperado por meio do método GetLocation) e o tipo da matriz é sempre mantido. Qualquer símbolo de tipo de TypeArray tem um tipo base (conforme retornado pelo método GetBaseType) do tipo do qual a matriz é uma matriz.
TypeFunction Uma função.
TypeTypedef Um typedef. Um objeto de modelo que tem um tipo nativo cujo tipo seria TypeTypedef tem uma representação canônica idêntica à representação canônica do tipo final subjacente ao typedef. Isso parece completamente transparente para o usuário final do objeto e as informações de tipo, a menos que os métodos typedef explícitos de IDebugHostType2 sejam utilizados para consultar informações typedef ou haja um modelo de dados explícito registrado no typedef. Observe que o método GetTypeKind nunca retornará TypeTypedef. Cada método retornará o que o tipo final subjacente ao typedef retornaria. Há métodos específicos de typedef em IDebugHostType2 que podem ser usados para obter as informações específicas do typedef.
TypeEnum Uma enumeração. Um objeto de modelo que tem um tipo nativo cujo tipo é TypeEnum tem uma representação canônica de ObjectIntrinsic em que o valor e o tipo do intrínseco são idênticos ao valor de enumeração.
TypeIntrinsic Um intrínseco (tipo base). Um objeto de modelo que tem um tipo nativo cujo tipo é TypeIntrinsic tem uma representação canônica de ObjectIntrinsic. As informações de tipo podem ou não ser mantidas , especialmente se o tipo subjacente for totalmente descrito pelo tipo de dados variante (VT_*) dos dados intrínsecos armazenados no IModelObject

A interface IDebugHostType2/IDebugHostType geral é definida da seguinte maneira (excluindo métodos IDebugHostSymbol):

DECLARE_INTERFACE_(IDebugHostType2, IDebugHostType)
{
    //
    // IDebugHostType:
    //
    STDMETHOD(GetTypeKind)(_Out_ TypeKind *kind) PURE;
    STDMETHOD(GetSize)(_Out_ ULONG64* size) PURE;
    STDMETHOD(GetBaseType)(_Out_ IDebugHostType** baseType) PURE;
    STDMETHOD(GetHashCode)(_Out_ ULONG* hashCode) PURE;
    STDMETHOD(GetIntrinsicType)(_Out_opt_ IntrinsicKind *intrinsicKind, _Out_opt_ VARTYPE *carrierType) PURE;
    STDMETHOD(GetBitField)(_Out_ ULONG* lsbOfField, _Out_ ULONG* lengthOfField) PURE;
    STDMETHOD(GetPointerKind)(_Out_ PointerKind* pointerKind) PURE;
    STDMETHOD(GetMemberType)(_Out_ IDebugHostType** memberType) PURE;
    STDMETHOD(CreatePointerTo)(_In_ PointerKind kind, _COM_Outptr_ IDebugHostType** newType) PURE;
    STDMETHOD(GetArrayDimensionality)(_Out_ ULONG64* arrayDimensionality) PURE;
    STDMETHOD(GetArrayDimensions)(_In_ ULONG64 dimensions, _Out_writes_(dimensions) ArrayDimension *pDimensions) PURE;
    STDMETHOD(CreateArrayOf)(_In_ ULONG64 dimensions, _In_reads_(dimensions) ArrayDimension *pDimensions, _COM_Outptr_ IDebugHostType** newType) PURE;
    STDMETHOD(GetFunctionCallingConvention)(_Out_ CallingConventionKind* conventionKind) PURE;
    STDMETHOD(GetFunctionReturnType)(_COM_Outptr_ IDebugHostType** returnType) PURE;
    STDMETHOD(GetFunctionParameterTypeCount)(_Out_ ULONG64* count) PURE;
    STDMETHOD(GetFunctionParameterTypeAt)(_In_ ULONG64 i, _Out_ IDebugHostType** parameterType) PURE;
    STDMETHOD(IsGeneric)(_Out_ bool* isGeneric) PURE;
    STDMETHOD(GetGenericArgumentCount)(_Out_ ULONG64* argCount) PURE;
    STDMETHOD(GetGenericArgumentAt)(_In_ ULONG64 i, _Out_ IDebugHostSymbol** argument) PURE;
    //
    // IDebugHostType2:
    //
    STDMETHOD(IsTypedef)(_Out_ bool* isTypedef) PURE;
    STDMETHOD(GetTypedefBaseType)(_Out_ IDebugHostType2** baseType) PURE;
    STDMETHOD(GetTypedefFinalBaseType)(_Out_ IDebugHostType2** finalBaseType) PURE;
    STDMETHOD(GetFunctionVarArgsKind)(_Out_ VarArgsKind* varArgsKind) PURE;
}

Métodos gerais IDebugHostType2/IDebugHostType

Os seguintes métodos IDebugHostType são gerais para qualquer tipo, independentemente do tipo retornado do método GetTypeKind:

STDMETHOD(GetTypeKind)(_Out_ TypeKind *kind) PURE;
STDMETHOD(GetSize)(_Out_ ULONG64* size) PURE;
STDMETHOD(GetBaseType)(_Out_ IDebugHostType** baseType) PURE;
STDMETHOD(GetHashCode)(_Out_ ULONG* hashCode) PURE;

GetTypeKind

O método GetTypeKind retorna o tipo de tipo (ponteiro, matriz, intrínseco etc...) ao qual o símbolo se refere.

GetSize

O método GetSize retorna o tamanho do tipo (como se alguém tivesse feito sizeof(type) em C++).

GetBaseType

Se o tipo for um derivado de outro tipo único (por exemplo: como MyStruct * é derivado de MyStruct'), o método GetBaseType retornará o tipo base da derivação. Para ponteiros, isso retorna o tipo apontado. Para matrizes, isso retorna do que a matriz é uma matriz. Se o tipo não for um tipo derivado, um erro será retornado.

GetHashCode

O método GetHashCode retorna um código hash de 32 bits para o tipo. Com exceção de uma correspondência global (por exemplo: uma assinatura de tipo equivalente a * que corresponde a tudo, se permitido pelo host), qualquer instância de tipo que possa corresponder a uma assinatura de tipo específico deve retornar o mesmo código hash. Esse método é usado em conjunto com assinaturas de tipo para corresponder assinaturas de tipo a instâncias de tipo.

Métodos intrínsecos IDebugHostType2/IDebugHostType

Os seguintes métodos IDebugHostType são específicos para tipos intrínsecos (ou tipos que contêm dados intrínsecos, como enumerações):

STDMETHOD(GetIntrinsicType)(_Out_opt_ IntrinsicKind *intrinsicKind, _Out_opt_ VARTYPE *carrierType) PURE;

GetIntrinsicType

O método GetIntrinsicType retorna informações sobre que tipo de tipo intrínseco o tipo é. Dois valores são retornados desse método:

  • O tipo intrínseco indica o tipo geral (por exemplo: inteiro, sem sinal, ponto flutuante), mas não o tamanho do tipo (por exemplo: 8 bits, 16 bits, 32 bits, 64 bits)
  • O tipo de operadora indica como o tipo intrínseco empacota em uma estrutura VARIANT. Esta é uma constante VT_*.

A combinação dos dois valores fornece o conjunto completo de informações sobre o intrínseco.

Métodos bitfield IDebugHostType2/IDebugHostType

Os métodos IDebugHostType a seguir são específicos para tipos que armazenam dados em campos de bits. As informações sobre o posicionamento de campo de bits em um intrínseco são armazenadas como parte do símbolo de tipo no modelo de dados, em vez de serem um atributo do local.

STDMETHOD(GetBitField)(_Out_ ULONG* lsbOfField, _Out_ ULONG* lengthOfField) PURE;

GetBitField

Se um determinado membro de uma estrutura de dados for um campo de bits (por exemplo: ULONG MyBits:8), as informações de tipo para o campo serão fornecidas com ela informações sobre o posicionamento do campo de bits. O método GetBitField pode ser usado para recuperar essas informações. Esse método falhará em qualquer tipo que não seja um campo de bits. Esse é o único motivo pelo qual o método falhará. Simplesmente chamar esse método e examinar o êxito/falha é suficiente para distinguir um campo de bits de um campo não bit. Se um determinado tipo for um campo de bits, as posições de campo serão definidas pelo meio conjunto aberto (lsbOfField + lengthOfField : lsbOfField]

Métodos relacionados ao ponteiro IDebugHostType2/IDebugHostType

Os métodos IDebugHostType a seguir são específicos para tipos de ponteiro. Esses são tipos em que GetTypeKind retorna TypePointer ou TypeMemberPointer':

STDMETHOD(GetPointerKind)(_Out_ PointerKind* pointerKind) PURE;
STDMETHOD(GetMemberType)(_Out_ IDebugHostType** memberType) PURE;

GetPointerKind

Para tipos que são ponteiros, o método GetPointerKind retorna o tipo de ponteiro. Isso é definido pela enumeração PointerKind.

GetMemberType

Para tipos que são ponteiro para membro (conforme indicado por um tipo de tipo TypeMemberPointer), o método GetMemberType retorna a classe da qual o ponteiro é um ponteiro para membro.

Métodos relacionados à matriz IDebugHostType2/IDebugHostType

Matrizes são tipos em que GetTypeKind retorna TypeArray. Observe que as matrizes definidas pelo sistema de tipos do host de depuração não são iguais às matrizes unidimensionais, baseadas em índice zero, lineares unidimensionais empacotadas que o C utiliza. As matrizes de estilo C se encaixam na definição, mas o escopo geral de uma matriz é mais amplo em IDebugHostType. Uma matriz no host de depuração pode ser multidimensional e cada dimensão dentro da matriz é definida por um descritor conhecido como ArrayDimensionEste descritor tem os seguintes campos:

Campo Significado
Lowerbound O índice base da matriz como um valor assinado de 64 bits. Para uma matriz de estilo C, isso sempre será zero. Não precisa ser. Uma dimensão individual de uma matriz pode ser considerada para iniciar em qualquer índice de 64 bits, até mesmo um negativo.
Comprimento O comprimento da dimensão da matriz como um valor de 64 bits sem sinal. Os índices da matriz abrangem o conjunto semiaberto [LowerBound, LowerBound + Length).
Passo Define o passo da dimensão da matriz. Para um aumento de um (de N para N + 1) no índice dessa dimensão, isso indica quantos bytes avançar na memória. Para uma matriz de estilo C, esse seria o tamanho de cada elemento da matriz. Não precisa ser. O preenchimento entre elementos pode ser expresso como um passo maior que o tamanho de cada elemento individual. Para matrizes multidimensionais, esse valor indicaria como mover uma dimensão inteira para frente. Considere uma matriz M x N. Isso pode ser descrito na forma de linha principal como duas dimensões:
{ [LowerBound: 0, Length: M, Stride: N \* sizeof(element)], [LowerBound: 0, Length: N, Stride: sizeof(element)]} 

ou, como alternativa, ele pode ser descrito na forma de coluna principal como duas dimensões:

{ [LowerBound: 0, Length: M, Stride: sizeof(element)], [LowerBound: 0, Length: N, Stride: M \* sizeof(element)]} 

O conceito ArrayDimension permite esse grau de flexibilidade.

Os seguintes métodos IDebugHostType são específicos para tipos de matriz.

STDMETHOD(GetArrayDimensionality)(\_Out_ ULONG64\* arrayDimensionality) PURE; 
STDMETHOD(GetArrayDimensions)(\_In_ ULONG64 dimensions, \_Out_writes_(dimensions) ArrayDimension \*pDimensions) PURE;

GetArrayDimensionality

O método GetArrayDimensionality retorna o número de dimensões em que a matriz é indexada. Para matrizes de estilo C, o valor retornado aqui sempre será 1.

GetArrayDimensions

O método GetArrayDimensions retorna um conjunto de descritores, um para cada dimensão da matriz, conforme indicado pelo método GetArrayDimensionality. Cada descritor é uma estrutura ArrayDimension que descreve o índice inicial, o comprimento e o passo a passo de cada dimensão da matriz. Isso permite descrições de constructos de matriz significativamente mais poderosos do que são permitidos no sistema de tipos C.

Para matrizes de estilo C, uma única dimensão de matriz é retornada aqui com valores que são sempre:

  • LowerBound = 0
  • Length = ARRAYSIZE(array)
  • Stride = sizeof(elementType)

Métodos relacionados à função IDebugHostType2/IDebugHostType

Os tipos que indicam que são tipos de função por meio de um tipo de TypeFunction dão suporte aos métodos a seguir em IDebugHostType e IDebugHostType2.

//
// IDebugHostType:
//
STDMETHOD(GetFunctionCallingConvention)(_Out_ CallingConventionKind* conventionKind) PURE;
STDMETHOD(GetFunctionReturnType)(_COM_Outptr_ IDebugHostType** returnType) PURE;
STDMETHOD(GetFunctionParameterTypeCount)(_Out_ ULONG64* count) PURE;
STDMETHOD(GetFunctionParameterTypeAt)(_In_ ULONG64 i, _Out_ IDebugHostType** parameterType) PURE;
//
// IDebugHostType2:
//
STDMETHOD(GetFunctionVarArgsKind)(_Out_ VarArgsKind* varArgsKind) PURE;

GetFunctionCallingConvention

O método GetFunctionCallingConvention retorna a convenção de chamada da função. Isso é retornado como um membro da enumeração CallingConventionKind.

GetFunctionReturnType

O método GetFunctionReturnType retorna o tipo de retorno da função.

GetFunctionParameterTypeCount

O método GetFunctionParameterTypeCount retorna o número de argumentos que a função usa. Observe que o marcador de argumento de variável baseado em reticências C/C++ não é considerado nessa contagem. A presença desse tipo deve ser detectada por meio do método GetFunctionVarArgsKind. Isso incluirá apenas argumentos antes das reticências.

GetFunctionParameterTypeAt

O método GetFunctionParameterTypeAt retorna o tipo do argumento i-th para a função .

O método GetFunctionVarArgsKind retorna se uma determinada função utiliza uma lista de argumentos variáveis e, nesse caso, qual estilo de argumentos variáveis ele utiliza. Isso é definido por um membro da enumeração VarArgsKind definida da seguinte maneira:

Enumerante Significado
VarArgsNone A função não usa argumentos variáveis.
VarArgsCStyle A função é uma função varargs de estilo C (returnType(arg1, arg2, ...)). O número de argumentos relatados pela função não inclui o argumento de reticências. Qualquer passagem de argumento variável ocorre após o número de argumentos retornados pelo método GetFunctionParameterTypeCount.

IDebugHostType2 GetFunctionVarArgsKind

O método GetFunctionVarArgsKind retorna se uma determinada função utiliza uma lista de argumentos variáveis e, nesse caso, qual estilo de argumentos variáveis ele utiliza. Isso é definido por um membro da enumeração VarArgsKind definida da seguinte maneira:

Métodos relacionados ao Typedef IDebugHostType2/IDebugHostType

Qualquer tipo que seja um typedef se comportará como se o tipo fosse o tipo final subjacente ao typedef. Isso significa que métodos como GetTypeKind não indicarão que o tipo é um typedef. Da mesma forma, GetBaseType não retornará o tipo ao qual a definição se refere. Em vez disso, eles indicarão que se comportam como se fossem chamados na definição final subjacente ao typedef. Por exemplo:

typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;

Um IDebugHostType para 'PMYSTRUCT ou PTRMYSTRUCT relatará as seguintes informações:

  • O método GetTypeKind retornará TypePointer. O tipo subjacente final MYSTRUCT * é de fato um ponteiro.
  • O método 'GetBaseType retornará um tipo para MYSTRUCT. O tipo subjacente de MYSTRUCT * é MYSTRUCT.

A única diferença aqui é como os métodos específicos do typedef em IDebugHostType2 se comportam. Esses métodos são:

STDMETHOD(IsTypedef)(_Out_ bool* isTypedef) PURE;
STDMETHOD(GetTypedefBaseType)(_Out_ IDebugHostType2** baseType) PURE;
STDMETHOD(GetTypedefFinalBaseType)(_Out_ IDebugHostType2** finalBaseType) PURE;

Neste exemplo:

  • O método IsTypedef retornará true para PMYSTRUCT e PTRMYSTRUCT
  • O método GetTypedefBaseType retornará MYSTRUCT * para PMYSTRUCT e PMYSTRUCT para PTRMYSTRUCT
  • O método GetTypedefFinalBaseType retornará MYSTRUCT * para ambos os tipos

IsTypedef

O método IsTypedef é o único método capaz de ver se um tipo é um typedef. O método GetTypeKind se comportará como se fosse chamado no tipo subjacente.

GetTypedefBaseType

O método GetTypedefBaseType retornará qual é a definição imediata do typedef. Nos exemplos descritos na documentação:

typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;

esse método retornará MYSTRUCT * para PMYSTRUCT e PMYSTRUCT para PTRMYSTRUCT.

GetTypedefFinalBaseType

O método GetTypedefFinalBaseType retornará o tipo final para o qual o typedef é uma definição. Se o typedef for uma definição de outro typedef, isso continuará a seguir a cadeia de definição até atingir um tipo que não é um typedef e esse tipo será retornado. Nos exemplos descritos na documentação:

typedef MYSTRUCT *PMYSTRUCT;
typedef PMYSTRUCT PTRMYSTRUCT;

esse método retornará MYSTRUCT * quando chamado em PMYSTRUCT ou PTRMYSTRUCT.

Métodos de criação de tipo IDebugHostType2/IDebugHostType

STDMETHOD(CreatePointerTo)(_In_ PointerKind kind, _COM_Outptr_ IDebugHostType** newType) PURE;
STDMETHOD(CreateArrayOf)(_In_ ULONG64 dimensions, _In_reads_(dimensions) ArrayDimension *pDimensions, _COM_Outptr_ IDebugHostType** newType) PURE;

Valores de símbolo constante: IDebugHostConstant

Para locais em que valores constantes estão presentes em informações simbólicas (em que um valor específico é um símbolo que pode ou não ser um valor constante), a interface IDebugHostConstant expressa a noção de tal constante. Normalmente, isso é usado em locais como argumentos de modelo em que um determinado argumento normalmente é um tipo, mas pode ser um argumento de modelo não tipo (por exemplo: uma constante).

A interface IDebugHostConstant é definida da seguinte maneira (ignorando métodos genéricos implementados por IDebugHostSymbol):

DECLARE_INTERFACE_(IDebugHostConstant, IDebugHostSymbol)
{
    STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}

GetValue

O método GetValue retorna o valor da constante empacotada em uma VARIANT. É importante observar que o método GetType em IDebugHostSymbol pode retornar um símbolo de tipo específico para a constante. Nesses casos, não há nenhuma garantia de que o empacotamento do valor constante, conforme definido pelo símbolo de tipo, seja o mesmo que o empacotamento retornado pelo método GetValue aqui.

Acesso a membros de dados: IDebugHostField

A classe IDebugHostField representa um símbolo que é um membro de dados de uma classe, estrutura, união ou outro constructo de tipo. Ele não representa dados gratuitos (por exemplo, dados globais). A interface é definida da seguinte maneira (ignorando métodos genéricos para IDebugHostSymbol):

DECLARE_INTERFACE_(IDebugHostField, IDebugHostSymbol)
{
    STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
    STDMETHOD(GetOffset)(_Out_ ULONG64* offset) PURE;
    STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
    STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}

GetLocationKind

O método GetLocationKind retorna em que tipo de local o símbolo está de acordo com a enumeração LocationKind. Essa enumeração pode ser um dos seguintes valores:

Enumerante Significado
LocationMember O campo é um membro de dados regular de uma classe, estrutura, união ou outro constructo de tipo. Ele tem um deslocamento relativo ao endereço base do constructo de tipo que contém. Normalmente, esse endereço base é representado por esse ponteiro. O deslocamento do campo pode ser recuperado por meio do método GetOffset. Os métodos GetLocation e GetValue falharão em um campo que é LocationMember.
LocationStatic O campo é estático e tem seu próprio endereço. O método GetLocation retornará o local abstrato (por exemplo: endereço) do campo estático. Os métodos GetOffset e GetValue falharão em um campo que é LocationStatic.
LocationConstant O campo é uma constante e tem um valor. O método GetValue retornará o valor da constante. Os métodos GetOffset e GetLocation falharão em um campo que é LocationConstant
LocationNone O campo não tem local. Ele pode ter sido otimizado pelo compilador ou pode ser um campo estático que é declarado, mas nunca definido. Independentemente de como esse campo veio a ser, ele não tem presença física ou valor. Ele está apenas nos símbolos. Todos os métodos de aquisição (GetOffset, GetLocation e GetValue) falharão em um campo que é LocationNone.

GetOffset

Para campos que têm um deslocamento (por exemplo, campos cujo tipo de localização indica LocationMember), o método GetOffset retornará o deslocamento do endereço base do tipo que contém (o ponteiro este) para os dados do próprio campo. Esses deslocamentos são sempre expressos como valores de 64 bits sem sinal. Se o campo fornecido não tiver um local que seja um deslocamento do endereço base do tipo que contém, o método GetOffset falhará.

GetLocation

Para campos que têm um endereço independentemente da instância de tipo específica (por exemplo, campos cujo tipo de localização indica LocationStatic), o método GetLocation retornará o local abstrato (endereço) do campo. Se o campo especificado não tiver um local estático, o método GetLocation falhará.

GetValue

Para campos que têm um valor constante definido dentro das informações simbólicas (por exemplo, campos cujo tipo de localização indica LocationConstant), o método GetValue retornará o valor constante do campo. Se o campo fornecido não tiver um valor constante, o método GetValue falhará.

Acesso a dados gratuitos: IDebugHostData

Os dados em módulos que não são membros de outro tipo são representados pela interface IDebugHostData. Essa interface é definida da seguinte maneira (ignorando métodos genéricos para IDebugHostSymbol):

DECLARE_INTERFACE_(IDebugHostData, IDebugHostSymbol)
{
    STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
    STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
    STDMETHOD(GetValue)(_Out_ VARIANT* value) PURE;
}

Todos esses métodos são semanticamente equivalentes aos seus equivalentes em IDebugHostField. A única diferença é que o método GetLocationKind nunca retornará LocationMember para dados gratuitos.

GetLocationKind

O método GetLocationKind retorna em que tipo de local o símbolo está de acordo com a enumeração LocationKind. A descrição dessa enumeração pode ser encontrada na documentação de IDebugHostField.

GetLocation

Para dados que têm um endereço, o método GetLocation retornará o local abstrato (endereço) do campo. Se os dados especificados não tiverem um local estático, o método GetLocation falhará.

GetValue

Para dados que têm um valor constante definido dentro das informações simbólicas (por exemplo: dados cujo tipo de localização indica LocationConstant), o método GetValue retornará o valor constante do campo. Se os dados fornecidos não tiverem um valor constante, o método GetValue falhará.

Classes base: IDebugHostBaseClass

A hierarquia de herança de um determinado tipo é expressa por meio de filhos de um símbolo de tipo. Se um determinado tipo derivar (herança sábia) de um ou mais tipos, haverá um ou mais filhos SymbolBaseClass do símbolo de tipo para o tipo. Cada um desses símbolos SymbolBaseClass representa herança imediata de um tipo específico. O nome da classe base é o nome do símbolo SymbolBaseClass, bem como o do símbolo de tipo da classe base. O método GetType no símbolo SymbolBaseClass pode ser usado para obter o símbolo de tipo para a própria classe base. A hierarquia de herança completa pode ser percorrida explorando recursivamente símbolos filho SymbolBaseClass. Cada um desses símbolos de classe base é expresso pela interface IDebugHostBaseClass que é definida da seguinte maneira (ignorando métodos genéricos para IDebugHostSymbol):

DECLARE_INTERFACE_(IDebugHostBaseClass, IDebugHostSymbol)
{
    STDMETHOD(GetOffset)(_Out_ ULONG64* offset) PURE;
}

GetOffset

O método GetOffset retorna o deslocamento da classe base do endereço base da classe derivada. Esse deslocamento pode ser zero ou pode ser um valor positivo sem sinal de 64 bits.

Símbolos públicos: IDebugHostPublic

Símbolos públicos representam itens na tabela pública dentro de um arquivo de símbolo. Eles são, de fato, endereços de exportação. Não há informações de tipo associadas a um símbolo público , apenas um endereço. A menos que um símbolo público seja solicitado explicitamente pelo chamador, o host de depuração prefere retornar símbolos privados para cada consulta. Um símbolo público é expresso pela interface IDebugHostPublic que é definida da seguinte maneira (ignorando métodos genéricos para IDebugHostSymbol):

DECLARE_INTERFACE_(IDebugHostPublic, IDebugHostSymbol)
{
    STDMETHOD(GetLocationKind)(_Out_ LocationKind *locationKind) PURE;
    STDMETHOD(GetLocation)(_Out_ Location* location) PURE;
}

Todos esses métodos são semanticamente equivalentes aos seus equivalentes em IDebugHostField. A única diferença é que o método GetLocationKind nunca retornará LocationMember ou LocationConstant para esses símbolos.

GetLocationKind

O método GetLocationKind retorna em que tipo de local o símbolo está de acordo com a enumeração LocationKind. A descrição dessa enumeração pode ser encontrada na documentação de IDebugHostField.

GetLocation

Para dados que têm um endereço, o método GetLocation retornará o local abstrato (endereço) do campo. Se o público especificado não tiver um local estático, o método GetLocation falhará.

Assinaturas de módulo e correspondência de versão: IDebugHostModuleSignature

As assinaturas de módulo representam um meio de marcar se um determinado módulo atende a um conjunto de critérios relativos à nomenclatura e controle de versão. Uma assinatura de módulo é criada por meio do método CreateModuleSignature em IDebugHostSymbols. Ele pode corresponder ao nome do módulo e a um intervalo opcional de números de versão para o módulo. Depois que essa assinatura é criada, o cliente recebe uma interface IDebugHostModuleSignature que é definida da seguinte maneira:

DECLARE_INTERFACE_(IDebugHostModuleSignature, IUnknown)
{
    STDMETHOD(IsMatch)(_In_ IDebugHostModule* pModule, _Out_ bool* isMatch) PURE;
}

Ismatch

O método IsMatch compara um módulo específico (conforme fornecido por um símbolo IDebugHostModule) com uma assinatura, comparando o nome do módulo e a versão com o nome e o intervalo de versão indicados na assinatura. Uma indicação de se o símbolo de módulo fornecido corresponde à assinatura é retornada.

Digite Assinaturas e Correspondência de Tipos: IDebugHostTypeSignature

As assinaturas de tipo representam um meio para marcar se uma determinada instância de tipo atende a um conjunto de critérios sobre o nome do tipo, os argumentos genéricos para o tipo e o módulo no qual o tipo está localizado. Uma assinatura de tipo é criada por meio do método CreateTypeSignature em IDebugHostSymbols. Depois que essa assinatura é criada, o cliente recebe uma interface IDebugHostTypeSignature que é definida da seguinte maneira:

DECLARE_INTERFACE_(IDebugHostTypeSignature, IUnknown)
{
    STDMETHOD(GetHashCode)(_Out_ ULONG* hashCode) PURE;
    STDMETHOD(IsMatch)(_In_ IDebugHostType* type, _Out_ bool* isMatch, _COM_Outptr_opt_ IDebugHostSymbolEnumerator** wildcardMatches) PURE;
    STDMETHOD(CompareAgainst)(_In_ IDebugHostTypeSignature* typeSignature, _Out_ SignatureComparison* result) PURE;
}

GetHashCode

O método GetHashCode retorna um código hash de 32 bits para a assinatura de tipo. O host de depuração garante que haja sincronização na implementação entre o código hash retornado para instâncias de tipo e o código hash retornado para assinaturas de tipo. Com exceção de uma correspondência global, se uma instância de tipo for capaz de corresponder a uma assinatura de tipo, ambas terão o mesmo código hash de 32 bits. Isso permite uma comparação rápida inicial e uma correspondência entre uma instância de tipo e uma infinidade de assinaturas de tipo registradas com o gerenciador de modelos de dados.

Ismatch

O método IsMatch retorna uma indicação de se uma instância de tipo específico corresponde aos critérios especificados na assinatura de tipo. Se isso acontecer, uma indicação disso será retornada, bem como um enumerador que indicará todas as partes específicas da instância de tipo (como símbolos) que corresponderam curingas na assinatura de tipo.

Comparar com

O método CompareAgainst compara a assinatura de tipo com outra assinatura de tipo e retorna como as duas assinaturas se comparam. O resultado da comparação retornado é um membro da enumeração SignatureComparison que é definida da seguinte maneira:

Enumerante Significado
Unrelated Não há nenhuma relação entre as duas assinaturas ou tipos que estão sendo comparados.
Ambíguo Uma assinatura ou tipo é comparado de forma ambígua com a outra. Para duas assinaturas de tipo, isso significa que há possíveis instâncias de tipo que podem corresponder a uma assinatura igualmente bem. Por exemplo, as duas assinaturas de tipo mostradas abaixo são ambíguas. Assinatura 1: std::pair<*, int> Assinatura 2: std::pair<int,*> porque a instância std::pair<int, int> de tipo corresponde a um igualmente bem (ambos têm uma correspondência de caracteres curinga e concreto).
LessSpecific Uma assinatura ou tipo é menos específico do que o outro. Muitas vezes, isso significa que a assinatura menos específica tem um curinga em que o mais específico tem um tipo concreto. Por exemplo, a primeira assinatura abaixo é menos específica do que a segunda. Assinatura 1: std::pair<*, int> Assinatura 2: std::pair<int, int> porque tem um curinga (o *) em que o segundo tem um tipo concreto (int).
MoreSpecific Uma assinatura ou tipo é mais específico do que o outro. Geralmente, isso significa que a assinatura mais específica tem um tipo concreto em que o menos específico tem um curinga. Por exemplo, a primeira assinatura abaixo é mais específica do que a segunda. Assinatura 1: std::pair<int, int> Assinatura 2: std::pair<*, int> porque tem um tipo concreto (int) em que o segundo tem um curinga (o *).
Idêntico As duas assinaturas ou tipos são idênticos.

Confira também

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

Visão geral do modelo de dados do depurador C++

Interfaces C++ do modelo de dados do depurador

Objetos C++ do modelo de dados do depurador

Interfaces adicionais do modelo de dados do depurador C++

Conceitos do modelo de dados do depurador C++

Script C++ do modelo de dados do depurador