#[cfg(windows)]
pub mod inner {
use std::ffi::OsStr;
use std::iter::once;
use std::os::windows::ffi::OsStrExt;
use std::path::Path;
use std::ptr::addr_of_mut;
use winapi::shared::minwindef::{DWORD, LPVOID, WORD};
use winapi::um::libloaderapi::{FindResourceW, LoadResource, LockResource};
use winapi::um::winnt::{IMAGE_DOS_SIGNATURE, PIMAGE_DOS_HEADER, WCHAR};
use winapi::um::winuser::RT_VERSION;
use winapi::um::winver::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW};
#[allow(dead_code)]
#[repr(C)]
struct FIXEDFILEINFO {
signature: DWORD,
struc_version: DWORD,
file_version_ms: DWORD,
file_version_ls: DWORD,
product_version_ms: DWORD,
product_version_ls: DWORD,
file_flags_mask: DWORD,
file_flags: DWORD,
file_os: DWORD,
file_type: DWORD,
file_subtype: DWORD,
file_date_ms: DWORD,
file_date_ls: DWORD,
}
#[allow(dead_code)]
#[repr(C)]
struct VERSIONINFO {
length: WORD,
value_length: WORD,
value_type: WORD,
key: [WCHAR; 16],
padding1: WORD,
value: FIXEDFILEINFO,
padding2: WORD,
children: WORD,
}
type LPFIXEDFILEINFO = *mut FIXEDFILEINFO;
type LPVERSIONINFO = *mut VERSIONINFO;
pub fn test_extension(path: &Path) -> bool {
if let Some(ext) = path.extension() {
if let Some(ext) = ext.to_str() {
let ext = ext.to_lowercase();
return ext == "exe" || ext == "dll";
}
}
false
}
pub fn query_file(path: &Path) -> Option<String> {
unsafe {
let path = path.to_str()?;
let path = create_string(path);
let mut handle = 0u32;
let size = GetFileVersionInfoSizeW(path.as_ptr(), &mut handle);
let mut data = vec![0; size as usize];
if GetFileVersionInfoW(path.as_ptr(), 0, size, data.as_mut_ptr().cast()) != 0 {
let sub = create_string("\\");
let mut info = 0 as LPVOID;
let mut size = 0;
if VerQueryValueW(data.as_ptr().cast(), sub.as_ptr(), &mut info, &mut size) != 0 {
let info = info as LPFIXEDFILEINFO;
let version = format_version(info);
return Some(version);
}
}
None
}
}
pub fn query_buffer(buffer: &mut [u8]) -> Option<String> {
unsafe {
if buffer.len() >= 2 {
let header = buffer.as_ptr() as PIMAGE_DOS_HEADER;
if (*header).e_magic == IMAGE_DOS_SIGNATURE {
let module = &mut buffer[1..];
let name = create_string("#1");
let resource = FindResourceW(module.as_mut_ptr().cast(), name.as_ptr(), RT_VERSION);
if resource as usize != 0 {
let global = LoadResource(module.as_mut_ptr().cast(), resource);
if global as usize != 0 {
let memory = LockResource(global);
if memory as usize != 0 {
let info = memory as LPVERSIONINFO;
let info = addr_of_mut!((*info).value);
let version = format_version(info);
return Some(version);
}
}
}
}
}
None
}
}
fn format_version(info: LPFIXEDFILEINFO) -> String {
unsafe {
let major = ((*info).file_version_ms >> 16) & 0xffff;
let minor = (*info).file_version_ms & 0xffff;
let debug = ((*info).file_version_ls >> 16) & 0xffff;
let patch = (*info).file_version_ls & 0xffff;
format!("{major}.{minor}.{debug}.{patch}")
}
}
fn create_string(text: &str) -> Vec<u16> {
OsStr::new(text).encode_wide().chain(once(0)).collect()
}
}