Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
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.
| Türü | Açıklama | Örnek |
|---|---|---|
| Değere göre sınıf. | Yönetilen durumda olduğu gibi, tamsayı üyeleri olan bir sınıfı Girdi/Çıktı parametresi olarak geçirir. | SysTime örneği |
| Değere göre yapı. | Yapıları girdi parametreleri olarak geçirir. | Örnek yapılar |
| Referansa göre yapı. | Yapıları giriş/çıkış (In/Out) parametreleri olarak geçirir. | OSInfo örneği |
| İç içe yapılar içeren yapı (düzleştirilmiş). | Yönetilmeyen bir 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 işaretçi içeren bir yapıyı üye olarak 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 |
| Referans aracılığıyla tamsayılar ve metinler 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. | Değer türleri (tamsayı ve ondalık) ile birleşimleri geçirir. | Sendikalar örneği |
| Karma türleri olan birleşimler. | Karma türlerle (tamsayı ve metin) birleşimleri kabul eder. | Sendikalar örneği |
| Platforma özgü düzen ile yapı. | Yerel paketleme tanımlarına sahip bir tür aktarır. | Platform örneği |
| Yapıdaki null değerler. | Bir değer türüne başvuru yerine null referans (Nothing in Visual Basic) geçirir. | HandleRef örneği |
Yapı örneği
Bu örnek, ikinci bir yapıya işaret eden bir yapıyı geçirmeyi, içinde gömülü bir yapıya sahip bir yapıyı geçirmeyi ve içinde gömülü 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:
TestStructInStructPinvokeLib.dll dışa aktarıldı.int TestStructInStruct(MYPERSON2* pPerson2);PinvokeLib.dll'dan dışarı aktarılan TestStructInStruct3 .
void TestStructInStruct3(MYPERSON3 person3);TestArrayInStructPinvokeLib.dll dışa 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:
MyPersonyalnızca dize üyelerini içerir. CharSet alanı, yönetilmeyen işleve geçirildiğinde dizeleri ANSI biçimine ayarlar.MyPerson2birIntPtrMyPersonyapısına içerir.IntPtrtürü, .NET Framework uygulamaları kod güvensiz olarak işaretlenmediği sürece işaretçileri kullanmadığı için, yönetilmeyen yapının özgün işaretçisinin yerini alır.MyPerson3,MyPersonöğesini ekli bir yapı olarak içerir. 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.MyArrayStructbir tamsayı dizisi içerir. MarshalAsAttribute özniteliği numaralandırma değerini UnmanagedType olarak ayarlar ve bu değer dizideki öğelerin sayısını belirtmek için kullanılır.
Bu örnekteki tüm yapılar için, üyelerin bellekte göründükleri sırayla düzenlenmesini sağlamak amacıyla StructLayoutAttribute özniteliği uygulanır.
NativeMethods sınıfı, TestStructInStruct, TestStructInStruct3 ve TestArrayInStruct yöntemleri için App sınıfı tarafından çağrılan yönetilen prototipleri içerir. Her prototip aşağıdaki gibi tek bir parametre bildirir:
Tür
TestStructInStruct'ye yapılan bir referansı parametre olarakMyPerson2bildirir.TestStructInStruct3türünüMyPerson3parametresi olarak bildirir ve parametreyi değer olarak geçirir.Tür
TestArrayInStruct'ye yapılan bir referansı parametre olarakMyArrayStructbildirir.
Parametre (Visual Basic'te ref) 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, türü MyPerson2 olan bir nesneye başvuruyu (adresin değeri) yönetilmeyen koda aktarır. İşaret eden MyPerson2 yapıyı işlemek için, örnek belirtilen boyutta bir arabellek oluşturur ve Marshal.AllocCoTaskMem ile Marshal.SizeOf yöntemlerini birleştirerek bu adresi döndürür. Ardından, örnek yönetilen yapının içeriğini yönetilmeyen arabelleğe kopyalar. Son olarak, örnek, verileri yönetilmeyen arabellekten yönetilen bir nesneye taşımak için Marshal.PtrToStructure yöntemini ve yönetilmeyen bellek bloğunu boşaltmak için Marshal.FreeCoTaskMem yöntemini kullanır.
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($"{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($"{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ştirilmemiş bir gömülü 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:
FindFirstFileKernel32.dll dışa aktarıldı.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. Sınıf, iki özgün karakter arabelleği yerine dizeleri kullanır.
MarshalAsAttribute , yönetilmeyen yapıların UnmanagedType içinde görünen satır içi, sabit uzunlukta karakter dizilerini tanımlamak için kullanılan numaralandırmayı ByValTStrolarak ayarlar.
NativeMethods sınıfı, FindFirstFile sınıfını parametre olarak geçiren FindData yönteminin yönetilen bir prototipini içerir. Parametre, başvuru türleri olan sınıflar varsayılan olarak In parametresi olarak geçirildiğinden, InAttribute ve OutAttribute öznitelikleriyle bildirilmelidir.
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
Birlikler ö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:
TestUnionPinvokeLib.dll dışa aktarıldı.void TestUnion(MYUNION u, int type);
PinvokeLib.dll, daha önce listelenen işlev ve iki birleşimin (MYUNION ve MYUNION2) bir uygulamasını içeren özel bir yönetilmeyen kütüphanedir. 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. Bu FieldOffsetAttribute özniteliği, bir birleşimin yönetilmeyen temsili 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.
MyUnion2_1 düzeni belirgin ve kesin bir uzaklık değerine sahiptir. Buna karşılık, MyUnion2_2 sıralı bir düzene sahiptir, çünkü başvuru türleriyle açık düzenlere izin verilmez.
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ı, TestUnion ve TestUnion2 yöntemleri için prototipleri içerir.
TestUnion2, parametre olarak MyUnion2_1 veya MyUnion2_2 belirtmek 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, struct ve union düzenleri hedeflenen platforma bağlı olarak farklılık gösterebilir. Örneğin, bir COM senaryosunda tanımlandığında STRRET türünü göz önünde bulundurun.
#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 başlık dosyalarıyla birlikte 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 değerlendirilmemesi beklenmedik çöküşlere veya daha da kötüsü, 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 zamanına 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 sınıfa işaretçiyi, bir yapı işaretçisini bekleyen yönetilmeyen bir işlevine nasıl geçirileceğini gösterir.
SysTime örneği, özgün işlev bildirimiyle gösterilen aşağıdaki yönetilmeyen işlevi kullanır:
GetSystemTimeKernel32.dll dışa 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, SystemTime sınıfı 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.
NativeMethods sınıfı, GetSystemTime sınıfını varsayılan olarak In/Out parametresi olarak ileten SystemTime yönteminin yönetilen bir prototipini içerir. Parametre, başvuru türleri olan sınıflar varsayılan olarak In parametresi olarak geçirildiğinden, InAttribute ve OutAttribute öznitelikleriyle bildirilmelidir. Çağıranın sonuçları alması için bu yön özniteliklerinin açıkça uygulanması gerekir.
App sınıfı, SystemTime sınıfının yeni bir örneğini oluşturur ve onun veri alanlarına erişim sağlar.
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, Marshal sınıfını ve güvensiz kodu kullanarak yerleşik bir işlevin nasıl çağrılacağını gösterir.
Bu örnek, kaynak dosyalarda da sağlanan PinvokeLib.dlliçinde tanımlanan sarmalayıcı işlevlerini ve platform çağrılarını kullanır.
TestOutArrayOfStructs işlevini ve MYSTRSTRUCT2 yapısını kullanır. 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, bir dize yerine IntPtr türü 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ı, dizi geçirme işlemini gerçekleştiren UsingMarshaling yöntemini uygular. Dizi, verilerin çağırandan çağırana geçtiğini belirtmek için (out Visual Basic'te) anahtar sözcüğüyle ByRef işaretlenir. Uygulama aşağıdaki Marshal sınıf yöntemlerini kullanır:
PtrToStructure yönetilmeyen arabellekten yönetilen bir nesneye verileri aktarmak 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 Marshal dizisini geri döndürmek için sınıf yerine işaretçi kullanan alternatif bir yöntem uygulanmaktadı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 {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 {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