在 winapi 调用中使用字符串的更方便的方法
More convenient way to work with strings in winapi calls
我正在寻找更方便的方法来在 Rust 的 winapi 调用中使用 std::String
。
在 winapi 0.1.22 和 user32-sys 0.1.1 上使用 rust v 0.12.0-nigtly
现在我正在使用这样的东西:
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();
}
}
}
我认为,这种基于向量的内存分配相当奇怪。所以我正在寻找更简单的方法将 LPCWSTR
转换为 std::String
在您的情况下,您总是需要最多 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])
}
如果您想使用 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)
}
作为旁注,在 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()
}
但我从样本中删除了整个条件,因为没有必要以不同于 n
字符的方式处理 0
读取字符。
我正在寻找更方便的方法来在 Rust 的 winapi 调用中使用 std::String
。
在 winapi 0.1.22 和 user32-sys 0.1.1 上使用 rust v 0.12.0-nigtly
现在我正在使用这样的东西:
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();
}
}
}
我认为,这种基于向量的内存分配相当奇怪。所以我正在寻找更简单的方法将 LPCWSTR
转换为 std::String
在您的情况下,您总是需要最多 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])
}
如果您想使用 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)
}
作为旁注,在 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()
}
但我从样本中删除了整个条件,因为没有必要以不同于 n
字符的方式处理 0
读取字符。