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

使用 Rust 创建 32 位 DLL 的完整指南

使用 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() {// 显式加载 DLLHMODULE 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_rawBox::from_raw 转换所有权

2. ABI 兼容性

  • 使用 #[repr(C)] 确保结构体布局
  • 避免使用 Rust 特有类型(如 String, Vec)
  • 使用 libc crate 中的 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 应用程序中。

http://www.dtcms.com/a/325573.html

相关文章:

  • VoxCraft-生数科技推出的免费3D模型AI生成工具
  • Rust 库开发全面指南
  • Vue 项目中主从表异步保存实战:缓存导致接口不执行问题排查与解决
  • 芯盾时代 SDP 助力运营商远程接入体系全面升级
  • linux实战:基于Ubuntu的专业相机
  • MySQL 8.4.5 中分区相关变量的查看
  • kubeadm搭建生产环境的双master节点k8s高可用集群
  • ubuntu20.04交叉编译vlc3.0.21 x64 windows版本
  • C++ 限制类对象数量的技巧与实践
  • 案例实战,一文吃透 Web Components
  • Docker中ES安装分词器
  • CW32L011 GTIM通用定时器配置
  • 打破内网枷锁!TRAE SOLO + cpolar 让AI开发告别“孤岛困境”
  • ctc 解码原理
  • 正则表达式:文本模式的数学语言与编程工具
  • Selenium经典面试题 - 多窗口切换解决方案
  • redis笔记(二)
  • 排错000
  • 《基于Pytorch实现的声音分类 :网页解读》
  • 基于数据结构用java实现二叉树的排序器
  • Godot ------ 平滑拖动02
  • 使用Springboot实现简单的ELK日志搜索系统
  • 游戏引擎(Unreal Engine、Unity、Godot等)大对比:选择最适合你的工具
  • Godot ------ 平滑拖动01
  • OpenAI COO谈ChatGPT5的技术突破:编程、医疗、自动推理
  • 【LeetCode 热题 100】(七)链表
  • window显示驱动开发—创建多平面覆盖资源
  • 适合物流/应急/工业的对讲机,AORO M6 Pro构建高效指挥调度方案
  • 运动规划实战案例 | 基于多源流场(Flow Field)的路径规划(附ROS C++/Python实现)
  • 直接编辑pdf文件教程