非托管函数到托管 结构示例

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 是一个自定义非托管库,它包含前面列出的函数的实现和以下四种结构:MYPERSONMYPERSON2MYPERSON3 和 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;

托管的MyPersonMyPerson2MyPerson3MyArrayStruct结构具有以下特征:

  • MyPerson只包含字符串成员。 CharSet 字段在传递给非托管函数时将这些字符串设置为 ANSI 格式。

  • MyPerson2包含一个指向MyPerson结构的 IntPtr。 IntPtr 类型将替换指向非托管结构的原始指针,原因是除非代码被标记为 unsafe,否则 .NET Framework 应用程序不使用指针。

  • MyPerson3包含作为嵌入结构的MyPerson。 嵌入到另一个结构中的结构可以通过将嵌入结构的元素直接放置在主结构中而单一化;该结构也可保留为嵌入结构,此示例中即如此处理。

  • MyArrayStruct包含一个整数数组。 MarshalAsAttribute 特性将 UnmanagedType 枚举值设置为 ByValArray,后者用于指示数组中的元素数目。

对于此示例中的所有结构,都将应用 StructLayoutAttribute 特性,以确保成员在内存中按照它们的出现顺序依次排列。

LibWrap类包含由App类调用的TestStructInStructTestStructInStruct3TestArrayInStruct方法的托管原型。 每个原型都声明单个参数,如下所示:

  • TestStructInStruct将对MyPerson2类型的引用声明为其参数。

  • TestStructInStruct3MyPerson3类型声明为其参数并通过值传递该参数。

  • TestArrayInStruct将对MyArrayStruct类型的引用声明为其参数。

作为方法参数的结构将通过值传递,除非该参数包含 ref(在 Visual Basic 中为 ByRef)关键字。 例如,TestStructInStruct方法将对MyPerson2类型的对象的引用(一个地址值)传递给非托管代码。 为操作MyPerson2所指向的结构,该示例通过组合使用 MarshalAllocCoTaskMem 和 MarshalSizeOf 方法创建一个指定大小的缓冲区并返回其地址。 接着,该示例将该托管结构的内容复制到该非托管缓冲区。 最后,该示例使用 MarshalPtrToStructure方法从该非托管缓冲区向托管对象封送数据,并使用 MarshalFreeCoTaskMem 方法释放非托管内存块。

声明原型

' Declares a managed structure for each unmanaged structure.
 _
Public Structure MyPerson
    Public first As String
    Public last As String
End Structure 'MyPerson

 _
Public Structure MyPerson2
    Public person As IntPtr
    Public age As Integer
End Structure 'MyPerson2

 _
Public Structure MyPerson3
    Public person As MyPerson
    Public age As Integer
End Structure 'MyPerson3

 _
Public Structure MyArrayStruct
    Public flag As Boolean
     _
    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^ 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(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]);
    }
};

你可能感兴趣的:(C#)