ex-cli 1.20.1

Command line tool to find, filter, sort and list files.
Documentation
#[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
        }
    }

    // https://www.codeproject.com/Articles/23166/A-Fast-Way-to-Get-at-the-File-s-Version
    pub fn query_buffer(buffer: &mut [u8]) -> Option<String> {
        unsafe {
            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()
    }
}