我正在用 Rust 编写的 DLL 替换用 C++ 编写的 DLL。目前,DLL 中的函数调用方式如下:
BOOL calledFunction(wchar_t* pFileName)
我相信在这种情况下wchar_t
是一个 16 位 Unicode 字符,所以我选择在我的 Rust DLL 中公开以下函数:
pub fn calledFunction(pFileName: *const u16)
将该原始指针转换为我实际上可以用来从 Rust DLL 打开文件的最佳方法是什么?
一些示例代码:
use 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);
}
在u16_ptr_to_string
中,您做 3 件事:
- 通过使用
offset
计算非零字符来获取字符串的长度(不安全( - 使用
from_raw_parts
创建切片(不安全( - 将此
&[u16]
转变为具有from_wide
的OsString
最好使用 libc 板条箱中的wchar_t
和wcslen
,并使用另一个板条箱进行转换。重新实现已经在板条箱中维护的东西可能是一个坏主意。
使用 OsString
,它表示操作系统使用的本机字符串格式。在 Windows 中,这些是特定的 16 位字符串(通常是 UTF-16(。
引用文档:
当您需要将字符串传输到操作系统本身或从操作系统本身传输字符串或捕获外部命令的输出时,
OsString
和OsStr
非常有用。OsString
、OsStr
和 Rust 字符串之间的转换与CString
和CStr
之间的转换类似。
首先需要使用不安全代码将指针转换为切片:
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[..]);