Classe CComObjectRootEx

Essa classe fornece métodos para lidar com o gerenciamento de contagem de referência de objeto para objetos não agregados e agregados.

Sintaxe

template<class ThreadModel>
class CComObjectRootEx : public CComObjectRootBase

Parâmetros

ThreadModel
A classe cujos métodos implementam o modelo de threading desejado. Você pode escolher explicitamente o modelo de threading definindo ThreadModel como CComSingleThreadModel, CComMultiThreadModel ou CComMultiThreadModelNoCS. Você pode aceitar o modelo de thread padrão do servidor ao definir ThreadModel como CComObjectThreadModel ou CComGlobalsThreadModel.

Membros

Métodos

Função Descrição
CComObjectRootEx Construtor.
InternalAddRef Incrementa a contagem de referência para um objeto não agregado.
InternalRelease Diminui a contagem de referência para um objeto não agregado.
Lock Se o modelo de thread for multithread, obterá a propriedade de um objeto de seção crítico.
Unlock Se o modelo de thread for multithread, liberará a propriedade de um objeto de seção crítico.

Métodos CComObjectRootBase

Função Descrição
FinalConstruct Substitua em sua classe para executar qualquer inicialização exigida pelo objeto.
FinalRelease Substitua em sua classe para executar qualquer limpeza exigida pelo objeto.
OuterAddRef Incrementa a contagem de referência para um objeto agregado.
OuterQueryInterface Delega para o exterior IUnknown de um objeto agregado.
OuterRelease Diminui a contagem de referência para um objeto agregado.

Funções estáticas

Função Descrição
InternalQueryInterface Delega para o IUnknown de um objeto não agregado.
ObjectMain Chamado durante a inicialização e o encerramento do módulo para classes derivadas listadas no mapa do objeto.

Membros de dados

Membro de dados Descrição
m_dwRef Com m_pOuterUnknown, parte de uma união. Usado quando o objeto não é agregado para manter a contagem de referência de AddRefe Release.
m_pOuterUnknown Com m_dwRef, parte de uma união. Usado quando o objeto é agregado para manter um ponteiro para o desconhecido externo.

Comentários

O CComObjectRootEx manipula o gerenciamento de contagem de referências de objeto para objetos não agregados e agregados. Ele manterá a contagem de referência de objetos se o objeto não estiver sendo agregado e manterá o ponteiro para o desconhecido externo se o objeto estiver sendo agregado. Para objetos agregados, os métodos CComObjectRootEx podem ser usados para lidar com a falha do objeto interno a ser construído e para proteger o objeto externo da exclusão quando interfaces internas são liberadas ou o objeto interno é excluído.

Uma classe que implementa um servidor COM deve herdar de CComObjectRootEx ou CComObjectRoot.

Se a definição de classe especificar a macro DECLARE_POLY_AGGREGATABLE , a ATL criará uma instância de CComPolyObject<CYourClass> quando IClassFactory::CreateInstance é chamada. Durante a criação, o valor do desconhecido externo é verificado. Se for NULL, IUnknown será implementado para um objeto não agregado. Se o desconhecido externo não for NULL, IUnknown será implementado para um objeto agregado.

Se sua classe não especificar a macro DECLARE_POLY_AGGREGATABLE, a ATL criará uma instância para CAggComObject<CYourClass> objetos agregados ou uma instância de CComObject<CYourClass> objetos não agregados.

A vantagem de usar CComPolyObject é que você evita ter ambos CComAggObject e CComObject em seu módulo para lidar com os casos agregados e não agregados. Um único objeto CComPolyObject manipula os dois casos. Portanto, existe apenas uma cópia da vtable e uma cópia das funções em seu módulo. Se a vtable for grande, isso poderá diminuir substancialmente o tamanho do módulo. No entanto, se a vtable for pequena, usar CComPolyObject poderá resultar em um tamanho de módulo um pouco maior porque ele não é otimizado para um objeto agregado ou não agregado, como são CComAggObject e CComObject.

Se o objeto for agregado, IUnknown será implementado por CComAggObject ou CComPolyObject. Essas classes delegam QueryInterface, AddRefe Release chamadas para CComObjectRootEx's OuterQueryInterface, OuterAddRefe OuterRelease para encaminhar para o desconhecido externo. Normalmente, você substitui CComObjectRootEx::FinalConstruct em sua classe para criar quaisquer objetos agregados e substituir CComObjectRootEx::FinalRelease para liberar quaisquer objetos agregados.

Se o objeto não for agregado, IUnknown será implementado por CComObject ou CComPolyObject. Nesse caso, chamadas para QueryInterface, AddRefe Release são delegadas a CComObjectRootEx's InternalQueryInterface, InternalAddRefe InternalRelease para executar as operações reais.

