Aracılığıyla paylaş


Sınıflar, Yapılar ve Birleşimler Hazırlama

Sınıflar ve yapılar .NET Framework'te benzerdir. Her ikisi de alanlara, özelliklere ve olaylara sahip olabilir. Statik ve statik olmayan yöntemlere de sahip olabilirler. Önemli bir fark, yapıların değer türleri, sınıfların ise başvuru türleri olmasıdır.

Aşağıdaki tabloda sınıflar, yapılar ve birleşimler için sıralama seçenekleri listelenmiştir; kullanımlarını açıklar; ve ilgili platform çağırma örneğine bir bağlantı sağlar.

Type Açıklama Örnek
Değere göre sınıf. Yönetilen büyük/küçük harf gibi, tamsayı üyelerine sahip bir sınıfı In/Out parametresi olarak geçirir. SysTime örneği
Değere göre yapı. Yapıları In parametreleri olarak geçirir. Yapılar örneği
Başvuruya göre yapı. Yapıları In/Out parametreleri olarak geçirir. OSInfo örneği
İç içe yapıları olan yapı (düzleştirilmiş). Yönetilmeyen işlevde iç içe geçmiş yapılara sahip bir yapıyı temsil eden bir sınıf geçirir. Yapı, yönetilen prototipte tek bir büyük yapıya düzleştirilmiştir. FindFile örneği
Başka bir yapıya işaret eden bir yapı. İkinci bir yapıya üye olarak işaretçi içeren bir yapı geçirir. Yapılar Örneği
Değere göre tamsayılar içeren yapı dizisi. Yalnızca tamsayılar içeren bir yapı dizisini In/Out parametresi olarak geçirir. Dizinin üyeleri değiştirilebilir. Dizi örneği
Başvuruya göre tamsayılar ve dizeler içeren yapıların dizisi. Tamsayılar ve dizeler içeren bir yapı dizisini Out parametresi olarak geçirir. Çağrılan işlev dizi için bellek ayırır. OutArrayOfStructs Örneği
Değer türleriyle birleşimler. Birleşimleri değer türleriyle (tamsayı ve çift) geçirir. Birleşimler örneği
Karma türleri olan birleşimler. Birleşimleri karma türlerle (tamsayı ve dize) geçirir. Birleşimler örneği
Platforma özgü düzen ile yapı. Yerel paketleme tanımlarıyla bir tür geçirir. Platform örneği
Yapıdaki null değerler. Bir değer türüne başvuru yerine null başvuru (Visual Basic'te hiçbir şey ) geçirir. HandleRef örneği

Yapılar örneği

Bu örnek, ikinci bir yapıya işaret eden bir yapıyı geçirmeyi, katıştırılmış bir yapıya sahip bir yapıyı geçirmeyi ve katıştırılmış bir diziyle bir yapı geçirmeyi gösterir.

Yapılar örneği, özgün işlev bildirimiyle gösterilen aşağıdaki yönetilmeyen işlevleri kullanır:

  • TestStructInStruct PinvokeLib.dll dışarı aktarıldı.

    int TestStructInStruct(MYPERSON2* pPerson2);
    
  • TestStructInStruct3 PinvokeLib.dll dışarı aktarıldı.

    void TestStructInStruct3(MYPERSON3 person3);
    
  • TestArrayInStruct PinvokeLib.dll dışarı aktarıldı.

    void TestArrayInStruct(MYARRAYSTRUCT* pStruct);
    

PinvokeLib.dll, daha önce listelenen işlevlerin ve dört yapının uygulamalarını içeren özel bir yönetilmeyen kitaplıktır: MYPERSON, MYPERSON2, MYPERSON3 ve MYARRAYSTRUCT. Bu yapılar aşağıdaki öğeleri içerir:

typedef struct _MYPERSON
{
   char* first;
   char* last;
} MYPERSON, *LP_MYPERSON;

typedef struct _MYPERSON2
{
   MYPERSON* person;
   int age;
} MYPERSON2, *LP_MYPERSON2;

typedef struct _MYPERSON3
{
   MYPERSON person;
   int age;
} MYPERSON3;

typedef struct _MYARRAYSTRUCT
{
   bool flag;
   int vals[ 3 ];
} MYARRAYSTRUCT;

Yönetilen MyPerson, MyPerson2, MyPerson3ve MyArrayStruct yapıları aşağıdaki özelliğe sahiptir:

  • MyPerson yalnızca dize üyelerini içerir. CharSet alanı, yönetilmeyen işleve geçirildiğinde dizeleri ANSI biçimine ayarlar.

  • MyPerson2yapısına MyPerson bir IntPtr içerir. .NET Framework uygulamaları kod güvenli değil olarak işaretlenmediği sürece işaretçileri kullanmadığından, IntPtr türü özgün işaretçiyi yönetilmeyen yapıyla değiştirir.

  • MyPerson3 ekli bir yapı olarak içerir MyPerson . Başka bir yapıya katıştırılmış bir yapı, katıştırılmış yapının öğeleri doğrudan ana yapıya yerleştirilerek düzleştirilebilir veya bu örnekte olduğu gibi katıştırılmış yapı olarak bırakılabilir.

  • MyArrayStruct bir tamsayı dizisi içerir. MarshalAsAttribute özniteliği numaralandırma değerini ByValArray olarak ayarlar UnmanagedType ve bu değer dizideki öğelerin sayısını belirtmek için kullanılır.

Bu örnekteki tüm yapılar için, üyelerin StructLayoutAttribute bellekte sırayla, göründükleri sırayla düzenlendiklerinden emin olmak için özniteliği uygulanır.

sınıfıNativeMethods, sınıfı tarafından App çağrılan , TestStructInStruct3ve TestArrayInStruct yöntemleri için TestStructInStructyönetilen prototipler içerir. Her prototip aşağıdaki gibi tek bir parametre bildirir:

  • TestStructInStruct parametresi olarak tür MyPerson2 başvurusu bildirir.

  • TestStructInStruct3 türü MyPerson3 parametresi olarak bildirir ve parametresini değere göre geçirir.

  • TestArrayInStruct parametresi olarak tür MyArrayStruct başvurusu bildirir.

Parametre ref (Visual Basic'te ByRef) anahtar sözcüğünü içermediği sürece, yöntemlere bağımsız değişken olarak yapılar değere göre geçirilir. Örneğin, TestStructInStruct yöntemi bir başvuruyu (adresin değeri) yönetilmeyen koda türündeki MyPerson2 bir nesneye geçirir. İşaret eden MyPerson2 yapıyı işlemek için, örnek belirtilen boyutta bir arabellek oluşturur ve ve Marshal.SizeOf yöntemlerini birleştirerek Marshal.AllocCoTaskMem adresini döndürür. Ardından, örnek yönetilen yapının içeriğini yönetilmeyen arabelleğe kopyalar. Son olarak, örnek yönetilmeyen arabellekten yönetilen bir nesneye verileri sıralamak için yöntemini ve Marshal.FreeCoTaskMem yönetilmeyen bellek bloğunu boşaltmak için yöntemini kullanırMarshal.PtrToStructure.

Prototipleri Bildirme

// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Ansi)]
public value struct MyPerson
{
public:
    String^ first;
    String^ last;
};

[StructLayout(LayoutKind::Sequential)]
public value struct MyPerson2
{
public:
    IntPtr person;
    int age;
};

[StructLayout(LayoutKind::Sequential)]
public value struct MyPerson3
{
public:
    MyPerson person;
    int age;
};

[StructLayout(LayoutKind::Sequential)]
public value struct MyArrayStruct
{
public:
    bool flag;
    [MarshalAs(UnmanagedType::ByValArray, SizeConst = 3)]
    array<int>^ vals;
};

private ref class NativeMethods
{
public:
    // Declares a managed prototype for unmanaged function.
    [DllImport("..\\LIB\\PinvokeLib.dll")]
    static int TestStructInStruct(MyPerson2% person2);

    [DllImport("..\\LIB\\PinvokeLib.dll")]
    static int TestStructInStruct3(MyPerson3 person3);

    [DllImport("..\\LIB\\PinvokeLib.dll")]
    static int TestArrayInStruct(MyArrayStruct% myStruct);
};
// Declares a managed structure for each unmanaged structure.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MyPerson
{
    public string first;
    public string last;
}

[StructLayout(LayoutKind.Sequential)]
public struct MyPerson2
{
    public IntPtr person;
    public int age;
}

[StructLayout(LayoutKind.Sequential)]
public struct MyPerson3
{
    public MyPerson person;
    public int age;
}

[StructLayout(LayoutKind.Sequential)]
public struct MyArrayStruct
{
    public bool flag;

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public int[] vals;
}

internal static class NativeMethods
{
    // Declares a managed prototype for unmanaged function.
    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestStructInStruct(ref MyPerson2 person2);

    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestStructInStruct3(MyPerson3 person3);

    [DllImport("..\\LIB\\PinvokeLib.dll", CallingConvention = CallingConvention.Cdecl)]
    internal static extern int TestArrayInStruct(ref MyArrayStruct myStruct);
}
' Declares a managed structure for each unmanaged structure.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)>
Public Structure MyPerson
    Public first As String
    Public last As String
End Structure

<StructLayout(LayoutKind.Sequential)>
Public Structure MyPerson2
    Public person As IntPtr
    Public age As Integer
End Structure

<StructLayout(LayoutKind.Sequential)>
Public Structure MyPerson3
    Public person As MyPerson
    Public age As Integer
End Structure

<StructLayout(LayoutKind.Sequential)>
Public Structure MyArrayStruct
    Public flag As Boolean
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)>
    Public vals As Integer()
End Structure

Friend Class NativeMethods
    ' Declares managed prototypes for unmanaged functions.
    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend Shared Function TestStructInStruct(
        ByRef person2 As MyPerson2) As Integer
    End Function

    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend Shared Function TestStructInStruct3(
        ByVal person3 As MyPerson3) As Integer
    End Function

    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend Shared Function TestArrayInStruct(
        ByRef myStruct As MyArrayStruct) As Integer
    End Function
End Class

İşlevleri Çağırma

public ref class App
{
public:
    static void Main()
    {
        // Structure with a pointer to another structure.
        MyPerson personName;
        personName.first = "Mark";
        personName.last = "Lee";

        MyPerson2 personAll;
        personAll.age = 30;

        IntPtr buffer = Marshal::AllocCoTaskMem(Marshal::SizeOf(personName));
        Marshal::StructureToPtr(personName, buffer, false);

        personAll.person = buffer;

        Console::WriteLine("\nPerson before call:");
        Console::WriteLine("first = {0}, last = {1}, age = {2}",
            personName.first, personName.last, personAll.age);

        int res = NativeMethods::TestStructInStruct(personAll);

        MyPerson personRes =
            (MyPerson)Marshal::PtrToStructure(personAll.person,
                MyPerson::typeid);

        Marshal::FreeCoTaskMem(buffer);

        Console::WriteLine("Person after call:");
        Console::WriteLine("first = {0}, last = {1}, age = {2}",
            personRes.first, personRes.last, personAll.age);

        // Structure with an embedded structure.
        MyPerson3 person3;// = gcnew MyPerson3();
        person3.person.first = "John";
        person3.person.last = "Evans";
        person3.age = 27;
        NativeMethods::TestStructInStruct3(person3);

        // Structure with an embedded array.
        MyArrayStruct myStruct;// = new MyArrayStruct();

        myStruct.flag = false;
        myStruct.vals = gcnew array<int>(3);
        myStruct.vals[0] = 1;
        myStruct.vals[1] = 4;
        myStruct.vals[2] = 9;

        Console::WriteLine("\nStructure with array before call:");
        Console::WriteLine(myStruct.flag);
        Console::WriteLine("{0} {1} {2}", myStruct.vals[0],
            myStruct.vals[1], myStruct.vals[2]);

        NativeMethods::TestArrayInStruct(myStruct);
        Console::WriteLine("\nStructure with array after call:");
        Console::WriteLine(myStruct.flag);
        Console::WriteLine("{0} {1} {2}", myStruct.vals[0],
            myStruct.vals[1], myStruct.vals[2]);
    }
};
public class App
{
    public static void Main()
    {
        // Structure with a pointer to another structure.
        MyPerson personName;
        personName.first = "Mark";
        personName.last = "Lee";

        MyPerson2 personAll;
        personAll.age = 30;

        IntPtr buffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(personName));
        Marshal.StructureToPtr(personName, buffer, false);

        personAll.person = buffer;

        Console.WriteLine("\nPerson before call:");
        Console.WriteLine("first = {0}, last = {1}, age = {2}",
            personName.first, personName.last, personAll.age);

        int res = NativeMethods.TestStructInStruct(ref personAll);

        MyPerson personRes =
            (MyPerson)Marshal.PtrToStructure(personAll.person,
            typeof(MyPerson));

        Marshal.FreeCoTaskMem(buffer);

        Console.WriteLine("Person after call:");
        Console.WriteLine("first = {0}, last = {1}, age = {2}",
            personRes.first, personRes.last, personAll.age);

        // Structure with an embedded structure.
        MyPerson3 person3 = new MyPerson3();
        person3.person.first = "John";
        person3.person.last = "Evans";
        person3.age = 27;
        NativeMethods.TestStructInStruct3(person3);

        // Structure with an embedded array.
        MyArrayStruct myStruct = new MyArrayStruct();

        myStruct.flag = false;
        myStruct.vals = new int[3];
        myStruct.vals[0] = 1;
        myStruct.vals[1] = 4;
        myStruct.vals[2] = 9;

        Console.WriteLine("\nStructure with array before call:");
        Console.WriteLine(myStruct.flag);
        Console.WriteLine("{0} {1} {2}", myStruct.vals[0],
            myStruct.vals[1], myStruct.vals[2]);

        NativeMethods.TestArrayInStruct(ref myStruct);
        Console.WriteLine("\nStructure with array after call:");
        Console.WriteLine(myStruct.flag);
        Console.WriteLine("{0} {1} {2}", myStruct.vals[0],
            myStruct.vals[1], myStruct.vals[2]);
    }
}
Public Class App
    Public Shared Sub Main()
        ' Structure with a pointer to another structure.
        Dim personName As MyPerson
        personName.first = "Mark"
        personName.last = "Lee"

        Dim personAll As MyPerson2
        personAll.age = 30

        Dim buffer As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(
            personName))
        Marshal.StructureToPtr(personName, buffer, False)

        personAll.person = buffer

        Console.WriteLine(ControlChars.CrLf & "Person before call:")
        Console.WriteLine("first = {0}, last = {1}, age = {2}",
            personName.first, personName.last, personAll.age)

        Dim res As Integer = NativeMethods.TestStructInStruct(personAll)

        Dim personRes As MyPerson =
            CType(Marshal.PtrToStructure(personAll.person,
            GetType(MyPerson)), MyPerson)

        Marshal.FreeCoTaskMem(buffer)

        Console.WriteLine("Person after call:")
        Console.WriteLine("first = {0}, last = {1}, age = {2}",
        personRes.first,
            personRes.last, personAll.age)

        ' Structure with an embedded structure.
        Dim person3 As New MyPerson3()
        person3.person.first = "John"
        person3.person.last = "Evans"
        person3.age = 27
        NativeMethods.TestStructInStruct3(person3)

        ' Structure with an embedded array.
        Dim myStruct As New MyArrayStruct()

        myStruct.flag = False
        Dim array(2) As Integer
        myStruct.vals = array
        myStruct.vals(0) = 1
        myStruct.vals(1) = 4
        myStruct.vals(2) = 9

        Console.WriteLine(vbNewLine + "Structure with array before call:")
        Console.WriteLine(myStruct.flag)
        Console.WriteLine("{0} {1} {2}", myStruct.vals(0),
            myStruct.vals(1), myStruct.vals(2))

        NativeMethods.TestArrayInStruct(myStruct)
        Console.WriteLine(vbNewLine + "Structure with array after call:")
        Console.WriteLine(myStruct.flag)
        Console.WriteLine("{0} {1} {2}", myStruct.vals(0),
            myStruct.vals(1), myStruct.vals(2))
    End Sub
