Este artigo aborda o contexto em que é necessário o empacotador de referências personalizado. Este artigo fornece dois cenários diferentes.
cenário 1 O primeiro cenário descreve autenticação personalizado de um cliente .NET para um servidor COM. Neste cenário, tem de ter:
- Um servidor COM que implementa o IUnmanagedServer interface.
- Um IUnmanagedServer que tem um método único que é denominado UnmanagedServerMethod . Este método requer um único parâmetro do tipo IUnmanaged como entrada.
- Um cliente .NET que tem uma instância de escreva IManaged.
- Um cliente do .NET que transmita a instância IManaged para UnmanagedServerMethod do servidor COM.
O exemplo de código que se segue é um excerto do IUnmanaged interface:
interface IUnmanaged : IUnknown
{
HRESULT UnmanagedMethod([out, retval] LONG *RetVal);
}; a interface gerido (IManaged) é semanticamente semelhante a interface não gerida (IUnmanaged) é:
public interface IManaged
{
long ManagedMethod();
} cenário 2 Segundo cenário descreve autenticação personalizada de um cliente COM a um servidor de .NET. Neste cenário, tem de ter:
- Um servidor de .NET que implementa um método único que é denominado ManagedServerMethod . Este método requer um único parâmetro do tipo IManaged como entrada.
- Um cliente COM que tem uma instância de escreva IUnmanaged.
- Um cliente COM que passa a instância IUnmanaged para ManagedServerMethod do servidor .NET.
Quando tenta mapear tipos diferentes de semanticamente semelhantes, tem de criar uma classe de wrapper. Uma classe de wrapper contém uma instância de um tipo mas expõe a interface para outro tipo. Os tipos são mapeados tem de ser semelhantes para a classe de wrapper pode manter a semântica definidos para as interfaces. Este artigo descreve como utilizar uma classe de wrapper para o cenário onde o cliente de .NET acede ao servidor COM. Uma classe de wrapper chama ManagedIUnmanaged molda-se uma instância de IManaged mas expõe a interface IUnmanaged.
Do mesmo modo, quando o cliente COM acede ao servidor de .NET, uma classe de wrapper chama ComUnmanged molda-se uma instância de IUnmanaged mas expõe a interface IManaged.
O problema de mapeamento de uma interface de gestão para uma interface não gerida tem uma solução. A solução consiste em utilizar classes de moldagem. O empacotador de referências personalizado automatiza e oculta quando o wrapper é criado para o tipo que está a empacotar as referências umanaged domínio gerido e vice-versa.
Observe a classe de
transmissão em sequência e a interface IStream COM. Pode ver o que são necessários os mecanismos de conversão. Os mecanismos de conversão permite que um objecto não gerido para implementar determinados requisitos de interface tem de ser mapeados para um objecto de mensagens publicitárias. Esse objecto de dispositivo de moldagem, em seguida, expõe um conjunto diferente de interfaces. A Classe .NET
transmissão em sequência é semanticamente semelhante da interface IStream COM. Abstractions fornecidas a classe de
transmissão em sequência e a interface IStream COM são semelhantes. Tanto IStream
sequência permitem a leitura, escrita e procura através de uma memória intermédia. Uma classe .NET que utiliza uma instância da classe
sequência lógica pode ser transferida uma instância do objecto COM que implementa a interface IStream. Para efectuar este procedimento, o .NET Framework tem de fornecer um mecanismo onde um objecto de wrapper da
sequência de classe pode ser criado. Isto, em seguida, redirecciona o método de classe de
transmissão em sequência que chama o objecto
IStream COM incorporado. O mecanismo que permite uma conversão para ocorrer é a classe
CustomMarshaler fornecido no .NET Framework.
Em ambos os cenários, o empacotador de referências personalizado é construído dependendo da direcção que a autenticação é efectuada. Se a autenticação é efectuada do cliente nativo para um servidor gerido, tem de definir o empacotador de referências personalizado para empacotar referências do nativo para o domínio gerido. Se o empacotamento de referências personalizado é empacotar as referências em ambas as direcções, tem de combinar a definição de empacotador de referências personalizado conforme descrito em ambos os cenários.
Back to the topAutenticação personalizada a partir de um cliente .NET a um servidor COM
Passos para criar um servidor de COM ATL
Esta secção mostra como criar um servidor ATL COM que implementa a interface IUnmanagedServer.
- Abra o Microsoft Visual Studio .NET .
- No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
- Na caixa de diálogo Novo projecto , clique em Projectos do Visual C++ em Project Types e clique em Projecto ATL em modelos .
- Na caixa de texto nome , escreva ComServer .
- Clique em OK .
- Na caixa de diálogo do Assistente , clique no separador Definições da aplicação .
- Clique para desmarcar a caixa de verificação Attributed e, em seguida, clique em Concluir .
- No Solution Explorer , clique com o botão direito do rato no nó ComServer (projecto) , aponte para Adicionar e, em seguida, clique em Adicionar classe .
- Na caixa de diálogo Adicionar classe , clique em Objecto simples ATL em modelos e clique em Abrir .
- Na caixa de diálogo Assistente de objectos simples ATL , escreva UnmanagedServer na caixa de texto nome curto e clique em Concluir .
- No Solution Explorer , expanda os Ficheiros de origem .
- Faça duplo clique em ComServer.idl para abrir o ficheiro .idl num editor. Adicionar definição de interface seguinte ficheiro .idl.
[
object,
uuid(XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX),
helpstring("IUnmanaged Interface"),
pointer_default(unique)
]
interface IUnmanaged : IUnknown
{
HRESULT UnmanagedMethod([out, retval] LONG *RetVal);
}; substituir o conteúdo do atributo uuid com o GUID é gerado a partir da ferramenta guidgen . Na biblioteca, adicione a interface IUnmanaged como mostrado no código anterior. Isto expõe a interface através da biblioteca de tipos que é gerada. Adicione o seguinte código à instrução de biblioteca no ficheiro .idl:
library ComServerLib
{
importlib("stdole2.tlb");
//Add the following line to the idl file.
interface IUnmanaged;
...
};
- Na vista de classe , expanda ComServer .
- Clique com o botão direito do rato IUnmanagedServer , aponte para Adicionar e, em seguida, clique em Adicionar método .
- Na caixa de texto Nome do método , escreva UnmanagedServerMethod .
- Clique para seleccionar os atributos de parâmetro de caixa de verificação.
- Na caixa de combinação tipo de parâmetro , escreva IUnmanaged * .
- Na caixa de texto parâmetro , escreva não geridos e, em seguida, clique em Adicionar .
- Clique em Concluir .
- No Solution Explorer , faça duplo clique UnmanagedServer.cpp .
- Substitua o código predefinido que é gerado para o método CUnmanagedServer::UnmanagedServerMethod com o código que se segue:
LONG data;
HRESULT hr;
hr = unmanaged->UnmanagedMethod(&data);
if(FAILED(hr))
return hr;
printf("The output of the IUnmanaged::UnmanagedMethod is : %d", data);
return S_OK; - No menu criar , clique em criar soluções para criar a aplicação de servidor COM ATL.
Back to the
topPassos para criar um cliente de .NET
Esta secção mostra como criar um cliente .NET que acede ao servidor de COM e, em seguida, transmite
UnmanagedMethod do servidor com uma instância de IManaged:
- No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
- Na caixa de diálogo Novo projecto , clique em Visual C# Projects em Project Types e clique em Aplicação de consola em modelos .
- Clique para seleccionar a opção de Adicionar a solução e, em seguida, clique em OK .
- No Solution Explorer , expanda ConsoleApplication1 , clique com o botão direito do rato em References e, em seguida, clique em Add Reference .
- Na caixa de diálogo Adicionar referência do , clique no separador COM .
- Clique em Biblioteca de tipos de 1.0 ComServer em Nome do componente e clique em Seleccionar .
- Clique em OK .
- Substituir o código predefinido Class1.cs o código que se segue:
using System;
using System.Runtime.InteropServices;
public interface IManaged
{
long ManagedMethod();
}
public class ManagedImplementation : IManaged
{
public long ManagedMethod()
{
return 200;
}
}
class Class1
{
static void Main(string[] args)
{
comserverLib.IUnmanagedServer server = new comserverLib.UnmanagedServerClass();
IManaged managed = new ManagedImplementation();
server.UnmanagedServerMethod(managed);
}
}
Back to the
topPassos para criar uma mensagem publicitária
Esta secção mostra como criar uma classe de wrapper que molda-se uma instância do tipo IManaged mas expõe a interface IUnmanaged.
Para criar uma classe de wrapper, siga estes passos:
- Adicione o código que se segue Class1.cs:
[
ComImport,
Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)
]
public interface UCOMIUnmanaged
{
long UnmanagedMethod();
}
public class ManagedIUnmanaged : UCOMIUnmanaged
{
IManaged managedObj;
public ManagedIUnmanaged(IManaged managedObj)
{
if(managedObj != null)
this.managedObj = managedObj;
else
throw new ArgumentNullException("The instance of IManaged is null.");
}
public long UnmanagedMethod()
{
return managedObj.ManagedMethod();
}
}
substituir o conteúdo do atributo GUID com o conteúdo do atributo uuid . O atributo de uuid é gerado para interface IUnmanaged no ficheiro ComServer.idl.
Back to the
topPassos para criar um empacotador de referências personalizado
Esta secção mostra como criar um empacotador de referências personalizado que mapeia uma interface de gestão (IManaged) para uma interface não gerida (IUnmanaged):
O empacotador de referências personalizado tem implementa a interface ICustomMarshaler. O método
MarshalNativeToManaged é chamado quando uma interface não gerida é mapeada para uma interface de gestão. Porque o cenário actual marshals a partir de gerido para o domínio nativo, a implementação actual do método
MarshalNativeToManaged devolve um valor nulo. O método
MarshalManagedToNative molda-se o objecto nativo num objecto de mensagens publicitárias (
ManagedIUnmanaged ) definido na secção anterior. O método
MarshalManagedToNative é chamado quando uma interface gerida é mapeada para uma interface não gerida. O método
CleanUpNativeData é chamado quando o objecto que está associado com a interface nativa é libertado.
Do mesmo modo, o método
CleanUpManagedData é chamado quando o objecto que está associado com a interface gerida é libertado. Uma vez que o objecto gerido é lixo recolhido, a implementação para o método
CleanUpManagedData está vazia.
O método
GetNativeDataSize retorna
-1 .
Embora o método
GetInstance não está definido para a interface ICustomMarshaler, tem de definir o método estático
GetInstance devolve uma ocorrência de
ICustomMarshaler . Este método estático é chamado pelo tempo de execução .NET para criar uma instância de empacotador de referências personalizado.
- Add the code that follows to Class1.cs:
public class SampleMarshaler : ICustomMarshaler
{
static SampleMarshaler marshaler;
public object MarshalNativeToManaged(IntPtr pNativeData)
{
return null;
}
public IntPtr MarshalManagedToNative(object managedObj)
{
if(managedObj == null)
return IntPtr.Zero;
if(!(managedObj is IManaged))
throw new MarshalDirectiveException("This custom marshaler must be used on a IManaged derived type.");
ManagedIUnmanaged customObject = new ManagedIUnmanaged((IManaged)managedObj);
return Marshal.GetComInterfaceForObject(customObject, typeof(UCOMIUnmanaged));
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.Release(pNativeData);
}
public void CleanUpManagedData(object managedObj)
{
}
public int GetNativeDataSize()
{
return -1;
}
public static ICustomMarshaler GetInstance(string cookie)
{
if(marshaler == null)
return marshaler = new SampleMarshaler();
return marshaler;
}
} - Associa o empacotamento de referências da instância da interface a uma instância da interface IUnmanaged IManaged de empacotador de referências personalizado. Adicione o código que se segue Class1.cs para associar o empacotador de referências personalizado:
[
ComImport,
Guid("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)
]
public interface UCOMIUnmanagedServer
{
void UnmanagedServerMethod(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(SampleMarshaler)), In]
object unmanaged);
} é O GUID especificado com o atributo GUID o mesmo que o atributo de uuid especificado para a interface IUnmanagedServer .idl para o servidor COM. - Modificar o método principal Aula1 em Class1.cs da seguinte forma:
static void Main(string[] args)
{
UCOMIUnmanagedServer server = (UCOMIUnmanagedServer)new ComServerLib.UnmanagedServerClass();
IManaged managed = new ManagedImplementation();
server.UnmanagedServerMethod(managed);
} quando o cliente não gerido chama o servidor não gerido, o cliente não gerido transmite uma instância de um objecto gerido para o servidor não gerido. O objecto gerido é personalizado empacotar as referências a um objecto que expõe a interface não gerida como esperada pelo servidor COM. - No menu criar , clique em criar soluções .
- No Solution Explorer , clique com o botão direito do rato no nó de projecto ConsoleApplication1 e clique em Definir como projecto de arranque .
- No menu Debug , clique em Iniciar .
Back to the
topAutenticação personalizada a partir de um cliente COM para o .NET Server
O cenário que se segue mostra empacotamento de referências personalizado como é efectuado a partir de um cliente COM um servidor de .NET.
Passos para criar um cliente COM
Esta secção mostra como criar um componente COM ATL que implementa a interface IManaged:
- No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
- Clique em Projectos do Visual C++ em Project Types e clique em Projecto ATL em modelos .
- Na caixa de texto nome , escreva ComComponent e, em seguida, clique em OK .
- Na caixa de diálogo Assistente de Projecto ATL , clique no separador Definições da aplicação .
- Clique para desmarcar a caixa de verificação Attributed e, em seguida, clique em Concluir .
- No Solution Explorer , clique com o botão direito do rato ComComponent (projecto) , aponte para Adicionar e, em seguida, clique em Adicionar classe .
- Na caixa de diálogo Adicionar classe , clique em Objecto simples ATL em modelos e clique em Abrir .
- Na caixa de diálogo Assistente de objectos simples ATL , escreva Unmanaged no nome de mais texto caixa e, em seguida, clique em Concluir .
- Na Vista de classe , expanda ComComponent , clique com o botão direito do rato IUnmanaged , aponte para Adicionar e, em seguida, clique em Adicionar método .
- Na caixa de diálogo Assistente de método , escreva UnmanagedMethod na caixa de texto Nome do método .
- Selecione LONG * na lista em tipo de parâmetro .
- Clique para seleccionar retval em atributos de parâmetro e, em seguida, escreva lRetVal na caixa de texto nome de parâmetro .
- Clique em Adicionar e clique em Concluir .
- No Solution Explorer , faça duplo clique Unmanaged.cpp para abrir o ficheiro.
- Substituir o código por defeito para CUnmanaged::UnmanagedMethod o código que se segue:
*lRetVal = 300;
return S_OK;
- No menu criar , clique em criar soluções para criar o componente COM.
Back to the
topPassos para criar um .NET Server
Esta secção mostra como criar um servidor de .NET que implementa um método único que é denominado
ManagedServerMethod .
ManagedServerMethod tem uma instância do tipo IManaged:
- No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
- Clique em Visual C# Projects em Project Types e clique em Biblioteca de classes em modelos .
- Clique para seleccionar a opção de Adicionar a solução e, em seguida, clique em OK .
- No ficheiro de Class1.cs gerado por predefinição, substitua o código por defeito pelo código que se segue:
using System;
using System.Runtime.InteropServices;
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IManaged
{
long ManagedMethod();
}
[ClassInterface(ClassInterfaceType.AutoDual)]
public class ManagedServer
{
public void ManagedServerMethod(IManaged managed)
{
Console.WriteLine("The output of IManaged.ManagedMethod is : {0}", managed.ManagedMethod());
}
}
Back to the
topPassos para criar uma mensagem publicitária
Esta secção mostra como criar uma classe de wrapper que molda-se uma instância do tipo IUnmanaged mas expõe a interface IManaged:
- No Solution Explorer , expanda ClassLibrary1 .
- Na ClassLibrary1 , clique com o botão direito do rato em References e clique em Add Reference .
- Na caixa de diálogo Adicionar referência do , clique no separador COM .
- Clique em biblioteca de tipos de ComComponent 1.0 em nome do componente .
- Clique em Seleccionar e clique em OK .
- No ficheiro Class1.cs, adicione o código que se segue:
[ComVisible(false)]
public class ComUnmanaged : IManaged
{
ComComponentLib.IUnmanaged unmanaged;
public ComUnmanaged(ComComponentLib.IUnmanaged unmanaged)
{
if(unmanaged != null)
this.unmanaged = unmanaged;
else
throw new ArgumentNullException("NULL");
}
public long ManagedMethod()
{
return unmanaged.UnmanagedMethod();
}
}
Back to the
topPassos para criar um empacotador de referências personalizado
Esta secção mostra como criar um empacotador de referências personalizado que mapeia uma interface não gerida (IUnmanaged) para uma interface de gestão (IManaged):
O empacotador de referências personalizado tem implementa a interface ICustomMarshaler. O método
MarshalManagedToNative é chamado quando uma interface gerida é mapeada para uma interface não gerida. Uma vez que o cenário actual marshals a partir de não gerido para o domínio gerido, a implementação actual do método
MarshalManagedToNative devolve
IntPtr.Zero .
O método
MarshalNativeToManaged molda-se o objecto nativo num objecto de mensagens publicitárias (
ComUnmanaged ) definido na secção anterior. O método
MarshalNativeToManaged é chamado quando uma interface não gerida é mapeada para uma interface de gestão.
O método
CleanUpNativeData é chamado quando o objecto que está associado com a interface nativa é libertado.
Do mesmo modo, o método
CleanUpManagedData é chamado quando o objecto que está associado com a interface gerida é libertado. Uma vez que o objecto gerido é lixo recolhido, a implementação para o método
CleanUpManagedData está vazia.
O método
GetNativeDataSize retorna
-1 .
Embora o método
GetInstance não está definido para a interface ICustomMarshaler, tem de definir o método estático
GetInstance devolve uma ocorrência de ICustomMarshaler. Este método estático é chamado pelo tempo de execução .NET para criar uma instância de empacotador de referências personalizado.
- Adicione o código que se segue Class1.cs:
[ComVisible(false)]
public class SampleMarshaler : ICustomMarshaler
{
static SampleMarshaler marshaler;
public object MarshalNativeToManaged(IntPtr pNativeData)
{
if(pNativeData == IntPtr.Zero)
return null;
object rcw = Marshal.GetObjectForIUnknown(pNativeData);
if(!(rcw is ComComponentLib.IUnmanaged))
throw new ArgumentException("The object must implement IUnmanaged");
return new ComUnmanaged((ComComponentLib.IUnmanaged) rcw);
}
public IntPtr MarshalManagedToNative(object managedObj)
{
return IntPtr.Zero;
}
public void CleanUpNativeData(IntPtr pNativeData)
{
Marshal.Release(pNativeData);
}
public void CleanUpManagedData(object managedObj)
{
}
public int GetNativeDataSize()
{
return -1;
}
public static ICustomMarshaler GetInstance(string cookie)
{
if(marshaler == null)
return marshaler = new SampleMarshaler();
return marshaler;
}
} - Adicione MarshalAsAttribute o parâmetro é personalizada empacotar as referências. Modifique o código para ManagedServerMethod da seguinte forma:
public void ManagedServerMethod(
[MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(SampleMarshaler)), In]
IManaged managed)
{
Console.WriteLine("The output of IManaged.ManagedMethod is : {0}", managed.ManagedMethod());
} - No menu criar , clique em criar soluções .
- No menu ficheiro , aponte para Novo e, em seguida, clique em projecto .
- Na caixa de diálogo Novo projecto , clique em Projectos do Visual C++ em Project Types e clique em Project Win32 em modelos .
- Na caixa de texto nome , escreva ComClient .
- Clique para seleccionar a opção de Adicionar a solução e, em seguida, clique em OK .
- Na caixa de diálogo Assistente de aplicação de Win32 , clique no separador Definições da aplicação .
- Clique para seleccionar a Aplicação de consola de opção na secção Escreva aplicação e, em seguida, clique em Concluir .
- No Solution Explorer , expanda ComClient e faça duplo clique Stdafx.h ficheiro para abrir esse ficheiro. Adicione o código que se segue para o ficheiro:
#import "ComComponent.tlb" no_namespace raw_interfaces_only named_guids
#import "ClassLibrary1.tlb" no_namespace raw_interfaces_only named_guids
- No Solution Explorer , expanda ComClient e, em seguida, faça duplo clique no ficheiro ComClient.cpp para abrir esse ficheiro. Adicione o código que se segue para o _tmain do file:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
HRESULT hr;
IUnmanaged *unmanagedObj;
_ManagedServer *managedServer;
CoInitialize(NULL);
hr = CoCreateInstance(CLSID_Unmanaged, NULL, CLSCTX_INPROC_SERVER, IID_IUnmanaged, (LPVOID *)&unmanagedObj);
if(FAILED(hr))
goto Error;
hr = CoCreateInstance(CLSID_ManagedServer, NULL, CLSCTX_INPROC_SERVER, IID__ManagedServer, (LPVOID *)&managedServer);
if(FAILED(hr))
goto Error;
hr = managedServer->ManagedServerMethod(unmanagedObj);
if(FAILED(hr))
goto Error;
return 0;
Error:
CoUninitialize();
return hr;
} - Para gerar o ClassLibrary1.tlb, escreva o comando que se segue na linha de comandos:
RegAsm /tlb ClassLibrary1.dll
Verifique se o ficheiro ClassLibrary1.dll está no directório de compilação para o projecto ClassLibrary1. O ClassLibrary1.dll gera o ClassLibrary1.tlb e também regista a biblioteca de classes. - Copiar o ficheiro ClassLibrary1.tlb e o ComComponent.tlb ficheiro para o directório do projecto para a aplicação ComClient.
- No menu criar , clique em criar soluções .
- Copiar o ficheiro de ClassLibrary1.dll e o ficheiro Interop.comclientLib.dll do directório de compilação do ClassLibrary1 projecto para o directório compilação da aplicação de consola ComClient.
- No Solution Explorer , clique com o botão direito do rato ComClient e clique em Definir como projecto de arranque .
- No menu Debug , clique em Iniciar .
Back to the
top