Compartilhar via


Padrão de marshaling para objetos

Parâmetros e sistema autônomo campos digitados sistema autônomo System.Object podem ser expostos a código não gerenciado sistema autônomo um dos seguintes tipos:

  • Uma variante quando o objeto é um parâmetro.

  • Uma interface quando o objeto é um campo de estrutura.

Somente a interoperabilidade COM oferece suporte para marshaling de tipos de objeto.O comportamento padrão é realizar realizar marshaling objetos COM variantes.Essas regras se aplicam apenas para o tipo de Objeto e não se aplicam a objetos com rigidez de tipos que derivam de Objeto classe.

Este tópico fornece as seguintes informações adicionais sobre o marshaling de tipos de objeto:

  • Opções de marshaling

  • Objeto para a interface de marshaling

  • Objeto de marshaling para Variant

  • marshaling de Variant para objeto

  • marshaling de variantes de ByRef

Opções de marshaling

A tabela a seguir mostra as opções de marshaling para o Objeto tipo de dados.The MarshalAsAttribute atributo fornece vários UnmanagedType valores de enumeração para realizar realizar marshaling objetos.

Tipo de enumeração

Descrição do formato não gerenciado

UnmanagedType.Struct

(padrão para parâmetros)

Uma variante COM estilo.

UnmanagedType.Interface

An IDispatch interface, se possível; caso contrário, um IUnknown interface.

UnmanagedType.IUnknown

(padrão para campos)

An IUnknown interface.

UnmanagedType.IDispatch

An IDispatch interface.

O exemplo a seguir mostra o gerenciado interface definição para MarshalObject.

Interface MarshalObject
   Sub SetVariant(o As Object)
   Sub SetVariantRef(ByRef o As Object)
   Function GetVariant() As Object

   Sub SetIDispatch( <MarshalAs(UnmanagedType.IDispatch)> o As Object)
   Sub SetIDispatchRef(ByRef <MarshalAs(UnmanagedType.IDispatch)> o _
      As Object)
   Function GetIDispatch() As <MarshalAs(UnmanagedType.IDispatch)> Object
   Sub SetIUnknown( <MarshalAs(UnmanagedType.IUnknown)> o As Object)
   Sub SetIUnknownRef(ByRef <MarshalAs(UnmanagedType.IUnknown)> o _
      As Object)
   Function GetIUnknown() As <MarshalAs(UnmanagedType.IUnknown)> Object
End Interface
interface MarshalObject {
   void SetVariant(Object o);
   void SetVariantRef(ref Object o);
   Object GetVariant();

   void SetIDispatch ([MarshalAs(UnmanagedType.IDispatch)]Object o);
   void SetIDispatchRef([MarshalAs(UnmanagedType.IDispatch)]ref Object o);
   [MarshalAs(UnmanagedType.IDispatch)] Object GetIDispatch();
   void SetIUnknown ([MarshalAs(UnmanagedType.IUnknown)]Object o);
   void SetIUnknownRef([MarshalAs(UnmanagedType.IUnknown)]ref Object o);
   [MarshalAs(UnmanagedType.IUnknown)] Object GetIUnknown();
}

O código a seguir exporta o MarshalObject interface para uma biblioteca de tipos.

interface MarshalObject {
   HRESULT SetVariant([in] VARIANT o);
   HRESULT SetVariantRef([in,out] VARIANT *o);
   HRESULT GetVariant([out,retval] VARIANT *o) 
   HRESULT SetIDispatch([in] IDispatch *o);
   HRESULT SetIDispatchRef([in,out] IDispatch **o);
   HRESULT GetIDispatch([out,retval] IDispatch **o) 
   HRESULT SetIUnknown([in] IUnknown *o);
   HRESULT SetIUnknownRef([in,out] IUnknown **o);
   HRESULT GetIUnknown([out,retval] IUnknown **o) 
}
Observação:

Interop marshaler libera automaticamente qualquer objeto dentro da variante alocado após a telefonar.

O exemplo a seguir mostra um tipo de valor formatado.

Public Structure ObjectHolder
   Dim o1 As Object
   <MarshalAs(UnmanagedType.IDispatch)> Public o2 As Object
End Structure
public struct ObjectHolder {
   Object o1;
   [MarshalAs(UnmanagedType.IDispatch)]public Object o2;
}

O código a seguir exporta o tipo de formatação para uma biblioteca de tipos.

struct ObjectHolder {
   VARIANT o1;
   IDispatch *o2;
}

Objeto para a interface de marshaling

