如何在 Win32 函数成功后从 PWSTR 检索字符串?
How do I retrieve a string from a PWSTR after a Win32 function succeeds?
我想使用 windows-rs crate 在 std::String
中获取我的用户名。
use bindings::Windows::Win32::{
System::WindowsProgramming::GetUserNameW,
Foundation::PWSTR,
};
fn main() {
let mut pcbbuffer: u32 = 255;
let mut helper: u16 = 0;
let lpbuffer = PWSTR(&mut helper);
println!("lpbuffer: {:?}\npcbbuffer: {:?}", lpbuffer, pcbbuffer);
unsafe {
let success = GetUserNameW(lpbuffer, &mut pcbbuffer);
println!("GetUserNameW succeeded: {:?}\nlpbuffer: {:?}\npcbbuffer: {:?}", success.as_bool(), lpbuffer, pcbbuffer);
}
}
产生输出:
lpbuffer: PWSTR(0xca20f5f76e)
pcbbuffer: 255
GetUserNameW succeeded: true
lpbuffer: PWSTR(0x7200650073)
pcbbuffer: 5
用户名为“user”,即 4 + 1 终止字符 = 5,这很好。我还看到 GetUserNameW
函数成功并且指向字符串的指针发生了变化。
下一步是什么?
发布的代码纯属巧合。它表现出惊人的缓冲区溢出,这几乎不是您希望在 Rust 代码中看到的。具体来说,您正在获取单个 u16
值的地址,并将其传递给 API,告诉它指向的内存大小为 255 个元素。
需要解决的问题:您必须先分配一个足够大的缓冲区来容纳 API 的输出。
将 UTF-16 编码的字符串转换为具有其本机编码的 Rust String
可以使用多种不同的方式完成,例如 String::from_utf16_lossy()
.
下面的代码大致勾勒出了方法:
fn main() {
let mut cb_buffer = 257_u32;
// Create a buffer of the required size
let mut buffer = Vec::<u16>::with_capacity(cb_buffer as usize);
// Construct a `PWSTR` by taking the address to the first element in the buffer
let lp_buffer = PWSTR(buffer.as_mut_ptr());
let result = unsafe { GetUserNameW(lp_buffer, &mut cb_buffer) };
// If the API returned success, and more than 0 characters were written
if result.as_bool() && cb_buffer > 0 {
// Construct a slice over the valid data
let buffer = unsafe { slice::from_raw_parts(lp_buffer.0, cb_buffer as usize - 1) };
// And convert from UTF-16 to Rust's native encoding
let user_name = String::from_utf16_lossy(buffer);
println!("User name: {}", user_name);
}
}
我想使用 windows-rs crate 在 std::String
中获取我的用户名。
use bindings::Windows::Win32::{
System::WindowsProgramming::GetUserNameW,
Foundation::PWSTR,
};
fn main() {
let mut pcbbuffer: u32 = 255;
let mut helper: u16 = 0;
let lpbuffer = PWSTR(&mut helper);
println!("lpbuffer: {:?}\npcbbuffer: {:?}", lpbuffer, pcbbuffer);
unsafe {
let success = GetUserNameW(lpbuffer, &mut pcbbuffer);
println!("GetUserNameW succeeded: {:?}\nlpbuffer: {:?}\npcbbuffer: {:?}", success.as_bool(), lpbuffer, pcbbuffer);
}
}
产生输出:
lpbuffer: PWSTR(0xca20f5f76e)
pcbbuffer: 255
GetUserNameW succeeded: true
lpbuffer: PWSTR(0x7200650073)
pcbbuffer: 5
用户名为“user”,即 4 + 1 终止字符 = 5,这很好。我还看到 GetUserNameW
函数成功并且指向字符串的指针发生了变化。
下一步是什么?
发布的代码纯属巧合。它表现出惊人的缓冲区溢出,这几乎不是您希望在 Rust 代码中看到的。具体来说,您正在获取单个 u16
值的地址,并将其传递给 API,告诉它指向的内存大小为 255 个元素。
需要解决的问题:您必须先分配一个足够大的缓冲区来容纳 API 的输出。
将 UTF-16 编码的字符串转换为具有其本机编码的 Rust String
可以使用多种不同的方式完成,例如 String::from_utf16_lossy()
.
下面的代码大致勾勒出了方法:
fn main() {
let mut cb_buffer = 257_u32;
// Create a buffer of the required size
let mut buffer = Vec::<u16>::with_capacity(cb_buffer as usize);
// Construct a `PWSTR` by taking the address to the first element in the buffer
let lp_buffer = PWSTR(buffer.as_mut_ptr());
let result = unsafe { GetUserNameW(lp_buffer, &mut cb_buffer) };
// If the API returned success, and more than 0 characters were written
if result.as_bool() && cb_buffer > 0 {
// Construct a slice over the valid data
let buffer = unsafe { slice::from_raw_parts(lp_buffer.0, cb_buffer as usize - 1) };
// And convert from UTF-16 to Rust's native encoding
let user_name = String::from_utf16_lossy(buffer);
println!("User name: {}", user_name);
}
}