Conceitos de C++ do modelo de dados do depurador

Este tópico descreve os conceitos no Modelo de Dados C++ do Depurador.

Conceitos no modelo de dados

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) compatíveis com o modelo de dados. Os 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 com suporte no momento está listado aqui.
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á 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 por meio de acesso aleatório) em uma ou mais dimensões.
IPreferredRuntimeTypeConcept O objeto entende mais sobre tipos derivados dele do que o sistema de tipo subjacente é capaz de fornecer e gostaria de lidar com suas próprias conversões de tipo estático para runtime.
IDynamicKeyProviderConcept O objeto é um provedor dinâmico de chaves e deseja assumir todas as principais consultas do modelo de dados principal. Normalmente, essa interface é 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 conceituais do modelo de dados principal. Normalmente, essa interface é 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 dar suporte direto ao conceito de modelo de dados. O conceito de modelo de dados requer suporte a uma interface IDataModelConcept definida da seguinte maneira.

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

InitializeObject

Um modelo de dados pode ser registrado como 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 é anexado automaticamente como um modelo pai a qualquer objeto nativo cujo tipo corresponde à assinatura passada no registro. No ponto em que esse anexo é feito automaticamente, o método InitializeObject é chamado no modelo de dados. Ele é passado o objeto de instância, a assinatura de tipo que causou o anexo e um enumerador que produz as instâncias de tipo (em ordem linear) que corresponderam a quaisquer caracteres curinga na assinatura de tipo. A implementação do modelo de dados pode usar essa chamada de método para inicializar todos os caches necessários.

GetName

Se um determinado modelo de dados for registrado em 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. Observe que é perfeitamente legítimo que um modelo seja registrado em vários nomes (o padrão ou o melhor deve ser retornado aqui). Um modelo pode ser completamente sem nome (desde que não esteja registrado em um nome). Nessas circunstâncias, o método GetName deve retornar E_NOTIMPL.

O conceito exibivel de cadeia de caracteres: IStringDisplayableConcept

Um objeto que deseja fornecer uma conversão de cadeia de caracteres para fins de exibição pode implementar o conceito exibivel de cadeia de caracteres por meio da implementação da interface IStringDisplayableConcept. A interface é definida assim:

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

Todisplaystring

O método ToDisplayString é chamado sempre que um cliente deseja converter um objeto em uma cadeia de caracteres a ser exibida (para console, na interface do usuário etc...). Essa conversão de cadeia de caracteres não deve ser usada com base em 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 cadeia de caracteres deve fazer todas as tentativas de honrar 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 dar suporte ao conceito iterável por meio de uma implementação das interfaces IIterableConcept e IModelIterator. Há uma relação muito importante entre o suporte ao conceito iterável e o suporte ao conceito indexável. Um objeto que dá suporte ao acesso aleatório aos objetos contidos pode dar suporte ao conceito indexável, além do conceito iterável. Nesse caso, os elementos iterados também devem produzir um índice padrão que, quando passados para o conceito indexável, se referem ao mesmo objeto. Uma falha ao satisfazer essa invariável resultará em um comportamento indefinido no host de depuração.

O IIterableConcept é definido da seguinte maneira:

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 maneira:

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

GetDefaultIndexDimensionality de IIterableConcept

O método GetDefaultIndexDimensionality 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 dá suporte ao conceito indexável por meio 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, conforme indicado aqui.
  • Passar os índices retornados do método GetNext do IModelIterator para o método GetAt no conceito indexável (IIndexableConcept) se referirá ao mesmo objeto que GetNext produziu. O mesmo valor é retornado.

GetIterator de IIterableConcept

O método GetIterator no conceito iterável retorna uma interface iterador que pode ser usada para iterar o objeto. O iterador retornado deve se lembrar do objeto de contexto que foi passado para o método GetIterator. Ele não será passado para métodos no 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 ele estava quando o iterador foi criado pela primeira vez (antes do primeiro elemento). Embora seja altamente recomendável que o iterador dê suporte ao método Reset, ele não é necessário. Um iterador pode ser equivalente a um iterador de entrada C++ e permitir apenas uma única passagem de iteração para frente. Nesse caso, o método Reset pode falhar com E_NOTIMPL.

