在winapi调用中使用字符串的更方便的方法

Che*_*lla 7 string winapi rust

我正在寻找更方便的方法来处理std::StringRust中的winapi调用.

使用生锈v 0.12.0-nigtly与winapi 0.1.22和user32-sys 0.1.1

现在我正在使用这样的东西:

use winapi;
use user32;

pub fn get_window_title(handle: i32) -> String {
    let mut v: Vec<u16> = Vec::new();
    v.reserve(255);
    let mut p = v.as_mut_ptr();
    let len = v.len();
    let cap = v.capacity();
    let mut read_len = 0;
    unsafe {
        mem::forget(v);
        read_len = unsafe { user32::GetWindowTextW(handle as winapi::HWND, p, 255) };
        if read_len > 0 {
            return String::from_utf16_lossy(Vec::from_raw_parts(p, read_len as usize, cap).as_slice());
        } else {
            return "".to_string();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为,这种基于矢量的内存分配相当奇怪.所以我正在寻找更简单的投射LPCWSTR方式std::String

oli*_*obk 4

在您的情况下,您始终需要最多 255 个字节,因此您可以使用数组而不是向量。这将整个样板简化为一次mem::uninitialized()调用、一次as_mut_ptr()调用和一次切片操作。

unsafe {
    let mut v: [u16; 255] = mem::uninitialized();
    let read_len = user32::GetWindowTextW(
        handle as winapi::HWND,
        v.as_mut_ptr(),
        255,
    );
    String::from_utf16_lossy(&v[0..read_len])
}
Run Code Online (Sandbox Code Playgroud)

如果您想使用 a Vec,有一种比销毁 vec 并重新创建它更简单的方法。您可以直接写入 的Vec内容并让 Rust 处理其他所有事情。

let mut v: Vec<u16> = Vec::with_capacity(255);
unsafe {
    let read_len = user32::GetWindowTextW(
        handle as winapi::HWND,
        v.as_mut_ptr(),
        v.capacity(),
    );
    v.set_len(read_len); // this is undefined behavior if read_len > v.capacity()
    String::from_utf16_lossy(&v)
}
Run Code Online (Sandbox Code Playgroud)

顺便说一句,Rust 中的惯用做法是不要return在函数的最后一个语句上使用,而是简单地让表达式不带分号。在您的原始代码中,最终的 if 表达式可以写为

if read_len > 0 {
    String::from_utf16_lossy(Vec::from_raw_parts(p, read_len as usize, cap).as_slice())
} else {
    "".to_string()
}
Run Code Online (Sandbox Code Playgroud)

但我从样本中删除了整个条件,因为没有必要以0不同的方式处理读取的字符和n字符。