Quando um objeto é exposto a COM sistema autônomo uma interface, interface é a interface de classe para o tipo gerenciado Object (o _Object interface).Essa interface é digitada sistema autônomo um IDispatch (UnmanagedType.IDispatch) ou um IUnknown (UnmanagedType.IUnknown) na biblioteca de tipos resultante.Clientes COM podem chamar dinamicamente os membros da classe gerenciada ou todos os membros implementados por suas classes derivadas por meio de _Object interface.O cliente também pode chamar QueryInterface para obter qualquer Outros interface implementada explicitamente pelo tipo gerenciado.

Objeto de marshaling para Variant

Quando um objeto é empacotado para uma variante, o tipo de variante interno é determinado em time de execução, com base nas seguintes regras:

  • Se a referência de objeto for nulo (Nada no Visual Basic), o objeto é empacotado para uma variante do tipo VT_EMPTY.

  • Se o objeto for uma instância de qualquer tipo listado na tabela a seguir, o tipo de variante resultante é determinado pelas regras incorporada ao empacotamento e mostrado na tabela.

  • Outros objetos que precisam explicitamente controle o comportamento de marshaling pode implementar o IConvertible interface. Nesse caso, o tipo de variante é determinado pelo código de tipo retornado do IConvertible.GetTypeCode método. Caso contrário, o objeto é empacotado sistema autônomo uma variante do tipo VT_UNKNOWN.

marshaling de tipos de sistema para Variant

A tabela a seguir mostra tipos de objeto gerenciado e seus tipos de variantes COM correspondentes.Esses tipos são convertidos somente quando a assinatura do método sendo chamado é do tipo System.Object.

Tipo de objeto

Tipo de variante COM

Referência de objeto nulo (Nada no Visual Basic).

VT_EMPTY

System.DBNull

VT_NULL

System.Runtime.InteropServices.ErrorWrapper

VT_ERROR

System.Reflection.Missing

VT_ERROR with E_PARAMNOTFOUND

System.Runtime.InteropServices.DispatchWrapper

VT_DISPATCH

System.Runtime.InteropServices.UnknownWrapper

VT_UNKNOWN

System.Runtime.InteropServices.CurrencyWrapper

VT_CY

System.Boolean

VT_BOOL

System.SByte

VT_I1

System.Byte

VT_UI1

System.Int16

VT_I2

System.UInt16

VT_UI2

System.Int32

VT_I4

System.UInt32

VT_UI4

System.Int64

VT_I8

System.UInt64

VT_UI8

System.Single

VT_R4

System.Double

VT_R8

System.Decimal

VT_DECIMAL

System.DateTime

VT_DATE

System.String

VT_BSTR

System.IntPtr

VT_INT

System.UIntPtr

VT_UINT

System.Array

VT_ARRAY

Usando o MarshalObject interface definida no exemplo anterior, o exemplo de código a seguir demonstra como passar vários tipos de variantes para um servidor COM.

Dim mo As New MarshalObject()
mo.SetVariant(Nothing)         ' Marshal as variant of type VT_EMPTY.
mo.SetVariant(System.DBNull.Value) ' Marshal as variant of type VT_NULL.
mo.SetVariant(CInt(27))        ' Marshal as variant of type VT_I2.
mo.SetVariant(CLng(27))        ' Marshal as variant of type VT_I4.
mo.SetVariant(CSng(27.0))      ' Marshal as variant of type VT_R4.
mo.SetVariant(CDbl(27.0))      ' Marshal as variant of type VT_R8.
MarshalObject mo = new MarshalObject();
mo.SetVariant(null);            // Marshal as variant of type VT_EMPTY.
mo.SetVariant(System.DBNull.Value); // Marshal as variant of type VT_NULL.
mo.SetVariant((int)27);          // Marshal as variant of type VT_I2.
mo.SetVariant((long)27);          // Marshal as variant of type VT_I4.
mo.SetVariant((single)27.0);   // Marshal as variant of type VT_R4.
mo.SetVariant((double)27.0);   // Marshal as variant of type VT_R8.

Tipos COM que não possuem tipos gerenciado correspondentes podem ser empacotados usando classes de wrapper, sistema autônomo ErrorWrapper, DispatchWrapper, UnknownWrapper, e CurrencyWrapper. O exemplo de código a seguir demonstra como usar esses invólucros para passar vários tipos de variantes para um servidor COM.

Imports System.Runtime.InteropServices
' Pass inew as a variant of type VT_UNKNOWN interface.
mo.SetVariant(New UnknownWrapper(inew))
' Pass inew as a variant of type VT_DISPATCH interface.
mo.SetVariant(New DispatchWrapper(inew))
' Pass a value as a variant of type VT_ERROR interface.
mo.SetVariant(New ErrorWrapper(&H80054002))
' Pass a value as a variant of type VT_CURRENCY interface.
mo.SetVariant(New CurrencyWrapper(New Decimal(5.25)))
using System.Runtime.InteropServices;
// Pass inew as a variant of type VT_UNKNOWN interface.
mo.SetVariant(new UnknownWrapper(inew));
// Pass inew as a variant of type VT_DISPATCH interface.
mo.SetVariant(new DispatchWrapper(inew));
// Pass a value as a variant of type VT_ERROR interface.
mo.SetVariant(new ErrorWrapper(0x80054002));
// Pass a value as a variant of type VT_CURRENCY interface.
mo.SetVariant(new CurrencyWrapper(new Decimal(5.25)));

