トップ回答者
C++関数で unsigned char のポインターのポインターを引き数に持つ関数のラッパーの書き方は?

質問
回答
-
byte[]はmanaged heap上に存在します。
一方C++側のBufferはheapなりstackなりunmangedなmemory空間上に存在します。
お互い相容れませんから、copyが必要になります。直接C++のbufferにaccessしたければ、unsafe codeで記述することになります。
>C++のmallocで確保された領域をC#の配列と同じ場所にできないかと考えましたが、ダメですかね?
ダメですね。>unsafe で、関数を作って行くという対応になりますか。
そうなりますね。- 回答としてマーク クサキ 2011年6月24日 2:34
すべての返信
-
P/Invokeの書き方は、以下のK. Takaokaさんの回答と同じノリでよいです。
[C++でポインターのポインターを引き数に持つ関数のラッパーはどう書けば良いでしょうか?]
http://social.msdn.microsoft.com/Forums/ja-JP/csharpgeneralja/thread/c9cc04f6-584b-48c7-bfae-d23dd2f7c7e2以下も参考にしてください。
[プラットフォーム呼び出しチュートリアル]
http://msdn.microsoft.com/ja-jp/library/aa288468(v=vs.71).aspx>その利用の仕方
どう利用したいのですか? -
-
「unsigned char のポインターのポインター」なのに、なぜ Byte が出てくるのでしょうか。BYTE が typedef unsigned char BYTE だから?
尋ねたいのですが、「ポインターのポインターを引数に持つ関数のラッパー」の書き方と、「unsigned char のポインターのポインターを引数に持つ関数のラッパー」の書き方が、なぜ違うとお考えなのでしょうか。前回は文字列定数へのポインターを設定する関数でしたが、今回は「文字列配列を関数引数で返す」関数なのでしょうか。タイトルだけ見ていると、「どうして同じ質問を繰り返すの?」と思ってしまいます。
「C++のバッファーから、C#の配列にわざわざ転送したくありません.」というのも、よくわかりません。C++ でどの様に定義されているものを扱いたいのか、C# でどの様に扱いたいのか。その辺も明確にしましょう。
それから、「プラットフォーム呼び出しによるデータのマーシャリング」は、参考になります。それから、Win32 API が対象なら、pinvoke.net で探すとよいでしょう。
Jitta@わんくま同盟 -
>「unsigned char のポインターのポインター」なのに、なぜ Byte が出てくるのでしょうか。
> BYTE が typedef unsigned char BYTE だから?
C++のunsigned char も C#のbyteも符号なしの8bitで同じものと、
C#を始めた時からから思っていまして、unsigned charは全て、byteとして
やってきて問題なく動いていますが、違うのですか?何が正解なのでしょうか?
C++のDLLで、mallocでデータ領域を確保しています。
最大で、unsigned charの場合は16Mbyte、floatの複素数の場合は128Mbyteになります。
高速で動かしたいので、C++のバッファーから、C#の配列にわざわざ転送したくありません。また、C++のDLLで初期化処理、終了処理なども行っていてひとつの体系ができあがっています。
現在、実績もあり安定しています。さらに、VB6.0のアプリからも利用していまして、
こちらの仕様を変える気にはなりません。というわけで、C++側でメモリの確保は行います。マーシャリングのところを少し調べましたら、
C++の関数
int TestRefArrayOfInts(int** ppArray, int* pSize);
ラッパー
[ DllImport( "..\\LIB\\PinvokeLib.dll" )]
public static extern int TestRefArrayOfInts( ref IntPtr array, ref int size );
利用側
int[] array2 = new int[ 10 ];
IntPtr buffer = Marshal.AllocCoTaskMem( Marshal.SizeOf( size ) * array2.Length );
Marshal.Copy( array2, 0, buffer, array2.Length );
int sum2 = LibWrap.TestRefArrayOfInts( ref buffer, ref size );
というのがありました。この例題はC#側で配列を確保していて私の場合に当てはまりません。
また、Marshal.Copyなどがあり、コピーをしているようで、私がやりたいこととは違います。
文字列定数へのポインターの場合はファイル名を渡すぐらいで速度的な問題がなく、
どんな内部的な処理がなされていてもよく、C#から簡単に利用できれば良かったのですが、
こちらのは速度的な問題と大きな配列をC#側で、また確保するのを避けたいということです。
unsafe な関数を作り、fixed (byte* pBuf = aBuf) のような形で
C++のmallocで確保された領域をC#の配列と同じ場所にできないかと考えましたが、ダメですかね?
ダメでしたら、unsafe で、関数を作って行くという対応になりますか。 -
byte[]はmanaged heap上に存在します。
一方C++側のBufferはheapなりstackなりunmangedなmemory空間上に存在します。
お互い相容れませんから、copyが必要になります。直接C++のbufferにaccessしたければ、unsafe codeで記述することになります。
>C++のmallocで確保された領域をC#の配列と同じ場所にできないかと考えましたが、ダメですかね?
ダメですね。>unsafe で、関数を作って行くという対応になりますか。
そうなりますね。- 回答としてマーク クサキ 2011年6月24日 2:34
-
ダメでしたら、unsafe で、関数を作って行くという対応になりますか。
少し気になったのは、「unsafe で関数を作っていく」という表現です。
普段は IntPtr でやりとりし、実際に unmanaged な配列を参照する必要があるところだけ、unsafe コンテキストにすればよいのですが、そんなにいっぱい参照する関数が存在するということでしょうか。IntPtr をメンバーに持ち、unmanaged 配列へのアクセスを実現させるラッパークラスを作ってもいいかもしれませんね。
ただ、処理の書き方次第では、アクセス効率が落ちるやもしれませんが。
質問スレッドで解決した場合は、解決の参考になった投稿に対して「回答としてマーク」のボタンを押すことで、同じ問題に遭遇した別のユーザが役立つ投稿を見つけやすくなります。