Compartir por


Clase CComObjectRootEx

Esta clase proporciona métodos para controlar la administración del recuento de referencias de objetos para objetos no agregados y agregados.

Sintaxis

template<class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase

Parámetros

ThreadModel
Clase cuyos métodos implementan el modelo de subprocesos deseado. Puede elegir explícitamente el modelo de subprocesos estableciendo ThreadModel en CComSingleThreadModel, CComMultiThreadModel o CComMultiThreadModelNoCS. Puede aceptar el modelo de subprocesos predeterminado del servidor estableciendo ThreadModel en CComObjectThreadModel o CComGlobalsThreadModel.

Miembros

Métodos

Función Descripción
CComObjectRootEx Constructor.
InternalAddRef Incrementa el recuento de referencias de un objeto no agregado.
InternalRelease Disminuye el recuento de referencias de un objeto no agregado.
Bloquear Si el modelo de subprocesos es multiproceso, obtiene la propiedad de un objeto de sección crítica.
Unlock Si el modelo de subprocesos es multiproceso, libera la propiedad de un objeto de sección crítica.

Métodos de CComObjectRootBase

Función Descripción
FinalConstruct Invalide el método en la clase para realizar cualquier inicialización requerida por el objeto.
FinalRelease Invalide el método en la clase para realizar cualquier limpieza requerida por el objeto.
OuterAddRef Incrementa el recuento de referencias de un objeto agregado.
OuterQueryInterface Delega en el elemento IUnknown exterior de un objeto agregado.
OuterRelease Disminuye el recuento de referencias de un objeto agregado.

Funciones estáticas

Función Descripción
InternalQueryInterface Delega al objeto IUnknown de un objeto no agregado.
ObjectMain Se le llama durante la inicialización y finalización del módulo para las clases derivadas enumeradas en el mapa de objetos.

Miembros de datos

Miembro de datos Descripción
m_dwRef Con m_pOuterUnknown, parte de una unión. Se usa cuando el objeto no está agregado para contener el recuento de referencias de AddRef y Release.
m_pOuterUnknown Con m_dwRef, parte de una unión. Se usa cuando el objeto está agregado para contener un puntero al elemento desconocido externo.

Comentarios

CComObjectRootEx controla la administración del recuento de referencias de objetos para objetos no agregados y agregados. Contiene el recuento de referencias de objetos si el objeto no está agregado y contiene el puntero al elemento desconocido externo si el objeto está agregado. En el caso de los objetos agregados, los métodos CComObjectRootEx se pueden usar para controlar el error del objeto interno que se va a construir y para proteger el objeto externo frente a la eliminación cuando se liberan interfaces internas o se elimina el objeto interno.

Una clase que implementa un servidor COM debe heredar de CComObjectRootEx o CComObjectRoot.

Si la definición de clase especifica la macro DECLARE_POLY_AGGREGATABLE, ATL crea una instancia de CComPolyObject<CYourClass> cuando se llama a IClassFactory::CreateInstance. Durante la creación, se comprueba el valor del elemento desconocido externo. Si es null, IUnknown se implementa para un objeto no agregado. Si el desconocido externo no es null, IUnknown se implementa para un objeto agregado.

Si la clase no especifica la macro DECLARE_POLY_AGGREGATABLE, ATL crea una instancia de CAggComObject<CYourClass> para objetos agregados o una instancia de CComObject<CYourClass> para objetos no agregados.

La ventaja de usar CComPolyObject es que evita tener tanto CComAggObject como CComObject en el módulo para controlar los casos agregados y no agregados. Un solo objeto CComPolyObject controla ambos casos. Por lo tanto, solo existe una copia de la tabla virtual y una copia de las funciones en el módulo. Si la tabla virtual es grande, esto puede reducir considerablemente el tamaño del módulo. Pero si la tabla virtual es pequeña, el uso de CComPolyObject puede dar lugar a un tamaño de módulo ligeramente mayor porque no está optimizado para un objeto agregado o no agregado, como sí lo están CComAggObject y CComObject.

