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

C# 呼叫 C++ DLL 與 MATLAB DLL 完整實戰指南(上)

     編輯:關於C++

為了記錄開發過程中踩過的坑,避免日後重蹈覆轍,我決定將這段跨語言互操作的經驗完整記錄下來,也希望能幫助有類似需求的開發者少走彎路。

專案背景與技術選型

近期需要開發一個介面系統,包裝先前完成的人臉屬性識別模型。使用者可隨機選取圖片(未來將整合攝影機即時拍攝),系統自動分析圖中人臉屬性(如是否戴眼鏡、帽子等)。整個流程包含人臉偵測、人臉對齊、屬性預測三個階段:

  • 人臉屬性識別核心由 C++ 實作
  • 人臉對齊演算法由 MATLAB 開發
  • 考慮介面友善度與開發效率,主程式選用 C# (Visual Studio 環境)

為什麼不直接混合編譯?雖然可行,但程式碼可讀性極差、除錯困難,我嘗試過最終仍選擇放棄。採用 DLL 封裝雖然初期包裝費時數天,但後續使用如同黑盒子般簡單:依規定參數型別傳入,即可獲得預期輸出,幾行程式碼搞定,基本免配置環境。

本機環境:Windows 7 64位 + Visual Studio 2013 + MATLAB 2015

請務必確認你的環境與上述一致,否則我的成功路徑不一定適用。我當初搜尋資料時找不到完全相同環境的教學,全靠摸索才通過,關鍵在於不放棄。

第一部分:C# 呼叫 C++ DLL 完整流程

核心概念:托管與非托管代碼

C++ 屬於非托管代碼,直接由作業系統執行;C# 屬於托管代碼,在 CLR (Common Language Runtime) 環境下執行,享有自動垃圾回收、型別檢查等服務。若 C# 要呼叫 C++,必須將 C++ 代碼包裝成托管代碼並編譯為 DLL。

步驟 1:建立 Native 類(非托管層)

假設有一個人臉偵測+5點定位函數,輸入兩個字串(圖片路徑、特徵點儲存路徑)。首先將此函數封裝為類的成員函數,稱為 NativeClass:

Native 類標頭檔

關鍵提示:C++ 的 std::string 封裝後在 C# 端型別極其複雜,強烈建議使用 char* 作為參數,對應 C# 的 sbyte*,轉換極為方便。

步驟 2:實作 Native 類

Native 類實作

步驟 3:專案屬性設定為 CLR 托管 DLL

專案屬性設定

需修改兩處紅框標示:

  1. Configuration Type → Dynamic Library (.dll)
  2. Common Language Runtime Support → /clr

小插曲:設定屬性後有時關鍵字高亮會消失(編譯器識別異常),多試幾次保存直到高亮恢復,不影響最終編譯但寫碼體驗大打折扣。

步驟 4:建立 Managed Wrapper 類(托管層)

Managed Wrapper 類

核心要點:

  • public ref class 宣告托管類,供 C# 可見
  • private 區必須持有 Native 類實例,否則無法呼叫非托管函數

步驟 5:實作 Managed Wrapper

Managed Wrapper 實作

兩處紅框關鍵:

  1. 建構子中 必須實例化 Native 物件
  2. 成員函數中呼叫 Native 類對應函數

步驟 6:產出 DLL 並部署到 C# 專案

產出 DLL 位置

若 C++ 專案依賴額外 DLL/LIB,必須一併複製到 C# 專案輸出目錄,否則執行時會報「DLL 依賴缺失」。

步驟 7:C# 端呼叫 DLL

將 DLL 複製到 C# 專案 bin\Release 目錄,並在「參考」中加入該 DLL。

複製 DLL 到 C# 專案 加入參考

資料型別對應與 Unsafe 程式碼

C++ char* 對應 C# sbyte*。字串轉換範例:

字串轉 sbyte*

需在方法標記 unsafe,且專案屬性 → Build → 勾選 Allow unsafe code:

unsafe 標記 專案允許 unsafe

關鍵坑點:若 C++ DLL 以 x64 編譯,C# 專案 必須取消勾選 "Prefer 32-bit",否則執行會報錯。

取消 Prefer 32-bit

最終呼叫僅需三行

C# 呼叫範例
var wrapper = new ManagedWrapper();  // 托管類名稱
wrapper.DetectFace(imgPath, ptsPath); // 呼叫函數
string result = Marshal.PtrToStringAnsi((IntPtr)ptr); // 結果轉回 string

至此 C# 呼叫 C++ DLL 大功告成!MATLAB DLL 呼叫請見下篇。

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