Interface IMarshal (objidl.h)

Permite que um objeto COM defina e gerencie o marshaling de seus ponteiros de interface.

Herança

A interface IMarshal herda da interface IUnknown . O IMarshal também tem esses tipos de membros:

Métodos

A interface IMarshal tem esses métodos.

 
IMarshal::D isconnectObject

O método IMarshal::D isconnectObject (objidl.h) libera todas as conexões com um objeto antes de desligar.
IMarshal::GetMarshalSizeMax

Recupera o tamanho máximo do buffer que será necessário durante o marshaling.
IMarshal::GetUnmarshalClass

Recupera o CLSID do código unmarshaling.
IMarshal::MarshalInterface

O método IMarshal::MarshalInterface (objidl.h) realiza marshaling de um ponteiro de interface.
IMarshal::ReleaseMarshalData

O método IMarshal::ReleaseMarshalData (objidl.h) destrói um pacote de dados marshaled.
IMarshal::UnmarshalInterface

O método IMarshal::UnmarshalInterface (objidl.h) desmarca um ponteiro de interface.

Comentários

Marshaling é o processo de empacotamento de dados em pacotes para transmissão para um processo ou computador diferente. A desmarcação é o processo de recuperação desses dados na extremidade de recebimento. Em qualquer chamada fornecida, os argumentos de método são empacotados e não são gravados em uma direção, enquanto os valores retornados são marshaled e não são gravados na outra.

Embora o marshaling se aplique a todos os tipos de dados, os ponteiros de interface exigem tratamento especial. O problema fundamental é como o código do cliente em execução em um espaço de endereço pode desreferenciar corretamente um ponteiro para uma interface em um objeto que reside em um espaço de endereço diferente. A solução COM é que um aplicativo cliente se comunique com o objeto original por meio de um objeto alternativo ou proxy, que reside no processo do cliente. O proxy contém uma referência a uma interface no objeto original e entrega ao cliente um ponteiro para uma interface em si mesmo. Quando o cliente chama um método de interface no objeto original, sua chamada está realmente indo para o proxy. Portanto, do ponto de vista do cliente, todas as chamadas estão em processo.

Ao receber uma chamada, o proxy realiza marshaling dos argumentos do método e, por meio de alguns meios de comunicação entre processos, como RPC, os passa para o código no processo do servidor, o que desmarca os argumentos e os passa para o objeto original. Esse mesmo código faz marshaling de valores retornados para transmissão de volta para o proxy, o que desmarca os valores e os passa para o aplicativo cliente.

O IMarshal fornece métodos para criar, inicializar e gerenciar um proxy em um processo de cliente; ele não determina como o proxy deve se comunicar com o objeto original. A implementação padrão COM do IMarshal usa RPC. Ao implementar essa interface por conta própria, você está livre para escolher qualquer método de comunicação entre processos que considerar apropriado para seu aplicativo — memória compartilhada, pipe nomeado, identificador de janela, RPC — em resumo, o que funcionar.

Implementação padrão do IMarshal

O COM usa sua própria implementação interna da interface IMarshal para realizar marshaling de qualquer objeto que não forneça sua própria implementação. COM faz essa determinação consultando o objeto para IMarshal. Se a interface estiver ausente, COM usará como padrão sua implementação interna.

A implementação padrão COM do IMarshal usa um proxy genérico para cada objeto e cria stubs e proxies individuais, conforme necessário, para cada interface implementada no objeto . Esse mecanismo é necessário porque o COM não pode saber com antecedência quais interfaces específicas um determinado objeto pode implementar. Os desenvolvedores que não usam o marshaling padrão COM, optando por escrever suas próprias rotinas de proxy e marshaling, conhecem em tempo de compilação todas as interfaces a serem encontradas em seus objetos e, portanto, entendem exatamente qual código de marshaling é necessário. O COM, ao fornecer suporte de marshaling para todos os objetos, deve fazer isso em tempo de execução.

O proxy de interface reside no processo do cliente; o stub de interface reside no servidor. Juntos, cada par manipula todo o marshaling para a interface. O trabalho de cada proxy de interface é realizar marshaling de argumentos e desmarcar valores retornados e parâmetros de saída que são passados para frente e para trás em chamadas subsequentes para sua interface. O trabalho de cada stub de interface é desmarcar argumentos de função e passá-los para o objeto original e, em seguida, realizar marshaling dos valores retornados e dos parâmetros retornados pelo objeto.

