使用 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.pswp.cn/bicheng/93323.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/93323.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/93323.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

算法基础 第3章 数据结构

1.单调栈 1.什么是单调栈 单调栈&#xff0c;即具有单调性的栈。 实现 #include <iostream> #include <stack> using namespace std; const int N 3e6 10; int a[N], n; void test1() {stack<int> st; // 维护⼀个单调递增的栈for(int i 1; i < n; i…

[机器学习]08-基于逻辑回归模型的鸢尾花数据集分类

使用sklearn的LogisticRegression多分类模型程序代码&#xff1a;import numpy as np from sklearn.linear_model import LogisticRegression import matplotlib.pyplot as plt import matplotlib as mpl from sklearn import datasets from sklearn import preprocessing impo…

【STM32入门教程】stm32简介

一、STM32简介二、ARM三、stm32f103c8t6四、命名规则五、系统结构六、引脚定义七、启动配置一般情况下&#xff0c;都是在flash开始程序&#xff0c;而启动程序也可以进行配置在其他地方启动程序&#xff0c;通过配置boot0和boot1来进行配置八、最小系统电路

SAE J2716多协议网关的硬件架构与实时协议转换机制解析

本文解析符合SAE J2716标准的工业级协议转换设备技术架构&#xff0c;通过拆解其四路双向SENT通道与多总线&#xff08;CANFD/Ethernet/USB&#xff09;的实时交互机制、MicroSD独立日志系统设计及模拟量动态映射方案&#xff0c;为汽车电子与工业通信开发者提供可复用的技术参…

VS2022+QT5.15.2+OCCT7.9.1的开发环境搭建流程

以下是VS2022 QT5.15.2 OCCT7.9.1开发环境搭建的完整流程&#xff1a; 一、安装Visual Studio 2022 下载安装程序 访问VS官网下载Community版安装组件 选择"使用C的桌面开发"工作负载勾选&#xff1a; MSVC v143 - VS 2022 C x64/x86生成工具Windows 10 SDK (建议…

数据库访问模式详解

数据库访问模式详解数据库访问模式是软件架构中数据访问层&#xff08;Data Access Layer&#xff09;设计的核心&#xff0c;它定义了应用程序如何与数据库进行交互的策略和方法。选择合适的访问模式对于系统的性能、可维护性、可扩展性、事务一致性和开发效率至关重要。不同的…

BGE向量算法

一、是什么 什么是BGE向量算法&#xff1f;先说说网上的概念吧。本文不讲解太深的算法知识&#xff0c;主要讲解如何用&#xff01; BGE&#xff08;BAAI General Embedding&#xff09;是北京智源研究院开源的“通用语义向量模型”。一句话&#xff1a;把中文或英文句子变成…

AI数据仓库的核心优势解析

内容概要本文旨在全面解析AI数据仓库的核心优势&#xff0c;为读者提供清晰的框架。文章首先从基础定义出发&#xff0c;探讨其如何高效整合多源数据&#xff0c;并支持人工智能与机器学习应用。随后&#xff0c;将详细阐述处理TB级数据的能力&#xff0c;包括兼容结构化和非结…

具身智能Scaling Law缺失:机器人界的“摩尔定律“何时诞生?

8月9日&#xff0c;在世界机器人大会的演讲台上&#xff0c;宇树科技创始人王兴兴谈论到目前机器人运动控制领域存在的RL Scaling Law问题&#xff0c;他认为现在的机器人在学习一项新的技能时&#xff0c;往往都是需要从头开始研究以及教学。而在未来更加希望的是能够在原有的…

【跨越 6G 安全、防御与智能协作:从APT检测到多模态通信再到AI代理语言革命】

跨越 6G 安全、防御与智能协作&#xff1a;从APT检测到多模态通信再到AI代理语言革命引言单篇总结**2. Integrated Multimodal Sensing and Communication: Challenges, Technologies, and Architectures****3. Why do AI agents communicate in human language?**引言 在迈向…

微前端-解决MicroApp微前端内存泄露问题