Si el objeto está agregado, IUnknown se implementa mediante CComAggObject o CComPolyObject. Estas clases delegan las llamadas a QueryInterface, AddRef y Release a OuterQueryInterface, OuterAddRef y OuterRelease del elemento CComObjectRootEx para su reenvío al elemento desconocido externo. Normalmente, se invalida CComObjectRootEx::FinalConstruct en la clase para crear cualquier objeto agregado y se invalida CComObjectRootEx::FinalRelease para liberar los objetos agregados.

Si el objeto no está agregado, IUnknown se implementa mediante CComObject o CComPolyObject. En este caso, las llamadas a QueryInterface, AddRef y Release se delegan en InternalQueryInterface, InternalAddRef y InternalRelease de CComObjectRootEx para llevar a cabo las operaciones reales.

Requisitos

Encabezado: atlcom.h

CComObjectRootEx::CComObjectRootEx

El constructor inicializa el recuento de referencias en 0.

CComObjectRootEx();

CComObjectRootEx::FinalConstruct

Puede invalidar este método en la clase derivada para realizar cualquier inicialización necesaria para el objeto.

HRESULT FinalConstruct();

Valor devuelto

Devuelve S_OK si se ejecuta correctamente o uno de los valores HRESULT de error estándar.

Comentarios

De manera predeterminada, CComObjectRootEx::FinalConstruct simplemente devuelve S_OK.

Hay ventajas al realizar la inicialización en FinalConstruct en lugar de en el constructor de la clase:

  • No puede devolver un código de estado desde un constructor, pero puede devolver un valor HRESULT mediante el valor devuelto de FinalConstruct. Cuando se crean objetos de la clase mediante el generador de clases estándar proporcionado por ATL, este valor devuelto se propaga de vuelta al cliente COM, lo que le permite proporcionarle información detallada del error.

  • No puede llamar a funciones virtuales mediante el mecanismo de función virtual desde el constructor de una clase. Llamar a una función virtual desde el constructor de una clase da como resultado una llamada resuelta estáticamente a la función tal como se define en ese punto en la jerarquía de herencia. Las llamadas a funciones virtuales puras producen errores del enlazador.

    La clase no es la clase más derivada de la jerarquía de herencia: se basa en una clase derivada proporcionada por ATL para proporcionar parte de su funcionalidad. Existe una buena posibilidad de que la inicialización tenga que usar las características proporcionadas por esa clase (esto es especialmente cierto cuando los objetos de la clase tienen que agregar otros objetos), pero el constructor de la clase no tiene forma de acceder a esas características. El código de construcción de la clase se ejecuta antes de que se construya completamente la clase más derivada.

    Sin embargo, se llama a FinalConstruct inmediatamente después de que la clase más derivada esté totalmente construida, lo que le permite llamar a funciones virtuales y usar la implementación de recuento de referencias proporcionada por ATL.

Ejemplo

Normalmente, se invalida este método en la clase derivada de CComObjectRootEx para crear cualquier objeto agregado. Por ejemplo:

class ATL_NO_VTABLE CMyAggObject :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CMyAggObject, &CLSID_MyAggObject>,
   public IDispatchImpl<IMyAggObject, &IID_IMyAggObject, &LIBID_NVC_ATL_COMLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
public:
   DECLARE_GET_CONTROLLING_UNKNOWN()
   HRESULT FinalConstruct()
   {
      return CoCreateInstance(CLSID_MyCustomClass, GetControllingUnknown(), 
         CLSCTX_ALL, IID_IUnknown, (void**)&m_pMyCustomClass);
   }

   IMyCustomClass* m_pMyCustomClass;

   // Remainder of class declaration omitted.

Si se produce un error en la construcción, puede devolver un error. También puede usar la macro DECLARE_PROTECT_FINAL_CONSTRUCT para proteger la eliminación del objeto externo si, durante la creación, el objeto agregado interno incrementa el recuento de referencias y, después, disminuye el recuento a 0.

