当前位置: 首页 > news >正文

Rust:如何开发Windows 动态链接库 DLL

以下是一个完整的 Rust 创建 Windows DLL 动态库的实例,包含详细步骤和代码示例:

🚀 完整步骤

1. 创建 DLL 项目
cargo new --lib rust_dll
cd rust_dll
2. 配置 Cargo.toml
[package]
name = "rust_dll"
version = "0.1.0"
edition = "2021"# 关键配置:指定生成动态链接库
[lib]
crate-type = ["cdylib"]  [dependencies]
windows = { version = "0.54.0", features = ["Win32_Foundation", "Win32_System_LibraryLoader"
]}
3. 编写 DLL 代码 (src/lib.rs)
use std::os::raw::c_char;
use std::ffi::{CStr, CString};
use windows::Win32::System::LibraryLoader;// 基本数学函数示例
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 {a + b
}// 字符串处理示例 (Rust <-> C)
#[no_mangle]
pub extern "C" fn to_uppercase(input: *const c_char) -> *mut c_char {let c_str = unsafe { CStr::from_ptr(input) };let r_str = c_str.to_str().unwrap();let uppercased = r_str.to_uppercase();CString::new(uppercased).unwrap().into_raw()
}// 内存释放函数 (必须暴露!)
#[no_mangle]
pub extern "C" fn free_string(ptr: *mut c_char) {unsafe {if ptr.is_null() {return;}let _ = CString::from_raw(ptr);}
}// DLL 入口点 (可选)
#[no_mangle]
pub extern "system" fn DllMain(_module: isize,call_reason: u32,_reserved: *mut std::ffi::c_void
) -> i32 {match call_reason {LibraryLoader::DLL_PROCESS_ATTACH => 1,LibraryLoader::DLL_PROCESS_DETACH => 1,_ => 1,}
}// 结构体示例
#[repr(C)]
pub struct Point {pub x: f64,pub y: f64
}#[no_mangle]
pub extern "C" fn create_point(x: f64, y: f64) -> Point {Point { x, y }
}#[no_mangle]
pub extern "C" fn distance(p1: Point, p2: Point) -> f64 {let dx = p2.x - p1.x;let dy = p2.y - p1.y;(dx * dx + dy * dy).sqrt()
}
4. 编译 DLL
cargo build --release
# 生成的DLL: target\release\rust_dll.dll

🔑 关键要点详解

1. crate-type = ["cdylib"]
  • 必需配置:指定生成 C 兼容的动态链接库
  • 其他类型:
    • rlib:Rust 静态库
    • staticlib:C 兼容静态库
    • dylib:Rust 动态库 (不推荐用于跨语言)
2. #[no_mangle]
#[no_mangle]
pub extern "C" fn add(a: i32, b: i32) -> i32 { a + b }
  • 禁止 Rust 的名称修饰(name mangling)
  • 保证函数名在 DLL 中保持原样 add
3. extern "C"
  • 使用 C 的调用约定(cdecl)
  • 保证函数参数传递方式兼容 Windows API
4. 字符串处理
#[no_mangle]
pub extern "C" fn to_uppercase(input: *const c_char) -> *mut c_char {let c_str = unsafe { CStr::from_ptr(input) };// ...转换处理...CString::new(uppercased).unwrap().into_raw()
}
  • CString::into_raw() 移交所有权给调用方
  • 必须 提供对应的释放函数:
    #[no_mangle]
    pub extern "C" fn free_string(ptr: *mut c_char) {unsafe { let _ = CString::from_raw(ptr); }
    }
    
5. DLL 入口点 (可选)
#[no_mangle]
pub extern "system" fn DllMain(...)
  • extern "system" 指定使用 stdcall 调用约定
  • 处理生命周期事件:加载/卸载/线程附加/分离
6. 结构体处理
#[repr(C)]
pub struct Point {pub x: f64,pub y: f64
}
  • #[repr(C)] 强制 C 兼容的内存布局
  • 保证字段顺序和内存对齐与 C 相同

📊 C++ 调用示例

创建 test_dll.cpp:

#include <iostream>
#include <Windows.h>// 函数声明
typedef int(__cdecl* FnAdd)(int, int);
typedef char* (__cdecl* FnToUpper)(const char*);
typedef void(__cdecl* FnFreeString)(char*);struct Point {double x;double y;
};
typedef Point(__cdecl* FnCreatePoint)(double, double);
typedef double(__cdecl* FnDistance)(Point, Point);int main() {// 1. 加载DLLHMODULE dll = LoadLibrary(TEXT("rust_dll.dll"));if (!dll) {std::cerr << "无法加载DLL!" << std::endl;return 1;}// 2. 获取函数指针FnAdd add = (FnAdd)GetProcAddress(dll, "add");FnToUpper to_upper = (FnToUpper)GetProcAddress(dll, "to_uppercase");FnFreeString free_string = (FnFreeString)GetProcAddress(dll, "free_string");FnCreatePoint create_point = (FnCreatePoint)GetProcAddress(dll, "create_point");FnDistance distance = (FnDistance)GetProcAddress(dll, "distance");// 3. 调用函数std::cout << "5 + 3 = " << add(5, 3) << std::endl;const char* input = "hello from c++";char* result = to_upper(input);std::cout << "Uppercase: " << result << std::endl;free_string(result);Point p1 = create_point(0.0, 0.0);Point p2 = create_point(3.0, 4.0);std::cout << "Distance: " << distance(p1, p2) << std::endl;// 4. 卸载DLLFreeLibrary(dll);return 0;
}

