Compartilhar via


Padrão de marshaling de tipos de valor

A maioria dos tipos de valor, sistema autônomo números inteiros e números de ponto flutuante são blittable e não necessitam de marshaling. Outrosnão blittable tipos têm representações diferentes na memória gerenciada e e exigem o marshaling.Ainda outros tipos requerem formatação explícito entre o limite de interoperação.

Este tópico fornece as informações a seguir em tipos de valor formatado:

  • Tipos de valor utilizados na invocação de plataforma

  • Tipos de valor utilizados na interoperabilidade COM

Como descrever tipos formatados, este tópico identifica Tipos de valor do sistema que têm comportamento incomum de marshaling.

Um tipo de formatação é um tipo complexo que contém informações que explicitamente controla o layout de seus membros na memória.As informações de layout de membro são fornecidas usando o StructLayoutAttribute atributo. O layout pode ser uma da seguir LayoutKind valores de enumeração:

  • LayoutKind.automático

    Indica que o common linguagem tempo de execução está disponível para reorganizar os membros de tipo para a eficiência.No entanto, quando um tipo de valor é passado para código não gerenciado, o layout dos membros é previsível.Uma tentativa de realizar realizar marshaling dessa estrutura automaticamente faz com que uma exceção.

  • LayoutKind.Sequential

    Indica que membros do tipo devem ser dispostos em memória não gerenciada na mesma ordem em que aparecem na definição de tipo gerenciado.

  • LayoutKind.Explicit

    Indica que os membros são dispostos de acordo com para o FieldOffsetAttribute fornecido com cada campo.

Tipos de valor utilizados na invocação de plataforma

No exemplo a seguir o Point e Rect tipos de fornecem informações de layout de membro utilizando o StructLayoutAttribute.

Imports System.Runtime.InteropServices
<StructLayout(LayoutKind.Sequential)> Public Structure Point
   Public x As Integer
   Public y As Integer
End Structure
<StructLayout(LayoutKind.Explicit)> Public Structure Rect
   <FieldOffset(0)> Public left As Integer
   <FieldOffset(4)> Public top As Integer
   <FieldOffset(8)> Public right As Integer
   <FieldOffset(12)> Public bottom As Integer
End Structure
using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential)]
public struct Point {
   public int x;
   public int y;
}   

[StructLayout(LayoutKind.Explicit)]
public struct Rect {
   [FieldOffset(0)] public int left;
   [FieldOffset(4)] public int top;
   [FieldOffset(8)] public int right;
   [FieldOffset(12)] public int bottom;
}

Quando empacotado para código não gerenciado, esses tipos de formatação são empacotados sistema autônomo estilo C estruturas.Isso oferece uma maneira fácil de chamar uma API não gerenciada possui os argumentos de estrutura.Por exemplo, a POINT e RECT estruturas podem ser passadas para o Microsoft Win32 API PtInRect funcionam da seguinte maneira:

BOOL PtInRect(const RECT *lprc, POINT pt);

Você pode passar estruturas usando a plataforma seguinte chamar definição:

Class Win32API    
   Declare Auto Function PtInRect Lib "User32.dll" _
    (ByRef r As Rect, p As Point) As Boolean
End Class
class Win32API {
   [DllImport("User32.dll")]
   public static extern Bool PtInRect(ref Rect r, Point p);
}

The Rect tipo de valor deve ser passado por referência porque a API não gerenciada é esperado um ponteiro para um RECT a ser passada para a função. The Point tipo de valor é passado por valor porque a API não gerenciada espera que o POINT a ser passada na pilha. Essa diferença sutil é muito importante.Referências são passadas para código não gerenciado sistema autônomo ponteiros.Valores são passados para o código não gerenciado na pilha.

Observação:

Quando um tipo formatado é empacotado sistema autônomo uma estrutura, somente sistema autônomo campos dentro do tipo são acessíveis.Se o tipo tem métodos, propriedades ou eventos, eles são inacessíveis a partir do código não gerenciado.