Esta es una manera típica de crear un agregado:

  • Agregue un puntero IUnknown al objeto de clase e inicialícelo en NULL en el constructor.

  • Invalide FinalConstruct para crear el agregado.

  • Use el puntero IUnknown que definió como parámetro para la macro COM_INTERFACE_ENTRY_AGGREGATE.

  • Invalide FinalRelease para liberar el puntero IUnknown.

CComObjectRootEx::FinalRelease

Puede invalidar este método en la clase derivada para realizar cualquier limpieza necesaria para el objeto.

void FinalRelease();

Comentarios

De manera predeterminada, CComObjectRootEx::FinalRelease no hace nada.

Es preferible realizar la limpieza en FinalRelease para agregar código al destructor de la clase, ya que el objeto todavía está totalmente construido en el punto en el que se llama a FinalRelease. Esto le permite acceder de forma segura a los métodos proporcionados por la clase más derivada. Esto es especialmente importante para liberar los objetos agregados antes de la eliminación.

CComObjectRootEx::InternalAddRef

Incrementa en 1 el recuento de referencias de un objeto no agregado.

ULONG InternalAddRef();

Valor devuelto

Valor que puede ser útil para los diagnósticos y las pruebas.

Comentarios

Si el modelo de subprocesos es multiproceso, se usa InterlockedIncrement para evitar que más de un subproceso cambie el recuento de referencias al mismo tiempo.

CComObjectRootEx::InternalQueryInterface

Recupera un puntero a la interfaz solicitada.

static HRESULT InternalQueryInterface(
    void* pThis,
    const _ATL_INTMAP_ENTRY* pEntries,
    REFIID iid,
    void** ppvObject);

Parámetros

pThis
[in] Puntero al objeto que contiene el mapa COM de interfaces expuestas a QueryInterface.

pEntries
[in] Puntero a la estructura _ATL_INTMAP_ENTRY que accede a un mapa de interfaces disponibles.

iid
[in] GUID de la interfaz que se solicita.

ppvObject
[out] Puntero al puntero de interfaz especificado en iid o NULL si no se encuentra la interfaz.

Valor devuelto

Uno de los valores HRESULT estándar.

Comentarios

InternalQueryInterface solo administra interfaces de la tabla de asignación COM. Si el objeto se agrega, InternalQueryInterface no delega al desconocido externo. Para especificar interfaces en la tabla de asignación COM, puede usar la macro COM_INTERFACE_ENTRY o cualquiera de sus variantes.

CComObjectRootEx::InternalRelease

Disminuye en 1 el recuento de referencias de un objeto no agregado.

ULONG InternalRelease();

Valor devuelto

En las compilaciones de depuración y las que no son de depuración, esta función devuelve un valor que puede ser útil para diagnósticos o pruebas. El valor devuelto exacto depende de muchos factores, como el sistema operativo utilizado y, tal vez, el recuento de referencias.

Comentarios

Si el modelo de subprocesos es multiproceso, se usa InterlockedDecrement para evitar que más de un subproceso cambie el recuento de referencias al mismo tiempo.

CComObjectRootEx::Lock

Si el modelo de subprocesos es multiproceso, este método llama a la función EnterCriticalSection de la API de Win32, que espera hasta que el subproceso pueda tomar la propiedad del objeto de sección crítica obtenido mediante un miembro de datos privado.

void Lock();

Comentarios

Cuando el código protegido termine de ejecutarse, el subproceso debe llamar a Unlock para liberar la propiedad de la sección crítica.

Si el modelo de subprocesos es de un solo subproceso, este método no hace nada.

CComObjectRootEx::m_dwRef

Parte de una unión que tiene acceso a cuatro bytes de memoria.

long m_dwRef;

Comentarios

Con m_pOuterUnknown, parte de una unión:

