Delen via


Structuren doorgeven

Veel niet-beheerde functies verwachten dat u, als parameter aan de functie, leden van structuren (door de gebruiker gedefinieerde typen in Visual Basic) of leden van klassen die zijn gedefinieerd in beheerde code, doorgeeft. Wanneer u structuren of klassen doorgeeft aan onbeheerde code met behulp van platformoproep, moet u aanvullende informatie opgeven om de oorspronkelijke indeling en uitlijning te behouden. In dit onderwerp wordt het StructLayoutAttribute kenmerk geïntroduceerd dat u gebruikt om opgemaakte typen te definiëren. Voor beheerde structuren en klassen kunt u kiezen uit verschillende voorspelbare indelingsgedragen die worden geleverd door de opsomming LayoutKind .

Centraal in de concepten die in dit onderwerp worden gepresenteerd, is een belangrijk verschil tussen structuur- en klassetypen. Structuren zijn waardetypen en klassen zijn referentietypen. Klassen bieden altijd ten minste één niveau van geheugen indirectie (een aanwijzer naar een waarde). Dit verschil is belangrijk omdat onbeheerde functies vaak indirectie vereisen, zoals wordt weergegeven door de handtekeningen in de eerste kolom van de volgende tabel. In de beheerde structuur en klassedeclaraties in de resterende kolommen ziet u de mate waarin u het niveau van indirectie in uw declaratie kunt aanpassen. Declaraties worden opgegeven voor Visual Basic en Visual C#.

Onbeheerde handtekening Beheerde declaratie:
geen indirectie
Structure MyType
struct MyType;
Beheerde declaratie:
één niveau van indirectie
Class MyType
class MyType;
DoWork(MyType x);

Vereist nul niveaus van indirectie.
DoWork(ByVal x As MyType)
DoWork(MyType x)

Hiermee worden nul niveaus van indirectie toegevoegd.
Niet mogelijk omdat er al één niveau van indirectie is.
DoWork(MyType* x);

Vereist één niveau van indirectie.
DoWork(ByRef x As MyType)
DoWork(ref MyType x)

Hiermee wordt één niveau van indirectie toegevoegd.
DoWork(ByVal x As MyType)
DoWork(MyType x)

Hiermee worden nul niveaus van indirectie toegevoegd.
DoWork(MyType** x);

Vereist twee niveaus van indirectie.
Niet mogelijk omdat ByRefByRef of refref niet kan worden gebruikt. DoWork(ByRef x As MyType)
DoWork(ref MyType x)

Hiermee wordt één niveau van indirectie toegevoegd.

In de tabel worden de volgende richtlijnen beschreven voor het aanroepen van platformdeclaraties:

  • Gebruik een structuur die door de waarde wordt doorgegeven wanneer de onbeheerde functie geen indirecte invloed vereist.

  • Gebruik een structuur die wordt doorgegeven door verwijzing of een klasse die door een waarde wordt doorgegeven wanneer de onbeheerde functie één niveau van indirectie vereist.

  • Gebruik een klasse die door een verwijzing wordt doorgegeven wanneer de onbeheerde functie twee niveaus van indirectie vereist.

Structuren declareren en doorgeven

In het volgende voorbeeld ziet u hoe u de Point en Rect structuren in beheerde code definieert en de typen als parameter doorgeeft aan de functie PtInRect in het bestand User32.dll. PtInRect heeft de volgende onbeheerde handtekening:

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

U moet de rect-structuur doorgeven aan een verwijzing, omdat de functie een aanwijzer naar een RECT-type verwacht.

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);  
}  

Klassen declareren en doorgeven

U kunt leden van een klasse doorgeven aan een niet-beheerde DLL-functie, zolang de klasse een vaste lidindeling heeft. In het volgende voorbeeld ziet u hoe u leden van de MySystemTime klasse, die in opeenvolgende volgorde zijn gedefinieerd, doorgeeft aan GetSystemTimein het User32.dll-bestand. GetSystemTime heeft de volgende niet-beheerde handtekening:

void GetSystemTime(SYSTEMTIME* SystemTime);  

In tegenstelling tot waardetypen hebben klassen altijd ten minste één niveau van indirectie.

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);  
    }  
}  

Zie ook