如何在C#程序中调用依赖多文件的Rust库函数?
在C#中调用Rust库的
create函数步骤 要在C#里调用这个Rust函数,核心是把Rust库导出为C兼容的接口,再通过C#的P/Invoke机制调用,具体操作如下:
1. 改造Rust代码,导出C兼容接口
原函数依赖Rust专属的Config、Path等类型,无法直接被C#调用,需要封装一层C兼容的接口:
1.1 定义C兼容的数据结构
在Rust库中添加C兼容的结构体和枚举,替代原有的Rust类型:
use std::os::raw::{c_int, c_char}; use std::ffi::{CStr, CString}; use std::path::Path; // 对应原Config的C兼容结构体 #[repr(C)] pub struct CConfig { verbose: c_int, // 用int代替bool,C中bool通常以int表示 game_id: c_int, // 用枚举值标识游戏类型,比如0=GameA,1=GameB等 } // 定义游戏类型枚举,和C#端保持一致 #[repr(C)] pub enum CGameType { GameA, GameB, }
1.2 封装导出函数
添加#[no_mangle]标记的函数,负责把C类型转换为Rust内部类型,调用原create函数,并返回错误码(0=成功,非0=失败):
#[no_mangle] pub extern "C" fn create_mod_pack(c_config: CConfig, c_path: *const c_char) -> c_int { // 转换C字符串为Rust Path let path = unsafe { if c_path.is_null() { return 1; // 路径为空返回错误 } CStr::from_ptr(c_path).to_str().map_err(|_| 2)? }; let path = Path::new(path); // 转换CConfig为原Config类型 let config = Config { verbose: c_config.verbose != 0, game: Some(match c_config.game_id { x if x == CGameType::GameA as c_int => Game::GameA, x if x == CGameType::GameB as c_int => Game::GameB, _ => return 3, // 无效游戏类型返回错误 }), }; // 调用原create函数,处理结果 match create(&config, path) { Ok(_) => 0, Err(e) => { eprintln!("Error creating mod pack: {}", e); 4 // 通用错误码 } } }
1.3 配置Cargo.toml
确保Rust库编译为动态链接库,在Cargo.toml中添加:
[lib] crate-type = ["cdylib"] # 编译为C兼容的动态链接库
2. 编译Rust库
执行编译命令生成对应平台的动态链接库:
cargo build --release
编译完成后,在target/release目录下会得到对应的文件(Windows为.dll,Linux为.so,macOS为.dylib)。
3. 在C#中调用该动态链接库
3.1 定义对应的数据结构和枚举
在C#中定义和Rust端内存布局一致的结构体和枚举:
using System; using System.Runtime.InteropServices; // 对应Rust的CGameType枚举 public enum CGameType { GameA, GameB } // 对应Rust的CConfig结构体 [StructLayout(LayoutKind.Sequential)] public struct CConfig { public int verbose; public int game_id; }
3.2 导入Rust导出的函数
用DllImport导入动态链接库中的函数:
public class RustModPackApi { // 替换为你的Rust库文件名 [DllImport("your_lib_name.dll", CallingConvention = CallingConvention.Cdecl)] public static extern int create_mod_pack(CConfig config, string path); }
3.3 调用函数
在C#代码中构造参数并调用:
var config = new CConfig { verbose = 1, // 1表示开启verbose,0关闭 game_id = (int)CGameType.GameA }; string modPackPath = @"C:\path\to\mod.pack"; int result = RustModPackApi.create_mod_pack(config, modPackPath); if (result == 0) { Console.WriteLine("Mod pack created successfully"); } else { Console.WriteLine($"Failed to create mod pack, error code: {result}"); }
注意事项
- 内存管理:如果Rust函数需要返回字符串给C#,需额外提供内存释放函数;本场景无需返回数据,只需关注输入参数转换。
- 编码一致性:确保Rust和C#使用相同的字符串编码,若需UTF-8,可在C#的
DllImport中添加CharSet = CharSet.Unicode并调整Rust端字符串处理逻辑。 - 平台适配:不同操作系统对应不同的库文件格式,C#代码需根据运行平台加载对应库文件。
内容的提问来源于stack exchange,提问作者romanCastro
相关产品推荐
相关产品推荐