union {
    long m_dwRef;
    IUnknown* m_pOuterUnknown;
};

Si el objeto no está agregado, el recuento de referencias al que acceden AddRef y Release se almacena en m_dwRef. Si el objeto está agregado, el puntero al elemento exterior desconocido se almacena en m_pOuterUnknown.

CComObjectRootEx::m_pOuterUnknown

Parte de una unión que tiene acceso a cuatro bytes de memoria.

IUnknown*
    m_pOuterUnknown;

Comentarios

Con m_dwRef, parte de una unión:

union {
    long m_dwRef;
    IUnknown* m_pOuterUnknown;
};

Si el objeto está agregado, el puntero al elemento exterior desconocido se almacena en m_pOuterUnknown. Si el objeto no está agregado, el recuento de referencias al que acceden AddRef y Release se almacena en m_dwRef.

CComObjectRootEx::ObjectMain

Para cada clase enumerada en el mapa de objetos, se llama a esta función una vez cuando se inicializa el módulo y, de nuevo, cuando finaliza.

static void WINAPI ObjectMain(bool bStarting);

Parámetros

bStarting
[out] El valor es TRUE si la clase se está inicializando; en caso contrario, FALSE.

Comentarios

El valor del parámetro bStarting indica si el módulo se está inicializando o finalizando. La implementación predeterminada de ObjectMain no hace nada, pero puede invalidar esta función en la clase para inicializar o limpiar los recursos que desea asignar para la clase. Tenga en cuenta que se llama a ObjectMain antes de que se soliciten instancias de la clase.

Se llama a ObjectMain desde el punto de entrada de la biblioteca de vínculos dinámicos, por lo que el tipo de operación que la función de punto de entrada puede realizar está restringida. Para obtener más información sobre estas restricciones, consulte Archivos DLL y comportamiento de la biblioteca en tiempo de ejecución de Visual C++ y Punto de entrada de DllMain.

Ejemplo

class ATL_NO_VTABLE CMyApp :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CMyApp, &CLSID_MyApp>,
   public IMyApp
{
public:
   CMyApp()
   {
   }

   static void WINAPI ObjectMain(bool bStarting)
   {
      if (bStarting)
         ;// Perform custom initialization routines
      else
         ;// Perform custom termination routines
   }

   // Remainder of class declaration omitted.

CComObjectRootEx::OuterAddRef

Incrementa el recuento de referencias del elemento desconocido externo de una agregación.

ULONG OuterAddRef();

Valor devuelto

Valor que puede ser útil para los diagnósticos y las pruebas.

CComObjectRootEx::OuterQueryInterface

Recupera un puntero indirecto a la interfaz solicitada.

HRESULT OuterQueryInterface(REFIID iid, void** ppvObject);

Parámetros

iid
[in] GUID de la interfaz que se solicita.

ppvObject
[out] Puntero al puntero de interfaz especificado en iid o NULL si la agregación no admite la interfaz.

Valor devuelto

Uno de los valores HRESULT estándar.

CComObjectRootEx::OuterRelease

Disminuye el recuento de referencias del elemento desconocido externo de una agregación.

ULONG OuterRelease();

Valor devuelto

En compilaciones que no son de depuración, siempre devuelve 0. En las compilaciones de depuración, devuelve un valor que puede ser útil para los diagnósticos o las pruebas.

CComObjectRootEx::Unlock

Si el modelo de subprocesos es multiproceso, este método llama a la función LeaveCriticalSection de la API de Win32, que libera la propiedad del objeto de sección crítica obtenido mediante un miembro de datos privado.

void Unlock();

Comentarios

Para obtener la propiedad, el subproceso debe llamar a Lock. Cada llamada a Lock requiere una llamada correspondiente a Unlock para liberar la propiedad de la sección crítica.

Si el modelo de subprocesos es de un solo subproceso, este método no hace nada.

Consulte también

CComAggObject (clase)
CComObject (clase)
CComPolyObject (clase)
Información general sobre la clase