Concetti relativi al modello di dati del debugger C++

Questo argomento descrive i concetti in Debugger C++ Data Model .

Concetti nel modello di dati

Gli oggetti sintetici nel modello di dati sono effettivamente due cose:

  • Dizionario delle tuple chiave/valore/metadati.
  • Set di concetti (interfacce) supportati dal modello di dati. I concetti sono interfacce che un client (anziché il modello di dati) implementa per fornire un set specificato di comportamento semantico. Il set di concetti attualmente supportato è elencato qui.
Interfaccia concetto Descrizione
IDataModelConcept Il concetto è un modello padre. Se questo modello viene collegato automaticamente a un tipo nativo tramite una firma del tipo registrato, il metodo InitializeObject verrà chiamato automaticamente ogni volta che viene creata un'istanza di un nuovo oggetto di tale tipo.
IStringDisplayableConcept L'oggetto può essere convertito in una stringa a scopo di visualizzazione.
IIterableConcept L'oggetto è un contenitore e può essere iterazione.
IIndexableConcept L'oggetto è un contenitore e può essere indicizzato (accessibile tramite accesso casuale) in una o più dimensioni.
IPreferredRuntimeTypeConcept L'oggetto comprende più sui tipi derivati rispetto al sistema di tipi sottostanti in grado di fornire e di gestire le proprie conversioni dal tipo statico al tipo di runtime.
IDynamicKeyProviderConcept L'oggetto è un provider dinamico di chiavi e vuole assumere tutte le query chiave dal modello di dati di base. Questa interfaccia viene in genere usata come bridge a linguaggi dinamici, ad esempio JavaScript.
IDynamicConceptProviderConcept L'oggetto è un provider dinamico di concetti e vuole assumere tutte le query di concetto dal modello di dati di base. Questa interfaccia viene in genere usata come bridge a linguaggi dinamici, ad esempio JavaScript.

Concetto di modello di dati: IDataModelConcept

Qualsiasi oggetto modello collegato a un altro oggetto modello come modello padre deve supportare direttamente il concetto di modello di dati. Il concetto di modello di dati richiede il supporto di un'interfaccia, IDataModelConcept definita come indicato di seguito.

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

Un modello di dati può essere registrato come visualizzatore canonico o come estensione per un determinato tipo nativo tramite i metodi RegisterModelForTypeSignature o RegisterExtensionForTypeSignature. Quando un modello viene registrato tramite uno di questi metodi, il modello di dati viene collegato automaticamente come modello padre a qualsiasi oggetto nativo il cui tipo corrisponde alla firma passata nella registrazione. Nel punto in cui viene eseguito automaticamente l'allegato, il metodo InitializeObject viene chiamato nel modello di dati. Viene passato l'oggetto istanza, la firma del tipo che ha causato l'allegato e un enumeratore che produce le istanze di tipo (in ordine lineare) che corrispondono a qualsiasi carattere jolly nella firma del tipo. L'implementazione del modello di dati può usare questa chiamata al metodo per inizializzare tutte le cache necessarie.

GetName

Se un determinato modello di dati viene registrato con un nome predefinito tramite il metodo RegisterNamedModel, l'interfaccia IDataModelConcept del modello di dati registrato deve restituire tale nome da questo metodo. Si noti che è perfettamente legittimo che un modello venga registrato in più nomi (il valore predefinito o migliore deve essere restituito qui). Un modello può essere completamente senza nome (purché non sia registrato in un nome). In tali circostanze, il metodo GetName deve restituire E_NOTIMPL.

Concetto visualizzabile stringa: IStringDisplayableConcept

Un oggetto che vuole fornire una conversione stringa a scopo di visualizzazione può implementare il concetto visualizzabile stringa tramite l'implementazione dell'interfaccia IStringDisplayableConcept. L'interfaccia viene definita come segue:

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

ToDisplayString

