这似乎部分工作,但我无法获得要打印的字符串值
pub fn test() {
let mut buf: Vec<u16> = vec![0; 64];
let mut sz: DWORD = 0;
unsafe {
advapi32::GetUserNameW(buf.as_mut_ptr(), &mut sz);
}
let str1 = OsString::from_wide(&buf).into_string().unwrap();
println!("Here: {} {}", sz, str1);
}
Run Code Online (Sandbox Code Playgroud)
打印:
Here: 10
Run Code Online (Sandbox Code Playgroud)
当我希望它也打印
Here: 10 <username>
Run Code Online (Sandbox Code Playgroud)
作为测试,C版
TCHAR buf[100];
DWORD sz;
GetUserName(buf, &sz);
Run Code Online (Sandbox Code Playgroud)
似乎buf很好.
She*_*ter 10
GetUserName您应该重新阅读API文档GetUserName以回忆参数的工作原理:
lpnSize [in, out]在输入时,此变量
lpBuffer以TCHARs 为单位指定缓冲区的大小 .在输出时,变量接收TCHAR复制到缓冲区的s 数,包括终止空字符.如果lpBuffer太小,则函数失败并GetLastError返回ERROR_INSUFFICIENT_BUFFER.此参数接收所需的缓冲区大小,包括终止空字符.
TL; DR:
这有一个固定大小的堆栈分配数组,为100 TCHAR秒.
此代码已损坏且不安全,因为sz未初始化.这允许API将未定义数量的字符写入仅长100的缓冲区.如果用户名超过100个字符,那么您刚刚在程序中引入了一个安全漏洞.
Rust代码以更好的方式被破坏.sz设置为零,这意味着"您可以写入零数据条目",因此它会写入零条目.因此,Vec缓冲区充满零,结果字符串为空.报告的缓冲区太小而无法接收用户名,因此GetUserNameW设置sz为缓冲区需要分配的字符数.
一个"修复"是设置sz为数组的长度.但是,这可能会使缓冲区分配过多或过少.
如果您对截断的字符串没问题(我不确定TCHAR字符串是否可以任意拆分,我知道UTF-8不能),那么最好使用像C代码那样的固定大小的数组.
如果您想更合适地分配内存来调用这种类型的WinAPI函数,请参阅分配数据以传递给FFI调用的正确方法是什么?.
extern crate advapi32;
extern crate winapi;
use std::ptr;
fn get_user_name() -> String {
unsafe {
let mut size = 0;
let retval = advapi32::GetUserNameW(ptr::null_mut(), &mut size);
assert_eq!(retval, 0, "Should have failed");
let mut username = Vec::with_capacity(size as usize);
let retval = advapi32::GetUserNameW(username.as_mut_ptr(), &mut size);
assert_ne!(retval, 0, "Perform better error handling");
assert!((size as usize) <= username.capacity());
username.set_len(size as usize);
// Beware: This leaves the trailing NUL character in the final string,
// you may want to remove it!
String::from_utf16(&username).unwrap()
}
}
fn main() {
println!("{:?}", get_user_name()); // "IEUser\u{0}"
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
617 次 |
| 最近记录: |