如何在Rust中避免extern "stdcall"的名称修饰问题?
解决Rust调用wx.dll中__stdcall函数的链接问题
一、动态加载DLL(最稳妥的 workaround)
如果导入库名称匹配有问题,直接绕开链接器,用Windows API手动加载DLL并获取函数地址,完全避免名称修饰的困扰:
use std::os::windows::ffi::OsStrExt; use std::ptr; use winapi::{ shared::minwindef::HMODULE, um::libloaderapi::{FreeLibrary, GetProcAddress, LoadLibraryW}, }; // 定义函数指针类型,匹配__stdcall调用约定 type WXReleaseFn = unsafe extern "stdcall" fn(ptr: *mut std::ffi::c_void); fn main() { // 加载wx.dll,若不在当前工作目录需传入完整路径 let dll_name: Vec<u16> = "wx.dll".encode_utf16().chain(std::iter::once(0)).collect(); let h_module = unsafe { LoadLibraryW(dll_name.as_ptr()) }; if h_module == ptr::null_mut() { panic!("无法加载wx.dll"); } // 获取函数地址,这里填DLL中实际导出的函数名 let func_addr = unsafe { GetProcAddress(h_module, b"WXRelease\0".as_ptr() as _) }; if func_addr == ptr::null_mut() { unsafe { FreeLibrary(h_module) }; panic!("找不到WXRelease函数"); } // 将地址转换为可调用的函数指针 let wx_release: WXReleaseFn = unsafe { std::mem::transmute(func_addr) }; // 使用函数(ptr从业务逻辑中获取) // let ptr = ...; // unsafe { wx_release(ptr) }; // 若程序不再需要DLL,可释放(长期使用则保留) unsafe { FreeLibrary(h_module) }; }
记得在Cargo.toml中添加依赖:
[dependencies] winapi = { version = "0.3", features = ["libloaderapi", "minwindef"] }
二、修正链接器名称匹配
如果坚持用静态链接(需要wx.dll对应的导入库wx.lib),首先用VS的dumpbin /exports wx.dll命令查看WXRelease的实际导出名称:
- 如果导出名是
_WXRelease@4,直接在Rust代码中指定完整链接名:
use std::ffi::c_void; #[link(name="wx", kind = "dylib")] extern "stdcall" { #[link_name = "_WXRelease@4"] fn WXRelease(ptr_to_release: *mut c_void); }
- 若导出名是无修饰的
WXRelease(比如通过.def文件导出),动态加载依然是更简单的选择,因为Rust的stdcall绑定会自动追加@N后缀,难以直接匹配无修饰名称。
三、关于静态链接DLL的说明
Windows下不存在“静态链接DLL”的说法——DLL本身是动态链接组件。如果要静态链接,你需要该库的静态编译版本(通常是同名的.lib文件,但和DLL的导入库不是同一个)。如果有这样的静态库,修改链接属性为kind = "static"即可:
use std::ffi::c_void; #[link(name="wx", kind = "static")] extern "stdcall" { fn WXRelease(ptr_to_release: *mut c_void); }
但前提是你能获取到对应的静态库文件,否则只能用动态加载或匹配导入库的方式。
内容的提问来源于stack exchange,提问作者NoobOfCpp
相关产品推荐
相关产品推荐

