使用 Rust 创建 32 位 DLL 的完整指南
在 Rust 中创建 32 位 DLL 需要特定的工具链配置和编译选项。以下是详细步骤和最佳实践:
环境准备
1. 安装 Rust 工具链
# 安装 Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# 安装 32 位目标
rustup target add i686-pc-windows-gnu # GNU ABI
# 或
rustup target add i686-pc-windows-msvc # MSVC ABI
2. 安装 MinGW-w64 (GNU ABI 需要)
# Ubuntu/Debian
sudo apt install gcc-mingw-w64-i686
# Arch Linux
sudo pacman -S mingw-w64-gcc
创建 DLL 项目
1. 新建库项目
cargo new --lib mydll
cd mydll
2. 配置 Cargo.toml
[package]
name = "mydll"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"] # 关键:指定为 C 兼容动态库
[dependencies]
libc = "0.2" # 用于 C 类型兼容
编写 DLL 代码
基本示例 (src/lib.rs)
use std::ffi::CStr;
use std::os::raw::{c_char, c_int};
// 导出函数必须使用 extern "C" 和 #[no_mangle]
#[no_mangle]
pub extern "C" fn add_numbers(a: c_int, b: c_int) -> c_int {
a + b
}
#[no_mangle]
pub extern "C" fn greet(name: *const c_char) -> *const c_char {
let c_str = unsafe { CStr::from_ptr(name) };
let name_str = c_str.to_str().unwrap_or("stranger");
let greeting = format!("Hello, {}!", name_str);
let c_greeting = std::ffi::CString::new(greeting).unwrap();
c_greeting.into_raw() // 调用方需要释放内存
}
// 内存释放函数
#[no_mangle]
pub extern "C" fn free_string(s: *mut c_char) {
unsafe {
if s.is_null() {
return;
}
let _ = std::ffi::CString::from_raw(s);
}
}
编译 32 位 DLL
GNU ABI 编译
cargo build --target i686-pc-windows-gnu --release
MSVC ABI 编译
cargo build --target i686-pc-windows-msvc --release
输出文件:target/i686-pc-windows-gnu/release/mydll.dll
创建头文件 (mydll.h)
#ifdef __cplusplus
extern "C" {
#endif
__declspec(dllimport) int add_numbers(int a, int b);
__declspec(dllimport) const char* greet(const char* name);
__declspec(dllimport) void free_string(char* s);
#ifdef __cplusplus
}
#endif
在 C/C++ 中使用 DLL
C++ 示例 (test.cpp)
#include <iostream>
#include <Windows.h>
#include "mydll.h"
int main() {
// 显式加载 DLL
HMODULE dll = LoadLibraryA("mydll.dll");
if (!dll) {
std::cerr << "Failed to load DLL" << std::endl;
return 1;
}
// 获取函数指针
auto add_func = (int(*)(int, int))GetProcAddress(dll, "add_numbers");
auto greet_func = (const char*(*)(const char*))GetProcAddress(dll, "greet");
auto free_func = (void(*)(char*))GetProcAddress(dll, "free_string");
if (!add_func || !greet_func || !free_func) {
std::cerr << "Failed to get function pointers" << std::endl;
FreeLibrary(dll);
return 1;
}
// 使用函数
int result = add_func(5, 7);
std::cout << "5 + 7 = " << result << std::endl;
const char* greeting = greet_func("World");
std::cout << greeting << std::endl;
free_func(const_cast<char*>(greeting));
FreeLibrary(dll);
return 0;
}
高级主题
1. 处理结构体
#[repr(C)]
pub struct Point {
pub x: i32,
pub y: i32,
}
#[no_mangle]
pub extern "C" fn create_point(x: i32, y: i32) -> Box<Point> {
Box::new(Point { x, y })
}
#[no_mangle]
pub extern "C" fn distance(p1: *const Point, p2: *const Point) -> f64 {
unsafe {
let p1 = &*p1;
let p2 = &*p2;
let dx = (p2.x - p1.x) as f64;
let dy = (p2.y - p1.y) as f64;
(dx * dx + dy * dy).sqrt()
}
}
2. 回调函数
type Callback = extern "C" fn(i32);
#[no_mangle]
pub extern "C" fn register_callback(cb: Callback) {
for i in 0..5 {
cb(i);
}
}
3. 错误处理
#[repr(C)]
pub enum ErrorCode {
Success = 0,
InvalidInput,
CalculationError,
}
#[no_mangle]
pub extern "C" fn safe_divide(
a: f64,
b: f64,
result: *mut f64
) -> ErrorCode {
if b == 0.0 {
return ErrorCode::InvalidInput;
}
unsafe {
*result = a / b;
}
ErrorCode::Success
}
构建优化
1. 减小 DLL 大小
# Cargo.toml
[profile.release]
opt-level = "z" # 优化大小
lto = true # 链接时优化
codegen-units = 1 # 减少并行编译
panic = "abort" # 禁用panic展开
2. 移除符号信息
# 安装 strip 工具
cargo install cargo-strip
# 构建并剥离符号
cargo build --target i686-pc-windows-gnu --release
cargo strip --target i686-pc-windows-gnu
调试技巧
1. 使用 Dependency Walker
Dependency Walker 分析 DLL 导出函数
2. Rust 调试符号
# Cargo.toml
[profile.release]
debug = true # 保留调试符号
3. 日志输出
#[no_mangle]
pub extern "C" fn debug_log(msg: *const c_char) {
let c_str = unsafe { CStr::from_ptr(msg) };
println!("[DEBUG] {}", c_str.to_str().unwrap_or(""));
}
常见问题解决
1. 内存管理问题
- Rust 分配的内存必须在 Rust 中释放
- 使用
Box::into_raw和Box::from_raw转换所有权
2. ABI 兼容性
- 使用
#[repr(C)]确保结构体布局 - 避免使用 Rust 特有类型(如 String, Vec)
- 使用
libccrate 中的 C 类型
3. 线程安全
// 标记线程安全函数
#[no_mangle]
pub extern "C" fn thread_safe_function() {
// 使用互斥锁等同步机制
}
4. 入口点函数
// DLL 入口点 (可选)
#[no_mangle]
#[allow(non_snake_case)]
pub extern "system" fn DllMain(
_hinstDLL: isize,
_fdwReason: u32,
_lpvReserved: isize,
) -> i32 {
1 // 成功
}
完整项目结构
mydll/
├── Cargo.toml
├── src/
│ └── lib.rs
├── include/
│ └── mydll.h
└── examples/
└── test.cpp
通过遵循这些步骤和最佳实践,您可以创建高效、稳定的 32 位 DLL,并轻松集成到各种 Windows 应用程序中。
Rust 创建 32 位 DLL 完整指南

580

被折叠的 条评论
为什么被折叠?



