web-dev-qa-db-ja.com

C#でp / invokeを使用して配列へのポインターを渡すにはどうすればよいですか?

C API署名の例:

void Func(unsigned char* bytes);

Cでは、配列へのポインターを渡したい場合、次のことができます。

unsigned char* bytes = new unsigned char[1000];
Func(bytes); // call

上記のAPIをP/Invokeに変換して、C#バイト配列へのポインターを渡すにはどうすればよいですか?

21

バイトの配列を渡す最も簡単な方法は、インポートステートメントでパラメータをバイト配列として宣言することです。

[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(byte[]);

byte[] ar = new byte[1000];
Func(ar);

また、パラメーターをIntPtrとして宣言し、データを手動でマーシャリングできる必要があります。

[DllImport EntryPoint="func" CharSet=CharSet.Auto, SetLastError=true]
public extern static void Func(IntPtr p);

byte[] ar = new byte[1000];
IntPtr p = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte)) * ar.Length);
Marshal.Copy(ar, 0, p, ar.Length);
Func(p);
Marshal.FreeHGlobal(p);
34
asponge

安全でないコードを使用できます:

unsafe 
{
     fixed(byte* pByte = byteArray)
     IntPtr intPtr = new IntPtr((void *) pByte);
     Func(intPtr);
}

安全なコードを使用する必要がある場合は、いくつかのトリックを使用できます。

IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(byteArray));
Marshal.Copy(byteArray, 0, intPtr, Marshal.SizeOf(byteArray));

Func(intPtr);

Marshal.FreeHGlobal(intPtr);

ただし、安全なコードは私見では遅くなります。

7
FlySwat

ネイティブ関数の適切なシグネチャは次のとおりです。

[System.Runtime.InteropServices.DllImportAttribute("<Unknown>", EntryPoint="Func")]
public static extern  void Func(System.IntPtr bytes) ;
3
JaredPar