前言 之前使用京东微前端框架MicroApp集成10个微前端的页面到AngularJs的后台管理系统中&#xff0c;每个微前端做成一个菜单&#xff0c;一共10个&#xff0c;每次打开都是一个新的微前端&#xff0c;但是发现打开的微前端越多&#xff0c;容易造成内存泄露&#xff0c;下面讲…

线性代数 · 向量运算 | 叉乘 / 几何意义 / 推导

注&#xff1a;本文为 “线性代数 向量运算” 相关合辑。 图片清晰度受引文原图所限。 略作重排&#xff0c;未整理去重。 如有内容异常&#xff0c;请看原文。 数学基础 —— 向量运算&#xff08;叉乘&#xff09; keng_s 于 2016-08-05 17:17:57 发布 1_ 向量的叉乘 向量…

方法中只包含查询操作需要添加事务吗?

方法中只包含查询操作需要添加事务吗?绝大部分情况都不需要 是否需要为包含数据库查询操作的方法添加 @Transactional 注解,取决于业务需求和查询操作的特性,不能一概而论。以下是具体分析: 一、不需要添加 @Transactional 的常见场景 如果查询操作满足以下条件,通常不需…

MTK平台Wi-Fi学习--wifi channel 通过国家码进行功率限制和wifi eFEM 基本配置和wifi Tx SEM问题

一. 国家码可以用来限制功率上限,可以针对各国家实现By channel降功率的能力 可以通过country code来设置不同channel的power limit,操作方法如下: 在rlm_txpwr_init.h文件中g_rRlmPowerLimitConfiguration[]下添加需要限制功率的channel, 例如:国家码CN,信道:CH1,po…

MedGemma: 多模态医学文本与图像处理的创新模型

MedGemma: 多模态医学文本与图像处理的创新模型 今天&#xff0c;我有幸参加了在上海举行的Google 2025 I/O大会&#xff0c;这是一场充满创新与突破的技术盛宴。作为全球最具影响力的科技大会之一&#xff0c;Google I/O每年都会吸引来自世界各地的开发者、企业领袖以及科技爱…

深入剖析 C++ STL 中的 std::list 容器

基本介绍在 C 标准库&#xff08;STL&#xff09;中&#xff0c;std::list 是一个基于双向链表实现的序列容器。它与 std::vector、std::deque 等连续存储容器不同&#xff0c;提供了在序列中高效插入和删除元素的能力&#xff0c;尤其是在序列中间位置操作时优势明显。1. std:…

大规模调用淘宝商品详情 API 的分布式请求调度实践

在电商数据分析、比价系统、选品工具等业务场景中&#xff0c;往往需要大规模调用淘宝商品详情 API 以获取商品标题、价格、销量、评价等核心数据。然而&#xff0c;面对淘宝开放平台的严格限流策略、海量商品 ID 的处理需求以及系统高可用要求&#xff0c;传统的单节点调用方式…

在 Windows 系统中解决 Git 推送时出现的 Permission denied (publickey) 错误,请按照以下详细步骤操作:

完整解决方案步骤&#xff1a; 1. 检查并生成 SSH 密钥 # 打开 Git Bash ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" 全程按回车&#xff08;使用默认路径&#xff0c;不设密码&#xff09; 密钥将生成在&#xff1a;C:\Users\<用户名>\.ssh\ 目…

【入门级-算法-2、入门算法:枚举法】

枚举法&#xff08;Brute Force&#xff09;&#xff1a;是一种直接遍历所有可能情况的算法思想&#xff0c;适合解决数据范围较小的问题。它的核心是穷举所有可能性&#xff0c;并检查哪些情况符合要求。 枚举法的基本思想&#xff1a;计算机主要功能&#xff0c;或者说它的优…

Python/Node.js 调用taobao API:构建实时商品详情数据采集服务

在电商数据分析、价格监控、竞品分析等场景中&#xff0c;实时获取商品详情数据至关重要。淘宝提供了丰富的 API 接口&#xff0c;允许开发者合法合规地获取商品信息。本文将介绍如何使用 Python 和 Node.js 两种主流语言调用淘宝 API&#xff0c;构建一个实时商品详情数据采集…