這是最常見、最隱蔽、最致命的坑。委托若只在區域變數宣告,GC 會在不可預期時機回收,導致回調失效、程式崩潰或靜默失效。
private void PreviewAndClientConnect()
{
// 錯誤:區域變數,方法結束即可被 GC 回收
STREAM_DIRECT_READ_CALLBACK sdrc = new STREAM_DIRECT_READ_CALLBACK(STREAM_DIRECT_READ_CALLBACK1);
HikVisionSDK.RegisterStreamDirectReadCallback(sdrc, this.Handle);
}
// 類別層級成員變數
private STREAM_DIRECT_READ_CALLBACK sdrc;
private void PreviewAndClientConnect()
{
// 正確:成員變數持有參考,GC 不會回收
sdrc = new STREAM_DIRECT_READ_CALLBACK(STREAM_DIRECT_READ_CALLBACK1);
HikVisionSDK.RegisterStreamDirectReadCallback(sdrc, this.Handle);
}
char* → C# 應為 IntPtr 或 StringBuilder,不可直接用 stringDWORD* / ULONG* → C# 應為 out uint / out int[StructLayout(LayoutKind.Sequential, Pack=1)] 強制對齊如前節所述,已強調多次並給出範例,此處不再贅述。
錯誤訊息常為「記憶體已被釋放」、「CallStack 損壞」或 AccessViolationException。
解決方案:在委托宣告上加上呼叫慣例屬性:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int STREAM_DIRECT_READ_CALLBACK(int channelNum, IntPtr DataBuf, int Length, FrameType_t frameType, IntPtr context);
Cdecl 呼叫慣例StdCall 則用 CallingConvention.StdCall (預設值)VC++ 轉 C# 還有許多細節需靠經驗累積:結構體對齊、字串編碼 (ANSI/Unicode)、陣列封送、指標運算、錯誤碼對照等。建議:
祝大家開發順利!