GetNext de IModelIterator

O método GetNext move o iterador para frente e busca o próximo elemento iterado. Se o objeto for indexável além de ser iterável e isso for indicado pelo argumento GetDefaultIndexDimensionality retornando um valor diferente de zero, esse método poderá retornar opcionalmente 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 inválido que o chamador solicite índices parciais (por exemplo: menor que o número produzido por GetDefaultIndexDimensionality).

Se o iterador avançou com êxito, mas houve um erro ao ler o valor do elemento iterado, o método poderá 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 intervindo) também retornará E_BOUNDS.

O conceito indexável: IIndexableConcept

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

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 como usar o 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 a falha de alocação de memória. Ele pressupõe um novo lançamento (o que pode ser uma suposição ruim dependendo do ambiente no qual o código existe -- os métodos COM do modelo de dados não podem ter exceções C++ escape):

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 indicies.
            //
            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 em que o objeto é 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 índice N dimensional específico de dentro do objeto indexado. Um indexador de N dimensões em que N é o valor retornado de GetDimensionality deve ter suporte. Observe que um objeto pode ser indexável em domínios diferentes por tipos diferentes (por exemplo: indexável por meio de ordinais e cadeias de caracteres). 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 índice N dimensional específico de dentro do objeto indexado. Um indexador de N dimensões em que N é o valor retornado de GetDimensionality deve ter suporte. Observe que um objeto pode ser indexável em domínios diferentes por tipos diferentes (por exemplo: indexável por meio de ordinais e cadeias de caracteres). Alguns indexadores são somente leitura. Nesses casos, E_NOTIMPL será retornado de qualquer chamada para o método SetAt.

O conceito de tipo de runtime preferencial: IPreferredRuntimeTypeConcept

Um host de depuração pode ser consultado para tentar determinar o tipo de runtime real de um objeto 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 qualquer tabela 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 runtime porque não se encaixam na heurística do host de depuração (por exemplo, eles não têm tabelas rtti ou de função virtual). Nesses casos, um modelo de dados para um objeto pode optar por substituir o comportamento padrão e declarar que ele sabe mais sobre o "tipo de runtime" de um objeto do que o host de depuração é capaz de entender. Isso é feito por meio do conceito de tipo de runtime preferencial e do suporte da interface IPreferredRuntimeTypeConcept.

A interface IPreferredRuntimeTypeConcept é declarada da seguinte maneira:

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

CastToPreferredRuntimeType

