C#&アンマネージDLLマーシャリング 普通の配列の受け取り
関連記事
- 【#Assembler】結局x64のアセンブラでゴニョゴニョと書き始めたオイラはバカかっ!(爆 【2024年05月13日(月)】
- 【#VCPP #VisualStudio】VS2022のVC 64ビットコンパイルでインラインアセンブラが使えなくなってるぞー 【2024年05月10日(金)】
- 【#CSHARP】ソリューション内でサービス,Winformアプリを混在で作成させ,バイナリ出力先を同じにするとサービスが起動しない 【2024年02月08日(木)】
- 【#CPP】出先でC++にてライブラリの緊急実装!脳死したーキョムリすぎるー 【2024年01月15日(月)】
- 【#PHP】謎な #Laravel 案件 引き渡したじ 【2024年01月11日(木)】
【追記】
GCHandleを利用した
C#&アンマネージDLL 普通の配列の引渡し
方法を記載しました.参考にどうぞ!
いや,アンマネージな構造体配列の受け取りは,大昔書いていたんだけど
intやら,floatやらの配列は,p/Invokeが良きに計らってくれると思ってたり
今日,とある画像解析エンジン構築中にどっぷりハマって...
画像中,しきい値を超えた,画素ブロックの
ブロック内重心座標XYを,各々floatの配列で戻そうとしたのであった
これが,動かねぇ~(涙
引っかかったのは,間違いなく,アンマネージ側DLLでセットした配列ポインタの受け取り部
でもまぁ,何のことはない,Marshal.Copy()を使えってことで(汗
後から来られる人のために,書いておきまする
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#側
//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
{
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);
//アンマネージな配列から
//マネージな配列へ一旦コピー
float[] aryX = new float[aryCount];
float[] aryY = new float[aryCount];
Marshal.Copy(aryXPtr, aryX, 0, aryCount);
Marshal.Copy(aryYPtr, aryY, 0, aryCount);
//以後,処理が扱い易いようにList<>クラスに載せ替える
for(int i = 0; i < aryCount; i++)
{
l.Add(new classBMPoint(aryX[i], aryY[i]));
}
return ercd;
}
[/csharp]
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;
}
と同じコードをデストラクタに挿入してありますです
また、わからないことがあったらよろしくですぅ 😉
【城主注】
あ~~また,C++側の開放の仕方間違ってる!!
NG:
delete m_XArray;
delete m_YArray;
OK:
delete[] m_XArray;
delete[] m_YArray;
float配列の動的確保なんで開放は deleteじゃなくてdelete[]が正解
floatなんで大勢に影響ないけど,気色悪いので念の為(爆