首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 視訊監控系列(十四):總結貼——VC++ 轉 C# 實戰心得(二)

     編輯:關於C語言

3. 回調函數委托必須宣告為成員變數

這是最常見、最隱蔽、最致命的坑。委托若只在區域變數宣告,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);
}

4. 委托呼叫常見三大錯誤類型

4.1 參數型別不匹配

  • VC++ char* → C# 應為 IntPtr 或 StringBuilder,不可直接用 string
  • VC++ DWORD* / ULONG* → C# 應為 out uint / out int
  • 結構體大小/對齊不一致 → [StructLayout(LayoutKind.Sequential, Pack=1)] 強制對齊

4.2 委托未宣告為成員變數

如前節所述,已強調多次並給出範例,此處不再贅述。

4.3 非受控函數指標呼叫慣例錯誤

錯誤訊息常為「記憶體已被釋放」、「CallStack 損壞」或 AccessViolationException。

解決方案:在委托宣告上加上呼叫慣例屬性:

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate int STREAM_DIRECT_READ_CALLBACK(int channelNum, IntPtr DataBuf, int Length, FrameType_t frameType, IntPtr context);
  • 大多數 Hikvision SDK 為 Cdecl 呼叫慣例
  • 若為 StdCall 則用 CallingConvention.StdCall (預設值)
  • 加上此屬性後,CLR 會正確處理堆疊平衡,避免記憶體損壞

結語

VC++ 轉 C# 還有許多細節需靠經驗累積:結構體對齊、字串編碼 (ANSI/Unicode)、陣列封送、指標運算、錯誤碼對照等。建議:

  1. 保持 細心對比 VC++ 原始碼與 C# 封裝
  2. 善用 Memory Window / Disassembly 除錯非受控邊界
  3. 建立 封裝庫專案 集中管理所有 P/Invoke 簽名,統一維護
  4. 持續關注本系列後續更新,會補充更多實戰踩坑記錄

祝大家開發順利!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved