version_info/
lib.rs

1/// Returns a file version composed of four numbers if the given file has the version information.
2///
3/// Returns `None` if the file does not have the version information or if the version information is invalid.
4///
5/// ## Example
6///
7/// ```rust
8/// let (a1, a2, a3, a4) = version_info::get_file_version("mylib.dll")?;
9/// println!("mylib.dll's version is {}.{}.{}.{}", a1, a2, a3, a4);
10/// ```
11pub fn get_file_version(file_name: &str) -> Option<(u32, u32, u32, u32)> {
12    use winapi::um::winver::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW};
13
14    #[allow(non_snake_case)]
15    #[repr(C)]
16    struct VS_FIXEDFILEINFO {
17        pub dwSignature: u32,
18        pub dwStrucVersion: u32,
19        pub dwFileVersionMS: u32,
20        pub dwFileVersionLS: u32,
21        pub dwProductVersionMS: u32,
22        pub dwProductVersionLS: u32,
23        pub dwFileFlagsMask: u32,
24        pub dwFileFlags: u32,
25        pub dwFileOS: i32,
26        pub dwFileType: i32,
27        pub dwFileSubtype: i32,
28        pub dwFileDateMS: u32,
29        pub dwFileDateLS: u32,
30    }
31
32    unsafe {
33        let filename = to_wide(file_name);
34
35        let mut handle = 0;
36        let size = GetFileVersionInfoSizeW(filename.as_ptr(), &mut handle);
37
38        if size == 0 {
39            return None;
40        }
41
42        let mut buf = vec![0u8; size as usize];
43        let pbuf = buf.as_mut_ptr() as *mut _;
44
45        if GetFileVersionInfoW(filename.as_ptr(), 0, size, pbuf) == 0 {
46            return None;
47        }
48
49        let mut pinfo: winapi::um::winnt::PVOID = std::ptr::null_mut();
50        let mut length = 0;
51
52        let path: Vec<u16> = to_wide("\\");
53
54        if VerQueryValueW(pbuf, path.as_ptr(), &mut pinfo, &mut length) == 0 {
55            return None;
56        }
57
58        let info = &*(pinfo as *const VS_FIXEDFILEINFO);
59
60        let v1 = info.dwFileVersionMS >> 16 & 0xFFFF;
61        let v2 = info.dwFileVersionMS >> 0 & 0xFFFF;
62        let v3 = info.dwFileVersionLS >> 16 & 0xFFFF;
63        let v4 = info.dwFileVersionLS >> 0 & 0xFFFF;
64        return Some((v1, v2, v3, v4));
65    }
66}
67
68fn to_wide(s: &str) -> Vec<u16> {
69    use std::{ffi::OsStr, iter::once, os::windows::prelude::OsStrExt};
70
71    OsStr::new(s).encode_wide().chain(once(0)).collect()
72}