Compartilhar via


Interface ICustomMarshaler

 

Dica

The .NET API Reference documentation has a new home. Visit the .NET API Browser on docs.microsoft.com to see the new experience.

Fornece wrappers personalizados para manipular chamadas de método.

Namespace:   System.Runtime.InteropServices
Assembly:  mscorlib (em mscorlib.dll)

Sintaxe

[ComVisibleAttribute(true)]
public interface ICustomMarshaler
[ComVisibleAttribute(true)]
public interface class ICustomMarshaler
[<ComVisibleAttribute(true)>]
type ICustomMarshaler = interface end
<ComVisibleAttribute(True)>
Public Interface ICustomMarshaler

Métodos

Nome Descrição
System_CAPS_pubmethod CleanUpManagedData(Object)

Executa a limpeza necessária dos dados gerenciados quando eles não forem mais necessários.

System_CAPS_pubmethod CleanUpNativeData(IntPtr)

Executa a limpeza necessária dos dados não gerenciados quando eles não forem mais necessários.

System_CAPS_pubmethod GetNativeDataSize()

Retorna o tamanho dos dados nativos cujo marshaling deve ser realizado.

System_CAPS_pubmethod MarshalManagedToNative(Object)

Converte os dados gerenciados em dados não gerenciados.

System_CAPS_pubmethod MarshalNativeToManaged(IntPtr)

Converte os dados não gerenciados em dados gerenciados.

Comentários

Um empacotamento fornece uma ponte entre a funcionalidade antigas e novas interfaces. Empacotamento personalizado oferece os seguintes benefícios:

  • Ele permite que aplicativos cliente que foram projetados para trabalhar com uma interface antiga também trabalhar com servidores que implementam uma nova interface.

  • Permite aplicativos cliente criados para funcionar com uma nova interface trabalhar com servidores que implementam uma interface antiga.

Se você tiver uma interface que apresenta o comportamento de marshaling diferente ou que é exposto para o modelo COM (Component Object) de forma diferente, você pode criar um marshaler personalizado em vez de usar o empacotamento de interoperabilidade. Usando um marshaler personalizado, você pode minimizar a distinção entre os novos componentes do .NET Framework e componentes COM existentes.

Por exemplo, suponha que você está desenvolvendo uma interface gerenciada chamada INew. Quando essa interface é exposta a COM por meio de um padrão COM callable wrapper (CCW), ela tem os mesmos métodos de como a interface gerenciada e usa as regras de empacotamento incorporadas interop marshaler. Agora suponha que uma interface COM conhecido chamado IOld já fornecem a mesma funcionalidade que o INew interface. Criando um marshaler personalizado, você pode fornecer uma implementação não gerenciada de IOld que simplesmente delega as chamadas para a implementação gerenciada do INew interface. Portanto, o marshaler personalizado atua como uma ponte entre as interfaces gerenciadas e não gerenciados.

Dica

Marshalers personalizados não serão chamados durante a chamada do código gerenciado para código não gerenciado em uma interface somente de expedição.

Definindo o tipo Marshaling

Antes de criar um marshaler personalizado, você deve definir as interfaces gerenciadas e que irá ser empacotadas. Essas interfaces geralmente realizam a mesma função, mas são expostas diferente para objetos gerenciados e não gerenciados.

Um compilador gerenciado gera uma interface gerenciada dos metadados e a interface resultante parece com qualquer outra interface gerenciada. O exemplo a seguir mostra uma interface comum.

public interface INew
{
    void NewMethod();
}
Public Interface INew
    Sub NewMethod()
End Interface
public interface class INew
{
    void NewMethod();
};

Defina o tipo não gerenciado na Interface Definition Language (IDL) e compilá-lo com o compilador de linguagem de definição de Interface da Microsoft (MIDL). Definir a interface dentro de uma instrução de biblioteca e atribuir uma ID de interface com o atributo de identificador exclusivo universal (UUID), como demonstrado no exemplo a seguir.

 [uuid(9B2BAADA-0705-11D3-A0CD-00C04FA35826)]
library OldLib {
     [uuid(9B2BAADD-0705-11D3-A0CD-00C04FA35826)]
     interface IOld : IUnknown
         HRESULT OldMethod();
}

O compilador MIDL produz vários arquivos de saída. Se a interface é definida em Old.idl, o arquivo de saída Old_i.c define um const variável com o identificador de interface (IID) da interface, como demonstrado no exemplo a seguir.

const IID IID_IOld = {0x9B2BAADD,0x0705,0x11D3,{0xA0,0xCD,0x00,0xC0,0x4F,0xA3,0x58,0x26}};

