Partilhar via


Criando um objeto em COM

Depois que um thread inicializa a biblioteca COM, é seguro que o thread use interfaces COM. Para usar uma interface COM, seu programa primeiro cria uma instância de um objeto que implementa essa interface.

Em geral, há duas maneiras de criar um objeto COM:

  • O módulo que implementa o objeto pode fornecer uma função especificamente projetada para criar instâncias desse objeto.
  • Como alternativa, o COM fornece uma função de criação genérica chamada CoCreateInstance.

Por exemplo, use o objeto hipotético Shape do tópico O que é uma interface COM?. Nesse exemplo, o Shape objeto implementa uma interface chamada IDrawable. A biblioteca de gráficos que implementa o Shape objeto pode exportar uma função com a assinatura a seguir.

// Not an actual Windows function. 

HRESULT CreateShape(IDrawable** ppShape);

Dada essa função, você pode criar um novo Shape objeto da seguinte maneira.

IDrawable *pShape;

HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

O parâmetro ppShape é do tipo pointer-to-pointer-to-IDrawable. Se você não viu esse padrão antes, o redirecionamento duplo pode ser intrigante.

Considere os requisitos da CreateShape função. A função deve devolver um IDrawable ponteiro ao chamador. Mas o valor retornado da função já é usado para o código de erro/êxito. Portanto, o ponteiro deve ser retornado por meio de um argumento para a função . O chamador passará uma variável do tipo IDrawable* para a função e a função substituirá essa variável por um novo IDrawable ponteiro. No C++, há apenas duas maneiras de uma função substituir um valor de parâmetro: passar por referência ou passar por endereço. O COM usa a última passagem por endereço. E o endereço de um ponteiro é um ponteiro para um ponteiro, portanto, o tipo de parâmetro deve ser IDrawable**.

Aqui está um diagrama para ajudar a visualizar o que está acontecendo.

diagrama que mostra a indireção de ponteiro duplo

A CreateShape função usa o endereço de pShape (&pShape) para gravar um novo valor de ponteiro em pShape.

CoCreateInstance: uma maneira genérica de criar objetos

A função CoCreateInstance fornece um mecanismo genérico para a criação de objetos. Para entender CoCreateInstance, tenha em mente que dois objetos COM podem implementar a mesma interface e um objeto pode implementar duas ou mais interfaces. Portanto, uma função genérica que cria objetos precisa de duas informações.

  • Qual objeto criar.
  • Qual interface obter do objeto .

Mas como podemos indicar essas informações quando chamamos a função? No COM, um objeto ou uma interface é identificado atribuindo-lhe um número de 128 bits, chamado guid ( identificador global exclusivo ). Os GUIDs são gerados de uma maneira que os torna efetivamente exclusivos. Os GUIDs são uma solução para o problema de como criar identificadores exclusivos sem uma autoridade de registro central. Às vezes, os GUIDs são chamados de UUIDs ( identificadores universalmente exclusivos ). Antes do COM, eles eram usados no DCE/RPC (Distributed Computing Environment/Remote Procedure Call). Existem vários algoritmos para criar novos GUIDs. Nem todos esses algoritmos garantem estritamente a exclusividade, mas a probabilidade de criar acidentalmente o mesmo valor guid duas vezes é extremamente pequena— efetivamente zero. Os GUIDs podem ser usados para identificar qualquer tipo de entidade, não apenas objetos e interfaces. No entanto, esse é o único uso que nos preocupa neste módulo.

Por exemplo, a Shapes biblioteca pode declarar duas constantes GUID:

extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable; 

(Você pode supor que os valores numéricos reais de 128 bits para essas constantes sejam definidos em outro lugar.) A constante CLSID_Shape identifica o Shape objeto, enquanto a constante IID_IDrawable identifica a IDrawable interface. O prefixo "CLSID" significa identificador de classe e o IID do prefixo significa identificador de interface. Essas são convenções de nomenclatura padrão no COM.

Considerando esses valores, você criaria uma nova Shape instância da seguinte maneira:

IDrawable *pShape;
hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_IDrawable,
     reinterpret_cast<void**>(&pShape));

if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

A função CoCreateInstance tem cinco parâmetros. O primeiro e o quarto parâmetros são o identificador de classe e o identificador de interface. Na verdade, esses parâmetros informam à função "Criar o objeto Shape e me dar um ponteiro para a interface IDrawable".

Defina o segundo parâmetro como NULL. (Para obter mais informações sobre o significado desse parâmetro, consulte o tópico Agregação na documentação com.) O terceiro parâmetro usa um conjunto de sinalizadores cuja finalidade main é especificar o contexto de execução para o objeto . O contexto de execução especifica se o objeto é executado no mesmo processo que o aplicativo; em um processo diferente no mesmo computador; ou em um computador remoto. A tabela a seguir mostra os valores mais comuns para esse parâmetro.

Sinalizador Descrição
CLSCTX_INPROC_SERVER Mesmo processo.
CLSCTX_LOCAL_SERVER Processo diferente, mesmo computador.
CLSCTX_REMOTE_SERVER Computador diferente.
CLSCTX_ALL Use a opção mais eficiente à qual o objeto dá suporte. (A classificação, da mais eficiente para a menos eficiente, é: dentro do processo, fora do processo e entre computadores.)

 

A documentação de um componente específico pode informar a qual contexto de execução o objeto dá suporte. Caso contrário, use CLSCTX_ALL. Se você solicitar um contexto de execução ao qual o objeto não dá suporte, a função CoCreateInstance retornará o código de erro REGDB_E_CLASSNOTREG. Esse código de erro também pode indicar que o CLSID não corresponde a nenhum componente registrado no computador do usuário.

O quinto parâmetro para CoCreateInstance recebe um ponteiro para a interface . Como CoCreateInstance é um mecanismo genérico, esse parâmetro não pode ser fortemente tipado. Em vez disso, o tipo de dados é void**, e o chamador deve forçar o endereço do ponteiro para um tipo void** . Essa é a finalidade do reinterpret_cast no exemplo anterior.

É crucial marcar o valor retornado de CoCreateInstance. Se a função retornar um código de erro, o ponteiro da interface COM será inválido e tentar desreferenciar isso poderá causar uma falha no programa.

Internamente, a função CoCreateInstance usa várias técnicas para criar um objeto . No caso mais simples, ele pesquisa o identificador de classe no registro. A entrada do Registro aponta para uma DLL ou EXE que implementa o objeto . O CoCreateInstance também pode usar informações de um catálogo COM+ ou de um manifesto SxS (lado a lado). Independentemente disso, os detalhes são transparentes para o chamador. Para obter mais informações sobre os detalhes internos do CoCreateInstance, consulte Clientes e servidores COM.

O Shapes exemplo que temos usado é um pouco inventado, portanto, agora vamos recorrer a um exemplo real de COM em ação: exibindo a caixa de diálogo Abrir para o usuário selecionar um arquivo.

Avançar

Exemplo: a caixa de diálogo Abrir