将原始指针转换为16位Unicode字符到Rust中的文件路径

wat*_*tts 3 windows unicode rust

我用一个用Rust编写的DLL替换用C++编写的DLL.目前DLL中的函数调用如下:

BOOL calledFunction(wchar_t* pFileName)
Run Code Online (Sandbox Code Playgroud)

我相信在这个上下文中wchar_t是一个16位的Unicode字符,所以我选择在我的Rust DLL中公开以下函数:

pub fn calledFunction(pFileName: *const u16)
Run Code Online (Sandbox Code Playgroud)

将原始指针转换为实际可用于从Rust DLL打开文件的内容的最佳方法是什么?

Sir*_*ius 6

您需要使用OsString,它表示操作系统使用的本机字符串格式.在Windows中,这些是特定的16位字符串(通常是UTF-16).

引用文档:

OsStringOsStr当您需要在操作系统本身之间传输字符串或捕获外部命令的输出时,它们非常有用.之间的转换OsString,OsStr防锈字符串和类似的工作,那些CStringCStr.

首先需要使用不安全的代码将指针转换为切片:

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);
}
Run Code Online (Sandbox Code Playgroud)

这假设您知道字符串的大小,这意味着您的函数也应该将字符数作为参数.

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[..]);
Run Code Online (Sandbox Code Playgroud)

  • 假设字符串以空值终止,您仍然不能使用`strlen`.`"Abc\0"`被编码为小端UTF-16,为"[65,0,98,0,09,0,0,0]".`strlen`逐字节,因此它将返回1.您需要使用一次两个字节的函数来获得所需的值(3). (2认同)

Fre*_*ios 6

下面是一些示例代码:

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);
}
Run Code Online (Sandbox Code Playgroud)

在 中u16_ptr_to_string,您要做 3 件事:

  • 通过使用offset(不安全)计算非零字符来获取字符串的长度
  • 使用from_raw_parts(不安全)创建切片
  • 将其&[u16]转换为OsStringwithfrom_wide

这是更好地使用wchar_twcslen从箱子的libc,并使用另一个箱子转换。重新实现已经在 crate 中维护的东西可能是一个坏主意。