Conceptos de C++ del modelo de datos del depurador

En este tema se describen los conceptos del modelo de datos de C++ del depurador.

Conceptos del modelo de datos

Los objetos sintéticos del modelo de datos son de hecho dos cosas:

  • Diccionario de tuplas clave/valor/metadatos.
  • Conjunto de conceptos (interfaces) admitidos por el modelo de datos. Los conceptos son interfaces que un cliente (en lugar del modelo de datos) implementa para proporcionar un conjunto especificado de comportamiento semántico. El conjunto de conceptos admitidos actualmente se enumeran aquí.
Interfaz de concepto Descripción
IDataModelConcept El concepto es un modelo primario. Si este modelo se adjunta automáticamente a un tipo nativo a través de una firma de tipo registrado, se llamará automáticamente al método InitializeObject cada vez que se cree una instancia de un nuevo objeto de este tipo.
IStringDisplayableConcept El objeto se puede convertir en una cadena con fines de presentación.
IIterableConcept El objeto es un contenedor y se puede iterar.
IIndexableConcept El objeto es un contenedor y se puede indexar (a través del acceso aleatorio) en una o varias dimensiones.
IPreferredRuntimeTypeConcept El objeto entiende más sobre los tipos derivados de él que el sistema de tipos subyacente es capaz de proporcionar y desea controlar sus propias conversiones de tipo estático a en tiempo de ejecución.
IDynamicKeyProviderConcept El objeto es un proveedor dinámico de claves y desea asumir todas las consultas de clave del modelo de datos principal. Esta interfaz se usa normalmente como puente a lenguajes dinámicos, como JavaScript.
IDynamicConceptProviderConcept El objeto es un proveedor dinámico de conceptos y desea asumir todas las consultas de concepto del modelo de datos principal. Esta interfaz se usa normalmente como puente a lenguajes dinámicos, como JavaScript.

El concepto del modelo de datos: IDataModelConcept

Cualquier objeto de modelo que esté asociado a otro objeto de modelo como modelo primario debe admitir directamente el concepto del modelo de datos. El concepto del modelo de datos requiere compatibilidad con una interfaz, IDataModelConcept definida como se indica a continuación.

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 modelo de datos se puede registrar como visualizador canónico o como una extensión para un tipo nativo determinado a través de los métodos RegisterModelForTypeSignature o RegisterExtensionForTypeSignature del administrador de modelos de datos. Cuando se registra un modelo a través de cualquiera de estos métodos, el modelo de datos se adjunta automáticamente como modelo primario a cualquier objeto nativo cuyo tipo coincida con la firma pasada en el registro. En el punto donde se realizan automáticamente los datos adjuntos, se llama al método InitializeObject en el modelo de datos. Se pasa el objeto de instancia, la firma de tipo que provocó los datos adjuntos y un enumerador que genera las instancias de tipo (en orden lineal) que coinciden con los caracteres comodín de la firma de tipo. La implementación del modelo de datos puede usar esta llamada al método para inicializar las memorias caché que requiera.

GetName

Si un modelo de datos determinado se registra con un nombre predeterminado a través del método RegisterNamedModel, la interfaz IDataModelConcept del modelo de datos registrado debe devolver ese nombre de este método. Tenga en cuenta que es perfectamente legítimo que un modelo se registre con varios nombres (el valor predeterminado o el mejor debe devolverse aquí). Un modelo puede estar completamente sin nombre (siempre y cuando no esté registrado bajo un nombre). En tales circunstancias, el método GetName debe devolver E_NOTIMPL.

El concepto que se puede mostrar de cadena: IStringDisplayableConcept

Un objeto que desea proporcionar una conversión de cadena con fines de visualización puede implementar el concepto que se puede mostrar de cadena mediante la implementación de la interfaz IStringDisplayableConcept. La interfaz se define de la siguiente manera:

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

ToDisplayString

