Předávání struktur

Mnoho nespravovaných funkcí očekává předání členů struktur (uživatelem definovaných typů v jazyce Visual Basic) jako parametr funkce nebo členů tříd definovaných ve spravovaném kódu. Při předávání struktur nebo tříd nespravovanému kódu pomocí vyvolání platformy musíte poskytnout další informace, abyste zachovali původní rozložení a zarovnání. Toto téma představuje StructLayoutAttribute atribut, který slouží k definování formátovaných typů. U spravovaných struktur a tříd můžete vybírat z několika předvídatelných chování rozložení poskytovaných výčtem LayoutKind .

Ústředním aspektem konceptů uvedených v tomto tématu je důležitý rozdíl mezi strukturou a typy tříd. Struktury jsou typy hodnot a třídy jsou referenčními typy – třídy vždy poskytují alespoň jednu úroveň nepřímé paměti (ukazatel na hodnotu). Tento rozdíl je důležitý, protože nespravované funkce často vyžadují nepřímý vliv, jak ukazuje podpisy v prvním sloupci následující tabulky. Spravovaná struktura a deklarace tříd ve zbývajících sloupcích zobrazují stupeň, ve kterém můžete upravit úroveň nepřímých deklarací. Deklarace jsou k dispozici pro Visual Basic i Visual C#.

Nespravovaný podpis Spravovaná deklarace:
bez nepřímých
Structure MyType
struct MyType;
Spravovaná deklarace:
jedna úroveň nepřímých
Class MyType
class MyType;
DoWork(MyType x);

Vyžaduje nulové úrovně nepřímých znalostí.
DoWork(ByVal x As MyType)
DoWork(MyType x)

Přidá nulové úrovně nepřímých znalostí.
Není možné, protože už existuje jedna úroveň nepřímých výrazů.
DoWork(MyType* x);

Vyžaduje jednu úroveň nepřímých požadavků.
DoWork(ByRef x As MyType)
DoWork(ref MyType x)

Přidá jednu úroveň indirectionu.
DoWork(ByVal x As MyType)
DoWork(MyType x)

Přidá nulové úrovně nepřímých znalostí.
DoWork(MyType** x);

Vyžaduje dvě úrovně nepřímých znalostí.
Není možné, protože byRef ByRef Nebo refref nelze použít. DoWork(ByRef x As MyType)
DoWork(ref MyType x)

Přidá jednu úroveň indirectionu.

Tabulka popisuje následující pokyny pro deklarace volání platformy:

  • Pokud nespravovaná funkce nevyžaduje žádné nepřímé použití, použijte strukturu předanou hodnotou.

  • Pokud nespravovaná funkce požaduje jednu úroveň nepřímých funkcí, použijte buď strukturu předanou odkazem, nebo třídu předanou hodnotou.

  • Pokud nespravovaná funkce vyžaduje dvě úrovně nepřímých funkcí, použijte třídu předanou odkazem.

Deklarace a předávání struktur

Následující příklad ukazuje, jak definovat Point a Rect struktury ve spravovaném kódu a předat typy jako parametr do funkce PtInRect v souboru User32.dll. PtInRect má následující nespravovaný podpis:

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

Všimněte si, že je nutné předat strukturu Rect odkazem, protože funkce očekává ukazatel na typ 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  
  
Friend Class NativeMethods
    Friend 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;  
}
  
internal static class NativeMethods
{  
    [DllImport("User32.dll")]  
    internal static extern bool PtInRect(ref Rect r, Point p);  
}  

Deklarace a předávání tříd

Členy třídy můžete předat funkci nespravované knihovny DLL, pokud má třída pevné rozložení členů. Následující příklad ukazuje, jak předat členy MySystemTime třídy, které jsou definovány v sekvenčním pořadí, GetSystemTime v User32.dll souboru. GetSystemTime má následující nespravovaný podpis:

void GetSystemTime(SYSTEMTIME* SystemTime);  

Na rozdíl od hodnotových typů mají třídy vždy aspoň jednu úroveň nepřímých výrazů.

Imports System.Runtime.InteropServices  
  
<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  
  
Friend Class NativeMethods  
    Friend Declare Auto Sub GetSystemTime Lib "Kernel32.dll" (
        sysTime As MySystemTime)  
    Friend Declare Auto Function MessageBox Lib "User32.dll" (
        hWnd As IntPtr, lpText As String, lpCaption As String, uType As UInteger) As Integer  
End Class  
  
Public Class TestPlatformInvoke
    Public Shared Sub Main()  
        Dim sysTime As New MySystemTime()  
        NativeMethods.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  
        NativeMethods.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;
}  
internal static class NativeMethods
{  
    [DllImport("Kernel32.dll")]  
    internal static extern void GetSystemTime(MySystemTime st);  
  
    [DllImport("user32.dll", CharSet = CharSet.Auto)]  
    internal static extern int MessageBox(
        IntPtr hWnd, string lpText, string lpCaption, uint uType);  
}  
  
public class TestPlatformInvoke  
{  
    public static void Main()  
    {  
        MySystemTime sysTime = new MySystemTime();  
        NativeMethods.GetSystemTime(sysTime);  
  
        string dt;  
        dt = "System time is: \n" +  
              "Year: " + sysTime.wYear + "\n" +  
              "Month: " + sysTime.wMonth + "\n" +  
              "DayOfWeek: " + sysTime.wDayOfWeek + "\n" +  
              "Day: " + sysTime.wDay;  
        NativeMethods.MessageBox(IntPtr.Zero, dt, "Platform Invoke Sample", 0);  
    }  
}  

Viz také