我有点生锈了。所以我试着从windows机箱里提取FileDescription。我未能将descriptionBuffer从VerQueryValueA转换为utf8字符串。我不知道我做错了什么。
fn get_proc_data(pid: u32) -> Option<String> {
let mut path = None;
unsafe {
let h_snap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
if h_snap != INVALID_HANDLE_VALUE {
let mut mod_entry: MODULEENTRY32 = MODULEENTRY32 {
..Default::default()
};
mod_entry.dwSize = size_of_val(&mod_entry) as u32;
if Module32First(h_snap, &mut mod_entry).as_bool() {
let char_vec = mod_entry.szExePath.iter().map(|f| f.0).collect::<Vec<u8>>();
path = match from_utf8(&char_vec) {
Ok(s) => Some(String::from(s.to_string().trim_end_matches(char::from(0)))),
Err(_) => None,
};
}
}
CloseHandle(h_snap);
if path.is_some() {
let mut infoBuffer: [u8; 2048] = [0; 2048];
let pat = path.as_ref().unwrap();
let lpvoid: *mut c_void = infoBuffer.as_mut_ptr() as *mut c_void;
let c_str = CString::new(pat.as_str()).unwrap();
let pstr = PSTR(c_str.as_ptr() as *const u8);
let verInfoLen = GetFileVersionInfoSizeA(pstr, &mut 0);
let ok = GetFileVersionInfoA(pstr, 0, verInfoLen, lpvoid);
let mut descriptionBuffer: [u8; 256] = [0; 256];
let descriptionPtr: *mut *mut c_void =
descriptionBuffer.as_mut_ptr() as *mut *mut c_void;
let mut descriptionLen = 0;
if ok.as_bool()
&& VerQueryValueA(
lpvoid,
"\\StringFileInfo\\040904E4\\FileDescription",
descriptionPtr,
&mut descriptionLen,
)
.as_bool()
{
info!("{:?}", descriptionBuffer);
let res = from_utf8_lossy(&descriptionBuffer);
info!("{:?} {:?}", path, res);
}
}
}
return path;
}示例输出
info!("{:?}", descriptionBuffer);
信息- 180,162,146,165,206,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,00,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
info!("{:?} {:?}", path, res);
信息-一些(“C:\Users\acoop\AppData\Local\Amazon\AmazonMusic.exe”) "�����\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}“
发布于 2022-03-15 09:39:28
查询文件信息属性是一个多步骤的过程:
GetFileVersionInfoSizeW确定版本信息大小Vec提供所需的一切(连续内存、运行时动态大小、低堆栈内存开销)GetFileVersionInfoW将整个版本信息读入分配的缓冲区VerQueryValueW查询感兴趣的信息;在成功时,该函数将指针/大小对返回到上面分配的缓冲区这是在提供的代码中最终出错的最后一步。API需要存储结果的指针变量的地址。然而,代码传递的是descriptionBuffer的第一个元素的地址,这就是API写入的地方(想必,代码是为64位目标编译的,这意味着前8个字节是指针值)。
本质上,代码确实成功地生成了指针/大小对,但未能根据API协议对它们进行解释。查询二进制文件描述的改进版本可能如下所示:
fn get_file_description(path: impl AsRef<Path>) -> Result<String, Box<dyn Error>> {
// Determine version info size
let size = unsafe { GetFileVersionInfoSizeW(path.as_ref().as_os_str(), null_mut()) };
if size == 0 {
return Err(core::Error::from_win32().into());
}
// Allocate buffer
let mut buffer = vec![0u8; size as usize];
// Read version info
unsafe {
GetFileVersionInfoW(
path.as_ref().as_os_str(),
0,
size,
buffer.as_mut_ptr() as *mut std::ffi::c_void,
)
}
.ok()?;
// Declare pointer/size pair for output
let mut ptr = null_mut();
let mut len = 0;
// Query for file description
let success = unsafe {
VerQueryValueW(
buffer.as_ptr() as *const std::ffi::c_void,
"\\StringFileInfo\\040904B0\\FileDescription",
&mut ptr,
&mut len,
)
}
// The API call doesn't set the last error code so we cannot use `.ok()?` here
.as_bool();
if !success {
return Err("Failed to query file description".into());
}
// `len` here is in elements (as opposed to bytes)
let descr = unsafe { slice::from_raw_parts(ptr as *const u16, len as usize) };
// Optionally use `from_utf16_lossy` if you don't need to handle invalid UTF-16
let descr = String::from_utf16(descr)?;
Ok(descr)
}这是更好的,但肯定不是十全十美的任何一个术语。大多数改进都围绕着字符编码的微妙性,当涉及到Windows上的锈蚀时,这是最痛苦的一点。在Rust中没有专门的字符串类型可以在Windows的本机字符编码UTF-16中存储字符串。
值得注意的变化:
Path引用的参数。底层存储是OsStr类型的,它具有一个轻松的UTF-8版本,能够表示任何UTF-16代码单元的序列,格式良好或其他。这一点至关重要,因为Windows不对文件系统对象提供字符编码保证。除了少数保留值外,几乎任何16位值序列都是允许的.你的计划需要为此做好准备。windows机箱提供了从&OsStr到PCWSTR的隐式转换,因此将Path传递到宽字符API并不完全不方便(但它们确实需要转换和分配)。windows机箱提供从&str到PCWSTR的转换,这是在"alloc"特性下设置的。这允许在调用VerQueryValueW时使用字符串文字,并根据需要将所有内容进行转换(同样,还有转换和分配成本)。要将其转换为一个完全工作的示例,生成一个命令行应用程序接受二进制图像的路径名作为其第一个参数,只需添加以下Cargo.toml
[package]
name = "fileinfo"
version = "0.0.0"
edition = "2021"
[dependencies.windows]
version = "0.33.0"
features = [
"alloc",
"Win32_Foundation",
"Win32_Storage_FileSystem",
]并将以下内容添加到src/main.rs文件中:
use std::{env, error::Error, path::Path, ptr::null_mut, slice};
use windows::{
core,
Win32::Storage::FileSystem::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW},
};
fn main() -> Result<(), Box<dyn Error>> {
let input = env::args_os()
.nth(1)
.ok_or("Expected 1 command line argument")?;
let path = Path::new(&input);
let descr = get_file_description(&path)?;
println!("File description: \"{}\"", &descr);
Ok(())
}https://stackoverflow.com/questions/71445517
复制相似问题