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

C# 調用 C++ DLL 實戰(一):生成非托管 DLL 與 P/Invoke 互操作

     編輯:關於C語言

C# 優勢在 UI,C++ 優勢在算法與庫生態。CPU 性能發展至今,C# 效率差距已非瓶頸,但現成 C++ 庫(幾萬行代碼)改寫成本極高,非托管 DLL + P/Invoke 是最佳協作方案。CLR 托管 C++ 僅為 C# 披馬甲,不如直接用 C#。

1. 建立非托管 C++ DLL 專案 (VS2012)

  • 新建 → VC++ → Win32 → Win32 專案,名稱 MyNativeDll。
  • 應用程式類型選 DLL,勾選 MFC(若後續需用 MFC 類,否則後期補齊會報 MFC apps must not #include <windows.h> 錯誤,必須重建專案)。

2. 實現導出函數

Define.h - 導出宏

#define _EXTERN_C_ extern "C" _declspec(dllexport)

CFunction.h - 函數宣告

struct SystemTime {
  int year, month, day, hour, minute, second, millsecond;
  SystemTime& operator=(SystemTime st) { ... }
};
_EXTERN_C_ int add(int x, int y);
_EXTERN_C_ int sub(int x, int y);
_EXTERN_C_ int testChar(char* src, char* res, int nCount);
_EXTERN_C_ int testStruct(SystemTime& stSrc, SystemTime& stRes);

CFunction.cpp - 實現

int add(int x, int y) { return x + y; }
int sub(int x, int y) { return x - y; }
int testChar(char* src, char* res, int nCount) { memcpy(res, src, sizeof(char)*nCount); return 1; }
int testStruct(SystemTime& stSrc, SystemTime& stRes) { stRes = stSrc; return 1; }

建置生成 MyNativeDll.dll、.lib 於 Debug 目錄。

3. C# 專案調用 (P/Invoke)

CFunction.cs - 簽名映射

[StructLayout(LayoutKind.Sequential)]
public struct SystemTime {
  public int year, month, day, hour, minute, second, millsecond;
  public SystemTime(DateTime dt) { ... }
  public override string ToString() { ... }
}

public class CFunction {
  [DllImport("MyNativeDll.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
  public extern static int add(int x, int y);
  [DllImport(...)] public extern static int sub(int x, int y);
  [DllImport(...)] public extern static int testChar(ref byte src, ref byte res, int nCount);
  [DllImport(...)] public extern static int testStruct(ref SystemTime stSrc, ref SystemTime stRes);
}

Form1.cs - 測試調用

int a = CFunction.add(100, 50); // 150
int b = CFunction.sub(100, 50); // 50

string src = "123456";
byte[] srcBytes = Encoding.ASCII.GetBytes(src);
byte[] resBytes = new byte[100];
CFunction.testChar(ref srcBytes[0], ref resBytes[0], src.Length);
string res = Encoding.ASCII.GetString(resBytes).TrimEnd(); // "123456"

SystemTime stSrc = new SystemTime(DateTime.Now);
SystemTime stRes = new SystemTime();
CFunction.testStruct(ref stSrc, ref stRes); // 結構體傳遞驗證

關鍵:將 DLL 複製至 C# 專案 bin\Debug\ 目錄下。

4. 核心經驗總結

  1. 非托管 DLL 導出函數可行,導出類極其繁瑣,不建議。
  2. 參數傳遞:基本類型直接對應;C++ & 引用 ↔ C# ref;指針 ↔ IntPtr。
  3. 字串處理:C# string 對應 C++ char* 易因編碼(Unicode/多字節)出錯,建議用 byte[] 透傳。
  4. 結構體:C# 必須重新定義,標註 [StructLayout(LayoutKind.Sequential)] 保證記憶體對齊;含字串需 MarshalAs 指定長度。
  5. 返回值:避免直接返回字串,改用 ref 參數回傳。
  6. 指針參數:C# 用 IntPtr 轉換。

5. 類型對照參考

  • C++ int ↔ C# int
  • C++ char* ↔ C# byte[] / StringBuilder
  • C++ 結構體 ↔ C# struct + StructLayout

本文出自「幾縷蕭雨鎖清秋」博客,轉載請保留出處:https://joeyliu.blog.51cto.com/3647812/1289614

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