【#CSharp #VCPP】P/Invokeの沼にハマってたぁ~ ガベージがいたずらしまくる(汗 (C#の部)
関連記事
- 【#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日(木)】
ほいでもって,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++側の話 ⇒ こちら
コメント
「侍ジャパン」宮崎県入り 「プレミア12」向け きょうから合宿
【#総選挙】 衆議院選挙 きょう投票 ...ドロドロドロ(24/10/27)
【#線状降水帯】宮崎 延岡「土砂崩れで家がつぶれている」通報 1人不明(24/10/23)
【冬】お~日本海に筋雲が出ちょる!冬がキター
【#寒冷前線】13時頃30℃の気温が今は25℃無いぞー
【訃報】 俳優の西田敏行さん亡くなる 76歳 東京の自宅で
【#台風】衆議院議員選挙の投票日に超大型台風が直撃!なのか?(24/10/17)
【#キロタン】奄美地方(鹿児島県)記録的短時間大雨情報 第1号(24/10/16)
生駒高原へコスモスを見物しに行ってみた
急激に寒くなってキター 晩秋がやってきた!