Estruturas de passagem
Muitas funções não gerenciadas esperam que você passe, como um parâmetro para a função, membros de estruturas (tipos definidos pelo usuário em Visual Basic) ou membros de classes definidas no código gerenciado. Quando as estruturas de passagem ou classes para código não gerenciado usando a plataforma chamar, você deve fornecer informações adicionais para preservar o layout original e o alinhamento. Este tópico apresenta o StructLayoutAttribute atributo, que você usa para definir tipos formatado. Para classes e estruturas gerenciadas, você pode selecionar vários comportamentos de layout previsível fornecidos pelo LayoutKind enumeração.
Central para os conceitos apresentados neste tópico é uma diferença importante entre tipos de estrutura e a classe. Estruturas são tipos de valor e classes são tipos de referência — classes sempre fornecem pelo menos um nível de indireção de memória (um ponteiro para um valor). Essa diferença é importante porque as funções não gerenciadas geralmente demandam indireto, conforme mostrado pelas assinaturas na primeira coluna da tabela a seguir. As declarações de classe em que as colunas restantes e a estrutura gerenciada mostram o grau ao qual você pode ajustar o nível de indireção na sua declaração.
Assinatura não gerenciada |
Declaração gerenciada: Nenhum caminho indireto struct MyStruct(…); |
Declaração gerenciada: um nível de indireção class MyStruct(…); |
---|---|---|
DoWork(MyStruct x); Demandas de níveis de indireção zero. |
DoWork(ByVal x As MyStruct) Adiciona o zero níveis de indireção. |
Não é possível porque já existe um nível de indireção. |
DoWork(MyStruct* x); Exige um nível de indireção. |
DoWork(ByRef x As MyStruct) Adiciona um nível de indireção. |
DoWork(ByVal x As MyStruct) Adiciona o zero níveis de indireção. |
DoWork(MyStruct** x); Exige dois níveis de indireção. |
Não é possível porque ByRef ByRef não pode ser usado. |
DoWork(ByRef x As MyStruct) Adiciona um nível de indireção. |
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 passados por referência ou uma classe passado por valor quando a função não gerenciada exige um nível de indireção.
Use uma classe passada por referência, quando a função não gerenciada exige dois níveis de indireção.
Declarando e passar estruturas
O exemplo a seguir mostra como definir o Point e Rect estruturas no código gerenciado e passar os tipos como parâmetro para o PtInRect a função no arquivo User32. 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);
}
Declarando e passando de Classes
Você pode passar a membros de uma classe para uma função DLL não gerenciada, como a classe tem um layout fixo do membro. O exemplo a seguir demonstra como passar os membros do MySystemTime classe, que são definidos em ordem seqüencial, para o GetSystemTime no arquivo User32. dll. GetSystemTime tem a seguinte assinatura não gerenciada:
void GetSystemTime(SYSTEMTIME* SystemTime);
Ao contrário dos tipos de valor, classes sempre tem pelo menos um nível de indireção.
Imports System
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 IntPtr, _
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(IntPtr.Zero, 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);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern int MessageBox(IntPtr hWnd,
string text, string caption, int options);
}
public class TestPlatformInvoke
{
public static void Main()
{
MySystemTime sysTime = new MySystemTime();
Win32API.GetSystemTime(sysTime);
string dt;
dt = "System time is: \n" +
"Year: " + sysTime.wYear + "\n" +
"Month: " + sysTime.wMonth + "\n" +
"DayOfWeek: " + sysTime.wDayOfWeek + "\n" +
"Day: " + sysTime.wDay;
Win32API.MessageBox(IntPtr.Zero, dt, "Platform Invoke Sample", 0);
}
}
Consulte também
Referência
Classe de StructLayoutAttribute
Classe de StructLayoutAttribute
Classe de FieldOffsetAttribute