我正在将一个用C++编写的DLL替换为一个用Rust编写的DLL。 目前,DLL中的函数被如下调用:
BOOL calledFunction(wchar_t* pFileName)
我认为在这个上下文中,wchar_t
是一个16位Unicode字符,因此我选择在我的Rust DLL中公开以下函数:
pub fn calledFunction(pFileName: *const u16)
什么是将这个原始指针转换为我可以用来从Rust DLL打开文件的最佳方式?
OsString
。在Windows中,这些是特定的16位字符字符串(通常为UTF-16)。use std::slice;
// manifest a slice out of thin air!
let ptr = 0x1234 as const *u16;
let nb_elements = 10;
unsafe {
let slice = slice::from_raw_parts(ptr, nb_elements);
}
这里假设您已经知道了字符串的大小,也就是说,您的函数应该接受字符数作为参数。
from_wide
方法应该是从本地格式转换的所需方法:
use std::ffi::OsString;
use std::os::windows::prelude::*;
// UTF-16 encoding for "Unicode".
let arr = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065];
let string = OsString::from_wide(&arr[..]);
strlen
,因为 wchar_t
宽度为 16 位,而 strlen
假定没有嵌入的零字节。 - trentstrlen
。"Abc\0"
以小端 UTF-16 编码为 [65, 0, 98, 0, 99, 0, 0, 0]
。strlen
按字节逐个处理,因此它将返回 1。你需要使用一个每次处理两个字节的函数来获取所需的值(3)。 - trentuse std::ffi::OsString;
use std::os::windows::prelude::*;
unsafe fn u16_ptr_to_string(ptr: *const u16) -> OsString {
let len = (0..).take_while(|&i| *ptr.offset(i) != 0).count();
let slice = std::slice::from_raw_parts(ptr, len);
OsString::from_wide(slice)
}
// main example
fn main() {
let buf = vec![97_u16, 98, 99, 100, 101, 102, 0];
let ptr = buf.as_ptr(); // raw pointer
let string = unsafe { u16_ptr_to_string(ptr) };
println!("{:?}", string);
}
String::from_utf16
的事情。 - Boiethios
String::from_utf16
是 Rust 中的一个方法,用于将 UTF-16 编码的数据转换为字符串类型。 - Boiethioslibc::wchar_t
。 - Shepmasterwchar_t
是16位的:https://msdn.microsoft.com/zh-cn/library/windows/desktop/aa367308(v=vs.85).aspx - Boiethioswchar_t
硬编码为u16
是一个糟糕的选择。C 语言的类型定义相当滑稽(例如,“int
的大小是多少”)。使用 Rust 的一个原因就是避免这些类型的问题。使用libc::wchar_t
将防止代码在不同平台上编译,而不是编译但最终出现不匹配的指针,导致未定义的行为。 - Shepmaster