構造体のサンプル

このサンプルでは、第 2 の構造体を指す構造体の渡し方、埋め込み構造体を含む構造体の渡し方、および埋め込み配列を含む構造体の渡し方を示します。

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;

マネージ構造体の MyPerson、MyPerson2、MyPerson3、および MyArrayStruct には、次に示す特性があります。

  • MyPerson には文字列メンバーだけが含まれます。 CharSet フィールドは、アンマネージ関数に渡されたときに文字列を ANSI 形式に設定します。

  • MyPerson2 には MyPerson 構造体への IntPtr が含まれます。 コードに unsafe マークが付いていない場合、.NET Framework アプリケーションはポインターを使用しないため、アンマネージ構造体を指す元のポインターは IntPtr 型に置き換えられます。

  • MyPerson3 には埋め込み構造体としての MyPerson が含まれます。 別の構造体に埋め込まれた構造体は、埋め込み構造体の要素を主構造体に直接配置して平坦化することも、このサンプルのように埋め込み構造体のままにしておくこともできます。

  • MyArrayStruct には整数の配列が含まれます。 MarshalAsAttribute 属性により、UnmanagedType 列挙値に ByValArray が設定されます。これは、配列に属する要素の数を示すために使用されます。

このサンプルでは、各メンバーが出現する順番でメモリ内に順次配列されることを保証するために、すべての構造体に StructLayoutAttribute 属性が適用されます。

LibWrap クラスには App クラスによって呼び出される TestStructInStruct、TestStructInStruct3、および TestArrayInStruct メソッドのマネージ プロトタイプが含まれます。 各プロトタイプは、次に示すように 1 つのパラメーターを宣言します。

  • TestStructInStruct は MyPerson2 型への参照を独自のパラメーターとして宣言します。

  • TestStructInStruct3 は MyPerson3 型を独自のパラメーターとして宣言し、そのパラメーターを値渡しします。

  • TestArrayInStruct は MyArrayStruct 型への参照を独自のパラメーターとして宣言します。

メソッドへの引数としての構造体は、パラメーターの中にキーワード ref (Visual Basic では ByRef) が含まれる場合を除き、値渡しされます。 たとえば、the TestStructInStruct メソッドは MyPerson2 型のオブジェクトへの参照 (アドレスの値) をアンマネージ コードに渡します。 MyPerson2 が指す構造体を操作するには、サンプルでは、指定したサイズのバッファーを作成し、Marshal.AllocCoTaskMem メソッドと Marshal.SizeOf メソッドを組み合わせることにより、そのアドレスを返します。 次に、マネージ構造体の内容をアンマネージ バッファーにコピーします。 最後に、Marshal.PtrToStructure メソッドによってアンマネージ バッファーからマネージ オブジェクトへとデータをマーシャリングし、Marshal.FreeCoTaskMem メソッドによってメモリのアンマネージ ブロックを解放します。

プロトタイプの宣言

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

参照

概念

クラス、構造体、および共用体のマーシャリング

プラットフォーム呼び出しのデータ型

マネージ コードでのプロトタイプの作成