Yapıları Geçirme
Yönetilmeyen birçok işlev, işleve parametre olarak yapıların üyelerini (Visual Basic'te kullanıcı tanımlı türler) veya yönetilen kodda tanımlanan sınıfların üyelerini geçirmenizi bekler. Platform çağrısı kullanarak yapıları veya sınıfları yönetilmeyen koda geçirirken, özgün düzeni ve hizalamayı korumak için ek bilgiler sağlamanız gerekir. Bu konu, biçimlendirilmiş türleri tanımlamak için kullandığınız özniteliğini tanıtır StructLayoutAttribute . Yönetilen yapılar ve sınıflar için LayoutKind sabit listesi tarafından sağlanan tahmin edilebilir çeşitli düzen davranışları arasından seçim yapabilirsiniz.
Bu konuda sunulan kavramların merkezi, yapı ve sınıf türleri arasındaki önemli bir farktır. Yapılar değer türleridir ve sınıflar başvuru türleridir; sınıflar her zaman en az bir bellek dolaylı düzeyi (değer işaretçisi) sağlar. Yönetilmeyen işlevler genellikle aşağıdaki tablonun ilk sütunundaki imzalar tarafından gösterildiği gibi dolaylı işlem gerektirdiğinden bu fark önemlidir. Kalan sütunlardaki yönetilen yapı ve sınıf bildirimleri, bildiriminizdeki dolaylılık düzeyini ne derece ayarlayabileceğinizi gösterir. Hem Visual Basic hem de Visual C# için bildirimler sağlanır.
Yönetilmeyen imza | Yönetilen bildirim: dolaylı yok Structure MyType struct MyType; |
Yönetilen bildirim: bir dolaylılık düzeyi Class MyType class MyType; |
---|---|---|
DoWork(MyType x); Sıfır dolaylılık düzeyi talep ediyor. |
DoWork(ByVal x As MyType) DoWork(MyType x) Sıfır dolaylı düzey ekler. |
Zaten bir dolaylılık düzeyi olduğundan mümkün değildir. |
DoWork(MyType* x); Bir düzeyde dolaylılık talep eder. |
DoWork(ByRef x As MyType) DoWork(ref MyType x) Bir düzey dolaylılık ekler. |
DoWork(ByVal x As MyType) DoWork(MyType x) Sıfır dolaylı düzey ekler. |
DoWork(MyType** x); İki düzeyde dolaylılık talep ediyor. |
ByRef ByRef veya ref ref kullanılamadığından mümkün değil. |
DoWork(ByRef x As MyType) DoWork(ref MyType x) Bir düzey dolaylılık ekler. |
Tabloda platform çağırma bildirimleri için aşağıdaki yönergeler açıklanmaktadır:
Yönetilmeyen işlev herhangi bir dolaylılık gerektirmediğinde değer tarafından geçirilen bir yapı kullanın.
Yönetilmeyen işlev bir düzeyde dolaylılık gerektirdiğinde, başvuru tarafından geçirilen bir yapıyı veya değer tarafından geçirilen bir sınıfı kullanın.
Yönetilmeyen işlev iki düzeyde dolaylılık gerektirdiğinde başvuru tarafından geçirilen bir sınıf kullanın.
Yapıları Bildirme ve Geçirme
Aşağıdaki örnekte yönetilen kodda ve Rect
yapılarının Point
nasıl tanımlanacağı ve türlerin parametre olarak User32.dll dosyasındaki PtInRect işlevine nasıl geçirildiği gösterilmektedir. PtInRect aşağıdaki yönetilmeyen imzaya sahiptir:
BOOL PtInRect(const RECT *lprc, POINT pt);
İşlev bir RECT türüne işaretçi beklediğinden, Rect yapısını başvuruya göre geçirmeniz gerektiğine dikkat edin.
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);
}
Sınıfları Bildirme ve Geçirme
Sınıfın üyelerini, sınıfın sabit bir üye düzenine sahip olduğu sürece yönetilmeyen DLL işlevine geçirebilirsiniz. Aşağıdaki örnek, sıralı sırada tanımlanan sınıfın üyelerini MySystemTime
User32.dll dosyasındaki GetSystemTime'a geçirmeyi gösterir. GetSystemTime aşağıdaki yönetilmeyen imzaya sahiptir:
void GetSystemTime(SYSTEMTIME* SystemTime);
Değer türlerinden farklı olarak, sınıfların her zaman en az bir dolaylı düzeyi vardır.
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);
}
}