I'm struggling with calling the wide-char version of GetUserName
. The UTF-8 call works, though there might be a better way to do this:
#[cfg(windows)] extern crate advapi32;
#[cfg(windows)] extern crate winapi;
use std::ffi::CString;
fn get_user_name() -> String {
let mut sz: u32 = 64;
unsafe {
let mut username = CString::from_vec_unchecked(vec![0; sz as usize]);
let ptr = username.into_raw();
advapi32::GetUserNameA(ptr as *mut i8, &mut sz as *mut u32);
CString::from_raw(ptr).to_str().unwrap().to_owned()
}
}
Then I tried the UTF-16 version. This works but looks wrong as I have to create this blank string for OsStr::new()
:
fn get_user_name() -> String {
// for windows
use std::ffi::OsStr;
let mut sz: u32 = 64;
let mut username = OsStr::new(" ")
.encode_wide()
.collect::<Vec<u16>>();
unsafe {
advapi32::GetUserNameW(username.as_mut_ptr() as *mut u16, &mut sz as *mut u32);
}
String::from_utf16(&username[..sz as usize]).unwrap()
}
I also tried using OsString::with_capacity()
, but this crashes:
fn get_user_name() -> String {
// for windows
use std::ffi::OsStr;
let mut sz: u32 = 64;
let mut username = OsString::with_capacity(sz as usize)
.as_os_str()
.encode_wide()
.collect::<Vec<u16>>();
unsafe {
advapi32::GetUserNameW(username.as_mut_ptr() as *mut u16, &mut sz as *mut u32);
}
String::from_utf16(&username[..sz as usize]).unwrap()
}
There are other answers on Stack Overflow where Rust creates a string to pass into a function (e.g. MessageBoxW
), but none where the size is determined by Windows and Rust has to allocate space to be populated later.
What is the correct way of calling a wide char function on Windows where Rust has to preallocate a buffer and then convert back (eventually) to a standard UTF-8 string?