【#CSharp #VCPP】P/Invokeの沼にハマってたぁ~ ガベージがいたずらしまくる(汗 (C#の部)
関連記事
- 【memory leak】メモリーリーク発生...ドロドロドロ 【2025年10月27日(月)】
- う~~忙しい!あ~~忙しい!! 【2025年09月24日(水)】
- なんと!今週の土曜日も仕事してますた.来週の土曜日も仕事臭い.TCPソケット通信をゴリゴリ書いてる 【2025年08月30日(土)】
- 【ChatGPT o4】祝日なのに仕事ーバテすぎー今夜こそ絶命だーモルモルモル 【2025年03月20日(木)】
- 【#ChatGPT】ChatGPTのヤロー(怒 SJIS変換サンプルコード,嘘コード吐いてやがった.原因対応に2時間も悩んだぞー 【2025年02月22日(土)】
ほいでもって,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++側の話 ⇒ こちら

コメント
「ニュウハクシミ」紙を食べる害虫 生息19都道府県に拡大
文化の日な祭日らしい.文化的に休むもうず?
【#HTVX】新型宇宙輸送船HTV-X 油井さんがロボットアームでキャッチ
【冬】来週11℃予想とか出てきてる.秋があったのか,今年(25/10/23)
【ツル】出水平野に冬の訪れを告げるツル第一陣・今季初飛来 鹿児島(25/10/21)
都城でプロ野球・ロッテ1軍が春季キャンプ実施へ
山形で開催の映画祭 監督など国内外の参加者が“芋煮”味わう
連休なんで生駒高原でコスモスを愛でてきた
連休の中日ですの.天気は良くなる方向じゃげ