gpt4 book ai didi

winapi - 使用可变字符串调用 GetUserName WinAPI 函数不会填充字符串

转载 作者:行者123 更新时间:2023-11-29 08:10:05 31 4
gpt4 key购买 nike

这似乎部分有效,但我无法获取要打印的字符串值

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);
}

打印:

Here: 10

当我希望它也打印时

Here: 10 <username>

作为测试,C版

TCHAR buf[100];
DWORD sz;
GetUserName(buf, &sz);

似乎可以很好地填充 buf

最佳答案

获取用户名

您应该重新阅读 API documentation for GetUserName记忆一下参数是如何工作的:

lpnSize [in, out]

On input, this variable specifies the size of the lpBuffer buffer, in TCHARs. On output, the variable receives the number of TCHARs copied to the buffer, including the terminating null character. If lpBuffer is too small, the function fails and GetLastError returns ERROR_INSUFFICIENT_BUFFER. This parameter receives the required buffer size, including the terminating null character.

长话短说:

  • 在输入时:调用者告诉 API 缓冲区有多少空间。
  • 成功时:API 会告诉调用者使用了多少空格。
  • 失败时:API 告诉调用者需要多少空间。

C 版

这有一个由 100 个 TCHAR 组成的固定大小的堆栈分配数组。

此代码已损坏且不安全,因为sz 未初始化。这允许 API 将未定义数量的字符写入一个只有 100 长的缓冲区。如果用户名超过 100 个字符,则说明您刚刚在程序中引入了安全漏洞。

Rust 版本

Rust 代码以一种更好的方式被破坏。 sz 设置为零,这意味着“您可以写入零个数据条目”,因此它写入零个条目。因此,Vec 缓冲区充满了零,结果字符串为空。据报告缓冲区太小,无法接收用户名,因此 GetUserNameWsz 设置为缓冲区需要分配的字符数。

做什么

一个“修复”是将 sz 设置为数组的长度。但是,这可能会导致缓冲区分配过多或不足。

如果您接受截断的字符串(而且我不确定 TCHAR 字符串是否可以任意拆分,我知道 UTF-8 不能),那么最好使用固定的-size 数组,类似于 C 代码。

如果您想更适本地分配内存来调用此类 WinAPI 函数,请参阅 What is the right way to allocate data to pass to an FFI call? .

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}"
}

关于winapi - 使用可变字符串调用 GetUserName WinAPI 函数不会填充字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44709780/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com