As classes de wrapper são definidas no System.Runtime.InteropServices espaço para nome.

marshaling da interface IConvertible para Variant

Tipos diferentes dos listados na seção anterior podem controlar como eles são empacotados, Implementando o IConvertible interface. Se o objeto implementa a IConvertible interface, o tipo de variante COM é determinada em time de execução pelo valor do TypeCode enumeração retornada pela IConvertible.GetTypeCode método.

A tabela a seguir mostra os valores possíveis para o TypeCode enumeração e a correspondente variante COM tipo para cada valor.

TypeCode

Tipo de variante COM

TypeCode.Empty

VT_EMPTY

TypeCode.objeto

VT_UNKNOWN

TypeCode.DBNull

VT_NULL

TypeCode.booliano

VT_BOOL

TypeCode.Char

VT_UI2

TypeCode.sbyte

VT_I1

TypeCode.Byte

VT_UI1

TypeCode.Int16

VT_I2

TypeCode.UInt16

VT_UI2

TypeCode.Int32

VT_I4

TypeCode.UInt32

VT_UI4

TypeCode.Int64

VT_I8

TypeCode.UInt64

VT_UI8

TypeCode.Single

VT_R4

TypeCode.Double

VT_R8

TypeCode.Decimal

VT_DECIMAL

TypeCode.DateTime

VT_DATE

TypeCode.String

VT_BSTR

Sem suporte.

VT_INT

Sem suporte.

VT_UINT

Sem suporte.

VT_ARRAY

Sem suporte.

VT_RECORD

Sem suporte.

VT_CY

Sem suporte.

VT_VARIANT

O valor da variante COM é determinado chamando o IConvertible.ToTipo de interface de , onde ParaTipo de é a rotina de conversão corresponde ao tipo que foi retornado no IConvertible.GetTypeCode.Por exemplo, um objeto que retorna TypeCode.Double from IConvertible.GetTypeCode é empacotado sistema autônomo uma variante de COM do tipo VT_R8.Você pode obter o valor da variante (armazenado no dblVal campo da variante COM), a projeção para o IConvertible interface e chamar o ToDouble método.

marshaling de Variant para objeto

Quando uma variante de um objeto, o tipo e às vezes, o valor da variante empacotado de marshaling determina o tipo de objeto produzido.A tabela a seguir identifica cada tipo de variante e o tipo de objeto correspondente que cria o empacotador quando uma variante é passada de COM para o .NET estrutura.

Tipo de variante COM

Tipo de objeto

VT_EMPTY

Referência de objeto nulo (Nada no Visual Basic).

VT_NULL

System.DBNull

VT_DISPATCH

sistema.__ComObject ou se nulo (pdispVal == nulo)

VT_UNKNOWN

sistema.__ComObject ou se nulo (punkVal == nulo)

VT_ERROR

System.UInt32

VT_BOOL

System.Boolean

VT_I1

System.SByte

VT_UI1

System.Byte

VT_I2

System.Int16

VT_UI2

System.UInt16

VT_I4

System.Int32

VT_UI4

System.UInt32

VT_I8

System.Int64

VT_UI8

System.UInt64

VT_R4

System.Single

VT_R8

System.Double

VT_DECIMAL

System.Decimal

VT_DATE

System.DateTime

VT_BSTR

System.String

VT_INT

System.Int32

VT_UINT

System.UInt32

VT_ARRAY | VT_ *

System.Array

VT_CY

System.Decimal

VT_RECORD

Tipo de valor convertidos de correspondente.

VT_VARIANT

Sem suporte.

Tipos variantes de COM para código gerenciado e, em seguida, voltar ao COM podem não manter o mesmo tipo de variante da duração da telefonar.Considere o que acontece quando uma variante do tipo VT_DISPATCH são passados do COM para o .NET estrutura.Durante o marshaling, a variante é convertida em um System.Object. Se o Objeto é então passado ao COM, é empacotado para uma variante do tipo VT_UNKNOWN.Não há nenhuma garantia a variante produzida quando um objeto é empacotado do código gerenciado para COM o mesmo tipo de variante usado inicialmente para produzir o objeto de.

marshaling de variantes de ByRef

