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 AddRef e 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
, AddRef
e Release
chamadas para CComObjectRootEx
's OuterQueryInterface
, OuterAddRef
e 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
, AddRef
e Release
são delegadas a CComObjectRootEx
's InternalQueryInterface
, InternalAddRef
e 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 ponteiroIUnknown
.
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