1

サードパーティの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();
}
4

1 に答える 1

3

p / invoke署名をオーバーロードして、次のことを試してください。

[DllImport("LIBRARY.DLL", EntryPoint = "command")]
public static extern int Command(IntPtr Handle, int CommandNum, ref FormatInfoType Data, int DataSize);
于 2010-09-22T22:14:28.000 に答える