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

Rust:如何开发32位的DLL动态库

第一部分 完整示例

以下是一个完整的32位Rust DLL示例,包含所有必要的步骤和代码:

完整示例:创建32位DLL

1. 确保安装32位工具链
rustup target add i686-pc-windows-msvc
2. 创建项目
cargo new my_32bit_dll --lib
cd my_32bit_dll
3. 修改 Cargo.toml
[package]
name = "my_32bit_dll"
version = "0.1.0"
edition = "2021"[lib]
crate-type = ["cdylib"]  # 关键:生成动态链接库[dependencies]
windows = { version = "0.54", features = ["Win32_System_Diagnostics_Debug","Win32_Foundation"
]}
4. 修改 src/lib.rs
use std::ffi::{c_void, CString};
use windows::Win32::System::Diagnostics::Debug::OutputDebugStringA;// 简单的DLL入口点(可选)
#[no_mangle]
#[allow(non_snake_case)]
pub extern "stdcall" fn DllMain(_hinst_dll: *const c_void,reason: u32,_reserved: *mut c_void,
) -> bool {match reason {1 => debug_print("DLL_PROCESS_ATTACH"),0 => debug_print("DLL_PROCESS_DETACH"),2 => debug_print("DLL_THREAD_ATTACH"),3 => debug_print("DLL_THREAD_DETACH"),_ => {}}true
}// 导出函数示例1:数学运算
#[no_mangle]
pub extern "C" fn calculate(a: i32, b: i32) -> i32 {(a * b) + (a + b)
}// 导出函数示例2:字符串转换
#[no_mangle]
pub extern "C" fn to_uppercase(input: *const i8) -> *mut i8 {if input.is_null() {return std::ptr::null_mut();}let c_str = unsafe { std::ffi::CStr::from_ptr(input) };let r_str = c_str.to_string_lossy().to_uppercase();let c_string = match std::ffi::CString::new(r_str) {Ok(s) => s,Err(_) => return std::ptr::null_mut(),};// 返回新分配的内存(调用者需要释放)let ptr = unsafe { libc::malloc(c_string.as_bytes().len() + 1) } as *mut i8;if ptr.is_null() {return std::ptr::null_mut();}unsafe {std::ptr::copy_nonoverlapping(c_string.as_ptr() as *const i8,ptr,c_string.as_bytes().len() + 1);}ptr
}// 导出函数示例3:注册回调
pub type Callback = unsafe extern "C" fn(i32, *const i8);#[no_mangle]
pub extern "C" fn process_with_callback(values: *const i32, count: i32, callback: Callback) {if values.is_null() || callback.is_null() {return;}let values_slice = unsafe { std::slice::from_raw_parts(values, count as usize) };for (i, &value) in values_slice.iter().enumerate() {let message = format!("Processing #{}: {}", i + 1, value);let c_message = CString::new(message).unwrap();unsafe { callback(value, c_message.as_ptr()) };}
}// 辅助函数:输出调试信息
fn debug_print(msg: &str) {let msg_with_newline = CString::new(format!("[MyDLL] {}\n", msg)).unwrap();unsafe {OutputDebugStringA(msg_with_newline.as_ptr());}
}// 重要:释放内存的函数
#[no_mangle]
pub extern "C" fn free_memory(ptr: *mut c_void) {if !ptr.is_null() {unsafe { libc::free(ptr) };}
}
5. 编译32位DLL
cargo build --target i686-pc-windows-msvc --release

生成的DLL路径:
target/i686-pc-windows-msvc/release/my_32bit_dll.dll

C++ 测试代码 (test_dll.cpp)

#include <Windows.h>
#include <iostream>
#include <vector>typedef int(__cdecl* CalculateFunc)(int, int);
typedef char*(__cdecl* ToUpperFunc)(const char*);
typedef void(__cdecl* ProcessCallbackFunc)(int, const char*);
typedef void(__cdecl* ProcessWithCallbackFunc)(const int*, int, ProcessCallbackFunc);
typedef void(__cdecl* FreeMemoryFunc)(void*);void callback(int value, const char* message) {std::cout << "Callback: " << value << " - " << message << std::endl;
}int main() {// 加载DLLHMODULE dll = LoadLibraryA("my_32bit_dll.dll");if (!dll) {std::cerr << "无法加载DLL! 错误码: " << GetLastError() << std::endl;return 1;}// 获取函数指针CalculateFunc calculate = (CalculateFunc)GetProcAddress(dll, "calculate");ToUpperFunc to_upper = (ToUpperFunc)GetProcAddress(dll, "to_uppercase");ProcessWithCallbackFunc process = (ProcessWithCallbackFunc)GetProcAddress(dll, "process_with_callback");FreeMemoryFunc free_mem = (FreeMemoryFunc)GetProcAddress(dll, "free_memory");if (!calculate || !to_upper || !process || !free_mem) {std::cerr << "无法找到函数!" << std::endl;FreeLibrary(dll);return 1;}// 测试calculate函数std::cout << "calculate(3, 5) = " << calculate(3, 5) << std::endl;  // 应该输出 3*5 + 3+5 = 15+8 = 23// 测试to_uppercase函数const char* input = "Hello Rust DLL!";char* result = to_upper(input);if (result) {std::cout << "Uppercase: " << result << std::endl;free_mem(result);  // 必须释放内存}// 测试回调函数std::vector<int> numbers = {10, 20, 30, 40};process(numbers.data(), (int)numbers.size(), callback);// 清理FreeLibrary(dll);std::cout << "测试完成! 按回车键退出..." << std::endl;std::cin.get();return 0;
}

