アンマネージ Win32 C++ DLL に共通の構造があります。
// FirstElemPtrContainer.h
#include "stdafx.h"
typedef unsigned char elem_type; // a byte
typedef struct FirstElemPtrContainer {
unsigned char num_elems;
void *allocd_ary;
} FirstElemPtrContainer;
構造体の void* は、割り当てられたバイト配列の最初の要素へのポインターを含むことを意味します。
この定義を使用する DLL は、関数をエクスポートして、構造体を割り当て、設定し、割り当てを解除します。
// The exported allocator function.
extern "C" _declspec(dllexport)
FirstElemPtrContainer *BuildStruct(int elem_count)
{
FirstElemPtrContainer *fepc_ptr = new FirstElemPtrContainer;
fepc_ptr->num_elems = elem_count;
elem_type *ary = new elem_type[fepc_ptr->num_elems];
for (int i = 0; i < fepc_ptr->num_elems; i++)
{
ary[i] = ((i + 1) * 5); // multiples of 5
}
fepc_ptr->allocd_ary = ary;
return fepc_ptr;
}
// The exported deallocator function.
extern "C" _declspec(dllexport) void
DestroyStruct(FirstElemPtrContainer *fepc_ptr)
{
delete[] fepc_ptr->allocd_ary;
delete fepc_ptr;
}
これらは、ネイティブの呼び出し元にとっては問題なく機能します。
C# では、PInvoke を介してこれと同じ構造を記述しようとしています。
[StructLayout(LayoutKind.Sequential)]
public struct FirstElemPtrContainer
{
public byte num_elems;
[MarshalAs(UnmanagedType.LPArray,
ArraySubType = UnmanagedType.U1, SizeConst = 4)]
public IntPtr allocd_ary;
}
...そして呼び出しインターフェースを次のように記述します:
public static class Imports
{
[DllImport("MyLib", CallingConvention = CallingConvention.Winapi)]
public static extern IntPtr BuildStruct(int elem_count);
[DllImport("MyLib", CallingConvention = CallingConvention.Winapi)]
public static extern void DestroyStruct(IntPtr fepc_ptr);
}
今、私は自分のインターフェースを呼び出そうとします:
class Program
{
const int NUM_ELEMS = 4;
static void Main(string[] args)
{
IntPtr fepc_ptr = Imports.BuildStruct(NUM_ELEMS);
if ( fepc_ptr == IntPtr.Zero )
{
Console.WriteLine("Error getting struct from PInvoke.");
return;
}
FirstElemPtrContainer fepc =
(FirstElemPtrContainer)Marshal.PtrToStructure(fepc_ptr,
typeof(FirstElemPtrContainer));
//...
}
}
PtrToStructure() を呼び出すと、「タイプ 'MyLibInvoke.FirstElemPtrContainer' のフィールド 'allocd_ary' をマーシャリングできません: マネージド型とアンマネージド型の組み合わせが無効です (Int/UInt は SysInt または SysUInt とペアにする必要があります)」というエラーが表示されます。
特定の数の要素をハードコーディングしたことがわかります。これは、呼び出し元が遵守していると想定します。ArraySubType 句も追加しましたが、違いはないようです。型の不一致の苦情はなぜですか?