Classes também podem ser empacotados para código não gerenciado sistema autônomo estruturas de estilo C, desde que eles forem corrigidos membro layout.As informações de layout de membro para uma classe também são fornecidas com o StructLayoutAttribute atributo. A principal diferença entre tipos de valor com fixo layout e classes com layout fixo é a maneira na qual eles são empacotados para código não gerenciado.Tipos de valor são passados por valor (na pilha) e, conseqüentemente, todas as alterações efetuadas para membros do tipo, o computador chamado não são vistas pelo chamador.Tipos de referência são passados por referência (uma referência para o tipo passada na pilha); conseqüentemente, todas as alterações feitas pelo computador chamado tipo blittable membros de um tipo são vistas pelo chamador.

Observação:

Se um tipo de referência tiver membros de tipos blittable não, a conversão é necessária duas vezes: na primeira vez em quando um argumento é passado para o lado não gerenciado e a segunda vez no retornam da telefonar.Devido a isso adicionado sobrecarga, parâmetros in/out deve ser explicitamente aplicado a um argumento se o chamador deseja ver as alterações feitas pelo computador chamado.

No exemplo a seguir, a SystemTime classe tem layout seqüencial membro e pode ser passada para a API do Win32 GetSystemTime função.

<StructLayout(LayoutKind.Sequential)> Public Class SystemTime
   Public wYear As System.UInt16
   Public wMonth As System.UInt16
   Public wDayOfWeek As System.UInt16
   Public wDay As System.UInt16
   Public wHour As System.UInt16
   Public wMinute As System.UInt16
   Public wSecond As System.UInt16
   Public wMilliseconds As System.UInt16
End Class
[StructLayout(LayoutKind.Sequential)]
   public class SystemTime {
   public ushort wYear; 
   public ushort wMonth;
   public ushort wDayOfWeek; 
   public ushort wDay; 
   public ushort wHour; 
   public ushort wMinute; 
   public ushort wSecond; 
   public ushort wMilliseconds; 
}

The GetSystemTime função é definida sistema autônomo segue:

void GetSystemTime(SYSTEMTIME* SystemTime);

O equivalente da invocação de plataforma definição para GetSystemTime é o seguinte:

Public Class Win32
   Declare Auto Sub GetSystemTime Lib "Kernel32.dll" (ByVal sysTime _
   As SystemTime)
