3

PInvokeC# プログラムから C++ 関数を呼び出すために使用しています。コードは次のようになります。

IntPtr data = Poll(this.vhtHand);
double[] arr = new double[NR_FINGERS /* = 5 */ * NR_JOINTS /* = 3*/];
Marshal.Copy(data, arr, 0, arr.Length);

Poll()の署名は次のようになります。

[DllImport("VirtualHandBridge.dll")]
static public extern IntPtr Poll(IntPtr hand);

C 関数Pollの署名:

extern "C" __declspec(dllexport) double* Poll(CyberHand::Hand* hand)

私が大きな脳障害を抱えていない限り (確かに、私にとってはかなり一般的です)、これは機能しているように見えます.

ただし、取得している double 値は完全に正しくありません。これは、メモリ使用量が正しくないためだと思います。調べてみたところ、C# と C++ の double のサイズは同じだと思いますが、ここで別の問題が発生している可能性があります。私を間違った方向にこすっていることの 1 つは、Marshal.Copyどのタイプのデータが期待されるべきかが決して伝えられないことですが、このように使用されることになっていることを読みました。

手がかりはありますか?必要に応じて、正しい結果と返された結果を投稿できます。

4

2 に答える 2

1

P/Invoke を正しく宣言している限り、そのようにデータをマーシャリングする必要さえありません。

CyberHand::Hand*実際に double へのポインタである場合は、P/Invoke を次のように宣言する必要があります。

[DllImport("VirtualHandBridge.dll")]
static public extern IntPtr Poll(double[] data);

そして、double の配列で呼び出すだけです。

それ実際には double の配列でない場合、あなたがしていることは確かにできません。

また、「C」関数は配列の大きさをどのように知っていますか? サイズ固定ですか?

IntPtr の戻り値が問題になります。double*指しているのは何ですか?配列ですか、それとも単一のアイテムですか?

呼び出している関数に対して、より単純で使いやすい 'C' ラッパーを作成し、ラッパー関数自体を呼び出す方が (可能であれば) 簡単であることがわかります。もちろん、'C' DLL のソース コードを変更できる場合にのみ、これを行うことができます。しかし、あなたの機能が何をするのかを正確に知らなければ、具体的なアドバイスをすることはできません.

[編集]

わかりました。返されるメモリが台無しにされていない (解放されたなど)場合、コードは理論的には機能するはずです。それが機能していない場合は、そのようなことが起こっていると思います。内部メモリへのポインターを返すよりも、C# によって割り当てられ、関数に渡される配列を埋めるラッパー 'C' 関数を作成する方が確実に優れています。

ところで:メモリのブロックのサイズを渡さずにポインタを渡すコードは好きではありません。少し厄介なことになりやすいようです。

于 2013-04-04T08:48:43.803 に答える