http://msdn.microsoft.com/zh-cn/windows/hardware/eadtsekz(v=vs.71)
該示例說明如何傳遞指向另一個結構的結構,如何傳遞具有嵌入結構的結構,以及如何傳遞具有嵌入數組的結構。
Structs 示例使用以下非託管函數(這裏同時顯示其原始函數聲明):
-
從 PinvokeLib.dll 導出的 TestStructInStruct。
int TestStructInStruct(MYPERSON2* pPerson2);
-
從 PinvokeLib.dll 導出的 TestStructInStruct3。
void TestStructInStruct3(MYPERSON3 person3);
-
從 PinvokeLib.dll 導出的 TestArrayInStruct。
void TestArrayInStruct( MYARRAYSTRUCT* pStruct );
PinvokeLib.dll 是一個自定義非託管庫,它包含前面列出的函數的實現和以下四種結構:MYPERSON、MYPERSON2、MYPERSON3 和 MYARRAYSTRUCT。 這些結構包含以下元素:
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;
託管的MyPerson、MyPerson2、MyPerson3和MyArrayStruct結構具有以下特徵:
-
MyPerson只包含字符串成員。 CharSet 字段在傳遞給非託管函數時將這些字符串設置爲
ANSI 格式。
-
MyPerson2包含一個指向MyPerson結構的 IntPtr。 IntPtr 類型將替換指向非託管結構的原始指針,原因是除非代碼被標記爲 unsafe,否則
.NET Framework 應用程序不使用指針。
-
MyPerson3包含作爲嵌入結構的MyPerson。 嵌入到另一個結構中的結構可以通過將嵌入結構的元素直接放置在主結構中而單一化;該結構也可保留爲嵌入結構,此示例中即如此處理。
-
MyArrayStruct包含一個整數數組。 MarshalAsAttribute 特性將 UnmanagedType 枚舉值設置爲 ByValArray,後者用於指示數組中的元素數目。
對於此示例中的所有結構,都將應用 StructLayoutAttribute 特性,以確保成員在內存中按照它們的出現順序依次排列。
LibWrap類包含由App類調用的TestStructInStruct、TestStructInStruct3和TestArrayInStruct方法的託管原型。 每個原型都聲明單個參數,如下所示:
-
TestStructInStruct將對MyPerson2類型的引用聲明爲其參數。
-
TestStructInStruct3將MyPerson3類型聲明爲其參數並通過值傳遞該參數。
-
TestArrayInStruct將對MyArrayStruct類型的引用聲明爲其參數。
作爲方法參數的結構將通過值傳遞,除非該參數包含 ref(在 Visual
Basic 中爲 ByRef)關鍵字。 例如,TestStructInStruct方法將對MyPerson2類型的對象的引用(一個地址值)傳遞給非託管代碼。 爲操作MyPerson2所指向的結構,該示例通過組合使用 MarshalAllocCoTaskMem 和 MarshalSizeOf 方法創建一個指定大小的緩衝區並返回其地址。 接着,該示例將該託管結構的內容複製到該非託管緩衝區。 最後,該示例使用 MarshalPtrToStructure方法從該非託管緩衝區向託管對象封送數據,並使用 MarshalFreeCoTaskMem 方法釋放非託管內存塊。
聲明原型
' 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 'MyPerson
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyPerson2
Public person As IntPtr
Public age As Integer
End Structure 'MyPerson2
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyPerson3
Public person As MyPerson
Public age As Integer
End Structure 'MyPerson3
<StructLayout(LayoutKind.Sequential)> _
Public Structure MyArrayStruct
Public flag As Boolean
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=3)> _
Public vals As Integer()
End Structure 'MyArrayStruct
Public Class LibWrap
' Declares managed prototypes for unmanaged functions.
Declare Function TestStructInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef person2 As MyPerson2) As Integer
Declare Function TestStructInStruct3 Lib "..\LIB\PinvokeLib.dll" ( _
ByVal person3 As MyPerson3) As Integer
Declare Function TestArrayInStruct Lib "..\LIB\PinvokeLib.dll" ( _
ByRef myStruct As MyArrayStruct) As Integer
End Class 'LibWrap
// 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;
}
public class LibWrap
{
// Declares a managed prototype for unmanaged function.
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestStructInStruct(ref MyPerson2 person2);
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestStructInStruct3(MyPerson3 person3);
[DllImport("..\\LIB\\PinvokeLib.dll")]
public static extern int TestArrayInStruct(ref MyArrayStruct myStruct);
}
// 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;
};
public ref class LibWrap
{
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);
};
調用函數
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 = LibWrap.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
LibWrap.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))
LibWrap.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 'Main
End Class 'App
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 = LibWrap.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;
LibWrap.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]);
LibWrap.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 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 = LibWrap::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;
LibWrap::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]);
LibWrap::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]);
}
};