Se llama al método ToDisplayString cada vez que un cliente desea convertir un objeto en una cadena que se va a mostrar (en la consola, en la interfaz de usuario, etc.). Esta conversión de cadena no se debe usar para la base de la manipulación mediante programación adicional. La propia conversión de cadena puede estar profundamente influenciada por los metadatos pasados a la llamada. Una conversión de cadena debe realizar todos los intentos de respetar las claves PreferredRadix y PreferredFormat.

El concepto iterable: IIterableConcept e IModelIterator

Un objeto que es un contenedor de otros objetos y desea expresar la capacidad de iterar sobre esos objetos contenidos puede admitir el concepto iterable mediante una implementación de las interfaces IIterableConcept e IModelIterator. Existe una relación muy importante entre la compatibilidad del concepto iterable y la compatibilidad del concepto indizable. Un objeto que admite el acceso aleatorio a los objetos contenidos puede admitir el concepto indizable además del concepto iterable. En este caso, los elementos iterados también deben generar un índice predeterminado que, cuando se pasa al concepto indizable, hace referencia al mismo objeto. Si no se cumple esta invariable, se producirá un comportamiento indefinido en el host de depuración.

IIterableConcept se define de la siguiente manera:

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

El concepto IModelIterator se define de la siguiente manera:

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

El método GetDefaultIndexDimensionality devuelve el número de dimensiones al índice predeterminado. Si un objeto no es indizable, este método debe devolver 0 y correcto (S_OK). Cualquier objeto que devuelva un valor distinto de cero de este método declara la compatibilidad con un contrato de protocolo que indica:

  • El objeto admite el concepto indizable mediante la compatibilidad de IIndexableConcept.
  • El método GetNext del IModelIterator devuelto desde el método GetIterator del concepto iterable devolverá un índice predeterminado único para cada elemento generado. Este índice tendrá el número de dimensiones como se indica aquí.
  • Pasar las indicciones devueltas desde el método GetNext del IModelIterator al método GetAt en el concepto indizable (IIndexableConcept) hará referencia al mismo objeto generado por GetNext. Se devuelve el mismo valor.

GetIterator de IIterableConcept

El método GetIterator del concepto iterable devuelve una interfaz de iterador que se puede usar para iterar el objeto. El iterador devuelto debe recordar el objeto de contexto que se pasó al método GetIterator. No se pasará a los métodos en el propio iterador.

Restablecimiento de IModelIterator

El método Reset en un iterador devuelto desde el concepto iterable restaurará la posición del iterador a donde se creó por primera vez el iterador (antes del primer elemento). Aunque se recomienda encarecidamente que el iterador admita el método Reset, no es necesario. Un iterador puede ser el equivalente de un iterador de entrada de C++ y solo permitir un único paso de iteración hacia delante. En tal caso, el método Reset puede producir un error con E_NOTIMPL.

GetNext de IModelIterator

El método GetNext mueve el iterador hacia delante y captura el siguiente elemento iterado. Si el objeto es indizable además de que se puede iterar y esto se indica mediante el argumento GetDefaultIndexDimensionality que devuelve un valor distinto de cero, este método puede devolver opcionalmente las indicciones predeterminadas para volver al valor generado del indexador. Tenga en cuenta que un llamador puede optar por pasar 0/nullptr y no recuperar indicciones. Se considera ilegal que el autor de la llamada solicite indicciones parciales (por ejemplo, menor que el número generado por GetDefaultIndexDimensionality).

Si el iterador avanza correctamente, pero se produjo un error al leer el valor del elemento iterado, el método puede devolver un error Y rellenar "objeto" con un objeto de error. Al final de la iteración de los elementos contenidos, el iterador devolverá E_BOUNDS desde el método GetNext. Cualquier llamada posterior (a menos que haya habido una llamada reset intermedia) también devolverá E_BOUNDS.

El concepto indizable: IIndexableConcept

Un objeto que desea proporcionar acceso aleatorio a un conjunto de contenidos puede admitir el concepto indizable a través de la compatibilidad de la interfaz IIndexableConcept. La mayoría de los objetos que son indizables también serán iterables a través de la compatibilidad con el concepto iterable. Sin embargo, esto no es necesario. Si se admite, hay una relación importante entre el iterador y el indexador. El iterador debe admitir GetDefaultIndexDimensionality, devolver un valor distinto de cero de ese método y admitir el contrato documentado allí. La interfaz de concepto del indexador se define de la siguiente manera:

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

