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

C# 調用 C++ DLL 完整教程:從基礎函數到類對象跨語言互操作

     編輯:關於C++

第一部分:創建 C++ 動態鏈接庫

1. 項目設置

  • 選擇 Win32 Project → DLL 類型
  • 配置管理器:Active solution platform → x64(關鍵,匹配 C# 目標平台)

2. 導出函數聲明

// CppDemo.cpp
extern "C" __declspec(dllexport) int Add(int x, int y) { return x + y; }
extern "C" __declspec(dllexport) int Sub(int x, int y) { return x - y; }
extern "C" __declspec(dllexport) int Multiply(int x, int y) { return x * y; }
extern "C" __declspec(dllexport) int Divide(int x, int y) { return x / y; }

關鍵字解析:

  • extern "C":禁用 C++ 名稱修飾,按 C 語言規則導出,使 DllImport 能按名查找
  • __declspec(dllexport):將函數放入 DLL 導出表

第二部分:C# 調用簡單函數

1. 複製 DLL

將編譯生成的 CppDemo.dll 複製到 C# 項目 bin/x64/Debug/ 目錄(或設置 Copy to Output Directory)。

2. P/Invoke 聲明

public class CPPDLL {
    [DllImport("CppDemo.dll")]
    public static extern int Add(int x, int y);
    
    [DllImport("CppDemo.dll")]
    public static extern int Sub(int x, int y);
    
    [DllImport("CppDemo.dll")]
    public static extern int Multiply(int x, int y);
    
    [DllImport("CppDemo.dll")]
    public static extern int Divide(int x, int y);
}

3. 調用測試

int result = CPPDLL.Add(10, 20);
Console.WriteLine($"10 + 20 = {result}");
// 輸出:10 + 20 = 30

第三部分:跨語言傳遞類/結構體(進階)

1. C++ 定義結構體與工廠函數

// UserInfo.h
typedef struct {
    char name[32];
    int age;
} User;

class UserInfo {
    char* m_Name;
    int m_Age;
public:
    UserInfo(char* name, int age) : m_Name(name), m_Age(age) {}
    virtual ~UserInfo() {}
    int GetAge() { return m_Age; }
    char* GetName() { return m_Name; }
};

// UserInfo.cpp
extern "C" __declspec(dllexport) User* Create(char* name, int age) {
    User* user = (User*)malloc(sizeof(User));
    UserInfo* info = new UserInfo(name, age);
    strcpy(user->name, info->GetName());
    user->age = info->GetAge();
    return user;  // 返回堆分配的結構體指針
}

設計要點:

  • 使用 malloc 分配內存,避免 C++ new 與 C# 內存管理衝突
  • 返回指針而非值,防止局部變量銷毀
  • 固定長度 char[32] 便於 C# 封送

2. C# 定義對應結構體與調用

[StructLayout(LayoutKind.Sequential)]
public struct User {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string Name;
    public int Age;
}

public class CPPDLL {
    // ... 原有函數 ...
    
    [DllImport("CppDemo.dll")]
    public static extern IntPtr Create(string name, int age);
}

// 調用
IntPtr ptr = CPPDLL.Create("Shawn", 25);
User user = (User)Marshal.PtrToStructure(ptr, typeof(User));
Console.WriteLine($"Name: {user.Name}, Age: {user.Age}");
// 輸出:Name: Shawn, Age: 25

關鍵屬性解析

  • [StructLayout(LayoutKind.Sequential)]:按聲明順序佈局,匹配 C++ 內存排列
  • [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]:固定長度字符串封送
  • IntPtr:跨平台指針類型,接收 C++ 返回的指針
  • Marshal.PtrToStructure:將非托管內存轉為托管結構體

常見坑與最佳實踐

問題解決方案
BadImageFormatExceptionC++ DLL 與 C# 目標平台不一致(x86/x64),統一設置
EntryPointNotFoundException缺少 extern "C" 導致名稱修飾,或導出名拼寫錯誤
內存洩露/崩潰C++ 用 malloc,C# 用完需調用 C++ 導出的 Free 函數釋放
字符串亂碼指定 CharSet = CharSet.Ansi 或 Unicode,匹配 C++ 編譯選項

總結

C# 調用 C++ DLL 核心流程:C++ 導出 C 風格接口 → C# P/Invoke 聲明 → 內存佈局匹配 → 指針轉結構體。掌握 extern "C"、__declspec(dllexport)、StructLayout、MarshalAs、IntPtr 五大關鍵點,即可實現複雜類型的安全跨語言互操作。

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