O proxy e o stub se comunicam por meio de um canal RPC (chamada de procedimento remoto), que utiliza a infraestrutura RPC do sistema para comunicação entre processos. O canal RPC implementa uma única interface, IRpcChannelBuffer, para a qual proxies de interface e stubs contêm um ponteiro. O proxy e o stub chamam a interface para obter um pacote de marshaling, enviar os dados para seu equivalente e destruir o pacote quando terminarem. O stub da interface também contém um ponteiro para o objeto original.

Para qualquer interface específica, o proxy e o stub são implementados como instâncias da mesma classe, que é listada para cada interface no registro do sistema sob o rótulo ProxyStubClsid32. Essa entrada mapeia o IID da interface para o CLSID de seus objetos proxy e stub. Quando o COM precisa realizar marshaling de uma interface, ele procura no registro do sistema para obter o CLSID apropriado. O servidor identificado por esse CLSID implementa o proxy de interface e o stub da interface.

Na maioria das vezes, a classe à qual esse CLSID se refere é gerada automaticamente por uma ferramenta cuja entrada é uma descrição das assinaturas de função e semântica de uma determinada interface, escrita em alguma linguagem de descrição da interface. Embora o uso desse idioma seja altamente recomendado e incentivado para fins de precisão, isso não é necessário. Proxies e stubs são apenas componentes COM usados pela infraestrutura RPC e, como tal, podem ser escritos de qualquer maneira desejada, desde que os contratos externos corretos sejam mantidos. O programador que projeta uma nova interface é responsável por garantir que todos os proxies de interface e stubs que já existirem concordem com a representação de seus dados marshaled.

Quando criados, os proxies de interface são sempre agregados em um proxy maior, que representa o objeto como um todo. Esse proxy de objeto também agrega o objeto proxy genérico COM, que é conhecido como o gerenciador de proxy. O gerenciador de proxy implementa duas interfaces: IUnknown e IMarshal. Todas as outras interfaces que podem ser implementadas em um objeto são expostas em seu proxy de objeto por meio da agregação de proxies de interface individuais. Um cliente que contém um ponteiro para o proxy de objeto "acredita" que ele contém um ponteiro para o objeto real.

Um proxy que representa o objeto como um todo é necessário no processo do cliente para que um cliente possa distinguir chamadas para as mesmas interfaces implementadas em objetos totalmente diferentes. No entanto, esse requisito não existe no processo do servidor, em que o próprio objeto reside, pois todos os stubs de interface se comunicam apenas com os objetos para os quais foram criados. Nenhuma outra conexão é possível.

Os stubs de interface, ao contrário dos proxies de interface, não são agregados porque não há necessidade de que eles pareçam para algum cliente externo fazer parte de um todo maior. Quando conectado, um stub de interface recebe um ponteiro para o objeto de servidor para o qual ele deve encaminhar invocações de método recebidas. Embora seja útil se referir conceitualmente a um gerenciador de stubs, o que significa que quaisquer partes de código e estado na infraestrutura RPC do lado do servidor que servem a comunicação remota de um determinado objeto, não há nenhum requisito direto de que o código e o estado tomem qualquer formulário específico e bem especificado.

Na primeira vez que um cliente solicita um ponteiro para uma interface em um objeto específico, COM carrega um stub IClassFactory no processo do servidor e o usa para realizar marshaling do primeiro ponteiro de volta para o cliente. No processo do cliente, COM carrega o proxy genérico para o objeto de fábrica de classe e chama sua implementação de IMarshal para desmarcar esse primeiro ponteiro. EM seguida, o COM cria o primeiro proxy de interface e entrega um ponteiro para o canal RPC. Por fim, COM retorna o ponteiro IClassFactory para o cliente, que o usa para chamar IClassFactory::CreateInstance, passando-o uma referência para a interface.