O arquivo de Old.h também é produzido pelo MIDL. Ele contém uma definição de C++ da interface que pode ser incluída em seu código-fonte C++.

Implementando a interface ICustomMarshaler

O marshaler personalizado deve implementar o ICustomMarshaler interface para fornecer os wrappers apropriados para o tempo de execução.

O código c# a seguir exibe a interface base que deve ser implementada por todos os empacotadores personalizados.

public interface ICustomMarshaler
{
     Object MarshalNativeToManaged( IntPtr pNativeData );
     IntPtr MarshalManagedToNative( Object ManagedObj );
     void CleanUpNativeData( IntPtr pNativeData );
     void CleanUpManagedData( Object ManagedObj );
     int GetNativeDataSize();
}
Public Interface ICustomMarshaler
     Function MarshalNativeToManaged( pNativeData As IntPtr ) As Object
     Function MarshalManagedToNative( ManagedObj As Object ) As IntPtr
     Sub CleanUpNativeData( pNativeData As IntPtr )
     Sub CleanUpManagedData( ManagedObj As Object )
     Function GetNativeDataSize() As Integer
End Interface
public interface class ICustomMarshaler
{
     Object^ MarshalNativeToManaged( IntPtr^ pNativeData );
     IntPtr^ MarshalManagedToNative( Object^ ManagedObj );
     void CleanUpNativeData( IntPtr^ pNativeData );
     void CleanUpManagedData( Object^ ManagedObj );
     int GetNativeDataSize();
};

O ICustomMarshaler interface inclui métodos que oferecem suporte à conversão, suporte de limpeza e informações sobre os dados a ser empacotado.

Tipo de operação

Método ICustomMarshaler

Descrição

Conversão (de nativo para código gerenciado)

MarshalNativeToManaged

Realiza marshaling de um ponteiro para dados nativos em um objeto gerenciado. Esse método retorna um tempo de execução personalizado RCW (callable wrapper) que possa empacotar a interface de não gerenciada é passada como um argumento. O marshaler deve retornar uma instância de RCW personalizado para esse tipo.

Conversão (a partir do código gerenciado para nativo)

MarshalManagedToNative

Realiza marshaling de um objeto gerenciado em um ponteiro para dados nativos. Esse método retorna um personalizado COM callable wrapper (CCW) que possa empacotar a interface gerenciada é passada como um argumento. O marshaler deve retornar uma instância da CCW personalizado para esse tipo.

Limpeza (de código nativo)

CleanUpNativeData

Permite que o marshaler limpar os dados nativos (o CCW) que são retornados pelo MarshalManagedToNative método.

Limpeza (de código gerenciado)

CleanUpManagedData

Permite que o marshaler limpar os dados gerenciados (RCW) que são retornados pelo MarshalNativeToManaged método.

Informações (sobre código nativo)

GetNativeDataSize

Retorna o tamanho dos dados não gerenciados para ser empacotado.

Conversão

ICustomMarshaler.MarshalNativeToManaged

Realiza marshaling de um ponteiro para dados nativos em um objeto gerenciado. Esse método retorna um tempo de execução personalizado RCW (callable wrapper) que possa empacotar a interface de não gerenciada é passada como um argumento. O marshaler deve retornar uma instância de RCW personalizado para esse tipo.

ICustomMarshaler.MarshalManagedToNative

Realiza marshaling de um objeto gerenciado em um ponteiro para dados nativos. Esse método retorna um personalizado COM callable wrapper (CCW) que possa empacotar a interface gerenciada é passada como um argumento. O marshaler deve retornar uma instância da CCW personalizado para esse tipo.

Limpeza

ICustomMarshaler.CleanUpNativeData

Permite que o marshaler limpar os dados nativos (o CCW) que são retornados pelo MarshalManagedToNative método.

ICustomMarshaler.CleanUpManagedData

Permite que o marshaler limpar os dados gerenciados (RCW) que são retornados pelo MarshalNativeToManaged método.

Informações de tamanho

ICustomMarshaler.GetNativeDataSize

Retorna o tamanho dos dados não gerenciados para ser empacotado.

Implementando o método GetInstance

Além de implementar o ICustomMarshaler interface empacotadores personalizados devem implementar um static método chamado GetInstance que aceita um String como um parâmetro e tem um tipo de retorno ICustomMarshaler. Isso static método é chamado pela camada de interoperabilidade COM o common language runtime para criar uma instância do marshaler personalizado. A cadeia de caracteres que é passada para GetInstance é um cookie que o método pode usar para personalizar o marshaler personalizado retornado.

static ICustomMarshaler *GetInstance(String *pstrCookie);

