【#CSharp #VCPP】P/Invokeの沼にハマってたぁ~ ガベージがいたずらしまくる(汗 (C#の部)
関連記事
- ぎんゆぅ~さんの更新頻度が落ちているときは仕事炎上中(爆 【2025年01月09日(木)】
- 仕事が納まった,のか?一応,拘束解除命令が出たモルモルモル 【2024年12月27日(金)】
- さすがに激務すぎ,ワロタ! 【2024年12月25日(水)】
- 今週もひたすらモノ書き #JAVA 祭りがまだまだ続く そろそろC#を書かせろー 【2024年12月04日(水)】
- 【#Assembler】結局x64のアセンブラでゴニョゴニョと書き始めたオイラはバカかっ!(爆 【2024年05月13日(月)】
ほいでもって,C#側の実装
構造体&C++呼び出しデリゲートでのP/Invoke = マーシャリングの実装方法がワケワカラン
悩みに悩みまくったべ
そのお答えは↓
まずは,DLL-APIへのインターフェースを定義しましょう
DLLからコールバックで帰ってくる,構造体,デリゲートの定義,DLL-APIの実装
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 8)] public struct TFCALLBACKINFOAPI { public IntPtr ImageBuf; public uint ImageBufLen; public int ImageWidth; public int ImageHeight; public int ImageStride; public int DetectionNum; public IntPtr DetectionX; //int[] public IntPtr DetectionY; //int[] public IntPtr DetectionWidth; //int[] public IntPtr DetectionHeight; //int[] public IntPtr DetectionClassID; //int[] public IntPtr DetectionScore; //float[] public IntPtr DetectionTagName; //LPWSTR[] } //デリゲート型の定義 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate int CallbackDelegate_TFCapture([Out] TFCALLBACKINFOAPI argSource, [Out] TFCALLBACKINFOAPI argDest); //デリゲートエントリのポインタを放り込む DLL-API [DllImport("HOGEHOGE.dll")] private static extern long APISetCallbackFuncTFCapture([MarshalAs(UnmanagedType.FunctionPtr)] CallbackDelegate_TFCapture tmpFunc); private CallbackDelegate_TFCapture? m_CalbackFuncBackup; //この変数,メチャクチャ大事!無いとアプリが落ちる!!TFCALLBACKINFOAPIのDetection~な配列(ちゅうかC++側はnewしたポインタが格納されてくる)
をどうやって,マネージメモリに変換すべ?
マーシャリングが自動で良きに計らってくれないの?
良きに計らわない,らしい...ドロドロドロ
手動マーシャリングを実装した
//物体検出情報の子クラス public class ClassTFCallbackInfoDetection { public int DetectionX; public int DetectionY; public int DetectionWidth; public int DetectionHeight; public int DetectionClassID; public float DetectionScore; public string? DetectionTagName; public ClassTFCallbackInfoDetection( int tmpDetectionX, int tmpDetectionY, int tmpDetectionWidth, int tmpDetectionHeight, int tmpDetectionClassID, float tmpDetectionScore, string? tmpDetectionTagName ) { DetectionX = tmpDetectionX; DetectionY = tmpDetectionY; DetectionWidth = tmpDetectionWidth; DetectionHeight = tmpDetectionHeight; DetectionClassID = tmpDetectionClassID; DetectionScore = tmpDetectionScore; DetectionTagName = tmpDetectionTagName; } } //TFCALLBACKINFOAPI構造体の情報をマネージメモリ化格納し管理するクラス public class ClassTFCallbackInfo { public IntPtr ImageBuf; public uint ImageBufLen; public int ImageWidth; public int ImageHeight; public int ImageStride; public List<ClassTFCallbackInfoDetection> Detection; public ClassTFCallbackInfo(TFCALLBACKINFOAPI tmpInfo) { Detection = new List<ClassTFCallbackInfoDetection>(); ImageBuf = IntPtr.Zero; ImageBufLen = tmpInfo.ImageBufLen; ImageWidth = tmpInfo.ImageWidth;; ImageHeight = tmpInfo.ImageHeight; ImageStride = tmpInfo.ImageStride; int tmpDetectionNum = tmpInfo.DetectionNum; int[] tmpDetectionX = new int [tmpDetectionNum]; int[] tmpDetectionY = new int [tmpDetectionNum]; int[] tmpDetectionWidth = new int [tmpDetectionNum]; int[] tmpDetectionHeight = new int [tmpDetectionNum]; int[] tmpDetectionClassID = new int [tmpDetectionNum]; float[] tmpDetectionScore = new float [tmpDetectionNum]; IntPtr[] tmpDetectionTagNameAry = new IntPtr[tmpDetectionNum]; string?[] tmpDetectionTagName = new string[tmpDetectionNum]; Marshal.Copy(tmpInfo.DetectionX, tmpDetectionX, 0, tmpDetectionNum); //int float系の配列はそのままcopy Marshal.Copy(tmpInfo.DetectionY, tmpDetectionY, 0, tmpDetectionNum); Marshal.Copy(tmpInfo.DetectionWidth, tmpDetectionWidth, 0, tmpDetectionNum); Marshal.Copy(tmpInfo.DetectionHeight, tmpDetectionHeight, 0, tmpDetectionNum); Marshal.Copy(tmpInfo.DetectionClassID, tmpDetectionClassID, 0, tmpDetectionNum); Marshal.Copy(tmpInfo.DetectionScore, tmpDetectionScore, 0, tmpDetectionNum); Marshal.Copy(tmpInfo.DetectionTagName, tmpDetectionTagNameAry, 0, tmpDetectionNum); //LPWSTR配列は,いったんIntPtr配列として受け取り for(int i = 0; i < tmpDetectionNum; i++) //IntPtr配列をstring配列に変換 { string? st = Marshal.PtrToStringUni(tmpDetectionTagNameAry[i]); tmpDetectionTagName[i] = st; } for (int i = 0; i < tmpDetectionNum; i++) //マネージメモリの子クラスとして最終的に格納 { ClassTFCallbackInfoDetection tmpItem = new ClassTFCallbackInfoDetection( tmpDetectionX[i], tmpDetectionY[i], tmpDetectionWidth[i], tmpDetectionHeight[i], tmpDetectionClassID[i], tmpDetectionScore[i], tmpDetectionTagName[i] ); Detection.Add(tmpItem); } } }あとは,DLL-APIへのデリゲート情報流し込みやら
デリゲートの定義やら
//--------------------------------------------- //TFCAPTUREイベント(UIへ送信するデリゲート) // //--------------------------------------------- public class TFCaptureEventArgs : EventArgs { public ClassTFCallbackInfo Source; public ClassTFCallbackInfo Dest; public TFCaptureEventArgs(TFCALLBACKINFOAPI tmpSource, TFCALLBACKINFOAPI tmpDest) { Source = new ClassTFCallbackInfo(tmpSource); Dest = new ClassTFCallbackInfo(tmpDest); } } public delegate void OnTFCaptureEventHandler(object sender, TFCaptureEventArgs e); public event OnTFCaptureEventHandler OnTFCaptureEvent = delegate { }; //--------------------------------------------- //コンストラクタ // //--------------------------------------------- public HOGEHOGEDLLCtrl() { m_ActiveFL = true; ErrorCD = APICreate(); //DLL初期化API if (ErrorCD < 0) { return; } m_CalbackFuncBackup = CallBackFuncTFCapture; //DLL-APIへ渡す自デリゲートを必ず変数に代入して保存しておくこと!! ErrorCD = APISetCallbackFuncTFCapture(m_CalbackFuncBackup); //デリゲート登録API } //--------------------------------------------- //DLLから飛んでくるデリゲート // //--------------------------------------------- private int CallBackFuncTFCapture(TFCALLBACKINFOAPI tmpSource, TFCALLBACKINFOAPI tmpDest) { if (m_ActiveFL == false) { return 1; } OnTFCaptureEvent(this, new TFCaptureEventArgs(tmpSource, tmpDest)); //このままじゃUIで使いにくいので一回マネージ側デリゲートを挟んでUIへ伝達 return 1; }
m_CalbackFuncBackup = CallBackFuncTFCapture;
の一文が大事
動き出して,ホンの数秒で
NullReferenceException
でアプリが落ちる
C++側のスレッド内Sleepとか調整したけど
やっぱり落ちる.落ちるタイミングはいつも一緒
てか,Sleep長くなったら,長くなった分正常稼働している時間が比例で長くなる
ん?これ,ガベージコレクタが走るタイミングで落ちてね?
マネージメモリがある程度ゴミ貯めて,GCスタートすると
ひょっとして,C++に渡したデリゲートのポインタ位置まで整理されて移動している予感
調べたら,それっぽいカキコが書いてあって
回避策は,デリゲートポインタを変数で保持しとけ,らしい
それが↑
これで落ちなくなったですわ
ようやっと,スケルトンが固まった
さて,画像周りを書いていこう...モルモルモル
C++側の話 ⇒ こちら
コメント
【#大相撲】 横綱 照ノ富士 引退の意向を固める
【#日向灘地震】割れ残り部が依然健在じゃし.怖いわなぁ
【#大地震】宮崎に大地震キタ━(゚∀゚)━!!(25/1/13)
【#大雪】宮崎市に降雪予報キター(25/1/11)
【#2025】あけおめ~ 2025年が始まったらしい...ドロドロドロ
2024年が終わりますなぁ 1年ありがとうございました
ついに宮崎市も氷点下気温キター(24/12/23)