使用 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.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;構建一個實時商品詳情數據采集…