Megosztás a következőn keresztül:


Átmenő struktúrák

Számos nem felügyelt függvény elvárja, hogy paraméterként átadja a függvénynek a struktúrák tagjait (a Visual Basic felhasználó által definiált típusait) vagy a felügyelt kódban definiált osztályok tagjait. Ha struktúrákat vagy osztályokat ad át nem felügyelt kódnak platformhívás használatával, további információkat kell megadnia az eredeti elrendezés és igazítás megőrzése érdekében. Ez a témakör bemutatja a StructLayoutAttribute formázott típusok definiálásához használt attribútumot. Felügyelt struktúrák és osztályok esetén az LayoutKind enumerálás által biztosított számos kiszámítható elrendezési viselkedés közül választhat.

A jelen témakörben bemutatott fogalmak központi eleme a struktúra és az osztálytípusok közötti fontos különbség. A struktúrák értéktípusok, az osztályok pedig referenciatípusok – az osztályok mindig legalább egy szintű közvetett memóriát biztosítanak (egy értékre mutató mutatót). Ez a különbség azért fontos, mert a nem felügyelt függvények gyakran indirekt műveletet igényelnek, ahogyan azt az alábbi táblázat első oszlopában látható aláírások is mutatják. A fennmaradó oszlopok felügyelt struktúrája és osztálydeklarációi azt mutatják, hogy milyen mértékben módosíthatja a deklaráció közvetettségi szintjét. A deklarációk a Visual Basic és a Visual C# esetében is elérhetők.

Nem felügyelt aláírás Felügyelt deklaráció:
nincs indirekt
Structure MyType
struct MyType;
Felügyelt deklaráció:
a közvetettség egy szintje
Class MyType
class MyType;
DoWork(MyType x);

Nulla indirektségi szintet igényel.
DoWork(ByVal x As MyType)
DoWork(MyType x)

Nulla indirekt szintet ad hozzá.
Nem lehetséges, mert már van egy szintű közvetettség.
DoWork(MyType* x);

Egy szintű közvetettségre van szükség.
DoWork(ByRef x As MyType)
DoWork(ref MyType x)

Egy szintű indirektizációt ad hozzá.
DoWork(ByVal x As MyType)
DoWork(MyType x)

Nulla indirekt szintet ad hozzá.
DoWork(MyType** x);

Két szintű közvetettségre van szükség.
Nem lehetséges, mert ByRef ByRef vagy ref ref nem használható. DoWork(ByRef x As MyType)
DoWork(ref MyType x)

Egy szintű indirektizációt ad hozzá.

A táblázat a következő irányelveket ismerteti a platformhívási deklarációkhoz:

  • Érték által átadott struktúrát használjon, ha a nem felügyelt függvény nem igényel közvetett elemet.

  • Használjon hivatkozással átadott struktúrát, vagy érték által átadott osztályt, ha a nem felügyelt függvény egy szintű indirektizációt igényel.

  • Használjon hivatkozással átadott osztályt, ha a nem felügyelt függvény két indirekt szintet igényel.

Struktúrák deklarálása és átadása

Az alábbi példa bemutatja, hogyan definiálhatja a felügyelt kódban a struktúrákat és a Point típusokat paraméterként a User32.dll fájl PtInRect függvényének.Rect A PtInRect a következő nem felügyelt aláírással rendelkezik:

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

Figyelje meg, hogy referencia alapján kell átadnia a Rect-struktúrát, mivel a függvény egy RECT-típusra mutató mutatót vár.

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

Osztályok deklarálása és átadása

Az osztály tagjait átadhatja egy nem felügyelt DLL-függvénynek, ha az osztály rögzített tagelrendezéssel rendelkezik. Az alábbi példa bemutatja, hogyan adhatja át az MySystemTime osztály szekvenciális sorrendben definiált tagjait a GetSystemTime-nak a User32.dll fájlban. A GetSystemTime a következő nem felügyelt aláírást tartalmazza:

void GetSystemTime(SYSTEMTIME* SystemTime);  

Az értéktípusoktól eltérően az osztályoknak mindig van legalább egy közvetett szintje.

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

Lásd még