End Class

FindFile örneği

Bu örnek, ikinci bir ekli yapı içeren bir yapının yönetilmeyen bir işleve nasıl geçirildiğini gösterir. Ayrıca yapı içinde sabit uzunlukta bir dizi bildirmek için özniteliğinin MarshalAsAttribute nasıl kullanılacağını gösterir. Bu örnekte, katıştırılmış yapı öğeleri üst yapıya eklenir. Düzleştirilmiş olmayan ekli bir yapı örneği için bkz . Yapı Örneği.

FindFile örneği, özgün işlev bildirimiyle gösterilen aşağıdaki yönetilmeyen işlevi kullanır:

  • Kernel32.dll dışarı aktarılan FindFirstFile .

    HANDLE FindFirstFile(LPCTSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);
    

İşleve geçirilen özgün yapı aşağıdaki öğeleri içerir:

typedef struct _WIN32_FIND_DATA
{
  DWORD    dwFileAttributes;
  FILETIME ftCreationTime;
  FILETIME ftLastAccessTime;
  FILETIME ftLastWriteTime;
  DWORD    nFileSizeHigh;
  DWORD    nFileSizeLow;
  DWORD    dwReserved0;
  DWORD    dwReserved1;
  TCHAR    cFileName[ MAX_PATH ];
  TCHAR    cAlternateFileName[ 14 ];
} WIN32_FIND_DATA, *PWIN32_FIND_DATA;