编译命令 (使用 MSVC):

cl /EHsc test_dll.cpp
test_dll.exe

⚡ 输出结果:

5 + 3 = 8
Uppercase: HELLO FROM C++
Distance: 5.0

🔧 高级主题

1. 错误处理最佳实践
#[no_mangle]
pub extern "C" fn safe_operation() -> *mut c_char {match std::panic::catch_unwind(|| {// 可能失败的操作}) {Ok(val) => CString::new(val).unwrap().into_raw(),Err(_) => {let error = CString::new("operation failed").unwrap();error.into_raw()}}
}
2. 回调函数支持
type Callback = extern "C" fn(i32);#[no_mangle]
pub extern "C" fn register_callback(cb: Callback) {for i in 1..=5 {cb(i);std::thread::sleep(std::time::Duration::from_secs(1));}
}
3. 优化技巧
  1. 减少 FFI 边界交叉:

    // 不推荐 (频繁跨边界)
    for i in 0..100 { c_callback(i); 
    }// 推荐 (单次数据聚合)
    let results: Vec<i32> = (0..100).map(|i| i * 2).collect();
    c_process_array(results.as_ptr(), results.len());
    
  2. 使用 #[repr(transparent)] 包装单一值:

    #[repr(transparent)]
    pub struct Handle(isize);
    

🛡️ 安全注意事项

  1. 线程安全

    use std::sync::Mutex;static COUNTER: Mutex<i32> = Mutex::new(0);#[no_mangle]
    pub extern "C" fn increment() {let mut count = COUNTER.lock().unwrap();*count += 1;
    }
    
  2. 资源泄漏

    • 为所有 into_raw() 创建的对象提供释放函数
    • 在 DLL 卸载时清理资源
  3. ABI 稳定性

    • 使用 #[repr(C)] 保证布局
    • 避免更改已发布的函数签名
    • 保持结构体字段顺序不变

📦 完整项目结构

rust_dll/
├── Cargo.toml
├── src/
│   └── lib.rs
└── tests/└── test_dll.cpp

此实现已在以下环境测试通过:

  • Rust 1.72+
  • Windows 10/11
  • MSVC Toolchain
  • x86_64-pc-windows-msvc target

可通过以下命令生成类型信息头文件:

cbindgen --lang c --output rust_dll.h
http://www.lryc.cn/news/609016.html

相关文章:

  • 【AI编程工具IDE/CLI/插件专栏】-国外IDE与Cursor能力对比
  • 08.Redis 持久化
  • Pytorch实现一个简单的贝叶斯卷积神经网络模型
  • (一)全栈(react配置/https支持/useState多组件传递/表单提交/React Query/axois封装/Router)
  • CICD--自动化部署--jinkins
  • TV电视版软件集合分享
  • 动感按钮:如何打造交互感十足的点击动画效果
  • 【前端安全】聊聊 HTML 闭合优先级和浏览器解析顺序
  • 二叉树算法之【前序遍历】
  • 设计原则和设计模式
  • 图像、视频、音频多模态大模型中长上下文token压缩方法综述
  • 【Leetcode】2106. 摘水果
  • 【openlayers框架学习】九:openlayers中的交互类(select和draw)
  • 安卓调javaScript Not find method “forceLogout“ implementatidsignature or namesp
  • 【C语言符号单词搜索首位置及数量】2022-10-4
  • web前端React和Vue框架与库安全实践
  • 数组和指针的关系
  • 【LeetCode刷题指南】--二叉树的后序遍历,二叉树遍历
  • VUE父级路由没有内容的解决方案
  • Python自动化测试框架:Unittest 断言
  • 数据结构中使用到的C语言
  • elk快速部署、集成、调优
  • [硬件电路-143]:模拟电路 - 开关电源与线性稳压电源的详细比较
  • mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件
  • MySQL极简安装挑战
  • nmon使用教程
  • sqli-labs:Less-23关卡详细解析
  • 基于Python实现生产者—消费者分布式消息队列:构建高可用异步通信系统
  • cpy相关函数区分
  • Ollama模型库模型下载慢完美解决(全平台)