【追記】
GCHandleを利用した
C#&アンマネージDLL 普通の配列の引渡し
方法を記載しました.参考にどうぞ!
いや,アンマネージな構造体配列の受け取りは,大昔書いていたんだけど
intやら,floatやらの配列は,p/Invokeが良きに計らってくれると思ってたり
今日,とある画像解析エンジン構築中にどっぷりハマって...
画像中,しきい値を超えた,画素ブロックの
ブロック内重心座標XYを,各々floatの配列で戻そうとしたのであった
これが,動かねぇ~(涙
引っかかったのは,間違いなく,アンマネージ側DLLでセットした配列ポインタの受け取り部
でもまぁ,何のことはない,Marshal.Copy()を使えってことで(汗
後から来られる人のために,書いておきまする
C++(ソースは抜粋)
C++:
- //souBuf 画像バッファへのポインタ
- //length 画像バッファ長
- //X 座標配列ポインタを格納するポインタ(受け取り)
- //Y 座標配列ポインタを格納するポインタ(受け取り)
- //Count 座標配列要素数を格納するポインタ(受け取り)
- extern "C" int WINAPI BMCalc_GetLoc(BYTE* souBuf, int length, float* &X, float* &Y, int &Count)
- {
- ClearArrayList(); //m_PointArrayの要素の破棄
- GetLocCore(souBuf, length); //画像からブロック重心座標の抽出メソッド(割愛)
- if (m_XArray != NULL)
- {
- delete m_XArray;
- }
- if (m_YArray != NULL)
- {
- delete m_YArray;
- }
- //m_PointArrayは,座標管理クラスを保持するCObArrayのインスタンス
- //これをC#に渡すために,普通のfloat配列に変換する作業が以下ズラズラと
- m_XYArrayCount = m_PointArray->GetCount(); //要素数を取得
- m_XArray = new float[m_XYArrayCount];
- m_YArray = new float[m_XYArrayCount];
- for(int i = 0; i <m_XYArrayCount; i++)
- {
- CBMCalcJob_Point *obj = (CBMCalcJob_Point *)m_PointArray->GetAt(i);
- m_XArray[i] = obj->X;
- m_YArray[i] = obj->Y;
- }
- //配列の先頭ポインタを,受け取り引数に乗せる
- X = m_XArray;
- Y = m_YArray;
- Count = m_XYArrayCount;
- return 0;
- }
C#側
C#:
- //API定義
- [DllImport("BMImageCalc.dll")]
- private static extern int BMCalc_GetLoc(IntPtr souBuf, int length, ref IntPtr X,ref IntPtr Y,ref int Count);
- //bs 画像データ(Bitmapクラス)
- //l 処理後得られる座標を格納したList<>クラス
- public int GetLoc(Bitmap bS, List<classBMPoint> l)
- {
- l.Clear();
- int ercd;
- IntPtr aryXPtr = IntPtr.Zero;
- IntPtr aryYPtr = IntPtr.Zero;
- int aryCount = 0;
- //Bitmapをロックして,ポインタを抜き出し,DLLへ渡す
- BitmapData bDataS = bS.LockBits(new Rectangle(0, 0, bS.Width, bS.Height), ImageLockMode.ReadWrite, bS.PixelFormat);
- IntPtr Scan0S = bDataS.Scan0; //取り出されたIntPtr
- int bufLen = bDataS.Stride * bDataS.Height;
- //outじゃだめ refでないと正常に動かない
- ercd = BMCalc_GetLoc(Scan0S, bufLen, ref aryXPtr, ref aryYPtr, ref aryCount);
- bS.UnlockBits(bDataS);
- //アンマネージな配列から
- //マネージな配列へ一旦コピー
- Marshal.Copy(aryXPtr, aryX, 0, aryCount);
- Marshal.Copy(aryYPtr, aryY, 0, aryCount);
- //以後,処理が扱い易いようにList<>クラスに載せ替える
- for(int i = 0; i <aryCount; i++)
- {
- }
- return ercd;
- }
C#側は,Intptrな引数をrefにて渡して,ポインタをもらってこないと
どうやら,正常に動かないっぽい
out float[]で良きにはからうかねぇ~と思ったけど,甘かったですわん
このソース,参考にドゾー




はじめまして。
BadImageException の対処方法を探していて貴兄のページを参考にさせていただきました。
ありがとうございます。
C# C++ の連携をするのにデータ受渡しに苦労しているので、このページも参考になります(感謝)。
この例題について質問ですが、
受け渡すfloat配列は、C++ 側でAllocされていますが、Freeはどうすればよいでしょうか?
Marshal.Copy(aryXPtr, aryX, 0, aryCount);
Marshal.Copy(aryYPtr, aryY, 0, aryCount);
のあとで、
Marshal.FreeHGlobal(aryX);
Marshal.FreeHGlobal(aryY);
でよいのでしょうか?(自信が全然ないのですみません)
>>きん さま
ようこそ!
うちのサンプルが、参考になってうれしい限りです♪
>>この例題について質問ですが、
>>受け渡すfloat配列は、C++ 側でAllocされていますが、Freeはどうすればよいでしょうか?
C++で確保したメモリは、C++側で開放すべきと思います
このDLLでは、処理クラスのデストラクタで、
メモリが確保されていたら、確保分の破棄の処理を行っています
(m_XArray, m_YArrayはクラスのメンバ変数です)
if (m_XArray != NULL)
{
delete m_XArray;
}
if (m_YArray != NULL)
{
delete m_YArray;
}
と同じコードをデストラクタに挿入してありますです
また、わからないことがあったらよろしくですぅ