Bu örnekte sınıfı, FindData özgün yapının ve katıştırılmış yapının her öğesi için karşılık gelen bir veri üyesi içerir. İki özgün karakter arabelleği yerine, sınıf dizelerin yerini alır. MarshalAsAttribute , numaralandırmayı UnmanagedTypeByValTStr olarak ayarlar. Bu, yönetilmeyen yapıların içinde görünen satır içi, sabit uzunlukta karakter dizilerini tanımlamak için kullanılır.

NativeMethods sınıfı, sınıfı parametre olarak geçiren yöntemin yönetilen bir prototipini FindFirstFileFindData içerir. Başvuru türleri olan sınıflar varsayılan olarak In parametreleri olarak geçirildiğinden parametresi ve OutAttribute öznitelikleriyle bildirilmelidirInAttribute.

Prototipleri Bildirme

// Declares a class member for each structure element.
[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Auto)]
public ref class FindData
{
public:
    int  fileAttributes;
    // creationTime was an embedded FILETIME structure.
    int  creationTime_lowDateTime;
    int  creationTime_highDateTime;
    // lastAccessTime was an embedded FILETIME structure.
    int  lastAccessTime_lowDateTime;
    int  lastAccessTime_highDateTime;
    // lastWriteTime was an embedded FILETIME structure.
    int  lastWriteTime_lowDateTime;
    int  lastWriteTime_highDateTime;
    int  nFileSizeHigh;
    int  nFileSizeLow;
    int  dwReserved0;
    int  dwReserved1;
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 260)]
    String^  fileName;
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 14)]
    String^  alternateFileName;
};