De volta ao processo do servidor, o COM agora cria uma nova instância do objeto, juntamente com um stub para a interface solicitada. Esse stub faz marshaling do ponteiro da interface de volta para o processo do cliente, em que outro proxy de objeto é criado, desta vez para o próprio objeto. Também é criado um proxy para a interface solicitada, um ponteiro para o qual é retornado ao cliente. Com chamadas subsequentes para outras interfaces no objeto , o COM carregará os stubs e proxies de interface apropriados, conforme necessário.

Quando um novo proxy de interface é criado, o COM entrega um ponteiro para a implementação do IUnknown pelo gerenciador de proxy, para o qual ele delega todas as chamadas QueryInterface . Cada proxy de interface implementa duas interfaces próprias: a interface que ele representa e IRpcProxyBuffer. O proxy de interface expõe sua própria interface diretamente aos clientes, que podem obter seu ponteiro chamando QueryInterface no gerenciador de proxy. Somente COM, no entanto, pode chamar IRpcProxyBuffer, que é usado para conectar e desconectar o proxy ao canal RPC. Um cliente não pode consultar um proxy de interface para obter um ponteiro para a interface IRpcProxyBuffer .

No lado do servidor, cada stub de interface implementa IRpcStubBuffer. O código do servidor que atua como um gerenciador de stub chama IRpcStubBuffer::Connect e passa o stub de interface do ponteiro IUnknown de seu objeto.

Quando um proxy de interface recebe uma invocação de método, ele obtém um pacote de marshaling de seu canal RPC por meio de uma chamada para IRpcChannelBuffer::GetBuffer. O processo de marshaling dos argumentos copiará dados para o buffer. Quando o marshaling é concluído, o proxy de interface invoca IRpcChannelBuffer::SendReceive para enviar o pacote marshalado para o stub de interface correspondente. Quando IRpcChannelBuffer::SendReceive retornar, o buffer no qual os argumentos foram marshalados terá sido substituído por um novo buffer que contém os valores retornados marshalados do stub da interface. O proxy de interface desmarca os valores retornados, invoca IRpcChannelBuffer::FreeBuffer para liberar o buffer e retorna os valores retornados para o chamador original do método.

É a implementação de IRpcChannelBuffer::SendReceive que realmente envia a solicitação para o processo do servidor e que sabe como identificar o processo do servidor e, dentro desse processo, o objeto para o qual a solicitação deve ser enviada. A implementação do canal também sabe como encaminhar a solicitação para o gerenciador de stub apropriado nesse processo. O stub de interface desmarca os argumentos do buffer fornecido, invoca o método indicado no objeto do servidor e faz marshaling dos valores retornados de volta para um novo buffer alocado por uma chamada para IRpcChannelBuffer::GetBuffer. Em seguida, o canal transmite o pacote de dados de retorno de volta para o proxy de interface, que ainda está no meio de IRpcChannelBuffer::SendReceive, que retorna para o proxy de interface.

Uma instância específica de um proxy de interface pode ser usada para atender a mais de uma interface, desde que as seguintes condições sejam atendidas:

  • Os IIDs das interfaces afetadas devem ser mapeados para o ProxyStubClsid apropriado no registro do sistema.
  • O proxy de interface deve dar suporte a chamadas para QueryInterface de uma interface com suporte para as outras interfaces, como de costume, bem como de IUnknown e IRpcProxyBuffer.
Uma única instância de um stub de interface também pode atender a mais de uma interface, mas somente se esse conjunto de interfaces tiver uma relação estrita de herança única. Essa restrição existe porque o stub pode direcionar invocações de método para várias interfaces somente onde ele sabe com antecedência quais métodos são implementados em quais interfaces.

Em vários momentos, proxies e stubs precisarão alocar ou liberar memória. Os proxies de interface, por exemplo, precisarão alocar memória para retornar parâmetros ao chamador. Nesse aspecto, proxies de interface e stubs de interface são apenas componentes COM normais, pois eles devem usar o alocador de tarefas padrão. (Consulte CoGetMalloc.)

Requisitos

Requisito Valor
Cliente mínimo com suporte Windows 2000 Professional [aplicativos da área de trabalho | Aplicativos UWP]
Servidor mínimo com suporte Windows 2000 Server [aplicativos da área de trabalho | Aplicativos UWP]
Plataforma de Destino Windows
Cabeçalho objidl.h (inclua ObjIdl.h)

Confira também

IStdMarshalInfo