编译和运行注意事项

  1. 编译C++测试程序

    • 使用Visual Studio命令提示符 (x86):
      cl /EHsc test_dll.cpp
      
  2. 关键要点

    • 调用约定:使用 __cdecl (默认) 或 __stdcall
    • 内存管理:
      • DLL分配的内存必须由DLL提供的函数释放
      • 字符串操作遵循"谁分配谁释放"原则
    • 错误处理:检查所有返回值和空指针
    • 类型兼容:
      • i32int
      • *const i8const char*
      • *mut c_voidvoid*
  3. 部署要求

    • 32位DLL只能用于32位应用程序
    • 依赖的Rust运行时静态链接到DLL中
    • 不需要额外安装Rust运行时

这个示例展示了三种常见的DLL使用场景:简单数学运算、字符串处理和回调函数,包含了完整的内存管理实践。

第二部分 如何安装32位编译环境

看起来你的构建环境缺少32位目标所需的编译工具链和库。这个问题通常可以通过以下步骤解决:

解决方案:

  1. 安装32位目标平台

    rustup target add i686-pc-windows-msvc
    
  2. 安装Visual Studio构建工具(如果尚未安装):

    • 打开Visual Studio Installer
    • 确保已安装:
      • "使用C++的桌面开发"工作负载
      • “MSVC v143 - VS 2022 C++ x64/x86 build tools”
      • “Windows 10 SDK (10.0.19041.0)或更新版本”
  3. 设置MSVC环境变量

    vcvarsall.bat x86
    
  4. 清理并重建

    cargo clean
    cargo build --target i686-pc-windows-msvc --release
    

如果问题仍然存在:

1. 检查工具链状态:
rustup show

确认i686-pc-windows-msvc出现在已安装目标列表中

2. 验证MSVC安装:

运行开发者命令行提示符并检查:

cl /?

应该看到32位x86架构选项

3. 简化测试(验证工具链):

创建一个新的测试项目:

cargo new test_dll --lib
cd test_dll

修改Cargo.toml:

[lib]
crate-type = ["cdylib"]

修改src/lib.rs:

#[no_mangle]
pub extern "C" fn simple_add(a: i32, b: i32) -> i32 {a + b
}

尝试构建:

cargo build --target i686-pc-windows-msvc --release
4. 替代方案(如果MSVC问题无法解决):

使用GNU工具链替代:

rustup target add i686-pc-windows-gnu
cargo build --target i686-pc-windows-gnu --release

常见问题诊断:

  1. 工具链冲突

    • 确保没有RUSTFLAGS环境变量覆盖
    • 尝试更新Rust: rustup update
  2. Windows SDK问题

    • 安装独立SDK: https://developer.microsoft.com/zh-cn/windows/downloads/windows-sdk/
    • 设置环境变量:
      set INCLUDE=C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\um;C:\Program Files (x86)\Windows Kits\10\Include\10.0.19041.0\shared
      set LIB=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.19041.0\um\x86
      
  3. 检查系统路径

    where link.exe
    where cl.exe
    

    确保显示的是Visual Studio工具路径

完成这些步骤后,你应该能成功编译32位DLL。如果仍然遇到问题,可以运行cargo build -vv --target i686-pc-windows-msvc --release查看详细构建日志以定位具体问题。

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

相关文章:

  • 单向链表(补充)与linux虚拟机网络配置
  • JS--获取事件的子元素与父元素
  • ZooKeeper 深度实践:从原理到 Spring Boot 全栈落地
  • 【unitrix】 7.1 二进制位加法(bit_add.rs)
  • 哪些第三方 Crate 可以直接用?
  • Mac桌面仿制项目--让ai一句话生成的
  • Qt 使用QtXlsx库处理Excel文件
  • Druid学习笔记 01、快速了解Druid中SqlParser实现
  • 赛灵思ZYNQ官方文档UG585自学翻译笔记:General Purpose I/O (GPIO)通用输入 / 输出
  • Linux文件权限管理全解
  • Java Getter 与 C# Getter 比较
  • WPF中引用其他元素各种方法
  • AUTOSAR AR-Explorer正式发布
  • C语言的数组与字符串
  • 从物理扇区到路径访问:Linux文件抽象的全景解析
  • 读写分离有那些坑?
  • 【企业架构】TOGAF概念之三
  • 【Linux | 网络】网络层(IP协议、NAT技术和ICMP协议)
  • 大模型 与 自驾 具身 3D世界模型等相关知识
  • GaussDB 数据库架构师(十二) 资源规划
  • 音视频文案字幕一键提取,免费使用,效率软件!
  • 开源的现代数据探索和可视化平台:Apache Superset 快速指南 Quickstart
  • 大模型探秘–AI 感知世界:从对话到掌控的交互革命
  • 13015计算机系统原理-速记宝典
  • 【Linux操作系统】简学深悟启示录:进程初步
  • Apache IoTDB(3):时序数据库 IoTDB Docker部署实战
  • Baumer工业相机堡盟工业相机如何通过YoloV8深度学习模型实现人脸面部表情的追踪识别(C#代码UI界面版)
  • 商标续展如果逾期了还有办法补救吗?
  • 第1章-信息系统与信息技术发展
  • 案件线索展示与交付项目