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

Ayrıca bkz.