Conceptos del modelo de datos del depurador de C++
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 realmente dos elementos:
- Un diccionario de tuplas clave/valor/metadatos.
- Un conjunto de conceptos (interfaces) compatibles con 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. Aquí se enumeran los conjuntos de conceptos admitidos actualmente.
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 visualización. |
IIterableConcept | El objeto es un contenedor y se puede iterar. |
IIndexableConcept | El objeto es un contenedor y se puede indexar (al que se accede a través del acceso aleatorio) en una o varias dimensiones. |
IPreferredRuntimeTypeConcept | El objeto entiende más sobre los tipos derivados de él de lo que el sistema de tipos subyacente es capaz de proporcionar y desea controlar sus propias conversiones de tipo estático a tipo 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 primario. 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 primario. 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;
}
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 conecta automáticamente como modelo primario a cualquier objeto nativo cuyo tipo coincida con la firma pasada en el registro. En el punto en el que se realiza automáticamente esa conexión, se llama al método InitializeObject en el modelo de datos. Se le pasa el objeto de instancia, la firma de tipo que provocó la conexión 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.
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 (aquí debe devolverse el predeterminado o el mejor). Un modelo puede no tener nombre (siempre que no esté registrado con 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 de cadena mostrable 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;
}
Se llama al método ToDisplayString cuando 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 como base para una manipulación mediante programación adicional. La conversión de la cadena en sí puede estar profundamente influenciada por los metadatos pasados a la llamada. Una conversión de cadena debe hacer todo lo posible por respetar las claves PreferredRadix y PreferredFormat.
El concepto iterable: IIterableConcept e IModelIterator
Un objeto que es contenedor de otros objetos y desea expresar la capacidad de iterar sobre los objetos contenidos puede admitir el concepto iterable mediante una implementación de las interfaces IIterableConcept e IModelIterator. Existe una relación muy importante entre admitir el concepto iterable y admitir el concepto indexable. Un objeto que admite el acceso aleatorio a los objetos contenidos puede admitir el concepto indexable además del concepto iterable. En este caso, los elementos iterados también deben generar un índice predeterminado que, cuando se pasa al concepto indexable, hacen referencia al mismo objeto. Si no se satisface esta invariante, se producirá un comportamiento indefinido en el host de depuración.
El concepto 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 indexable, este método debe devolver 0 y correcto (S_OK). Cualquier objeto que devuelva un valor distinto de cero con este método declara la compatibilidad con un contrato de protocolo que indica:
- El objeto admite el concepto indexable mediante la compatibilidad de IIndexableConcept
- El método GetNext del IModelIterator devuelto por 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 los índices devueltos desde el método GetNext de IModelIterator al método GetAt en el concepto indexable (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.
Reset de IModelIterator
El método Reset en un iterador devuelto desde el concepto iterable restaurará la posición del iterador a donde estaba cuando el iterador se creó por primera vez (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 a un iterador de entrada de C++ y solo permitir una única pasada 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 indexable además de iterable y así lo indica el argumento GetDefaultIndexDimensionality devolviendo un valor distinto de cero, este método puede devolver opcionalmente los índices por defecto para volver al valor generado desde el indexador. Tenga en cuenta que un llamador puede optar por pasar 0/nullptr y no recuperar ningún índice. Se considera ilegal que llamador solicite índices parciales (por ejemplo: menor que el número generado por GetDefaultIndexDimensionality).
Si el iterador se ha avanzado correctamente, pero se ha producido un error al leer el valor del elemento iterado, el método puede devolver un error Y rellenar el "objeto" con un objeto de error. Al final de la iteración de los elementos contenidos, el iterador devolverá E_BOUNDS del método GetNext. Cualquier llamada posterior (a menos que haya habido una llamada Reset intermedia) también devolverá E_BOUNDS.
El concepto indexable: IIndexableConcept
Un objeto que desea proporcionar acceso aleatorio a un conjunto de contenido puede admitir el concepto indexable a través de la compatibilidad con la interfaz IIndexableConcept. La mayoría de los objetos que son indexables también serán iterables a través de la compatibilidad del concepto iterable. No obstante, 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 de indexador se define de la manera siguiente:
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 de cómo usar el indexador (y su interacción con el iterador). En este ejemplo se itera el contenido de un contenedor indexable y se usa el indexador para volver al valor que se acaba de devolver. Aunque esa operación es funcionalmente inútil tal y como está escrita, demuestra cómo interactúan estas interfaces. Tenga en cuenta que el ejemplo siguiente no trata el error de asignación de memoria. Se asume un nuevo lanzamiento (que podría ser una suposición deficiente dependiendo del entorno en el que existe el código, los métodos COM del modelo de datos no pueden tener excepciones de escape 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 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.
//
}
}
}
}
El método GetDimensionality devuelve el número de dimensiones en las que se indexa el objeto. Tenga en cuenta que si el objeto es iterable e indexable, la implementación de GetDefaultIndexDimensionality debe estar de acuerdo con la implementación de GetDimensionality en cuanto a cuántas dimensiones tiene el indexador.
El método GetAt recupera el valor en un índice N dimensional determinado desde dentro del objeto indexado. Se debe admitir un indexador de N dimensiones, donde 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 puede acceder a él), 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.
El método SetAt intenta establecer el valor en un índice N dimensional determinado desde dentro del objeto indexado. Se debe admitir un indexador de N dimensiones, donde 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, se devolverá E_NOTIMPL 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: RTTI de C++) o puede basarse en heurística sólida, 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 funciones RTTI ni virtuales). En tales casos, un modelo de datos para un objeto puede optar por invalidar el comportamiento predeterminado y declarar que sabe más sobre el "tipo en tiempo de ejecución" de un objeto de lo que el host de depuración es capaz de comprender. Esto se hace a través del concepto de tipo en tiempo de ejecución preferido y la compatibilidad con 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;
}
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 el concepto de tipo en tiempo de ejecución preferido (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 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 RTTI, examen de la forma de las tablas de funciones virtuales, etc.
Los conceptos del proveedor dinámico: IDynamicKeyProviderConcept e IDynamicConceptProviderConcept
Aunque el modelo de datos en sí normalmente controla la administración de claves y conceptos para los objetos, hay ocasiones en las que esa noción es menor que la 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 de claves y conceptos 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 a través de una combinación de dos conceptos: el concepto de proveedor de claves dinámicas y el concepto de proveedor de conceptos dinámicos. Aunque sería habitual implementar ambos o ninguno de ellos, no hay ningún requisito para ello.
Si se implementan ambos, se debe agregar el concepto de proveedor de claves dinámicas antes del concepto de proveedor de conceptos dinámicos. 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 hacerlo es irreversible.
Hay una diferencia semántica adicional en torno a la extensibilidad entre un IModelObject, que es un proveedor de conceptos dinámicos y otro que no lo es. Estos conceptos están pensados 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 primario en lugar de una cadena lineal, como la cadena de prototipos de JavaScript. Para permitir una mejor relación con estos sistemas, un IModelObject que es un proveedor de conceptos dinámicos 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 elemento primario único. Desde una perspectiva externa, parece como si el proveedor de conceptos dinámicos tuviera una cadena normal de modelos primarios al estilo de un árbol. 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 de 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;
}
GetKey de IDynamicKeyProviderConcept
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ámicas 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 ser correcto 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. Si se devuelve 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 de conversión boxing como clave. Esto sería semánticamente idéntico al método GetKey en IModelObject, que devuelve un descriptor de acceso de propiedad.
SetKey de IDynamicKeyProviderConcept
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 como la creación de propiedades expando debe devolver E_NOTIMPL aquí.
EnumerateKeys de IDynamicKeyProviderConcept
El método EnumerateKeys en un proveedor de claves dinámicas es efectivamente una invalidación del método EnumerateKeys en IModelObject. 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 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 que se conectan a través de la cadena de modelos primarios, pero no puede ocurrir desde la perspectiva de un único proveedor.
GetConcept de IDynamicConceptProviderConcept
El método GetConcept en un proveedor de concepto dinámico es efectivamente una invalidación del método GetConcept en IModelObject. El proveedor de concepto dinámico 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. Devolver 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 efectivamente 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, cadena convertible, 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 conceptos dinámicos para informar al proveedor dinámico del modelo primario único que se crea para permitir el puente del paradigma de "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 tras la asignación del concepto de proveedor de conceptos dinámicos.
NotifyParentChange de IDynamicConceptProviderConcept
El método NotifyParent en un proveedor de conceptos dinámicos 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, este método se llamará una primera vez cuando se agregue dicho modelo primario y una segunda vez si se quita dicho modelo primario o cuando se quita dicho modelo primario.
NotifyDestruct de IDynamicConceptProviderConcept
El método NotifyDestruct en un proveedor de conceptos dinámicos 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 conceptos dinámicos. 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 compilar 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 del modelo de datos del depurador de C++
Objetos C++ del modelo de datos del depurador
Interfaces adicionales del modelo de datos del depurador de C++