Estruturas de passagem
Muitas funções não gerenciadas esperam que você passe, sistema autônomo um parâmetro da função, sistema autônomo membros do estruturas (tipos definidos pelo usuário no Visual Basic) ou membros de classes definidas no código gerenciado.Ao passar estruturas ou classes para código não gerenciado usando invocação de plataforma, você deve fornecer informações adicionais para preservar o layout original e o alinhamento.Este tópico apresenta o StructLayoutAttribute atributo use para definir tipos formatados. Para gerenciado estruturas e classes, você pode selecionar vários comportamentos previsível layout fornecidos pelo LayoutKind enumeração.
Uma diferença importante entre tipos de estrutura e a classe é fundamental aos conceitos apresentados neste tópico.Estruturas são tipos de valor e as classes são tipos de referência — classes sempre fornecem pelo menos um nível de indireção memória (um ponteiro para um valor).Essa diferença é importante porque funções não gerenciadas com freqüência exigem indireção, sistema autônomo mostrados pelas assinaturas na primeira coluna da tabela a seguir.O gerenciado declarações de estrutura e a classe nas colunas restantes mostram o grau ao qual você pode ajustar o nível de indireção na sua declaração.
Assinatura não gerenciada |
gerenciado declaração: Nenhum caminho indireto struct MyStruct(…); |
gerenciado declaração: um nível de engano class MyStruct(…); |
---|---|---|
DoWork(MyStruct x); As demandas de níveis de indireção de zero. |
DoWork(ByVal x As MyStruct) Adiciona zero níveis de indireção. |
Não é possível porque já existe um nível de engano. |
DoWork(MyStruct* x); Exige um nível de engano. |
DoWork(ByRef x As MyStruct) Adiciona um nível de engano. |
DoWork(ByVal x As MyStruct) Adiciona zero níveis de indireção. |
DoWork(MyStruct** x); Exige dois níveis de indireção. |
Not possible because ByRef ByRef cannot be used. |
DoWork(ByRef x As MyStruct) Adiciona um nível de engano. |
A tabela descreve as diretrizes a seguir para declarações de invocação de plataforma:
Use uma estrutura passada por valor quando a função não gerenciada não exige nenhum indireção.
Use uma estrutura passado por referência ou uma classe passado por valor quando a função não gerenciada exige um nível de engano.
Use uma classe passada por referência quando a função não gerenciada exige dois níveis de indireção.
Declarando e estruturas de passagem
O exemplo a seguir mostra sistema autônomo definir o Point e Rect estruturas no código gerenciado e passar sistema autônomo tipos sistema autônomo parâmetro para o PtInRect função o User32 arquivo .dll.PtInRect tem a seguinte assinatura não gerenciada:
BOOL PtInRect(const RECT *lprc, POINT pt);
Observe que você deve passar a estrutura Rect por referência, desde que a função espera um ponteiro para um tipo RECT.
Imports System.Runtime.InteropServices
<StructLayout(LayoutKind.Sequential)> Public Structure Point
Public x As Integer
Public y As Integer
End Structure
Public Structure <StructLayout(LayoutKind.Explicit)> 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
Class Win32API
Declare Auto Function PtInRect Lib "user32.dll" _
(ByRef r As Rect, p As Point) As Boolean
End Class
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;
}
class Win32API {
[DllImport("User32.dll")]
public static extern bool PtInRect(ref Rect r, Point p);
}
Classes de passagem e Delcaring
Você pode passar membros de uma classe para uma função DLL não gerenciada, desde que a classe tem um layout fixo do membro.O exemplo a seguir demonstra como passar os membros a MySystemTime classe, que são definidos em ordem seqüencial, como o GetSystemTime no arquivo User32.dll.GetSystemTime tem a seguinte assinatura não gerenciada:
void GetSystemTime(SYSTEMTIME* SystemTime);
Ao contrário de tipos de valor, classes sempre têm pelo menos um nível de indireção.
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic
<StructLayout(LayoutKind.Sequential)> Public Class MySystemTime
Public wYear As Short
Public wMonth As Short
Public wDayOfWeek As Short
Public wDay As Short
Public wHour As Short
Public wMinute As Short
Public wSecond As Short
Public wMiliseconds As Short
End Class
Public Class Win32
Declare Auto Sub GetSystemTime Lib "Kernel32.dll"(sysTime _
As MySystemTime)
Declare Auto Function MessageBox Lib "User32.dll"(hWnd As Integer, _
txt As String, caption As String, Typ As Integer) As Integer
End Class
Public Class TestPlatformInvoke
Public Shared Sub Main()
Dim sysTime As New MySystemTime()
Win32.GetSystemTime(sysTime)
Dim dt As String
dt = "System time is:" & ControlChars.CrLf & _
"Year: " & sysTime.wYear & _
ControlChars.CrLf & "Month: " & sysTime.wMonth & _
ControlChars.CrLf & "DayOfWeek: " & sysTime.wDayOfWeek & _
ControlChars.CrLf & "Day: " & sysTime.wDay
Win32.MessageBox(0, dt, "Platform Invoke Sample", 0)
End Sub
End Class
[StructLayout(LayoutKind.Sequential)]
public class MySystemTime {
public ushort wYear;
public ushort wMonth;
public ushort wDayOfWeek;
public ushort wDay;
public ushort wHour;
public ushort wMinute;
public ushort wSecond;
public ushort wMilliseconds;
}
class Win32API {
[DllImport("Kernel32.dll")]
public static extern void GetSystemTime(MySystemTime st);
}