Requisitos

Cabeçalho: atlcom.h

CComObjectRootEx::CComObjectRootEx

O construtor inicializa a contagem de referência como 0.

CComObjectRootEx();

CComObjectRootEx::FinalConstruct

Você pode substituir esse método em sua classe derivada para executar qualquer inicialização necessária para o objeto.

HRESULT FinalConstruct();

Valor de retorno

Retorna S_OK com êxito ou um dos valores HRESULT de erro padrão.

Comentários

Por padrão, CComObjectRootEx::FinalConstruct simplesmente retorna S_OK.

Há vantagens em executar a inicialização em FinalConstruct vez do construtor da classe:

  • Você não pode retornar um código de status de um construtor, mas pode retornar um HRESULT por meio do valor retornado de FinalConstruct. Quando objetos de sua classe estão sendo criados usando a fábrica de classes padrão fornecida pela ATL, esse valor retornado é propagado de volta para o cliente COM, permitindo que você forneça a eles informações detalhadas de erro.

  • Você não pode chamar funções virtuais por meio do mecanismo de função virtual do construtor de uma classe. Chamar uma função virtual do construtor de uma classe resulta em uma chamada estaticamente resolvida para a função, pois ela é definida nesse ponto na hierarquia de herança. Chamadas para funções virtuais puras resultam em erros do vinculador.

    Sua classe não é a classe mais derivada na hierarquia de herança: ela depende de uma classe derivada fornecida pela ATL para fornecer algumas de suas funcionalidades. Há uma boa chance de que sua inicialização precise usar os recursos fornecidos por essa classe (isso certamente é verdade quando objetos da sua classe precisam agregar outros objetos), mas o construtor em sua classe não tem como acessar esses recursos. O código de construção da classe é executado antes que a classe mais derivada seja totalmente construída.

    No entanto, FinalConstruct é chamado imediatamente depois que a classe mais derivada é totalmente construída, permitindo que você chame funções virtuais e use a implementação de contagem de referências fornecida pela ATL.

Exemplo

Normalmente, substitua esse método na classe derivada para CComObjectRootEx criar objetos agregados. Por exemplo:

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.

Se a construção falhar, você poderá retornar um erro. Você também pode usar a macro DECLARE_PROTECT_FINAL_CONSTRUCT para proteger seu objeto externo de ser excluído se, durante a criação, o objeto agregado interno incrementar a contagem de referência e, em seguida, diminuir a contagem para 0.

Aqui está uma maneira típica de criar uma agregação:

  • Adicione um IUnknown ponteiro ao objeto de classe e inicialize-o para NULL no construtor.

  • Substitua FinalConstruct para criar a agregação.

  • Use o ponteiro IUnknown, definido na Etapa 1, como o segundo parâmetro para as macros COM_INTERFACE_ENTRY_AGGREGATE.

  • Substitua FinalRelease para liberar o ponteiro IUnknown.

CComObjectRootEx::FinalRelease

Você pode substituir esse método em sua classe derivada para executar qualquer limpeza necessária para seu objeto.

void FinalRelease();

Comentários

Por padrão, CComObjectRootEx::FinalRelease não faz nada.

Executar a limpeza é FinalRelease preferível a adição de código ao destruidor de sua classe, pois o objeto ainda é totalmente construído no ponto em que FinalRelease é chamado. Isso permite que você acesse com segurança os métodos fornecidos pela classe mais derivada. Isso é particularmente importante para liberar objetos agregados antes da exclusão.

CComObjectRootEx::InternalAddRef

Incrementa a contagem de referência de um objeto não agregado por 1.

ULONG InternalAddRef();

Valor de retorno

Um valor que pode ser útil para diagnóstico e teste.

Comentários

Se o modelo de thread for multithread, InterlockedIncrement será usado para impedir que mais de um thread altere a contagem de referência ao mesmo tempo.

CComObjectRootEx::InternalQueryInterface

Recupera um ponteiro para a interface solicitada.

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

Parâmetros

pThis
[in] Um ponteiro para o objeto que contém o mapa COM de interfaces expostas a QueryInterface.

pEntries
[in] Um ponteiro para a _ATL_INTMAP_ENTRY estrutura que acessa um mapa de interfaces disponíveis.

iid
[in] O GUID da interface que está sendo solicitado.

ppvObject
[out] Um ponteiro para o ponteiro de interface especificado em iid ou NULL se a interface não for encontrada.

Valor de retorno

Um dos valores HRESULT padrão.

Comentários

