1#[cfg(windows)]
2pub mod inner {
3 use std::ffi::OsStr;
4 use std::iter::once;
5 use std::os::windows::ffi::OsStrExt;
6 use std::path::Path;
7 use std::ptr::addr_of_mut;
8 use winapi::shared::minwindef::{DWORD, LPVOID, WORD};
9 use winapi::um::libloaderapi::{FindResourceW, LoadResource, LockResource};
10 use winapi::um::winnt::{IMAGE_DOS_SIGNATURE, PIMAGE_DOS_HEADER, WCHAR};
11 use winapi::um::winuser::RT_VERSION;
12 use winapi::um::winver::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW};
13
14 #[allow(dead_code)]
15 #[repr(C)]
16 struct FIXEDFILEINFO {
17 signature: DWORD,
18 struc_version: DWORD,
19 file_version_ms: DWORD,
20 file_version_ls: DWORD,
21 product_version_ms: DWORD,
22 product_version_ls: DWORD,
23 file_flags_mask: DWORD,
24 file_flags: DWORD,
25 file_os: DWORD,
26 file_type: DWORD,
27 file_subtype: DWORD,
28 file_date_ms: DWORD,
29 file_date_ls: DWORD,
30 }
31
32 #[allow(dead_code)]
33 #[repr(C)]
34 struct VERSIONINFO {
35 length: WORD,
36 value_length: WORD,
37 value_type: WORD,
38 key: [WCHAR; 16],
39 padding1: WORD,
40 value: FIXEDFILEINFO,
41 padding2: WORD,
42 children: WORD,
43 }
44
45 type LPFIXEDFILEINFO = *mut FIXEDFILEINFO;
46 type LPVERSIONINFO = *mut VERSIONINFO;
47
48 pub fn test_extension(path: &Path) -> bool {
49 if let Some(ext) = path.extension() {
50 if let Some(ext) = ext.to_str() {
51 let ext = ext.to_lowercase();
52 return ext == "exe" || ext == "dll";
53 }
54 }
55 false
56 }
57
58 pub fn query_file(path: &Path) -> Option<String> {
59 unsafe {
60 let path = path.to_str()?;
61 let path = create_string(path);
62 let mut handle = 0u32;
63 let size = GetFileVersionInfoSizeW(path.as_ptr(), &mut handle);
64 let mut data = vec![0; size as usize];
65 if GetFileVersionInfoW(path.as_ptr(), 0, size, data.as_mut_ptr().cast()) != 0 {
66 let sub = create_string("\\");
67 let mut info = 0 as LPVOID;
68 let mut size = 0;
69 if VerQueryValueW(data.as_ptr().cast(), sub.as_ptr(), &mut info, &mut size) != 0 {
70 let info = info as LPFIXEDFILEINFO;
71 let version = format_version(info);
72 return Some(version);
73 }
74 }
75 None
76 }
77 }
78
79 pub fn query_buffer(buffer: &mut [u8]) -> Option<String> {
81 unsafe {
82 let header = buffer.as_ptr() as PIMAGE_DOS_HEADER;
83 if (*header).e_magic == IMAGE_DOS_SIGNATURE {
84 let module = &mut buffer[1..];
85 let name = create_string("#1");
86 let resource = FindResourceW(module.as_mut_ptr().cast(), name.as_ptr(), RT_VERSION);
87 if resource as usize != 0 {
88 let global = LoadResource(module.as_mut_ptr().cast(), resource);
89 if global as usize != 0 {
90 let memory = LockResource(global);
91 if memory as usize != 0 {
92 let info = memory as LPVERSIONINFO;
93 let info = addr_of_mut!((*info).value);
94 let version = format_version(info);
95 return Some(version);
96 }
97 }
98 }
99 }
100 None
101 }
102 }
103
104 fn format_version(info: LPFIXEDFILEINFO) -> String {
105 unsafe {
106 let major = ((*info).file_version_ms >> 16) & 0xffff;
107 let minor = (*info).file_version_ms & 0xffff;
108 let debug = ((*info).file_version_ls >> 16) & 0xffff;
109 let patch = (*info).file_version_ls & 0xffff;
110 format!("{major}.{minor}.{debug}.{patch}")
111 }
112 }
113
114 fn create_string(text: &str) -> Vec<u16> {
115 OsStr::new(text).encode_wide().chain(once(0)).collect()
116 }
117}