O método CastToPreferredRuntimeType é chamado sempre que um cliente deseja tentar converter de uma instância de tipo estático para o tipo de runtime dessa instância. Se o objeto em questão der suporte (por meio de um de seus modelos pai anexados) ao conceito de tipo de runtime preferencial, 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 de runtime, falhar por motivos não semânticos (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 fazer fallback para 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 do provedor dinâmico: IDynamicKeyProviderConcept e IDynamicConceptProviderConcept

Embora o próprio modelo de dados normalmente manipule o gerenciamento de chave e conceito para objetos, há momentos em que essa noção é menor que 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 conceito e chave da implementação no modelo de dados. Como o modelo de dados principal é a única implementação de IModelObject, isso é feito por meio de uma combinação de dois conceitos: o conceito de provedor de chave dinâmica e o conceito de provedor de conceito dinâmico. Embora seja comum implementar ambos ou nenhum dos dois, não há nenhum requisito para isso.

Se ambos forem implementados, o conceito de provedor de chave dinâmica deverá ser adicionado antes do conceito de provedor de conceito dinâmico. Ambos os conceitos são especiais. Eles efetivamente inverter um comutador no objeto alterando-o de "gerenciado estaticamente" para "gerenciado dinamicamente". Esses conceitos só poderão ser definidos se não houver chaves/conceitos gerenciados pelo modelo de dados no objeto . Depois 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 relação à extensibilidade entre um IModelObject, que é um provedor de conceito dinâmico e um que não é. Esses 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 um pouco fundamentalmente de sistemas como JavaScript 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 pai de modelo de dados único é um IModelObject normal que pode ter um número arbitrário de modelos pai, como é típico para o modelo de dados. Todas as solicitações ao provedor de conceito dinâmico para adicionar ou remover pais são redirecionadas automaticamente para o pai único. Da perspectiva de um forasteiro, parece que o provedor de conceito dinâmico tem uma cadeia de estilo de árvore normal de modelos pai. O implementador do conceito de provedor de conceito dinâmico é o único objeto (fora do modelo de dados principal) que está ciente do pai único intermediário. Esse único pai pode ser vinculado ao sistema de linguagem dinâmica para fornecer uma ponte (por exemplo: colocada na cadeia de protótipos do JavaScript).

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

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 de provedor de conceito dinâmico é definido da seguinte maneira:

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

GetKey de IDynamicKeyProviderConcept

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 todos os metadados associados a essa chave. Caso a chave não esteja presente (mas nenhum outro erro ocorra), o provedor deverá retornar false no parâmetro hasKey e ter êxito com S_OK. A falha nessa chamada é considerada uma falha ao buscar uma chave e interromperá explicitamente a pesquisa da chave por meio da cadeia de modelo pai. Retornar false em hasKey e êxito continuará a pesquisa pela chave. Observe que é perfeitamente legal para GetKey retornar um acessador de propriedade em caixa como a chave. Isso seria semanticamente idêntico ao método GetKey em IModelObject retornando um acessador de propriedade.

SetKey de IDynamicKeyProviderConcept

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 dá suporte a nenhuma noção de algo como a criação de propriedades expando deve retornar E_NOTIMPL aqui.

EnumerateKeys de IDynamicKeyProviderConcept

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:

  • Ele deve se comportar como uma chamada para EnumerateKeys e não EnumerateKeyValues ou EnumerateKeyReferences. Ele deve retornar os valores de chave que não resolvem os acessadores de propriedade subjacentes (se esse conceito existir no provedor).
  • Da perspectiva de um único provedor de chaves dinâmicas, é ilegal enumerar várias chaves de mesmo nome que são chaves fisicamente distintas. Isso pode acontecer em diferentes provedores anexados por meio da cadeia de modelos pai, mas isso não pode acontecer da perspectiva de um único provedor.

GetConcept de IDynamicConceptProviderConcept

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 deverá ser indicado por meio de um valor falso que está sendo retornado no argumento hasConcept e um retorno bem-sucedido. A falha desse método é uma falha ao buscar o conceito e interromperá explicitamente a pesquisa pelo conceito. Retornar false para hasConcept e um código bem-sucedido continuará a pesquisa do conceito por meio da árvore de modelo pai.

SetConcept de IDynamicConceptProviderConcept

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, conversível de cadeia de caracteres etc... Observe que um provedor que não permite a criação de conceitos nele deve retornar E_NOPTIMPL aqui.

NotifyParent de IDynamicConceptProviderConcept

A chamada NotifyParent em um provedor de conceito dinâmico é usada pelo modelo de dados principal para informar o provedor dinâmico do modelo pai único que é criado para permitir a ponte do paradigma "vários modelos pai" do modelo de dados para linguagens mais dinâmicas. Qualquer manipulação desse modelo pai único causará mais notificações ao provedor dinâmico. Observe que esse retorno de chamada é feito imediatamente após a atribuição do conceito de provedor de conceito dinâmico.

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 pela primeira vez quando o modelo pai for adicionado e uma segunda vez se/quando o modelo pai for removido.

NotifyDestruct de IDynamicConceptProviderConcept

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 limpo oportunidades adicionais para clientes que o exigem.

--

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 C++ do modelo de dados do depurador

Conceitos de C++ do modelo de dados do depurador

Script C++ do modelo de dados do depurador