Partilhar via


Conceitos do Depurador Modelo de Dados C++

Este tópico descreve conceitos no modelo de dados do depurador C++.

Conceitos no Modelo de Dados

Os objetos sintéticos no modelo de dados são efetivamente duas coisas:

  • Um dicionário de tuplas de chave/valor/metadados.
  • Um conjunto de conceitos (interfaces) que são suportados pelo modelo de dados. Conceitos são interfaces que um cliente (em oposição ao modelo de dados) implementa para fornecer um conjunto especificado de comportamento semântico. O conjunto de conceitos atualmente suportados está listado aqui.
Interface de conceito Descrição
IDataModelConcept O conceito é um modelo-mãe. Se esse modelo for anexado automaticamente a um tipo nativo por meio de uma assinatura de tipo registrada, o método InitializeObject será chamado automaticamente 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 (conceito de tipo de tempo de execução preferido) O objeto compreende mais sobre os tipos derivados dele do que o sistema de tipos subjacente é capaz de fornecer e gostaria de gerenciar suas próprias conversões do tipo estático para tipo em tempo de execução.
IDynamicKeyProviderConcept O objeto é um provedor dinâmico de chaves e deseja assumir todas as consultas de chave do modelo de dados principal. Essa interface é normalmente 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 é normalmente usada como uma ponte para linguagens dinâmicas, como JavaScript.

O conceito de modelo de dados: IDataModelConcept

Qualquer objeto de modelo anexado a outro objeto de modelo como um modelo pai deve suportar diretamente o conceito de modelo de dados. O conceito de modelo de dados requer o suporte de uma interface, IDataModelConcept definido da seguinte forma.

DECLARE_INTERFACE_(IDataModelConcept, IUnknown)
{
    STDMETHOD(InitializeObject)(_In_ IModelObject* modelObject, _In_opt_ IDebugHostTypeSignature* matchingTypeSignature, _In_opt_ IDebugHostSymbolEnumerator* wildcardMatches) PURE;
    STDMETHOD(GetName)(_Out_ BSTR* modelName) PURE;
}

InicializarObjeto

Um modelo de dados pode ser registrado como o visualizador canônico ou como uma extensão para um determinado tipo nativo por meio dos métodos RegisterModelForTypeSignature ou RegisterExtensionForTypeSignature do gerenciador de modelos de dados. Quando um modelo é registrado por meio de qualquer um desses métodos, o modelo de dados é automaticamente anexado como um modelo pai a qualquer objeto nativo cujo tipo corresponda à assinatura passada no registro. No ponto em que esse anexo é feito automaticamente, o método InitializeObject é chamado no modelo de dados. São passados o objeto de instância, a assinatura de tipo que causou a ligação e um enumerador que produz as instâncias de tipo (em ordem linear) que correspondem a quaisquer curingas na assinatura de tipo. A implementação do modelo de dados pode usar essa chamada de método para inicializar quaisquer caches necessários.

GetName

Se um determinado modelo de dados for registrado sob um nome padrão por meio do método RegisterNamedModel, a interface IDataModelConcept do modelo de dados registrado deverá retornar esse nome desse método. Note que é perfeitamente legítimo que um modelo seja registrado com vários nomes (o padrão ou o melhor deve ser devolvido aqui). Um modelo pode estar completamente sem nome (desde que não esteja registado com um nome). Nessas circunstâncias, o método GetName deve retornar E_NOTIMPL.

O conceito de exibição de strings: IStringDisplayableConcept

Um objeto que deseja fornecer uma conversão de cadeia de caracteres para fins de exibição pode implementar o conceito de cadeia de caracteres exibível através da implementação da interface IStringDisplayableConcept. A interface é definida da seguinte forma:

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

ParaExibirTexto

O método ToDisplayString é chamado sempre que um cliente deseja converter um objeto em uma cadeia de caracteres para exibição (para console, na interface do usuário, etc...). Essa conversão de cadeia de caracteres não deve ser usada para a base de manipulação programática adicional. A conversão de cadeia de caracteres em si pode ser profundamente influenciada pelos metadados passados para a chamada. Uma conversão de string deve fazer todos os esforços para respeitar as chaves PreferredRadix e PreferredFormat.