Aplicando MarshalAsAttribute

Para usar um marshaler personalizado, você deve aplicar o MarshalAsAttribute de atributo para o parâmetro ou campo que está sendo empacotado.

Você também deve transmitir o UnmanagedType.CustomMarshaler valor de enumeração para o MarshalAsAttributeconstrutor. Além disso, você deve especificar o MarshalType campo com um dos seguintes parâmetros nomeados:

  • MarshalType(obrigatório): O nome qualificado de assembly do marshaler personalizado. O nome deve incluir o namespace e classe de marshaler personalizado. Se o marshaler personalizado não está definido no assembly em que é usado, você deve especificar o nome do assembly no qual ela está definida.

    Dica

    Você pode usar o MarshalTypeRef campo em vez do MarshalType campo.MarshalTypeRefusa um tipo que é mais fácil de especificar.

  • MarshalCookie(opcional): um cookie que é passado para o marshaler personalizado. Você pode usar o cookie para fornecer informações adicionais para o empacotador. Por exemplo, se o mesmo marshaler é usado para fornecer um número de wrappers, o cookie identifica um wrapper específico. O cookie é passado para o GetInstance método de empacotamento.

O MarshalAsAttribute atributo identifica o marshaler personalizado para que ele pode ativar o wrapper apropriado. Serviço de interoperabilidade do common language runtime, em seguida, examina o atributo e cria o tempo de marshaler personalizado primeiro o argumento (parâmetro ou campo) precisa ser empacotado.

O tempo de execução, em seguida, chama o MarshalNativeToManaged e MarshalManagedToNative métodos em que o marshaler personalizado para ativar o wrapper correto para manipular a chamada.

Usando um Marshaler personalizado

Quando o marshaler personalizado for concluído, você pode usá-lo como um wrapper personalizado para um determinado tipo. O exemplo a seguir mostra a definição do IUserData interface gerenciada:

interface IUserData
{
    void DoSomeStuff(INew pINew);
}
Public Interface IUserData
    Sub DoSomeStuff(pINew As INew)
End Interface
public interface class IUserData
{
    void DoSomeStuff(INew^ pINew);
};

No exemplo a seguir, o IUserData interface usos de NewOldMarshaler marshaler personalizado para permitir que aplicativos cliente não gerenciados passar um IOld interface para o DoSomeStuff método. A descrição do gerenciado do DoSomeStuff leva um INew de interface, conforme mostrado no exemplo anterior, enquanto a versão não gerenciada de DoSomeStuff leva um IOld ponteiro de interface, conforme mostrado no exemplo a seguir.

[uuid(9B2BAADA-0705-11D3-A0CD-00C04FA35826)]
library UserLib {
     [uuid(9B2BABCD-0705-11D3-A0CD-00C04FA35826)]
     interface IUserData : IUnknown
         HRESULT DoSomeStuff(IUnknown* pIOld);
}

A biblioteca de tipos que é gerada por meio da exportação a definição gerenciada da IUserData gera a definição não gerenciada mostrada neste exemplo, em vez da definição padrão. O MarshalAsAttribute atributo aplicado para o INew argumento a definição gerenciada do DoSomeStuff método indica que o argumento usa um marshaler personalizado, como mostra o exemplo a seguir.

using System.Runtime.InteropServices;
Imports System.Runtime.InteropServices
using namespace System::Runtime::InteropServices;
interface IUserData
{
    void DoSomeStuff(
        [MarshalAs(UnmanagedType.CustomMarshaler,
             MarshalType="MyCompany.NewOldMarshaler")]
        INew pINew
    );
}
Public Interface IUserData
    Sub DoSomeStuff( _
        <MarshalAs(UnmanagedType.CustomMarshaler, _
        MarshalType := "MyCompany.NewOldMarshaler")> pINew As INew)
End Interface
public interface class IUserData
{
    void DoSomeStuff(
        [MarshalAs(UnmanagedType::CustomMarshaler,
             MarshalType="MyCompany.NewOldMarshaler")]
        INew^ pINew
    );
};

Nos exemplos anteriores, o primeiro parâmetro fornecido para o MarshalAsAttribute atributo é o UnmanagedType.CustomMarshaler valor de enumeração UnmanagedType.CustomMarshaler.

O segundo parâmetro é o MarshalType campo, que fornece o nome qualificado de assembly do marshaler personalizado. Esse nome consiste o namespace e classe de personalizado (MarshalType="MyCompany.NewOldMarshaler").

Informações de Versão

.NET Framework
Disponível desde 1.1

Confira Também

Namespace System.Runtime.InteropServices
Interoperabilidade

Retornar ao início