A continuación se muestra un ejemplo del uso del indexador (y su interacción con el iterador). En este ejemplo se itera el contenido de un contenedor indizable y se usa el indexador para volver al valor que se acaba de devolver. Aunque esa operación es funcionalmente inútil como se escribe, muestra cómo interactúan estas interfaces. Tenga en cuenta que el ejemplo siguiente no trata con el error de asignación de memoria. Se supone que se produce un nuevo lanzamiento (que puede ser una suposición deficiente en función del entorno en el que existe el código: los métodos COM del modelo de datos no pueden tener escape de excepciones de 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

El método GetDimensionality devuelve el número de dimensiones en las que se indiza el objeto. Tenga en cuenta que si el objeto es iterable e indizable, la implementación de GetDefaultIndexDimensionality debe estar de acuerdo con la implementación de GetDimensionality en cuanto al número de dimensiones que tiene el indexador.

GetAt

El método GetAt recupera el valor en un índice N dimensional determinado desde dentro del objeto indizado. Se debe admitir un indexador de N dimensiones en las que N es el valor devuelto de GetDimensionality. Tenga en cuenta que un objeto puede ser indexable en dominios diferentes por tipos diferentes (por ejemplo: indexable a través de ordinales y cadenas). Si el índice está fuera del intervalo (o no se pudo acceder), el método devolverá un error; sin embargo, en tales casos, el objeto de salida todavía se puede establecer en un objeto de error.

SetAt

El método SetAt intenta establecer el valor en un índice N dimensional determinado desde dentro del objeto indizado. Se debe admitir un indexador de N dimensiones en las que N es el valor devuelto de GetDimensionality. Tenga en cuenta que un objeto puede ser indexable en dominios diferentes por tipos diferentes (por ejemplo: indexable a través de ordinales y cadenas). Algunos indexadores son de solo lectura. En tales casos, E_NOTIMPL se devolverán desde cualquier llamada al método SetAt.

El concepto de tipo de tiempo de ejecución preferido: IPreferredRuntimeTypeConcept

Se puede consultar un host de depuración para intentar determinar el tipo en tiempo de ejecución real de un objeto de un tipo estático que se encuentra en información simbólica. Esta conversión puede basarse en información completamente precisa (por ejemplo: C++ RTTI) o puede basarse en heurística fuerte, como la forma de cualquier tabla de funciones virtuales dentro del objeto. Sin embargo, algunos objetos no se pueden convertir de un tipo estático a un tipo en tiempo de ejecución porque no caben en la heurística del host de depuración (por ejemplo, no tienen tablas de función virtual ni RTTI). En tales casos, un modelo de datos para un objeto puede optar por invalidar el comportamiento predeterminado y declarar que conoce más sobre el "tipo en tiempo de ejecución" de un objeto que el host de depuración es capaz de entender. Esto se realiza a través del concepto de tipo en tiempo de ejecución preferido y la compatibilidad de la interfaz IPreferredRuntimeTypeConcept.

La interfaz IPreferredRuntimeTypeConcept se declara de la siguiente manera:

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

CastToPreferredRuntimeType

Se llama al método CastToPreferredRuntimeType cada vez que un cliente desea intentar convertir de una instancia de tipo estático al tipo en tiempo de ejecución de esa instancia. Si el objeto en cuestión admite (a través de uno de sus modelos primarios adjuntos), se llamará a este método para realizar la conversión. Este método puede devolver el objeto original (no hay ninguna conversión o no se pudo analizar), devolver una nueva instancia del tipo en tiempo de ejecución, producir un error por motivos no semánticos (por ejemplo: memoria insuficiente) o devolver E_NOT_SET. El código de error de E_NOT_SET es un código de error muy especial que indica al modelo de datos que la implementación no desea invalidar el comportamiento predeterminado y que el modelo de datos debe revertir al análisis que realice el host de depuración (por ejemplo: análisis de RTTI, examen de la forma de las tablas de funciones virtuales, etc...)

Conceptos del proveedor dinámico: IDynamicKeyProviderConcept e IDynamicConceptProviderConcept

Aunque el propio modelo de datos normalmente controla la administración de conceptos y claves para objetos, hay ocasiones en las que esa noción es menor que ideal. En concreto, cuando un cliente desea crear un puente entre el modelo de datos y otra cosa que sea verdaderamente dinámica (por ejemplo: JavaScript), puede ser útil asumir la administración clave y de concepto de la implementación en el modelo de datos. Como el modelo de datos principal es la única implementación de IModelObject, esto se realiza en su lugar a través de una combinación de dos conceptos: el concepto de proveedor de claves dinámicos y el concepto de proveedor de conceptos dinámicos. Aunque sería habitual implementar ambas o ninguna, no hay ningún requisito para ello.

Si ambos se implementan, se debe agregar el concepto de proveedor de claves dinámicas antes del concepto de proveedor de concepto dinámico. Ambos conceptos son especiales. Invierten eficazmente un modificador en el objeto que lo cambia de "administrado estáticamente" a "administrado dinámicamente". Estos conceptos solo se pueden establecer si no hay claves o conceptos administrados por el modelo de datos en el objeto. Una vez agregados estos conceptos a un objeto, la acción de hacer esto es irreversible.

Hay una diferencia semántica adicional en torno a la extensibilidad entre un IModelObject, que es un proveedor de concepto dinámico y otro que no es. Estos conceptos están diseñados para permitir que los clientes creen puentes entre el modelo de datos y los sistemas de lenguaje dinámico, como JavaScript. El modelo de datos tiene un concepto de extensibilidad que difiere algo fundamentalmente de sistemas como JavaScript en que hay un árbol de modelos primarios en lugar de una cadena lineal como la cadena prototipo de JavaScript. Para permitir una mejor relación con estos sistemas, un IModelObject que es un proveedor de concepto dinámico tiene un único modelo de datos primario. Ese modelo de datos único primario es un IModelObject normal que puede tener un número arbitrario de modelos primarios, como es habitual para el modelo de datos. Las solicitudes al proveedor de conceptos dinámicos para agregar o quitar elementos primarios se redirigen automáticamente al único elemento primario. Desde la perspectiva de un exterior, parece que el proveedor de conceptos dinámicos tiene una cadena de estilo de árbol normal de los modelos primarios. El implementador del concepto de proveedor de conceptos dinámicos es el único objeto (fuera del modelo de datos principal) que es consciente del elemento primario único intermedio. Ese elemento primario único se puede vincular con el sistema de lenguaje dinámico para proporcionar un puente (por ejemplo: colocado en la cadena de prototipos de JavaScript).

El concepto de proveedor de claves dinámicas se define de la siguiente manera:

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

El concepto del proveedor de conceptos dinámicos se define de la siguiente manera:

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 de IDynamicKey

El método GetKey en un proveedor de claves dinámicas es en gran medida una invalidación del método GetKey en IModelObject. Se espera que el proveedor de claves dinámica devuelva el valor de la clave y los metadatos asociados a esa clave. En caso de que la clave no esté presente (pero no se produce ningún otro error), el proveedor debe devolver false en el parámetro hasKey y tener éxito con S_OK. Si se produce un error en esta llamada, se considera un error al capturar una clave y se detiene explícitamente la búsqueda de la clave a través de la cadena de modelos primaria. La devolución de false en hasKey y correcto continuará la búsqueda de la clave. Tenga en cuenta que es perfectamente legal que GetKey devuelva un descriptor de acceso de propiedad boxed como clave. Esto sería semánticamente idéntico al método GetKey en IModelObject que devuelve un descriptor de acceso de propiedad.

SetKeyProviderConcept de IDynamicKey

El método SetKey en un proveedor de claves dinámicas es eficazmente una invalidación del método SetKey en IModelObject. Esto establece una clave en el proveedor dinámico. Es efectivamente la creación de una nueva propiedad en el proveedor. Tenga en cuenta que un proveedor que no admite ninguna noción de algo parecido a la creación de propiedades expando debe devolver E_NOTIMPL aquí.

EnumerateKeyProviderConcept de IDynamicKey

El método EnumerateKeys en un proveedor de claves dinámicas es eficazmente una invalidación del método EnumerateKeys en IModelObject. Esto enumera todas las claves del proveedor dinámico. El enumerador devuelto tiene varias restricciones que la implementación debe respetar:

  • Debe comportarse como una llamada a EnumerateKeys y no a EnumerateKeyValues o EnumerateKeyReferences. Debe devolver los valores de clave que no resuelvan ningún descriptor de acceso de propiedad subyacente (si este concepto existe en el proveedor).
  • Desde la perspectiva de un único proveedor de claves dinámicas, no es válido enumerar varias claves del mismo nombre que son claves físicamente distintas. Esto puede ocurrir en distintos proveedores asociados a través de la cadena de modelos primarios, pero no puede ocurrir desde la perspectiva de un único proveedor.

IDynamicConceptProviderConcept's GetConcept

El método GetConcept en un proveedor de concepto dinámico es eficazmente una invalidación del método GetConcept en IModelObject. El proveedor de conceptos dinámicos debe devolver una interfaz para el concepto consultado si existe, así como los metadatos asociados a ese concepto. Si el concepto no existe en el proveedor, debe indicarse a través de un valor false que se devuelve en el argumento hasConcept y una devolución correcta. El error de este método es un error al capturar el concepto y detendrá explícitamente la búsqueda del concepto. La devolución de false para hasConcept y un código correcto continuará la búsqueda del concepto a través del árbol del modelo primario.

SetConcept de IDynamicConceptProviderConcept

El método SetConcept en un proveedor de concepto dinámico es eficazmente una invalidación del método SetConcept en IModelObject. El proveedor dinámico asignará el concepto. Esto puede hacer que el objeto sea iterable, indexable, convertible de cadena, etc. Tenga en cuenta que un proveedor que no permite la creación de conceptos en él debe devolver E_NOPTIMPL aquí.

NotifyParent de IDynamicConceptProviderConcept

El modelo de datos principal usa la llamada NotifyParent en un proveedor de concepto dinámico para informar al proveedor dinámico del modelo primario único que se crea para permitir el puente del paradigma "varios modelos primarios" del modelo de datos a lenguajes más dinámicos. Cualquier manipulación de ese modelo primario único provocará más notificaciones al proveedor dinámico. Tenga en cuenta que esta devolución de llamada se realiza inmediatamente después de la asignación del concepto del proveedor de conceptos dinámicos.

NotifyParentChange de IDynamicConceptProviderConcept

El método NotifyParent en un proveedor de concepto dinámico es una devolución de llamada realizada por el modelo de datos principal cuando se realiza una manipulación estática del modelo primario único del objeto. Para cualquier modelo primario determinado agregado, se llamará a este método una primera vez cuando se agregue dicho modelo primario y una segunda vez si se quita dicho modelo primario.

NotifyDestruct de IDynamicConceptProviderConcept

El método NotifyDestruct en un proveedor de concepto dinámico es una devolución de llamada realizada por el modelo de datos principal al principio de la destrucción del objeto que es un proveedor de concepto dinámico. Proporciona oportunidades de limpieza adicionales a los clientes que lo requieren.

--

Vea también

Este tema forma parte de una serie que describe las interfaces accesibles desde C++, cómo usarlas para crear una extensión de depurador basada en C++ y cómo usar otras construcciones de modelo de datos (por ejemplo: JavaScript o NatVis) desde una extensión de modelo de datos de C++.

Información general sobre el modelo de datos del depurador de C++

Interfaces de C++ del modelo de datos del depurador

Objetos C++ del modelo de datos del depurador

Interfaces adicionales del modelo de datos del depurador de C++

Conceptos de C++ del modelo de datos del depurador

Scripting del modelo de datos del depurador de C++