private ref class NativeMethods
{
public:
    // Declares a managed prototype for the unmanaged function.
    [DllImport("Kernel32.dll", CharSet = CharSet::Auto)]
    static IntPtr FindFirstFile(String^ fileName, [In, Out]
        FindData^ findFileData);
};
// Declares a class member for each structure element.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class FindData
{
    public int fileAttributes = 0;
    // creationTime was an embedded FILETIME structure.
    public int creationTime_lowDateTime = 0;
    public int creationTime_highDateTime = 0;
    // lastAccessTime was an embedded FILETIME structure.
    public int lastAccessTime_lowDateTime = 0;
    public int lastAccessTime_highDateTime = 0;
    // lastWriteTime was an embedded FILETIME structure.
    public int lastWriteTime_lowDateTime = 0;
    public int lastWriteTime_highDateTime = 0;
    public int nFileSizeHigh = 0;
    public int nFileSizeLow = 0;
    public int dwReserved0 = 0;
    public int dwReserved1 = 0;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    public string fileName = null;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
    public string alternateFileName = null;
}

internal static class NativeMethods
{
    // Declares a managed prototype for the unmanaged function.
    [DllImport("Kernel32.dll", CharSet = CharSet.Auto)]
    internal static extern IntPtr FindFirstFile(
        string fileName, [In, Out] FindData findFileData);
}
' Declares a class member for each structure element.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)>
Public Class FindData
    Public fileAttributes As Integer = 0
    ' creationTime was a by-value FILETIME structure.
    Public creationTime_lowDateTime As Integer = 0
    Public creationTime_highDateTime As Integer = 0
    ' lastAccessTime was a by-value FILETIME structure.
    Public lastAccessTime_lowDateTime As Integer = 0
    Public lastAccessTime_highDateTime As Integer = 0
    ' lastWriteTime was a by-value FILETIME structure.
    Public lastWriteTime_lowDateTime As Integer = 0
    Public lastWriteTime_highDateTime As Integer = 0
    Public nFileSizeHigh As Integer = 0
    Public nFileSizeLow As Integer = 0
    Public dwReserved0 As Integer = 0
    Public dwReserved1 As Integer = 0
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=260)>
    Public fileName As String = Nothing
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=14)>
    Public alternateFileName As String = Nothing
End Class

Friend Class NativeMethods
    ' Declares a managed prototype for the unmanaged function.
    Friend Declare Auto Function FindFirstFile Lib "Kernel32.dll" (
        ByVal fileName As String, <[In], Out> ByVal findFileData As _
        FindData) As IntPtr
End Class

İşlevleri Çağırma

public ref class App
{
public:
    static void Main()
    {
        FindData^ fd = gcnew FindData();
        IntPtr handle = NativeMethods::FindFirstFile("C:\\*.*", fd);
        Console::WriteLine("The first file: {0}", fd->fileName);
    }
};
public class App
{
    public static void Main()
    {
        FindData fd = new FindData();
        IntPtr handle = NativeMethods.FindFirstFile("C:\\*.*", fd);
        Console.WriteLine($"The first file: {fd.fileName}");
    }
}
Public Class App
    Public Shared Sub Main()
        Dim fd As New FindData()
        Dim handle As IntPtr = NativeMethods.FindFirstFile("C:\*.*", fd)
        Console.WriteLine($"The first file: {fd.fileName}")
    End Sub
End Class

Birleşimler örneği

Bu örnek, yalnızca değer türlerini içeren yapıların ve bir değer türü ile dize içeren yapıların birleşim bekleyen yönetilmeyen bir işleve parametre olarak nasıl geçirildiklerini gösterir. Birleşim, iki veya daha fazla değişken tarafından paylaşılabilen bir bellek konumunu temsil eder.

Unions örneği, özgün işlev bildirimiyle gösterilen aşağıdaki yönetilmeyen işlevi kullanır:

  • TestUnion PinvokeLib.dll dışarı aktarıldı.

    void TestUnion(MYUNION u, int type);
    