O Conceito Iterável: IIterableConcept e IModelIterator

Um objeto que é um contêiner de outros objetos e deseja expressar a capacidade de iterar sobre esses objetos contidos pode suportar o conceito iterável por uma implementação das interfaces IIterableConcept e IModelIterator. Existe uma relação muito importante entre o apoio ao conceito iterável e o apoio ao conceito indexável. Um objeto que suporta acesso aleatório aos objetos contidos pode suportar o conceito indexável, além do conceito iterável. Neste caso, os elementos iterados também devem produzir um índice padrão que, quando passado para o conceito indexável, refere-se ao mesmo objeto. Uma falha em satisfazer esse invariante resultará em um comportamento indefinido no host de depuração.

O IIterableConcept é definido da seguinte forma:

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

O conceito IModelIterator é definido da seguinte forma:

DECLARE_INTERFACE_(IModelIterator, IUnknown)
{
   STDMETHOD(Reset)() PURE;
   STDMETHOD(GetNext)(_COM_Errorptr_ IModelObject** object, _In_ ULONG64 dimensions, _Out_writes_opt_(dimensions) IModelObject** indexers, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
}

de IIterableConcept GetDefaultIndexDimensionality

O GetDefaultIndexDimensionality método retorna o número de dimensões para o índice padrão. Se um objeto não for indexável, esse método deverá retornar 0 e ter êxito (S_OK). Qualquer objeto que retorna um valor diferente de zero desse método está declarando suporte para um contrato de protocolo que afirma:

  • O objeto suporta o conceito indexável através do suporte de IIndexableConcept
  • O método GetNext do IModelIterator retornado do método GetIterator do conceito iterável retornará um índice padrão exclusivo para cada elemento produzido. Esse índice terá o número de dimensões indicado aqui.
  • Passar os índices retornados do método GetNext do IModelIterator para o método GetAt no conceito indexável (IIndexableConcept) fará referência ao mesmo objeto que GetNext produziu. O mesmo valor é retornado.

GetIterator de IIterableConcept

O método GetIterator no conceito iterável retorna uma interface iteradora que pode ser usada para iterar o objeto. O iterador retornado deve lembrar o objeto de contexto que foi passado para o método GetIterator. Isto não será passado para métodos do próprio iterador.

Redefinição de IModelIterator

O método Reset em um iterador retornado do conceito iterável restaurará a posição do iterador para onde estava quando o iterador foi criado pela primeira vez (antes do primeiro elemento). Embora seja altamente recomendável que o iterador suporte o método Reset, ele não é necessário. Um iterador pode ser o equivalente a um iterador de entrada C++ e permitir apenas um único percurso de iteração para a frente. Nesse caso, o método Reset pode falhar com E_NOTIMPL.

GetNext do IModelIterator

O método GetNext avança o iterador e busca o próximo elemento iterado. Se o objeto for indexável além de iterável e isso for indicado pelo argumento GetDefaultIndexDimensionality retornando um valor diferente de zero, esse método pode, opcionalmente, retornar os índices padrão para voltar ao valor produzido do indexador. Observe que um chamador pode optar por passar 0/nullptr e não recuperar nenhum índice. É considerado ilegal para o chamador solicitar índices parciais (por exemplo: menor do que o número produzido por GetDefaultIndexDimensionality).

Se o iterador avançou com êxito, mas houve um erro na leitura do valor do elemento iterado, o método pode retornar um erro E preencher "objeto" com um objeto de erro. No final da iteração dos elementos contidos, o iterador retornará E_BOUNDS do método GetNext. Qualquer chamada subsequente (a menos que tenha havido uma chamada de Redefinição interveniente) também retornará E_BOUNDS.

O Conceito Indexável: IIndexableConcept

Um objeto que deseja fornecer acesso aleatório a um conjunto de conteúdos pode suportar o conceito indexável através do suporte da interface IIndexableConcept. A maioria dos objetos que são indexáveis também serão iteráveis através do suporte do conceito iterável. No entanto, isso não é necessário. Se suportado, há uma relação importante entre o iterador e o indexador. O iterador deve suportar o método GetDefaultIndexDimensionality, retornar um valor diferente de zero desse método e suportar o contrato documentado lá. A interface do conceito de indexador é definida da seguinte forma:

DECLARE_INTERFACE_(IIndexableConcept, IUnknown)
{
    STDMETHOD(GetDimensionality)(_In_ IModelObject* contextObject, _Out_ ULONG64* dimensionality) PURE;
    STDMETHOD(GetAt)(_In_ IModelObject* contextObject, _In_ ULONG64 indexerCount, _In_reads_(indexerCount) IModelObject** indexers, _COM_Errorptr_ IModelObject** object, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata) PURE;
    STDMETHOD(SetAt)(_In_ IModelObject* contextObject, _In_ ULONG64 indexerCount, _In_reads_(indexerCount) IModelObject** indexers, _In_ IModelObject *value) PURE;
}

Um exemplo de uso do indexador (e sua interação com o iterador) é mostrado abaixo. Este exemplo itera o conteúdo de um contêiner indexável e usa o indexador para voltar ao valor que acabou de ser retornado. Embora essa operação seja funcionalmente inútil como escrita, ela demonstra como essas interfaces interagem. Observe que o exemplo abaixo não lida com falha de alocação de memória. Ele pressupõe um lançamento novo (o que pode ser uma suposição ruim dependendo do ambiente em que o código existe - os métodos COM do modelo de dados não podem ter exceções C++ escapar):

ComPtr<IModelObject> spObject;

//
// Assume we have gotten some object in spObject that is iterable (e.g.: an object which represents a std::vector<SOMESTRUCT>)
//
ComPtr<IIterableConcept> spIterable;
ComPtr<IIndexableConcept> spIndexer;
if (SUCCEEDED(spObject->GetConcept(__uuidof(IIterableConcept), &spIterable, nullptr)) &&
    SUCCEEDED(spObject->GetConcept(__uuidof(IIndexableConcept), &spIndexable, nullptr)))
{
    ComPtr<IModelIterator> spIterator;

    //
    // Determine how many dimensions the default indexer is and allocate the requisite buffer.
    //
    ULONG64 dimensions;
    if (SUCCEEDED(spIterable->GetDefaultIndexDimensionality(spObject.Get(), &dimensions)) && dimensions > 0 &&
        SUCCEEDED(spIterable->GetIterator(spObject.Get(), &spIterator)))
    {
        std::unique_ptr<ComPtr<IModelObject>[]> spIndexers(new ComPtr<IModelObject>[dimensions]);

        //
        // We have an iterator.  Error codes have semantic meaning here.  E_BOUNDS indicates the end of iteration.  E_ABORT indicates that
        // the debugger host or application is trying to abort whatever operation is occurring.  Anything else indicates
        // some other error (e.g.: memory read failure) where the iterator MIGHT still produce values.
        //
        for(;;)
        {
            ComPtr<IModelObject> spContainedStruct;
            ComPtr<IKeyStore> spContainedMetadata;

            //
            // When we fetch the value from the iterator, it will pass back the default indices.
            //
            HRESULT hr = spIterable->GetNext(&spContainedStruct, dimensions, reinterpret_cast<IModelObject **>(spIndexers.get()), &spContainedMetadata);
            if (hr == E_BOUNDS || hr == E_ABORT)
            {
                break;
            }

            if (FAILED(hr))
            {
                //
                // Decide how to deal with failure to fetch an element.  Note that spContainedStruct *MAY* contain an error object
                // which has detailed information about why the failure occurred (e.g.: failure to read memory at address X).
                //
            }

            //
            // Use the indexer to get back to the same value.  We already have them, so there isn't much functional point to this.  It simply
            // highlights the interplay between iterator and indexer.
            //
            ComPtr<IModelObject> spIndexedStruct;
            ComPtr<IKeyStore> spIndexedMetadata;

            if (SUCCEEDED(spIndexer->GetAt(spObject.Get(), dimensions, reinterpret_cast<IModelObject **>(spIndexers.get()), &spIndexedStruct, &spIndexedMetadata)))
            {
                //
                // spContainedStruct and spIndexedStruct refer to the same object.  They may not have interface equality.
                // spContainedMetadata and spIndexedMetadata refer to the same metadata store with the same contents.  They may not have interface equality.
                //
            }
        }
    }
}

GetDimensionality

O método GetDimensionality retorna o número de dimensões nas quais o objeto está indexado. Observe que, se o objeto for iterável e indexável, a implementação de GetDefaultIndexDimensionality deverá concordar com a implementação de GetDimensionality quanto a quantas dimensões o indexador tem.

GetAt

O método GetAt recupera o valor em um determinado índice N-dimensional de dentro do objeto indexado. Um indexador de N-dimensões onde N é o valor retornado de GetDimensionality deve ser suportado. Observe que um objeto pode ser indexável em diferentes domínios por diferentes tipos (por exemplo: indexável através de ordinais e strings). Se o índice estiver fora do intervalo (ou não puder ser acessado), o método retornará uma falha; No entanto, nesses casos, o objeto de saída ainda pode ser definido como um objeto de erro.

SetAt

O método SetAt tenta definir o valor em um determinado índice N-dimensional de dentro do objeto indexado. Um indexador de N-dimensões onde N é o valor retornado de GetDimensionality deve ser suportado. Observe que um objeto pode ser indexável em diferentes domínios por diferentes tipos (por exemplo: indexável através de ordinais e strings). Alguns indexadores são somente leitura. Nesses casos, E_NOTIMPL será retornado a partir de qualquer chamada para o método SetAt.

O conceito de tipo de tempo de execução preferido: IPreferredRuntimeTypeConcept

Um host de depuração pode ser consultado para fazer uma tentativa de determinar o tipo de tempo de execução real de um objeto a partir de um tipo estático encontrado em informações simbólicas. Essa conversão pode ser baseada em informações completamente precisas (por exemplo: C++ RTTI) ou pode ser baseada em heurísticas fortes, como a forma de quaisquer tabelas de funções virtuais dentro do objeto. Alguns objetos, no entanto, não podem ser convertidos de um tipo estático para um tipo de tempo de execução porque eles não se encaixam na heurística do host de depuração (por exemplo: eles não têm RTTI ou tabelas de funções virtuais). Nesses casos, um modelo de dados para um objeto pode optar por substituir o comportamento padrão e declarar que sabe mais sobre o "tipo de tempo de execução" de um objeto do que o host de depuração é capaz de entender. Isso é feito por meio do conceito de tipo de tempo de execução preferido e pelo suporte à interface IPreferredRuntimeTypeConcept.

A interface IPreferredRuntimeTypeConcept é declarada da seguinte forma:

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

ConverterParaTipoDeTempoDeExecuçãoPreferido

O método CastToPreferredRuntimeType é chamado sempre que um cliente deseja tentar converter de uma instância de tipo estático para o tipo de tempo de execução dessa instância. Se o objeto em questão suportar (através de um de seus modelos pai anexados) o conceito de tipo de tempo de execução preferido, esse método será chamado para executar a conversão. Esse método pode retornar o objeto original (não há conversão ou não pôde ser analisado), retornar uma nova instância do tipo runtime, falhar por razões não semânticas (por exemplo: falta de memória) ou retornar E_NOT_SET. O código de erro E_NOT_SET é um código de erro muito especial que indica ao modelo de dados que a implementação não deseja substituir o comportamento padrão e que o modelo de dados deve retornar a qualquer análise executada pelo host de depuração (por exemplo: análise RTTI, exame da forma das tabelas de funções virtuais, etc...)

Os conceitos de provedor dinâmico: IDynamicKeyProviderConcept e IDynamicConceptProviderConcept

Embora o modelo de dados em si normalmente lide com o gerenciamento de chaves e conceitos para objetos, há momentos em que essa noção não é ideal. Em particular, quando um cliente deseja criar uma ponte entre o modelo de dados e outra coisa que seja verdadeiramente dinâmica (por exemplo: JavaScript), pode ser valioso assumir o gerenciamento de chaves e conceitos a partir da implementação no modelo de dados. Como o modelo de dados principal é a única implementação de IModelObject, isto é realizado através de uma combinação de dois conceitos: o conceito de fornecedor de chave dinâmica e o conceito de fornecedor de conceito dinâmico. Embora seja típico implementar ambos ou nenhum, não há nenhum requisito para tal.

Se ambos forem implementados, o conceito de provedor de chave dinâmica deve ser adicionado antes do conceito de provedor dinâmico. Ambos os conceitos são especiais. Eles efetivamente acionam um interruptor no objeto, alterando-o de "gerenciado estaticamente" para "gerenciado dinamicamente". Esses conceitos só podem ser definidos se não houver chaves/conceitos gerenciados pelo modelo de dados no objeto. Uma vez que esses conceitos são adicionados a um objeto, a ação de fazer isso é irrevogável.

Há uma diferença semântica adicional em torno da extensibilidade entre um IModelObject que é um provedor de conceito dinâmico e um que não é. Estes conceitos destinam-se a permitir que os clientes criem pontes entre o modelo de dados e sistemas de linguagem dinâmica, como JavaScript. O modelo de dados tem um conceito de extensibilidade que difere fundamentalmente de sistemas como JavaScript na medida em que há uma árvore de modelos pai em vez de uma cadeia linear como a cadeia de protótipos JavaScript. Para permitir uma melhor relação com esses sistemas, um IModelObject que é um provedor de conceito dinâmico tem um único modelo de dados pai. Esse único modelo de dados pai é um IModelObject normal que pode ter um número arbitrário de modelos pai, como é típico para o modelo de dados. Quaisquer solicitações ao provedor de conceito dinâmico para adicionar ou remover pais são automaticamente redirecionadas para a mãe solteira. Do ponto de vista de um observador externo, parece que o fornecedor de conceitos dinâmicos tem uma cadeia normal de modelos hierarquizados em árvore. O implementador do conceito de provedor dinâmico é o único objeto (fora do modelo de dados principal) que está ciente do pai único intermediário. Esse objeto único pode ser vinculado ao sistema de linguagem dinâmica para fornecer uma ponte (por exemplo: colocado na cadeia de protótipos do JavaScript).

O conceito de provedor de chave dinâmica é definido da seguinte forma:

DECLARE_INTERFACE_(IDynamicKeyProviderConcept, IUnknown)
{
    STDMETHOD(GetKey)(_In_ IModelObject *contextObject, _In_ PCWSTR key, _COM_Outptr_opt_result_maybenull_ IModelObject** keyValue, _COM_Outptr_opt_result_maybenull_ IKeyStore** metadata, _Out_opt_ bool *hasKey) PURE;
    STDMETHOD(SetKey)(_In_ IModelObject *contextObject, _In_ PCWSTR key, _In_ IModelObject *keyValue, _In_ IKeyStore *metadata) PURE;
    STDMETHOD(EnumerateKeys)(_In_ IModelObject *contextObject, _COM_Outptr_ IKeyEnumerator **ppEnumerator) PURE;
}

O conceito dinâmico de provedor é definido da seguinte forma:

DECLARE_INTERFACE_(IDynamicConceptProviderConcept, IUnknown)
{
    STDMETHOD(GetConcept)(_In_ IModelObject *contextObject, _In_ REFIID conceptId, _COM_Outptr_result_maybenull_ IUnknown **conceptInterface, _COM_Outptr_opt_result_maybenull_ IKeyStore **conceptMetadata, _Out_ bool *hasConcept) PURE;
    STDMETHOD(SetConcept)(_In_ IModelObject *contextObject, _In_ REFIID conceptId, _In_ IUnknown *conceptInterface, _In_opt_ IKeyStore *conceptMetadata) PURE;
    STDMETHOD(NotifyParent)(_In_ IModelObject *parentModel) PURE;
    STDMETHOD(NotifyParentChange)(_In_ IModelObject *parentModel) PURE;
    STDMETHOD(NotifyDestruct)() PURE;
}

IDynamicKeyProviderConcept GetKey

O método GetKey em um provedor de chave dinâmica é em grande parte uma substituição do método GetKey em IModelObject. Espera-se que o provedor de chave dinâmica retorne o valor da chave e quaisquer metadados associados a essa chave. Caso a chave não esteja presente (mas nenhum outro erro ocorra), o provedor deve retornar false no parâmetro hasKey e ter êxito com S_OK. A falha nesta chamada é considerada uma falha ao buscar uma chave e interromperá explicitamente a procura pela chave através da corrente de modelos principal. Retornar falso em hasKey e obter sucesso continuará a busca pela chave. Observe que é perfeitamente legal que o GetKey devolva um acessador de propriedade encaixotado como a chave. Isso seria semanticamente idêntico ao método GetKey em IModelObject retornando um acessador de propriedade.

IDynamicKeyProviderConcept SetKey

O método SetKey em um provedor de chave dinâmica é efetivamente uma substituição do método SetKey em IModelObject. Isso define uma chave no provedor dinâmico. É efetivamente a criação de uma nova propriedade no provedor. Observe que um provedor que não suporta qualquer noção de algo como a criação de propriedades expando deve retornar E_NOTIMPL aqui.

IDynamicKeyProviderConcept's EnumerateKeys

O método EnumerateKeys em um provedor de chave dinâmica é efetivamente uma substituição do método EnumerateKeys em IModelObject. Isso enumera todas as chaves no provedor dinâmico. O enumerador retornado tem várias restrições que devem ser respeitadas pela implementação:

  • Deverá comportar-se como uma chamada para EnumerateKeys e não para EnumerateKeyValues ou EnumerateKeyReferences. Ele deve retornar os valores de chave não resolvendo nenhum acessador de propriedade subjacente (se tal conceito existir no provedor).
  • Da perspetiva de um único provedor de chave dinâmica, é ilegal enumerar várias chaves do mesmo nome que são chaves fisicamente distintas. Isso pode acontecer com diferentes fornecedores que são anexados pela cadeia do modelo pai, mas não pode acontecer da perspetiva de um único fornecedor.

IDynamicConceptProviderConcept ObterConceito

O método GetConcept em um provedor de conceito dinâmico é efetivamente uma substituição do método GetConcept em IModelObject. O provedor de conceito dinâmico deve retornar uma interface para o conceito consultado, se ele existir, bem como quaisquer metadados associados a esse conceito. Se o conceito não existir no provedor, isso deve ser indicado por meio de um valor falso sendo retornado no argumento hasConcept e um retorno bem-sucedido. O fracasso deste método é uma falha na busca do conceito e interromperá explicitamente a busca pelo conceito. O retorno de false para hasConcept e um código bem-sucedido continuará a busca pelo conceito por meio da árvore de modelo pai.

IDynamicConceptProviderConcept DefinirConceito

O método SetConcept em um provedor de conceito dinâmico é efetivamente uma substituição do método SetConcept em IModelObject. O provedor dinâmico atribuirá o conceito. Isso pode tornar o objeto iterável, indexável, string conversível, etc... Note que um provedor que não permite a criação de conceitos sobre ele deve retornar E_NOPTIMPL aqui.

IDynamicConceptProviderConcept's NotifyParent

A chamada NotifyParent num fornecedor de conceito dinâmico é usada pelo modelo de dados principal para informar o fornecedor dinâmico sobre o modelo único de pai que é criado para permitir a ligação do paradigma "modelos de múltiplos pais" do modelo de dados a linguagens mais dinâmicas. Qualquer manipulação desse modelo monoparental causará notificações adicionais ao provedor dinâmico. Observe que esta callback é executada imediatamente após a atribuição do conceito do fornecedor dinâmico.

O NotifyParentChange de IDynamicConceptProviderConcept

O método NotifyParent em um provedor de conceito dinâmico é um retorno de chamada feito pelo modelo de dados principal quando uma manipulação estática do modelo pai único do objeto é feita. Para qualquer modelo pai adicionado, esse método será chamado uma primeira vez quando o referido modelo pai for adicionado e uma segunda vez se/quando o referido modelo pai for removido.

O IDynamicConceptProviderConcept NotifyDestruct

O método NotifyDestruct em um provedor de conceito dinâmico é um retorno de chamada feito pelo modelo de dados principal no início da destruição do objeto, que é um provedor de conceito dinâmico. Ele fornece oportunidades adicionais de limpeza para os clientes que precisam dele.

--

Ver 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 de Modelo de Dados do Debugger C++

Objetos C++ do modelo de dados do depurador

Modelo de Dados do Depurador C++ Interfaces adicionais

Depurador de Modelo de Dados C++ Script