Padrão de empacotamento de tipos de valor
A maioria dos tipos de valor, como, por exemplo, inteiros e números de ponto flutuante são blittable e não necessitam de empacotamento. Outros não é blittable ter representações diferentes na memória gerenciada e de tipos e exigem o empacotamento. Ainda outros tipos requerem formatação explícito entre o limite de interoperação.
Este tópico fornece as informações de acompanhamento em tipos de valor formatado:
Tipos de valor usados na plataforma Invoke
Tipos de valor usados na interoperabilidade COM
Para além de descrever tipos formatados, este tópico identifica Tipos de valor de sistema que têm comportamento incomum de empacotamento.
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 do membro são fornecidas usando o StructLayoutAttribute atributo. O layout pode ser uma das seguintes LayoutKind valores de enumeração:
LayoutKind.Automatic
Indica que o common language runtime está livre para reorganizar os membros do 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 empacotar dessa estrutura automaticamente faz com que uma exceção.
LayoutKind
Indica que os membros do tipo devem ser dispostos em memória não gerenciada na mesma ordem em que aparecem na definição de tipo gerenciado.
Usando LayoutKind. Explicit
Indica que os membros são dispostos acordo com o FieldOffsetAttribute fornecido com cada campo.
Tipos de valor usados na plataforma Invoke
No exemplo a seguir a Point e Rect tipos de membro de fornecer informações de layout usando 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 como estruturas de estilo C. Isso fornece uma maneira fácil de chamar uma API não gerenciada que tem os argumentos de estrutura. Por exemplo, o POINT e RECT estruturas podem ser passadas para o Microsoft Win32 API PtInRect funciona da seguinte maneira:
BOOL PtInRect(const RECT *lprc, POINT pt);
Você pode passar estruturas usando a seguinte invocação de plataforma 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);
}
O Rect o tipo de valor deve ser passado por referência, porque a API não gerenciada é esperado um ponteiro para uma RECT a serem passados para a função. O Point tipo de valor é passado por valor, porque a API não gerenciada espera que o POINT a serem passados na pilha. Essa diferença sutil é muito importante. Referências são passadas para código não gerenciado como ponteiros. Valores são passados para código não gerenciado na pilha.
Observação
Quando um tipo formatado é empacotado como uma estrutura, somente os campos dentro do tipo são acessíveis.Se o tipo tem métodos, propriedades ou eventos, são inacessíveis a partir do código não gerenciado.
Classes também podem ser empacotados para código não gerenciado como estruturas de estilo C, fornecidos they have fixed layout do membro. As informações de layout de membro de uma classe também são fornecidas com o StructLayoutAttribute atributo. A principal diferença entre os tipos de valor com fixa o layout e as classes com layout fixo é a maneira na qual são empacotados para código não gerenciado. Tipos de valor são passados por valor (na pilha) e, conseqüentemente, qualquer alteração feita pelo receptor os membros do tipo nã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 receptor membros de tipo blittable de um tipo são vistas pelo chamador.
Observação
Se um tipo de referência tiver membros de tipos de não-blittable, a conversão é necessária duas vezes: na primeira vez em quando um argumento é passado para o lado de não gerenciado e pela segunda vez no retorno da chamada.Devido a isso maior sobrecarga, parâmetros In/Out deve ser explicitamente aplicado a um argumento se o chamador deseja ver as alterações feitas pelo receptor.
No exemplo a seguir, o SystemTime classe tem um layout de membro seqüencial e pode ser passado 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;
}
O GetSystemTime função é definida da seguinte maneira:
void GetSystemTime(SYSTEMTIME* SystemTime);
O equivalente 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 como um argumento de referência porque SystemTime é uma classe, não um valor tipo. Ao contrário dos tipos de valor, classes sempre são passados por referência.
O exemplo de código a seguir mostra um diferente Point classe que tem um método chamado SetXY. Porque o tipo tem layout seqüencial, pode ser passado para código não gerenciado e empacotado como uma estrutura. No entanto, o SetXY membro é não é acessível a partir 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 usados na interoperabilidade COM
Tipos de formatação também podem ser passados para chamadas de método de interoperabilidade COM. Na verdade, quando exportados para uma biblioteca de tipos, tipos de valor são convertidos automaticamente para estruturas. Como mostra o exemplo a seguir, o Point o tipo de valor se torna uma definição de tipo (typedef) com o nome Point. Todas as referências para o Point tipo de valor em outro lugar na biblioteca de tipos são substituídos com o 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 empacotar os valores e referências a plataforma chamam chamadas são usadas quando o empacotamento de interfaces COM. Por exemplo, quando uma instância de Point tipo de valor é passado do.NET Framework para COM, o Point é passado por valor. Se a Point o tipo de valor é passado por referência, um ponteiro para uma Point é passado na pilha. O empacotador de interoperabilidade não oferece suporte a altos níveis de indireção (ponto **) em qualquer direção.
Observação
Estruturas tendo o LayoutKind o valor de enumeração definida como Explicit não pode ser usado na interoperabilidade COM, porque a biblioteca de tipos exportados não pode expressar um layout explícito.
Tipos de valor do sistema
O System espaço para nome tem vários tipos de valor que representam o formulário in a box de tipos de primitivos de runtime. Por exemplo, o tipo de valor System.Int32 estrutura representa a forma in a box de ELEMENT_TYPE_I4. Em vez de empacotamento desses tipos de estruturas, como outros tipos de formatação, você empacotá-los da mesma forma como os tipos primitivos, que eles caixa. Int32 , portanto, é empacotado como ELEMENT_TYPE_I4 em vez de como uma estrutura que contém um único membro do tipo longo. A tabela a seguir contém uma lista dos tipos de valor da sistema namespace são representações in a box de tipos primitivos.
Tipo de valor do sistema |
Tipo de elemento |
---|---|
ELEMENT_TYPE_BOOLEAN |
|
ELEMENT_TYPE_I1 |
|
ELEMENT_TYPE_UI1 |
|
ELEMENT_TYPE_CHAR |
|
ELEMENT_TYPE_I2 |
|
ELEMENT_TYPE_U2 |
|
ELEMENT_TYPE_I4 |
|
ELEMENT_TYPE_U4 |
|
ELEMENT_TYPE_I8 |
|
ELEMENT_TYPE_U8 |
|
ELEMENT_TYPE_R4 |
|
ELEMENT_TYPE_R8 |
|
ELEMENT_TYPE_STRING |
|
ELEMENT_TYPE_I |
|
ELEMENT_TYPE_U |
Tipos de algum outro valor na sistema espaço para nome são tratados de maneira diferente. Porque o código não gerenciado já possui formatos bem estabelecidos para esses tipos, o empacotador tem regras especiais para empacotamento-los. A tabela a seguir lista os tipos de valor especial no sistema namespace, bem como o tipo não gerenciado, eles são empacotados para.
Tipo de valor do sistema |
Tipo IDL |
---|---|
DATA |
|
DECIMAL |
|
GUID |
|
OLE_COLOR |
O código a seguir mostra a definição dos tipos de não gerenciados Data de, GUID, DECIMAL, e 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 gerenciados 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 de não-Blittable