PinvokeLib.dll, daha önce listelenen işlev ve MYUNION ve MYUNION2 olmak üzere iki birleşim için bir uygulama içeren özel yönetilmeyen bir kitaplıktır. Birleşimler aşağıdaki öğeleri içerir:

union MYUNION
{
    int number;
    double d;
}

union MYUNION2
{
    int i;
    char str[128];
};

Yönetilen kodda birleşimler yapı olarak tanımlanır. Yapı, MyUnion üyeleri olarak iki değer türü içerir: bir tamsayı ve bir çift. StructLayoutAttribute özniteliği, her veri üyesinin tam konumunu denetlemek için ayarlanır. özniteliği, FieldOffsetAttribute bir birleşimin yönetilmeyen gösterimi içindeki alanların fiziksel konumunu sağlar. Her iki üyenin de aynı uzaklık değerlerine sahip olduğuna dikkat edin, böylece üyeler aynı bellek parçasını tanımlayabilir.

MyUnion2_1 ve MyUnion2_2 sırasıyla bir değer türü (tamsayı) ve bir dize içerir. Yönetilen kodda, değer türlerinin ve başvuru türlerinin çakışmasına izin verilmez. Bu örnek, çağıranın aynı yönetilmeyen işlevi çağırırken her iki türü de kullanmasını sağlamak için yöntemi aşırı yüklemeyi kullanır. düzeni MyUnion2_1 açık ve hassas bir uzaklık değerine sahiptir. Buna karşılık, MyUnion2_2 açık düzenlere başvuru türleriyle izin verilmediğinden sıralı bir düzen vardır. MarshalAsAttribute özniteliği, numaralandırmayı UnmanagedTypeByValTStr olarak ayarlar. Bu, birleşimin yönetilmeyen gösteriminde görünen satır içi, sabit uzunlukta karakter dizilerini tanımlamak için kullanılır.

NativeMethods sınıfı ve TestUnion2 yöntemleri için TestUnion prototipleri içerir. TestUnion2 veya parametre olarak bildirmek MyUnion2_1MyUnion2_2 için aşırı yüklenmiştir.

Prototipleri Bildirme

// Declares managed structures instead of unions.
[StructLayout(LayoutKind::Explicit)]
public value struct MyUnion
{
public:
    [FieldOffset(0)]
    int i;
    [FieldOffset(0)]
    double d;
};

[StructLayout(LayoutKind::Explicit, Size = 128)]
public value struct MyUnion2_1
{
public:
    [FieldOffset(0)]
    int i;
};

[StructLayout(LayoutKind::Sequential)]
public value struct MyUnion2_2
{
public:
    [MarshalAs(UnmanagedType::ByValTStr, SizeConst = 128)]
    String^ str;
};

private ref class NativeMethods
{
public:
    // Declares managed prototypes for unmanaged function.
    [DllImport("..\\LIB\\PInvokeLib.dll")]
    static void TestUnion(MyUnion u, int type);

    [DllImport("..\\LIB\\PInvokeLib.dll")]
    static void TestUnion2(MyUnion2_1 u, int type);

    [DllImport("..\\LIB\\PInvokeLib.dll")]
    static void TestUnion2(MyUnion2_2 u, int type);
};
// Declares managed structures instead of unions.
[StructLayout(LayoutKind.Explicit)]
public struct MyUnion
{
    [FieldOffset(0)]
    public int i;
    [FieldOffset(0)]
    public double d;
}

[StructLayout(LayoutKind.Explicit, Size = 128)]
public struct MyUnion2_1
{
    [FieldOffset(0)]
    public int i;
}

[StructLayout(LayoutKind.Sequential)]
public struct MyUnion2_2
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string str;
}

internal static class NativeMethods
{
    // Declares managed prototypes for unmanaged function.
    [DllImport("..\\LIB\\PInvokeLib.dll")]
    internal static extern void TestUnion(MyUnion u, int type);

    [DllImport("..\\LIB\\PInvokeLib.dll")]
    internal static extern void TestUnion2(MyUnion2_1 u, int type);

    [DllImport("..\\LIB\\PInvokeLib.dll")]
    internal static extern void TestUnion2(MyUnion2_2 u, int type);
}
' Declares managed structures instead of unions.
<StructLayout(LayoutKind.Explicit)>
Public Structure MyUnion
    <FieldOffset(0)> Public i As Integer
    <FieldOffset(0)> Public d As Double
End Structure

<StructLayout(LayoutKind.Explicit, Size:=128)>
Public Structure MyUnion2_1
    <FieldOffset(0)> Public i As Integer
End Structure

<StructLayout(LayoutKind.Sequential)>
Public Structure MyUnion2_2
    <MarshalAs(UnmanagedType.ByValTStr, SizeConst:=128)>
    Public str As String
End Structure

Friend Class NativeMethods
    ' Declares managed prototypes for unmanaged function.
    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend Shared Sub TestUnion(
        ByVal u As MyUnion, ByVal type As Integer)
    End Sub

    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend Overloads Shared Sub TestUnion2(
        ByVal u As MyUnion2_1, ByVal type As Integer)
    End Sub

    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend Overloads Shared Sub TestUnion2(
        ByVal u As MyUnion2_2, ByVal type As Integer)
    End Sub
End Class

İşlevleri Çağırma