InternalQueryInterface somente lida com interfaces na tabela de mapa COM. Se o objeto for agregado, InternalQueryInterface não delegará ao desconhecido externo. Você pode inserir interfaces na tabela de mapa COM com a macro COM_INTERFACE_ENTRY ou uma de suas variantes.

CComObjectRootEx::InternalRelease

Diminui a contagem de referência de um objeto não agregado por 1.

ULONG InternalRelease();

Valor de retorno

Em builds de não depuração e depuração, essa função retorna um valor que pode ser útil para diagnósticos ou testes. O valor exato retornado depende de muitos fatores, como o sistema operacional usado e pode, ou não, ser a contagem de referência.

Comentários

Se o modelo de thread for multithread, InterlockedDecrement será usado para impedir que mais de um thread altere a contagem de referência ao mesmo tempo.

CComObjectRootEx::Lock

Se o modelo de thread for multithread, esse método chamará a função de API do Win32 EnterCriticalSection, que aguarda até que o thread possa assumir a propriedade do objeto de seção crítico obtido por meio de um membro de dados privado.

void Lock();

Comentários

Quando o código protegido terminar de ser executado, o thread deverá chamar Unlock para liberar a propriedade da seção crítica.

Se o modelo de thread for de thread único, esse método não fará nada.

CComObjectRootEx::m_dwRef

Parte de uma união que acessa quatro bytes de memória.

long m_dwRef;

Comentários

Com m_pOuterUnknown, parte de uma união:

union {
    long m_dwRef;
    IUnknown* m_pOuterUnknown;
};

Se o objeto não for agregado, a contagem de referências será acessada por AddRef e Release armazenada em m_dwRef. Se o objeto for agregado, o ponteiro para o desconhecido externo será armazenado em m_pOuterUnknown.

CComObjectRootEx::m_pOuterUnknown

Parte de uma união que acessa quatro bytes de memória.

IUnknown*
    m_pOuterUnknown;

Comentários

Com m_dwRef, parte de uma união:

union {
    long m_dwRef;
    IUnknown* m_pOuterUnknown;
};

Se o objeto for agregado, o ponteiro para o desconhecido externo será armazenado em m_pOuterUnknown. Se o objeto não for agregado, a contagem de referências será acessada AddRef e Release armazenada em m_dwRef.

CComObjectRootEx::ObjectMain

Para cada classe listada no mapa do objeto, essa função é chamada uma vez quando o módulo é inicializado e outra vez quando é encerrado.

static void WINAPI ObjectMain(bool bStarting);

Parâmetros

bStarting
[out] O valor será TRUE se a classe estiver sendo inicializada; caso contrário, FALSE.

Comentários

O valor do parâmetro bStarting indica se o módulo está sendo inicializado ou encerrado. A implementação padrão não ObjectMain faz nada, mas você pode substituir essa função em sua classe para inicializar ou limpar os recursos que deseja alocar para a classe. Observe que é chamado antes de ObjectMain qualquer instância da classe ser solicitada.

ObjectMain é chamado do ponto de entrada da DLL, portanto, o tipo de operação que a função de ponto de entrada pode executar é restrito. Para obter mais informações sobre essas restrições, confira DLLs e comportamento de biblioteca de tempo de execução do Visual C++ e DllMain.

Exemplo

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 a contagem de referência do desconhecido externo de uma agregação.

ULONG OuterAddRef();

Valor de retorno

Um valor que pode ser útil para diagnóstico e teste.

CComObjectRootEx::OuterQueryInterface

Recupera um ponteiro indireto para a interface solicitada.

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

Parâmetros

iid
[in] O GUID da interface que está sendo solicitado.

ppvObject
[out] Um ponteiro para o ponteiro de interface especificado em iid ou NULL se a agregação não oferecer suporte à interface.

Valor de retorno

Um dos valores HRESULT padrão.

CComObjectRootEx::OuterRelease

Decrementa a contagem de referência do desconhecido externo de uma agregação.

ULONG OuterRelease();

Valor de retorno

Em builds que não sejam de depuração, sempre retorna 0. Em builds de depuração, retorna um valor que pode ser útil para diagnóstico ou teste.

CComObjectRootEx::Unlock

Se o modelo de thread for multithread, esse método chamará a função de API do Win32 LeaveCriticalSection, que libera a propriedade do objeto de seção crítico obtido por meio de um membro de dados privado.

void Unlock();

Comentários

Para obter a propriedade, o thread deve chamar Lock. Cada chamada de Lock exige uma chamada correspondente de Unlock para liberar a propriedade da seção crítica.

Se o modelo de thread for de thread único, esse método não fará nada.

Confira também

Classe CComAggObject
Classe CComObject
Classe CComPolyObject
Visão geral da aula