最近(半年前)有项目需要使用c#调用rust的dll,所以研究了一下如何调用(其实就是C#效率太低了,为了提高效率才用的这个办法)
需要实现的操作:
- c#调用RUST接口,传入int,不返回值
- c#调用RUST接口,获取i32
- C#传入byte数组
先新建一个rust项目:
cargo new csharpdll --lib
然后这里要注意,如果你是x64电脑,要编译x86的dll,那么需要按下面的步骤编译
rustup target add i686-pc-windows-msvc
cargo build --release --target=i686-pc-windows-msvc
另外,由于默认配置编译后会导致dll依赖vc库,我们需要配置打包静态库,参考:如何让RUST编译生成出不依赖VC++库的文件?
因为我追求让dll文件足够小,所以在Cargo.toml
里加了下面的东西,这里按需使用了
[profile.release]
lto = true
strip = true
codegen-units = 1
panic = "abort"
接着我们编写一个c#调用RUST接口,不返回值
的函数,这里注意,c#传入的int实际上就是i32
#[no_mangle]
pub extern fn func1(data:i32) {
//balabala一堆代码
}
主要就是前一行的#[no_mangle]
和函数前的pub extern
,别的没什么好注意的
然后在C#中,只要这样声明就能调用了(注意C#的exe文件需要与dll同级,或者dll在环境变量path路径,并且C#的x64/x86需要与dll相匹配)
[DllImport("csharpdll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void func1(int data);
接着我们来写c#调用RUST接口,获取i32
的接口,没啥特别的:
rust
#[no_mangle]
pub extern fn func2() -> i32 {
123
}
C#
[DllImport("csharpdll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern int func2();
最后就是C#传入byte数组
了,这里需要注意,必须传入长度
rust
#[no_mangle]
pub extern fn func3(ptr: *const u8, len: usize) {
//获取到传入的数组
let arr=unsafe{std::slice::from_raw_parts(ptr, len)};
//balabala一堆代码
}
C#这边和之前也差不多
[DllImport("csharpdll.dll", CallingConvention = CallingConvention.Cdecl)]
static extern void func3(byte[] ptr, uint len);