public ref class App
{
public:
    static void Main()
    {
        MyUnion mu;// = new MyUnion();
        mu.i = 99;
        NativeMethods::TestUnion(mu, 1);

        mu.d = 99.99;
        NativeMethods::TestUnion(mu, 2);

        MyUnion2_1 mu2_1;// = new MyUnion2_1();
        mu2_1.i = 99;
        NativeMethods::TestUnion2(mu2_1, 1);

        MyUnion2_2 mu2_2;// = new MyUnion2_2();
        mu2_2.str = "*** string ***";
        NativeMethods::TestUnion2(mu2_2, 2);
    }
};
public class App
{
    public static void Main()
    {
        MyUnion mu = new MyUnion();
        mu.i = 99;
        NativeMethods.TestUnion(mu, 1);

        mu.d = 99.99;
        NativeMethods.TestUnion(mu, 2);

        MyUnion2_1 mu2_1 = new MyUnion2_1();
        mu2_1.i = 99;
        NativeMethods.TestUnion2(mu2_1, 1);

        MyUnion2_2 mu2_2 = new MyUnion2_2();
        mu2_2.str = "*** string ***";
        NativeMethods.TestUnion2(mu2_2, 2);
    }
}
Public Class App
    Public Shared Sub Main()
        Dim mu As New MyUnion()
        mu.i = 99
        NativeMethods.TestUnion(mu, 1)

        mu.d = 99.99
        NativeMethods.TestUnion(mu, 2)

        Dim mu2_1 As New MyUnion2_1()
        mu2_1.i = 99
        NativeMethods.TestUnion2(mu2_1, 1)

        Dim mu2_2 As New MyUnion2_2()
        mu2_2.str = "*** string ***"
        NativeMethods.TestUnion2(mu2_2, 2)
    End Sub
End Class

Platform örneği

Bazı senaryolarda ve union düzenler hedeflenen struct platforma bağlı olarak farklılık gösterebilir. Örneğin, com senaryosunda tanımlandığında türünü göz önünde bulundurun STRRET :

#include <pshpack8.h> /* Defines the packing of the struct */
typedef struct _STRRET
    {
    UINT uType;
    /* [switch_is][switch_type] */ union
        {
        /* [case()][string] */ LPWSTR pOleStr;
        /* [case()] */ UINT uOffset;
        /* [case()] */ char cStr[ 260 ];
        }  DUMMYUNIONNAME;
    }  STRRET;
#include <poppack.h>

Yukarıdaki struct , türün bellek düzenini etkileyen Windows üst bilgileriyle bildirilir. Yönetilen bir ortamda tanımlandığında, yerel kodla düzgün bir şekilde birlikte çalışmak için bu düzen ayrıntıları gerekir.

32 bit işlemde bu türün doğru yönetilen tanımı:

[StructLayout(LayoutKind.Explicit, Size = 264)]
public struct STRRET_32
{
    [FieldOffset(0)]
    public uint uType;

    [FieldOffset(4)]
    public IntPtr pOleStr;

    [FieldOffset(4)]
    public uint uOffset;

    [FieldOffset(4)]
    public IntPtr cStr;
}

64 bitlik bir işlemde boyut ve alan uzaklıkları farklıdır. Doğru düzen şu şekildedir:

[StructLayout(LayoutKind.Explicit, Size = 272)]
public struct STRRET_64
{
    [FieldOffset(0)]
    public uint uType;

    [FieldOffset(8)]
    public IntPtr pOleStr;

    [FieldOffset(8)]
    public uint uOffset;

    [FieldOffset(8)]
    public IntPtr cStr;
}

Birlikte çalışma senaryosunda yerel düzenin düzgün düşünülmemesi rastgele kilitlenmelere veya daha kötü, yanlış hesaplamalara neden olabilir.

Varsayılan olarak, .NET derlemeleri .NET çalışma zamanının hem 32 bit hem de 64 bit sürümünde çalıştırılabilir. Uygulama, önceki tanımlardan hangisinin kullanılacağına karar vermek için çalışma süresine kadar beklemelidir.

Aşağıdaki kod parçacığında, çalışma zamanında 32 bit ile 64 bit tanımı arasında seçim yapma örneği gösterilmektedir.

if (IntPtr.Size == 8)
{
    // Use the STRRET_64 definition
}
else
{
    Debug.Assert(IntPtr.Size == 4);
    // Use the STRRET_32 definition
}

SysTime örneği

Bu örnek, bir işaretçiyi bir yapıya bekleyen yönetilmeyen bir işleve bir sınıfa nasıl geçirildiğini gösterir.

SysTime örneği, özgün işlev bildirimiyle gösterilen aşağıdaki yönetilmeyen işlevi kullanır:

  • getSystemTime Kernel32.dll dışarı aktarıldı.

    VOID GetSystemTime(LPSYSTEMTIME lpSystemTime);
    

İşleve geçirilen özgün yapı aşağıdaki öğeleri içerir:

typedef struct _SYSTEMTIME {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
} SYSTEMTIME, *PSYSTEMTIME;

Bu örnekte sınıfı, SystemTime sınıf üyeleri olarak temsil edilen özgün yapının öğelerini içerir. StructLayoutAttribute özniteliği, üyelerin bellekte sırayla, göründükleri sırayla düzenlendiklerinden emin olmak için ayarlanır.

sınıfı, NativeMethods sınıfı varsayılan olarak In/Out parametresi olarak geçiren yöntemin SystemTime yönetilen bir prototipini GetSystemTime içerir. Başvuru türleri olan sınıflar varsayılan olarak In parametreleri olarak geçirildiğinden parametresi ve OutAttribute öznitelikleriyle bildirilmelidirInAttribute. Çağıranın sonuçları alması için bu yön özniteliklerinin açıkça uygulanması gerekir. sınıfı, App sınıfının yeni bir örneğini SystemTime oluşturur ve veri alanlarına erişir.

Kod Örnekleri

using namespace System;
using namespace System::Runtime::InteropServices;     // For StructLayout, DllImport

[StructLayout(LayoutKind::Sequential)]
public ref class SystemTime
{
public:
    unsigned short year;
    unsigned short month;
    unsigned short weekday;
    unsigned short day;
    unsigned short hour;
    unsigned short minute;
    unsigned short second;
    unsigned short millisecond;
};

