显示页面讨论反向链接回到顶部 本页面只读。您可以查看源文件,但不能更改它。如果您觉得这是系统错误,请联系管理员。 ====== 使用 C++/CLI 连接 C++ 与 C# ====== 在软件开发中,我们经常需要结合 C# 的开发效率和 C++ 的运行性能。**C++/CLI** 是微软提供的一种技术,充当两者之间的桥梁(Wrapper)。 ===== 架构概览 ===== 整个解决方案通常包含三个部分(三个项目): - ** Native C++ (后端核心)**: 纯 C++ 代码,负责核心算法或底层操作。不依赖 .NET。 - ** C++/CLI (中间层/包装器)**: 编译为 DLL。内部调用 Native C++,外部向 C# 暴露 .NET 类。 - ** C# (前端应用)**: 引用 C++/CLI 生成的 DLL,像调用普通 C# 库一样使用。 ===== 步骤 1: 创建 Native C++ 核心库 ===== 首先,我们需要一个标准的 C++ 类。假设我们创建一个简单的数学库。 ==== Core.h ==== <code cpp> #pragma once #include <string> namespace NativeCore { class Calculator { public: Calculator(); ~Calculator(); double Add(double a, double b); std::string SayHello(const std::string& name); }; } </code> ==== Core.cpp ==== <code cpp> #include "Core.h" #include <iostream> namespace NativeCore { Calculator::Calculator() {} Calculator::~Calculator() {} double Calculator::Add(double a, double b) { return a + b; } std::string Calculator::SayHello(const std::string& name) { return "Hello " + name + " from Native C++!"; } } </code> ===== 步骤 2: 创建 C++/CLI 包装器 (Wrapper) ===== 这是最关键的一步。你需要创建一个 **C++ 动态链接库 (DLL)** 项目,并开启 CLR 支持。 **项目配置要点:** * 右键项目 -> **属性 (Properties)** * **配置属性 (Configuration Properties)** -> **C/C++** -> **常规 (General)** -> **公共语言运行时支持 (Common Language Runtime Support)**: 选择 **公共语言运行时支持 (/clr)**。 * 确保将 Native C++ 项目的头文件路径添加到 **包含目录 (Include Directories)**。 * 确保引用了 Native C++ 项目(或者链接了其 .lib 文件)。 ==== CliWrapper.h ==== <code cpp> #pragma once #include "Core.h" // 包含 Native C++ 头文件 #include <msclr/marshal_cppstd.h> // 用于字符串转换 using namespace System; namespace CliLibrary { // 使用 'public ref class' 定义一个托管类,这样 C# 才能看到它 public ref class ManagedCalculator { private: // 指向 Native C++ 对象的指针 NativeCore::Calculator* m_impl; public: // 构造函数:分配 Native 资源 ManagedCalculator() { m_impl = new NativeCore::Calculator(); } // 析构函数 (!ClassName):用于确定性销毁 (Dispose) !ManagedCalculator() { if (m_impl != nullptr) { delete m_impl; m_impl = nullptr; } } // 终结器 (~ClassName):用于垃圾回收 (Finalize) ~ManagedCalculator() { this->!ManagedCalculator(); } // 包装 Add 方法 double Add(double a, double b) { return m_impl->Add(a, b); } // 包装字符串方法 (涉及数据封送/Marshaling) String^ SayHello(String^ name) { // 1. 将 C# String (System::String) 转换为 C++ std::string msclr::interop::marshal_context context; std::string nativeName = context.marshal_as<std::string>(name); // 2. 调用 Native 方法 std::string nativeResult = m_impl->SayHello(nativeName); // 3. 将 C++ std::string 转换回 C# String return context.marshal_as<String^>(nativeResult); } }; } </code> ==== CliWrapper.cpp ==== <code cpp> #include "CliWrapper.h" // 如果逻辑很简单,代码可以直接写在 .h 文件中。 // 复杂的实现建议放在这里。 </code> ===== 步骤 3: C# 调用 ===== 在 C# 项目中: - 右键 **依赖项 (Dependencies)** -> **添加项目引用 (Add Project Reference)**。 - 勾选上面的 **C++/CLI 项目**。 ==== Program.cs ==== <code csharp> using System; using CliLibrary; // 引用 C++/CLI 定义的命名空间 namespace CSharpApp { class Program { static void Main(string[] args) { Console.WriteLine("正在初始化 C++ 包装器..."); // 使用 using 语句确保非托管资源被及时释放 (调用 C++/CLI 的析构函数) using (ManagedCalculator calc = new ManagedCalculator()) { // 1. 测试数值计算 double result = calc.Add(10.5, 20.3); Console.WriteLine($"C++ Add Result: {result}"); // 2. 测试字符串传递 String msg = calc.SayHello("C# User"); Console.WriteLine($"C++ Message: {msg}"); } Console.WriteLine("完成。"); Console.ReadKey(); } } } </code> ===== 关键概念解析 ===== ==== 1. 内存管理 ==== 在 C++/CLI 中,我们混合了两种内存模型: * **托管堆 (Managed Heap)**: 由 .NET 垃圾回收器 (GC) 管理。使用 `gcnew` 分配,用句柄 `^` (Handle) 引用。 * **本机堆 (Native Heap)**: 由 C++ 手动管理。使用 `new` 分配,用指针 `*` 引用。 **最佳实践**: 在 C++/CLI 类中持有一个指向 Native 对象的指针。在构造函数中 `new`,在析构函数中 `delete`。 ==== 2. 数据封送 (Marshaling) ==== C# 的数据类型和 C++ 不完全通用,需要转换: * **基本类型 (int, double, bool)**: 通常可以直接互通,无需特殊处理。 * **字符串 (System::String^ vs std::string)**: 需要转换。使用 `<msclr/marshal_cppstd.h>` 库非常方便。 * **数组**: 需要将托管数组的数据复制到非托管内存中,或者使用 `pin_ptr` 固定内存指针供 C++ 使用。 ==== 3. 编译模式 (/clr) ==== 开启 `/clr` 后,编译器会生成 **MSIL** (微软中间语言) 和 **Native Code** 的混合体。这使得生成的 DLL 既是一个标准的 .NET 程序集,又能直接执行机器码。 ===== 常见问题排查 ===== * **System.BadImageFormatException**: 通常是因为架构不匹配。确保 C# 项目、C++/CLI 项目和 Native C++ 项目都统一设置为 **x64** 或 **x86**。不要使用 "Any CPU" 混用。 * **Linker Error (LNK2019)**: C++/CLI 项目没有链接 Native C++ 的 `.lib` 文件。需要在属性中添加引用或配置链接器输入。 * **找不到 DLL**: 运行时,Native C++ 的 DLL (如果是动态链接) 必须和 C# 的 Exe 在同一目录下。 登录 Detach Close 该主题尚不存在 您访问的页面并不存在。如果允许,您可以使用创建该页面按钮来创建它。 csharp/cli.txt 最后更改: 2025/11/27 13:32由 张叶安 登录