End Class
class Win32API {
   [DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
   public static extern void GetSystemTime(SystemTime st);
}

Observe que o SystemTime argumento não for digitado sistema autônomo um argumento de referência porque SystemTime é uma classe, tipo de valor. Ao contrário de tipos de valor, classes são sempre passados por referência.

O exemplo de código a seguir mostra um diferentes Point classe que tem um método chamado SetXY. sistema autônomo o tipo tem layout seqüencial, pode ser passado para código não gerenciado e empacotado sistema autônomo uma estrutura.No entanto, a SetXY membro não é pode ser chamado do código não gerenciado, mesmo que o objeto é passado por referência.

<StructLayout(LayoutKind.Sequential)> Public Class Point
   Private x, y As Integer
   Public Sub SetXY(x As Integer, y As Integer)
      Me.x = x
      Me.y = y
   End Sub
End Class
[StructLayout(LayoutKind.Sequential)]
public class Point {
   int x, y;
   public void SetXY(int x, int y){ 
      this.x = x;
      this.y = y;
   }
}

Tipos de valor utilizados na interoperabilidade COM

Tipos formatados também podem ser passados para chamadas de método interop COM.Na verdade, quando exportados para uma biblioteca de tipos, tipos de valor são convertidos automaticamente para estruturas.sistema autônomo mostra o exemplo seguinte, a Point tipo de valor se torna uma definição de tipo (typedef) com o nome Point. Todas as referências à Point tipo de valor em outro lugar na biblioteca de tipos são substituídos pela Point TypeDef.

Representação de biblioteca de tipo

typedef struct tagPoint {
   int x;
   int y;
} Point;
interface _Graphics {
   …
   HRESULT SetPoint ([in] Point p)
   HRESULT SetPointRef ([in,out] Point *p)
   HRESULT GetPoint ([out,retval] Point *p)
}

As mesmas regras usadas para realizar realizar marshaling valores e as referências invocação de plataforma chamadas são usadas quando o realizar marshaling de interfaces COM.Por exemplo, quando uma instância do Point tipo de valor é passado do .NET estrutura para COM, o Point é passado por valor. Se o Point tipo de valor é passado por referência, um ponteiro para um Point é passado na pilha. Interop marshaler não oferece suporte a altos níveis de indireção (Ponto **) em qualquer direção.

Observação:

Estruturas tendo o LayoutKind valor de enumeração definido como Explícita não pode ser usado na interoperabilidade COM, porque a biblioteca de tipos exportada não pode expressar um layout explícito.

Tipos de valor do sistema

The System espaço para nome tem vários tipos de valor que representam o formulário dos tipos primitivos de tempo de execução in a box. Por exemplo, o valor digite System.Int32 estrutura representa a forma do processador in a box ELEMENT_TYPE_I4.Em vez de realizar marshaling desses tipos de estruturas, sistema autônomo outros tipos de formatação, você realizar realizar marshaling eles da mesma forma sistema autônomo sistema autônomo tipos primitivos que eles caixa.sistema.Int32 , portanto, é empacotado sistema autônomo ELEMENT_TYPE_I4 em vez de sistema autônomo uma estrutura que contém um único membro do tipo longo.A tabela a seguir contém uma lista dos tipos de valor no Sistemanamespace de são representações in a box de tipos primitivos.

Tipo de valor do sistema

Tipo de elemento

System.Boolean

ELEMENT_TYPE_BOOLEAN

System.SByte

ELEMENT_TYPE_I1

System.Byte

ELEMENT_TYPE_UI1

System.Char

ELEMENT_TYPE_CHAR

System.Int16

ELEMENT_TYPE_I2

System.UInt16

ELEMENT_TYPE_U2

System.Int32

ELEMENT_TYPE_I4

System.UInt32

ELEMENT_TYPE_U4

System.Int64

ELEMENT_TYPE_I8

System.UInt64

ELEMENT_TYPE_U8

System.Single

ELEMENT_TYPE_R4

System.Double

ELEMENT_TYPE_R8

System.String

ELEMENT_TYPE_STRING

System.IntPtr

ELEMENT_TYPE_I

System.UIntPtr

ELEMENT_TYPE_U

Alguns outros tipos de valor de Sistema namespace são tratados de maneira diferente.Como o código não gerenciado já tem formatos bem estabelecidos para esses tipos, o empacotador tem regras especiais para marshaling-los.A tabela a seguir lista sistema autônomo tipos de valor especial no Sistema namespace, bem sistema autônomo o tipo não gerenciado, para que eles são empacotados.

Tipo de valor do sistema

Tipo IDL

System.DateTime

DATA

System.Decimal

DECIMAL

System.Guid

GUID

System.Drawing.Color

OLE_COLOR

O código a seguir mostra a definição do tipos não gerenciados DATA, GUID, DECIMAL, and OLE_COLOR na biblioteca de tipos Stdole2.

Representação de biblioteca de tipo

typedef double DATE;
typedef DWORD OLE_COLOR;

typedef struct tagDEC {
    USHORT    wReserved;
    BYTE      scale;
    BYTE      sign;
    ULONG     Hi32;
    ULONGLONG Lo64;
} DECIMAL;

typedef struct tagGUID {
    DWORD Data1;
    WORD  Data2;
    WORD  Data3;
    BYTE  Data4[ 8 ];
} GUID;

O código a seguir mostra as definições correspondentes no gerenciado IValueTypes interface.

Public Interface IValueTypes
   Sub M1(d As System.DateTime)
   Sub M2(d As System.Guid)
   Sub M3(d As System.Decimal)
   Sub M4(d As System.Drawing.Color)
End Interface
public interface IValueTypes {
   void M1(System.DateTime d);
   void M2(System.Guid d);
   void M3(System.Decimal d);
   void M4(System.Drawing.Color d);
}

Representação de biblioteca de tipo

[…]
interface IValueTypes : IDispatch {
   HRESULT M1([in] DATE d);
   HRESULT M2([in] GUID d);
   HRESULT M3([in] DECIMAL d);
   HRESULT M4([in] OLE_COLOR d);
};

Consulte também

Conceitos

Blittable e tipos Blittable não

Atributos direcionais

Copiando e fixação

Outros recursos

Comportamento de marshaling padrão