Á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 közvetett 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álhatók a Point
és Rect
struktúrák a felügyelt kódban, és hogyan adhatók át ezek a típusok paraméterként a PtInRect függvény számára a User32.dll fájlban.
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 továbbítá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);
}
}