public class NativeMethods
{
public:
    // Declares a managed prototype for the unmanaged function using Platform Invoke.
    [DllImport("Kernel32.dll")]
    static void GetSystemTime([In, Out] SystemTime^ st);
};

public class App
{
public:
    static void Main()
    {
        Console::WriteLine("C++/CLI SysTime Sample using Platform Invoke");
        SystemTime^ st = gcnew SystemTime();
        NativeMethods::GetSystemTime(st);
        Console::Write("The Date is: ");
        Console::Write("{0} {1} {2}", st->month, st->day, st->year);
    }
};

int main()
{
    App::Main();
}
// The program produces output similar to the following:
//
// C++/CLI SysTime Sample using Platform Invoke
// The Date is: 3 21 2010
using System;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public class SystemTime
{
    public ushort year;
    public ushort month;
    public ushort weekday;
    public ushort day;
    public ushort hour;
    public ushort minute;
    public ushort second;
    public ushort millisecond;
}

internal static class NativeMethods
{
    // Declares a managed prototype for the unmanaged function using Platform Invoke.
    [DllImport("Kernel32.dll")]
    internal static extern void GetSystemTime([In, Out] SystemTime st);
}

public class App
{
    public static void Main()
    {
        Console.WriteLine("C# SysTime Sample using Platform Invoke");
        SystemTime st = new SystemTime();
        NativeMethods.GetSystemTime(st);
        Console.Write("The Date is: ");
        Console.Write($"{st.month} {st.day} {st.year}");
    }
}

// The program produces output similar to the following:
//
// C# SysTime Sample using Platform Invoke
// The Date is: 3 21 2010
Imports System.Runtime.InteropServices

' Declares a class member for each structure element.
<StructLayout(LayoutKind.Sequential)>
Public Class SystemTime
    Public year As Short
    Public month As Short
    Public weekday As Short
    Public day As Short
    Public hour As Short
    Public minute As Short
    Public second As Short
    Public millisecond As Short
End Class

Friend Class NativeMethods
    ' Declares a managed prototype for the unmanaged function.
    Friend Declare Sub GetSystemTime Lib "Kernel32.dll" (
        <[In](), Out()> ByVal st As SystemTime)
End Class

Public Class App
    Public Shared Sub Main()
        Console.WriteLine("VB .NET SysTime Sample using Platform Invoke")
        Dim st As New SystemTime()
        NativeMethods.GetSystemTime(st)
        Console.Write($"The Date is: {st.month} {st.day} {st.year}")
    End Sub
End Class
' The program produces output similar to the following:
'
' VB .NET SysTime Sample using Platform Invoke
' The Date is: 3 21 2010

OutArrayOfStructs örneği

Bu örnek, tamsayılar ve dizeler içeren bir yapı dizisinin yönetilmeyen bir işleve Out parametresi olarak nasıl geçirildiğini gösterir.

Bu örnek, sınıfını kullanarak ve güvenli olmayan kod kullanarak yerel işlevi çağırmayı Marshal gösterir.

Bu örnek, kaynak dosyalarda da sağlanan PinvokeLib.dll tanımlanan sarmalayıcı işlevlerini ve platform çağrılarını kullanır. işlevini ve MYSTRSTRUCT2 yapısını kullanırTestOutArrayOfStructs. Yapı aşağıdaki öğeleri içerir:

typedef struct _MYSTRSTRUCT2
{
   char* buffer;
   UINT size;
} MYSTRSTRUCT2;

sınıfı ANSI MyStruct karakterlerinden oluşan bir dize nesnesi içerir. alanı CharSet ANSI biçimini belirtir. MyUnsafeStruct, dize yerine tür IntPtr içeren bir yapıdır.

NativeMethods sınıfı aşırı yüklenmiş TestOutArrayOfStructs prototip yöntemini içerir. Bir yöntem bir işaretçiyi parametre olarak bildirirse, sınıfı anahtar unsafe sözcüğüyle işaretlenmelidir. Visual Basic güvenli olmayan kodu kullanamadığından, aşırı yüklenmiş yöntem, güvenli olmayan değiştirici ve MyUnsafeStruct yapı gereksizdir.

App sınıfı, diziyi UsingMarshaling geçirmek için gereken tüm görevleri gerçekleştiren yöntemini uygular. Dizi, verilerin çağırandan çağırana geçtiğini belirtmek için (ByRef Visual Basic'te) anahtar sözcüğüyle out işaretlenir. Uygulama aşağıdaki Marshal sınıf yöntemlerini kullanır:

  • PtrToStructure yönetilmeyen arabellekten yönetilen bir nesneye verileri sıralamak için.

  • DestroyStructure yapısındaki dizeler için ayrılmış belleği serbest bırakmak için.

  • FreeCoTaskMem dizi için ayrılmış belleği serbest bırakmak için.

Daha önce belirtildiği gibi, C# güvenli olmayan koda izin verir ve Visual Basic izin vermez. C# örneğinde, UsingUnsafePointer yapıyı içeren MyUnsafeStruct diziyi geri geçirmek için sınıfı yerine Marshal işaretçiler kullanan alternatif bir yöntem uygulamasıdır.

Prototipleri Bildirme

// Declares a class member for each structure element.
[StructLayout(LayoutKind::Sequential, CharSet = CharSet::Ansi)]
public ref class MyStruct
{
public:
    String^ buffer;
    int size;
};

// Declares a structure with a pointer.
[StructLayout(LayoutKind::Sequential)]
public value struct MyUnsafeStruct
{
public:
    IntPtr buffer;
    int size;
};

private ref class NativeMethods
{
public:
    // Declares managed prototypes for the unmanaged function.
    [DllImport("..\\LIB\\PInvokeLib.dll")]
    static void TestOutArrayOfStructs(int% size, IntPtr% outArray);

    [DllImport("..\\LIB\\PInvokeLib.dll")]
    static void TestOutArrayOfStructs(int% size, MyUnsafeStruct** outArray);
};
// Declares a class member for each structure element.
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class MyStruct
{
    public string buffer;
    public int size;
}

// Declares a structure with a pointer.
[StructLayout(LayoutKind.Sequential)]
public struct MyUnsafeStruct
{
    public IntPtr buffer;
    public int size;
}

internal static unsafe class NativeMethods
{
    // Declares managed prototypes for the unmanaged function.
    [DllImport("..\\LIB\\PInvokeLib.dll")]
    internal static extern void TestOutArrayOfStructs(
        out int size, out IntPtr outArray);

    [DllImport("..\\LIB\\PInvokeLib.dll")]
    internal static extern void TestOutArrayOfStructs(
        out int size, MyUnsafeStruct** outArray);
}
' Declares a class member for each structure element.
<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Ansi)>
Public Class MyStruct
    Public buffer As String
    Public someSize As Integer
