1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::aliases::WinResult;
use crate::co;
use crate::funcs::{GetFileVersionInfo, VarQueryValue};
use crate::structs::{LANGID, VS_FIXEDFILEINFO};
use crate::various::WString;
pub struct ResourceInfo {
res_buf: Vec<u8>,
}
macro_rules! pub_fn_string_info {
($fun:ident, $name:expr) => {
pub fn $fun(&self, lang: LANGID, code_page: co::CP) -> Option<String> {
self.generic_string_info(lang, code_page, $name)
}
};
}
impl ResourceInfo {
pub fn read_from(exe_file: &str) -> WinResult<ResourceInfo> {
Ok(Self { res_buf: GetFileVersionInfo(exe_file)? })
}
pub fn fixed_file_info(&self) -> Option<&VS_FIXEDFILEINFO> {
unsafe {
VarQueryValue::<VS_FIXEDFILEINFO>(&self.res_buf, "\\")
.ok()
.map(|(pvsf, _)| &*pvsf)
}
}
pub fn langs_and_code_pages(&self) -> Option<&[(LANGID, co::CP)]> {
unsafe {
VarQueryValue::<(LANGID, co::CP)>(&self.res_buf, "\\VarFileInfo\\Translation")
.ok()
.map(|(plangs, sz)| {
std::slice::from_raw_parts(
plangs,
sz as usize / std::mem::size_of::<(LANGID, co::CP)>(),
)
})
}
}
pub_fn_string_info!(comments, "Comments");
pub_fn_string_info!(company_name, "CompanyName");
pub_fn_string_info!(file_description, "FileDescription");
pub_fn_string_info!(file_version, "FileVersion");
pub_fn_string_info!(internal_name, "InternalName");
pub_fn_string_info!(legal_copyright, "LegalCopyright");
pub_fn_string_info!(legal_trademarks, "LegalTrademarks");
pub_fn_string_info!(original_filename, "OriginalFilename");
pub_fn_string_info!(product_name, "ProductName");
pub_fn_string_info!(product_version, "ProductVersion");
pub_fn_string_info!(private_build, "PrivateBuild");
pub_fn_string_info!(special_build, "SpecialBuild");
fn generic_string_info(&self,
lang: LANGID, code_page: co::CP, info: &str) -> Option<String>
{
unsafe {
VarQueryValue::<u16>(
&self.res_buf,
&format!("\\StringFileInfo\\{:04x}{:04x}\\{}",
u16::from(lang), u16::from(code_page), info),
).ok()
.map(|(pstr, len)| {
WString::from_wchars_slice(
std::slice::from_raw_parts(pstr, len as _),
).to_string()
})
}
}
}