Rust 编译DLL
预备命令:
创建库:cargo new --lib native_dll
编译库:cargo build --release
指定目标平台:cargo build --target=i686-pc-windows-msvc [--release]
项目结构如下图所示:
添加依赖项
因为是编译为DLL 文件,这里仅添加最基本的windows-rs
依赖:
[package]
name = "native_dll"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "native_dll" # 项目类型是动态链接库
crate-type=["cdylib"]
[dependencies]
[dependencies.windows] # 添加windows-rs 依赖
version = "0.39.0"
features = [
"Data_Xml_Dom",
"Win32_Foundation",
"Win32_Security",
"Win32_System_Threading",
"Win32_UI_WindowsAndMessaging",
]
lib.rs 源码
生成普通的动态链接库很简单,但是我们在做项目时,有时会需要在动态链接库加载时就执行某些动作,例如弹出对话框、开启子线程等。这时候我们需要为DLL 添加入口函数:
use windows::{
s,
Win32::UI::WindowsAndMessaging::{MessageBoxA, MB_OK},
};
#[no_mangle] // 禁止编译器修改函数名称
pub extern "C" fn add (a: u8, b: u8) -> u8{ // 函数将被编译为C 语言风格
let s = a + b;
s // s 是windows-rs 中的宏命令,用于字符串处理
}
#[allow(unused)]
#[no_mangle]
pub extern "system" fn DllMain(_inst: isize, reason: u32, _: *const u8) -> u32 {
// win32 中应当用extern "stdcall"
if reason == 1 {
unsafe {
MessageBoxA(None, s!("Ansi"), s!("Caption"), MB_OK);
}
}
1
}
需要注意的是,DllMain 方法并不是必须的,很多情况下也不会用到。
在Python 中调用
在Python 中可以通过ctypes.cdll.LoadLibrary
方法调用DLL 文件,但是应该用绝对路径或者是.
、..
开头的相对路径:
from ctypes import*
# give location of dll
mydll = cdll.LoadLibrary("..\\native_dll\\native_dll.dll") # 自动执行DllMain 方法
print(mydll.add(1,2)) # 打印3
注意:
如果Python 的与DLL 的位数不一致,则会报OSError: [WinError 193] %1 不是有效的 Win32 应用程序。
的错误。
所以在通过Python 调用DLL 时要多加注意。
关于进程间通信的Idea
关于Rust 与Python 之间的互调,个人觉得还是通过进程间通信实现比较通用。实在没办法在将Python 打包成独立可调用的动态链接库 😦
📅 2022-08-15 Aachen