End Class

Friend Class NativeMethods
    ' Declares a managed prototype for the unmanaged function.
    <DllImport("..\LIB\PinvokeLib.dll", CallingConvention:=CallingConvention.Cdecl)>
    Friend Shared Sub TestOutArrayOfStructs(
        ByRef arrSize As Integer, ByRef outArray As IntPtr)
    End Sub
End Class

İşlevleri Çağırma

public ref class App
{
public:
    static void Main()
    {
        Console::WriteLine("\nUsing marshal class\n");
        UsingMarshaling();
        Console::WriteLine("\nUsing unsafe code\n");
        UsingUnsafePointer();
    }

    static void UsingMarshaling()
    {
        int size;
        IntPtr outArray;

        NativeMethods::TestOutArrayOfStructs(size, outArray);
        array<MyStruct^>^ manArray = gcnew array<MyStruct^>(size);
        IntPtr current = outArray;
        for (int i = 0; i < size; i++)
        {
            manArray[i] = gcnew MyStruct();
            Marshal::PtrToStructure(current, manArray[i]);

            Marshal::DestroyStructure(current, MyStruct::typeid);
            //current = (IntPtr)((long)current + Marshal::SizeOf(manArray[i]));
            current = current + Marshal::SizeOf(manArray[i]);

            Console::WriteLine("Element {0}: {1} {2}", i, manArray[i]->buffer,
                manArray[i]->size);
        }
        Marshal::FreeCoTaskMem(outArray);
    }

    static void UsingUnsafePointer()
    {
        int size;
        MyUnsafeStruct* pResult;

        NativeMethods::TestOutArrayOfStructs(size, &pResult);
        MyUnsafeStruct* pCurrent = pResult;
        for (int i = 0; i < size; i++, pCurrent++)
        {
            Console::WriteLine("Element {0}: {1} {2}", i,
                Marshal::PtrToStringAnsi(pCurrent->buffer), pCurrent->size);
            Marshal::FreeCoTaskMem(pCurrent->buffer);
        }
        Marshal::FreeCoTaskMem((IntPtr)pResult);
    }
};
public class App
{
    public static void Main()
    {
        Console.WriteLine("\nUsing marshal class\n");
        UsingMarshaling();
        Console.WriteLine("\nUsing unsafe code\n");
        UsingUnsafePointer();
    }

    public static void UsingMarshaling()
    {
        int size;
        IntPtr outArray;

        NativeMethods.TestOutArrayOfStructs(out size, out outArray);
        MyStruct[] manArray = new MyStruct[size];
        IntPtr current = outArray;
        for (int i = 0; i < size; i++)
        {
            manArray[i] = new MyStruct();
            Marshal.PtrToStructure(current, manArray[i]);

            //Marshal.FreeCoTaskMem((IntPtr)Marshal.ReadInt32(current));
            Marshal.DestroyStructure(current, typeof(MyStruct));
            current = (IntPtr)((long)current + Marshal.SizeOf(manArray[i]));

            Console.WriteLine("Element {0}: {1} {2}", i, manArray[i].buffer,
                manArray[i].size);
        }

        Marshal.FreeCoTaskMem(outArray);
    }

    public static unsafe void UsingUnsafePointer()
    {
        int size;
        MyUnsafeStruct* pResult;

        NativeMethods.TestOutArrayOfStructs(out size, &pResult);
        MyUnsafeStruct* pCurrent = pResult;
        for (int i = 0; i < size; i++, pCurrent++)
        {
            Console.WriteLine("Element {0}: {1} {2}", i,
                Marshal.PtrToStringAnsi(pCurrent->buffer), pCurrent->size);
            Marshal.FreeCoTaskMem(pCurrent->buffer);
        }

        Marshal.FreeCoTaskMem((IntPtr)pResult);
    }
}
Public Class App
    Public Shared Sub Main()
        Console.WriteLine(vbNewLine + "Using marshal class" + vbNewLine)
        UsingMarshaling()
        'Visual Basic 2005 cannot use unsafe code.
    End Sub

    Public Shared Sub UsingMarshaling()
        Dim arrSize As Integer
        Dim outArray As IntPtr

        NativeMethods.TestOutArrayOfStructs(arrSize, outArray)
        Dim manArray(arrSize - 1) As MyStruct
        Dim current As IntPtr = outArray
        Dim i As Integer

        For i = 0 To arrSize - 1
            manArray(i) = New MyStruct()
            Marshal.PtrToStructure(current, manArray(i))

            Marshal.DestroyStructure(current, GetType(MyStruct))
            current = IntPtr.op_Explicit(current.ToInt64() _
                + Marshal.SizeOf(manArray(i)))

            Console.WriteLine("Element {0}: {1} {2}", i, manArray(i).
                buffer, manArray(i).someSize)
        Next i
        Marshal.FreeCoTaskMem(outArray)
    End Sub
End Class

Ayrıca bkz.