サードパーティのCライブラリの周りにC#P/invokeラッパーを作成する際に問題が発生しました。特に、ライブラリには署名付きのメソッドがあります
int command(SomeHandle *handle, int commandNum, void *data, int datasize);
これは、commandNumに応じて異なることを行うワイルドカードメソッドです。データは、単一の整数、char []、またはある種の構造体(私の問題)など、あらゆるものへのポインターにすることができます。
私はラッパーを次のように宣言しました:
[DllImport("LIBRARY.DLL", EntryPoint = "command")]
public static extern int Command(IntPtr Handle, int CommandNum, [In, Out] IntPtr Data, int DataSize);
今、私がそれをオペコードで呼び出してbyte []を埋めると、それは機能します:
//WORKS, Buffer contains "library 1.0" after the call
const int BUFFER_SIZE = 128;
byte[] Buffer = new byte[BUFFER_SIZE];
int BytesWritten = 0;
GCHandle BufferHandle = GCHandle.Alloc(Buffer, GCHandleType.Pinned);
try
{
BytesWritten = Command(MyHandle, GET_VERSION, BufferHandle.AddrOfPinnedObject(), BUFFER_SIZE);
}
finally
{
BufferHandle.Free();
}
しかし、単純な構造体で同じことを試してみると、何を試しても機能しません。構造体は次のようになります。
public struct FormatInfoType
{
public int Format;
public IntPtr Name; //const char*
public IntPtr Extension; //const char*
}
ここでは、「Format」にint(たとえば、1)を入力することになっています。次に、「command(...)」を呼び出すと、名前と拡張子のフィールドが返されます。
この構造体を渡すと、コードは正しくコンパイルおよび実行されますが、構造体の値は変更されません。IntPtrをStringsまたはStringBuildersに変更した場合(そして無数のMarshalAs属性を試した場合)、IntPtrが非ブリット可能になり、GCHandle行が例外をスローするため、構造体にIntPtrを取得できません。
これに関する助けをいただければ幸いです。
編集:
構造体を使用してcommand()を呼び出す方法をいくつか試しましたが、現在は次のようになっています。
FormatInfoType f = new FormatInfoType();
f.Format = 1;
f.Name = IntPtr.Zero;
f.Extension = IntPtr.Zero;
GCHandle fHandle = GCHandle.Alloc(f, GCHandleType.Pinned);
try
{
Command(MyHandle, GET_FORMAT_INFO, fHandle.AddrOfPinnedObject(), Marshal.SizeOf(f));
}
finally
{
fHandle.Free();
}