Embora variantes se podem ser passados por valor ou referência, a VT_BYREF sinalizar também pode ser usado com qualquer tipo de variante para indicar que o Sumário da variante está sendo passado por referência, em vez de por valor.A diferença entre variantes de marshaling por referência e marshaling de uma variante com o VT_BYREF sinalizar conjunto pode ser confuso.A ilustração a seguir explica as diferenças.

Variantes passado por valor e por referência

Comportamento padrão para objetos e variantes de marshaling por valor

  • Quando passar objetos do código gerenciado para COM, o Sumário do objeto é copiado para uma nova variante criada pelo empacotador, usando as regras definidas no Objeto de marshaling para Variant.As alterações feitas a variante no lado não gerenciado não são propagadas volta para o objeto original no retorno de telefonar.

  • Quando passando variantes de COM para código gerenciado, o Sumário da variante é copiado para um objeto recém-criado, usando as regras definidas no marshaling de Variant para Object.As alterações feitas no objeto no lado gerenciado não são propagadas volta para a variante original no retorno de telefonar.

Comportamento padrão para objetos e variantes de marshaling por referência

Para propagar alterações de volta para o chamador, os parâmetros devem ser passados por referência.Por exemplo, você pode usar o ref palavra-chave em translation from VPE for Csharp (ou ByRef no Visual Basic código gerenciado) para passar parâmetros por referência.No COM, parâmetros de referência são passados usando um ponteiro sistema autônomo um variante *.

  • Ao passar um objeto para COM por referência, o empacotador cria uma nova variante e copia o Sumário da referência de objeto para a variante antes que a telefonar seja feita.A variante é passada para a função não gerenciada, onde o usuário está disponível para alterar o Sumário da variante.No retorno de telefonar, todas as alterações feitas a variante no lado não gerenciado são propagadas volta para o objeto original.Se o tipo da variante for diferente do tipo de variante passada para a telefonar, as alterações são propagadas volta a um objeto de um tipo diferente.Ou seja, o tipo de objeto passado para a telefonar pode diferir do tipo de objeto retornado da telefonar.

  • Ao passar uma variante para código gerenciado por referência, o empacotador cria um novo objeto e copia o Sumário da variante para o objeto antes de fazer a telefonar.Uma referência ao objeto é passada para o gerenciado função, onde o usuário está disponível para alterar o objeto.No retorno de telefonar, as alterações feitas no objeto referenciado são propagadas para a variante original.Se o tipo de objeto for diferente do tipo do objeto passado para a telefonar, o tipo de variante original será alterado e o valor é propagado de volta a variante.Novamente, o tipo de variante passada para a telefonar pode ser diferente do tipo de variante retornado da telefonar.

Comportamento de marshaling de uma variante com o sinalizar VT_BYREF padrão conjunto

  • Uma variante que está sendo passada para código gerenciado por valor pode ter o VT_BYREF sinalizar conjunto para indicar que a variante contém uma referência em vez de um valor.Nesse caso, a variante ainda é empacotada em um objeto porque a variante está sendo passada por valor.O empacotador cancela a referência de Sumário da variante automaticamente e a copia para um objeto recém-criado antes de fazer a telefonar.O objeto, em seguida, é passado para a função gerenciada; no entanto, no retorno de telefonar, o objeto não é propagado a variante original de volta.As alterações feitas no objeto gerenciado são perdidas.

    Cuidado:

    Não é possível alterar o valor de uma variante passada por valor, mesmo que tenha a variante a VT_BYREF flag conjunto.

  • Uma variante que está sendo passada para código gerenciado por referência também pode ter o VT_BYREF sinalizar conjunto para indicar que a variante contém outra referência.Em caso afirmativo, a variante é empacotada para um ref objeto porque a variante está sendo passada por referência.O empacotador cancela a referência de Sumário da variante automaticamente e a copia para um objeto recém-criado antes de fazer a telefonar.No retorno de telefonar, o valor do objeto é propagado de volta para a referência da variante original somente se o objeto for o mesmo tipo sistema autônomo o objeto passado.Isto é, propagação não altera o tipo de uma variante com o VT_BYREF sinalizar definido.Se o tipo de objeto for alterado durante a telefonar, um InvalidCastException ocorre no retorno de telefonar.

A tabela a seguir resume as regras de propagação para variantes e objetos.

From

Para

Alterações propagadas de volta

Variante v

Objeto o

Nunca

Objeto o

Variante v

Nunca

Variante *pv

Objeto ref o

Sempre

Objeto ref o

Variante *pv

Sempre

Variante v(VT_BYREF|VT_*)

Objeto o

Nunca

Variante v(VT_BYREF|VT_)

Objeto ref o

Somente se o tipo não foi alterado.

Consulte também

Conceitos

Blittable e tipos Blittable não

Atributos direcionais

Copiando e fixação

Outros recursos

Comportamento de marshaling padrão