Il metodo ToDisplayString viene chiamato ogni volta che un client desidera convertire un oggetto in una stringa da visualizzare (nella console, nell'interfaccia utente e così via). Tale conversione di stringa non deve essere usata per la base di una manipolazione a livello di codice aggiuntivo. La conversione della stringa stessa può essere profondamente influenzata dai metadati passati alla chiamata. Una conversione stringa deve eseguire ogni tentativo di rispettare le chiavi PreferredRadix e PreferredFormat.

Concetto iterabile: IIterableConcept e IModelIterator

Un oggetto che è un contenitore di altri oggetti e vuole esprimere la possibilità di eseguire l'iterazione su tali oggetti contenuti può supportare il concetto iterabile da un'implementazione delle interfacce IIterableConcept e IModelIterator. Esiste una relazione molto importante tra il supporto del concetto iterabile e il supporto del concetto indicizzatore. Un oggetto che supporta l'accesso casuale agli oggetti contenuti può supportare il concetto indicizzato oltre al concetto iterabile. In questo caso, gli elementi iterati devono anche produrre un indice predefinito che, quando passato al concetto indicizzato, fa riferimento allo stesso oggetto. Un errore per soddisfare questo invariante comporterà un comportamento non definito nell'host di debug.

L'IIterableConcept è definito come segue:

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

Il concetto IModelIterator è definito come segue:

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 di IIterableConcept

Il metodo GetDefaultIndexDimensionality restituisce il numero di dimensioni all'indice predefinito. Se un oggetto non è indicizzato, questo metodo deve restituire 0 e avere esito positivo (S_OK). Qualsiasi oggetto che restituisce un valore diverso da zero da questo metodo dichiara il supporto per un contratto protocollo che indica:

  • L'oggetto supporta il concetto indicizzatore tramite il supporto di IIndexableConcept
  • Il metodo GetNext dell'IModelIterator restituito dal metodo GetIterator del concetto iterabile restituirà un indice predefinito univoco per ogni elemento prodotto. Tale indice avrà il numero di dimensioni indicate qui.
  • Passando gli indici restituiti dal metodo GetNext del metodo IModelIterator al metodo GetAt nel concetto indicizzatore (IIndexableConcept) farà riferimento allo stesso oggetto prodotto da GetNext. Viene restituito lo stesso valore.

GetIterator di IIterableConcept

Il metodo GetIterator nel concetto iterabile restituisce un'interfaccia iteratore che può essere usata per iterare l'oggetto. L'iteratore restituito deve ricordare l'oggetto contesto passato al metodo GetIterator. Non verrà passato ai metodi sull'iteratore stesso.

Reimpostazione di IModelIterator

Il metodo Reset su un iteratore restituito dal concetto iterabile ripristina la posizione dell'iteratore in cui è stato creato l'iteratore (prima del primo elemento). Anche se è consigliabile che l'iteratore supporti il metodo Reset, non è obbligatorio. Un iteratore può essere l'equivalente di un iteratore di input C++ e consente solo un singolo passaggio di iterazione avanti. In tal caso, il metodo Reset potrebbe non riuscire con E_NOTIMPL.

GetNext di IModelIterator

Il metodo GetNext sposta l'iteratore in avanti e recupera l'elemento iterato successivo. Se l'oggetto è indicizzato oltre a essere iterabile e questo è indicato dall'argomento GetDefaultIndexDimensionality che restituisce un valore diverso da zero, questo metodo può facoltativamente restituire gli indici predefiniti per tornare al valore prodotto dall'indicizzatore. Si noti che un chiamante può scegliere di passare 0/nullptr e non recuperare alcun indici. È considerato illegale per il chiamante richiedere indici parziali (ad esempio, minore del numero prodotto da GetDefaultIndexDimensionality).

Se l'iteratore è stato spostato in avanti correttamente, ma si è verificato un errore durante la lettura del valore dell'elemento iterato, il metodo potrebbe restituire un errore E riempire "oggetto" con un oggetto error. Alla fine dell'iterazione degli elementi contenuti, l'iteratore restituirà E_BOUNDS dal metodo GetNext. Qualsiasi chiamata successiva (a meno che non sia stata eseguita una chiamata di reimpostazione) restituirà anche E_BOUNDS.

Concetto indicizzato: IIndexableConcept

Un oggetto che desidera fornire l'accesso casuale a un set di contenuti può supportare il concetto indicizzatore tramite il supporto dell'interfaccia IIndexableConcept. La maggior parte degli oggetti indicizzati sarà iterabile anche tramite il supporto del concetto iterabile. Non è tuttavia necessario. Se supportato, esiste una relazione importante tra iteratore e indicizzatore. L'iteratore deve supportare GetDefaultIndexDimensionality, restituire un valore diverso da zero da tale metodo e supportare il contratto documentato. L'interfaccia del concetto di indicizzatore è definita come segue:

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

Di seguito è riportato un esempio di uso dell'indicizzatore (e della relativa interazione con l'iteratore). In questo esempio viene eseguito l'iterazione del contenuto di un contenitore indicizzatore e viene usato l'indicizzatore per tornare al valore appena restituito. Anche se questa operazione è funzionalmente inutile come scritto, illustra come interagiscono queste interfacce. Si noti che l'esempio seguente non gestisce l'errore di allocazione della memoria. Presuppone una generazione di nuove (che potrebbero essere un presupposto scarso a seconda dell'ambiente in cui esiste il codice - i metodi COM del modello di dati non possono avere eccezioni C++):

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

Il metodo GetDimensionality restituisce il numero di dimensioni in cui viene indicizzato l'oggetto. Si noti che se l'oggetto è iterabile e indicizzato, l'implementazione di GetDefaultIndexDimensionality deve accettare l'implementazione di GetDimensionality come il numero di dimensioni dell'indicizzatore.

GetAt

Il metodo GetAt recupera il valore in corrispondenza di un particolare indice N-dimensionale dall'interno dell'oggetto indicizzato. Un indicizzatore di N dimensioni in cui N è il valore restituito da GetDimensionality deve essere supportato. Si noti che un oggetto può essere indicizzato in domini diversi in base a tipi diversi, ad esempio indicizzabili tramite ordinali e stringhe. Se l'indice non è compreso nell'intervallo (o non è possibile accedervi), il metodo restituirà un errore; In questi casi, tuttavia, l'oggetto di output può comunque essere impostato su un oggetto error.

SetAt

Il metodo SetAt tenta di impostare il valore in corrispondenza di un indice N-dimensionale specifico dall'interno dell'oggetto indicizzato. Un indicizzatore di N dimensioni in cui N è il valore restituito da GetDimensionality deve essere supportato. Si noti che un oggetto può essere indicizzato in domini diversi in base a tipi diversi, ad esempio indicizzabili tramite ordinali e stringhe. Alcuni indicizzatori sono di sola lettura. In questi casi, E_NOTIMPL verrà restituito da qualsiasi chiamata al metodo SetAt.

Concetto di tipo di runtime preferito: IPreferredRuntimeTypeConcept

È possibile eseguire una query su un host di debug per tentare di determinare il tipo di runtime reale di un oggetto da un tipo statico trovato nelle informazioni simbolica. Questa conversione può essere basata su informazioni completamente accurate (ad esempio, C++ RTTI) o può essere basata su un'euristica avanzata, ad esempio la forma di qualsiasi tabella di funzioni virtuali all'interno dell'oggetto. Alcuni oggetti, tuttavia, non possono essere convertiti da un tipo statico a un tipo di runtime perché non rientrano nell'euristica dell'host di debug ( ad esempio, non hanno tabelle RTTI o funzioni virtuali). In questi casi, un modello di dati per un oggetto può scegliere di eseguire l'override del comportamento predefinito e dichiarare che conosce meglio il "tipo di runtime" di un oggetto rispetto all'host di debug in grado di comprendere. Questa operazione viene eseguita tramite il concetto di tipo di runtime preferito e il supporto dell'interfaccia IPreferredRuntimeTypeConcept.

L'interfaccia IPreferredRuntimeTypeConcept viene dichiarata come segue:

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

CastToPreferredRuntimeType

Il metodo CastToPreferredRuntimeType viene chiamato ogni volta che un client desidera tentare di eseguire la conversione da un'istanza di tipo statico al tipo di runtime di tale istanza. Se l'oggetto in questione supporta (tramite uno dei modelli padre associati) il concetto di tipo di runtime preferito, questo metodo verrà chiamato per eseguire la conversione. Questo metodo può restituire l'oggetto originale (non è presente alcuna conversione o non è stato possibile analizzarlo), restituire una nuova istanza del tipo di runtime, non riuscire per motivi non semantici (ad esempio, memoria insufficiente) o restituire E_NOT_SET. Il codice di errore E_NOT_SET è un codice di errore molto speciale che indica al modello di dati che l'implementazione non vuole eseguire l'override del comportamento predefinito e che il modello di dati deve eseguire il fallback a qualsiasi analisi eseguita dall'host di debug (ad esempio, l'analisi RTTI, l'esame della forma delle tabelle delle funzioni virtuali, ecc...)

Concetti relativi al provider dinamico: IDynamicKeyProviderConcept e IDynamicConceptProviderConcept

Anche se il modello di dati stesso gestisce normalmente la gestione delle chiavi e dei concetti per gli oggetti, esistono momenti in cui tale nozione è minore dell'ideale. In particolare, quando un client vuole creare un ponte tra il modello di dati e qualcos'altro che è veramente dinamico (ad esempio, JavaScript), può essere utile assumere il controllo della gestione chiave e del concetto dall'implementazione nel modello di dati. Poiché il modello di dati di base è l'unica implementazione di IModelObject, questa operazione viene invece eseguita tramite una combinazione di due concetti: il concetto di provider chiave dinamica e il concetto di provider di concetti dinamici. Anche se sarebbe tipico implementare entrambi o nessuno dei due, non esiste alcun requisito per tali.

Se vengono implementati entrambi, il concetto di provider di chiavi dinamiche deve essere aggiunto prima del concetto di provider di concetti dinamici. Entrambi questi concetti sono speciali. Capovolgono in modo efficace un interruttore sull'oggetto modificandolo da "gestito in modo statico" a "gestito in modo dinamico". Questi concetti possono essere impostati solo se non sono presenti chiavi/concetti gestiti dal modello di dati nell'oggetto . Dopo aver aggiunto questi concetti a un oggetto, l'azione di questa operazione è irrevocabile.

Esiste una differenza semantica aggiuntiva per l'estendibilità tra un IModelObject che è un provider di concetti dinamici e uno che non lo è. Questi concetti sono progettati per consentire ai client di creare bridge tra il modello di dati e i sistemi del linguaggio dinamico, ad esempio JavaScript. Il modello di dati ha un concetto di estendibilità leggermente diverso da sistemi come JavaScript in quanto esiste un albero di modelli padre anziché una catena lineare come la catena di prototipi JavaScript. Per consentire una migliore relazione con tali sistemi, un IModelObject che è un provider di concetti dinamici ha un singolo elemento padre del modello di dati. Tale singolo modello di dati padre è un IModelObject normale che può avere un numero arbitrario di modelli padre, come è tipico per il modello di dati. Tutte le richieste al provider di concetti dinamici per aggiungere o rimuovere elementi padre vengono reindirizzate automaticamente al singolo elemento padre. Dal punto di vista di un esterno, sembra che il provider di concetti dinamici abbia una normale catena di stili di albero dei modelli padre. L'implementatore del concetto di provider di concetti dinamici è l'unico oggetto (al di fuori del modello di dati di base) che riconosce il singolo elemento padre intermedio. Tale singolo elemento padre può essere collegato al sistema del linguaggio dinamico per fornire un bridge (ad esempio, inserito nella catena di prototipi JavaScript).

Il concetto di provider di chiavi dinamiche è definito come segue:

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

Il concetto di provider di concetti dinamici è definito come segue:

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

GetKeyProviderConcept di IDynamicKey

Il metodo GetKey in un provider di chiavi dinamiche è in gran parte un override del metodo GetKey in IModelObject. È previsto che il provider di chiavi dinamico restituisca il valore della chiave e tutti i metadati associati a tale chiave. Nel caso in cui la chiave non sia presente (ma non si verifica alcun altro errore), il provider deve restituire false nel parametro hasKey e avere esito positivo con S_OK. L'esito negativo di questa chiamata viene considerato un errore durante il recupero di una chiave e interromperà in modo esplicito la ricerca della chiave tramite la catena di modelli padre. La restituzione di false in hasKey e l'esito positivo continuerà la ricerca della chiave. Si noti che è perfettamente legale per GetKey restituire una funzione di accesso alle proprietà boxed come chiave. Ciò sarebbe semanticamente identico al metodo GetKey in IModelObject che restituisce una funzione di accesso di proprietà.

SetKeyProviderConcept di IDynamicKey

Il metodo SetKey in un provider di chiavi dinamiche è in effetti un override del metodo SetKey in IModelObject. In questo modo viene impostata una chiave nel provider dinamico. Si tratta in effetti della creazione di una nuova proprietà nel provider. Si noti che un provider che non supporta alcuna nozione di qualcosa come la creazione di proprietà expando deve restituire E_NOTIMPL qui.

EnumerateKeyProviderConcept di IDynamicKeyProvider

Il metodo EnumerateKeys in un provider di chiavi dinamiche è in effetti un override del metodo EnumerateKeys in IModelObject. Enumera tutte le chiavi nel provider dinamico. L'enumeratore restituito presenta diverse restrizioni che devono essere rispettate dall'implementazione:

  • Deve comportarsi come una chiamata a EnumerateKeys e non EnumerateKeyValues o EnumerateKeyReferences. Deve restituire i valori di chiave che non risolvono le funzioni di accesso alle proprietà sottostanti (se tale concetto esiste nel provider).
  • Dal punto di vista di un singolo provider di chiavi dinamiche, è illegale enumerare più chiavi con lo stesso nome che sono chiavi fisicamente distinte. Ciò può verificarsi in provider diversi collegati tramite la catena di modelli padre, ma non può verificarsi dal punto di vista di un singolo provider.

GetConceptProviderConcept di IDynamicConcept

Il metodo GetConcept in un provider di concetti dinamici è in effetti un override del metodo GetConcept in IModelObject. Il provider di concetti dinamici deve restituire un'interfaccia per il concetto sottoposto a query, se esistente e tutti i metadati associati a tale concetto. Se il concetto non esiste nel provider, tale valore deve essere indicato tramite un valore false restituito nell'argomento hasConcept e un risultato restituito correttamente. L'errore di questo metodo non riesce a recuperare il concetto e interromperà in modo esplicito la ricerca del concetto. La restituzione di false per hasConcept e un codice riuscito continuerà la ricerca del concetto tramite l'albero del modello padre.

SetConceptProviderConcept di IDynamicConcept

Il metodo SetConcept in un provider di concetti dinamici è in effetti un override del metodo SetConcept in IModelObject. Il provider dinamico assegnerà il concetto. In questo modo l'oggetto può essere iterabile, indicizzato, convertibile in stringhe e così via. Si noti che un provider che non consente la creazione di concetti su di esso deve restituire E_NOPTIMPL qui.

NotifyParent di IDynamicConceptProviderConcept

La chiamata NotifyParent su un provider di concetti dinamici viene usata dal modello di dati principale per informare il provider dinamico del modello padre singolo creato per consentire il bridging del paradigma "più modelli padre" del modello di dati a linguaggi più dinamici. Qualsiasi manipolazione del modello padre singolo causerà ulteriori notifiche al provider dinamico. Si noti che questo callback viene eseguito immediatamente dopo l'assegnazione del concetto di provider di concetti dinamici.

NotifyParentChange di IDynamicConceptProviderConcept

Il metodo NotifyParent in un provider di concetti dinamici è un callback eseguito dal modello di dati principale quando viene eseguita una manipolazione statica del modello padre singolo dell'oggetto. Per qualsiasi modello padre specificato aggiunto, questo metodo verrà chiamato una prima volta quando viene aggiunto il modello padre e una seconda volta se/quando viene rimosso il modello padre.

NotifyDestruct di IDynamicConceptProviderConcept

Il metodo NotifyDestruct in un provider di concetti dinamici è un callback eseguito dal modello di dati di base all'inizio della distruzione dell'oggetto che è un provider di concetti dinamici. Offre ulteriori opportunità di pulizia per i client che lo richiedono.

--

Vedere anche

Questo argomento fa parte di una serie che descrive le interfacce accessibili da C++, come usarle per compilare un'estensione del debugger basata su C++ e come usare altri costrutti di modelli di dati (ad esempio JavaScript o NatVis) da un'estensione del modello di dati C++.

Panoramica del modello di dati del debugger C++

Interfacce C++ del modello di dati del debugger

Oggetti C++ del modello di dati del debugger

Interfacce aggiuntive del modello di dati del debugger C++

Concetti relativi al modello di dati del debugger C++

Scripting C++ del modello di dati del debugger