#![warn(unused_results)]
use std::convert::TryFrom;
use std::io;
use std::mem::{self, MaybeUninit};
use std::ptr;
use windows_sys::Win32::Foundation::{
FreeLibrary, BOOL, FALSE, FARPROC, HANDLE, HMODULE, NTSTATUS, STATUS_SUCCESS,
};
use windows_sys::Win32::Storage::FileSystem::{
GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW,
};
use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryW};
use windows_sys::Win32::System::SystemInformation::{
GetComputerNameExW, GetNativeSystemInfo, GetSystemDirectoryW, VerSetConditionMask,
VerifyVersionInfoW, COMPUTER_NAME_FORMAT, OSVERSIONINFOEXW, SYSTEM_INFO,
};
use windows_sys::Win32::System::Threading::GetCurrentProcess;
use super::{BYTE, DWORD, UINT, WORD};
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
type WCHAR = u16;
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
type LPVOID = *mut std::ffi::c_void;
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
type LPCVOID = *const std::ffi::c_void;
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
type ULONGLONG = u64;
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
type DWORDLONG = u64;
#[allow(non_camel_case_types)]
type RTL_OSVERSIONINFOEXW = OSVERSIONINFOEXW;
use super::util::{to_c_string, to_c_wstring, CWSTR};
use super::{WinApiFileVersionInfo, WinApiSystemInfo};
use super::PathStr;
use super::WinOSError;
#[allow(non_snake_case)]
#[allow(unused_variables)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(C)]
pub struct VS_FIXEDFILEINFO {
pub dwSignature: DWORD,
pub dwStrucVersion: DWORD,
pub dwFileVersionMS: DWORD,
pub dwFileVersionLS: DWORD,
pub dwProductVersionMS: DWORD,
pub dwProductVersionLS: DWORD,
pub dwFileFlagsMask: DWORD,
pub dwFileFlags: DWORD,
pub dwFileOS: DWORD,
pub dwFileType: DWORD,
pub dwFileSubtype: DWORD,
pub dwFileDateMS: DWORD,
pub dwFileDateLS: DWORD,
}
impl WinApiSystemInfo {
#[allow(non_snake_case)]
pub fn wProcessorArchitecture(&self) -> WORD {
unsafe { self.0.Anonymous.Anonymous.wProcessorArchitecture }
}
}
#[allow(non_snake_case)]
pub fn create_OSVERSIONINFOEXW(
) -> Result<OSVERSIONINFOEXW, crate::lib_impl::BoxedThreadSafeStdError> {
let os_info_size = DWORD::try_from(mem::size_of::<OSVERSIONINFOEXW>())?;
let mut os_info: OSVERSIONINFOEXW = unsafe { mem::zeroed() };
os_info.dwOSVersionInfoSize = os_info_size;
Ok(os_info)
}
#[allow(non_snake_case)]
pub fn WinAPI_FreeLibrary(module: HMODULE ) -> BOOL {
unsafe { FreeLibrary(module) }
}
#[allow(non_snake_case)]
pub fn WinAPI_GetComputerNameExW<'a, T>(
name_type: COMPUTER_NAME_FORMAT,
buffer: T,
size: &mut DWORD,
) -> BOOL
where
T: Into<Option<&'a mut Vec<WCHAR>>>,
{
let maybe_buffer = buffer.into();
let (buffer_ptr, length) = match maybe_buffer {
Some(buf) => (buf.as_mut_ptr(), DWORD::try_from(buf.len()).unwrap_or(0)),
None => (ptr::null_mut(), 0),
};
*size = length;
let result = unsafe { GetComputerNameExW(name_type, buffer_ptr, size) };
assert!((result == FALSE) || (*size <= length)); result
}
#[allow(dead_code)] #[allow(non_snake_case)]
pub fn WinAPI_GetCurrentProcess() -> HANDLE {
unsafe { GetCurrentProcess() }
}
#[allow(non_snake_case)]
pub fn WinAPI_GetFileVersionInfoSizeW<P: AsRef<PathStr>>(
file_path: P, ) -> DWORD {
let file_path_cws: CWSTR = to_c_wstring(file_path.as_ref());
unsafe {
GetFileVersionInfoSizeW(file_path_cws.as_ptr(), ptr::null_mut() )
}
}
#[allow(non_snake_case)]
pub fn WinAPI_GetFileVersionInfoW<P: AsRef<PathStr>>(
file_path: P,
data: &mut Vec<BYTE>,
) -> BOOL {
let file_path_cws: CWSTR = to_c_wstring(file_path.as_ref());
unsafe {
GetFileVersionInfoW(
file_path_cws.as_ptr(),
0,
DWORD::try_from(data.capacity()).unwrap(),
data.as_mut_ptr() as *mut _,
)
}
}
#[allow(non_snake_case)]
pub fn WinAPI_GetNativeSystemInfo() -> SYSTEM_INFO {
let mut sysinfo = MaybeUninit::<SYSTEM_INFO>::uninit();
unsafe {
GetNativeSystemInfo(sysinfo.as_mut_ptr());
sysinfo.assume_init()
}
}
#[allow(non_snake_case)]
pub fn WinAPI_GetProcAddress<P: AsRef<PathStr>>(
module: HMODULE,
symbol_name: P,
) -> FARPROC {
let symbol_name_cs = to_c_string(symbol_name.as_ref());
unsafe { GetProcAddress(module, symbol_name_cs.as_ptr().cast()) }
}
#[allow(non_snake_case)]
pub fn WinAPI_GetSystemDirectoryW<'a, T>(
buffer: T, ) -> UINT
where
T: Into<Option<&'a mut Vec<WCHAR>>>,
{
let (buffer_ptr, length) = match buffer.into() {
Some(buf) => (buf.as_mut_ptr(), UINT::try_from(buf.len()).unwrap_or(0)),
None => (ptr::null_mut(), 0),
};
unsafe { GetSystemDirectoryW(buffer_ptr, length) }
}
#[allow(non_snake_case)]
pub fn WinAPI_LoadLibrary<P: AsRef<PathStr>>(
module_name: P,
) -> HMODULE {
let module_name_cws: CWSTR = to_c_wstring(module_name.as_ref());
unsafe { LoadLibraryW(module_name_cws.as_ptr()) }
}
#[allow(non_snake_case)]
pub fn WinAPI_VerifyVersionInfoW(
version_info: &OSVERSIONINFOEXW,
type_mask: DWORD,
condition_mask: DWORDLONG,
) -> BOOL {
let version_info_ptr: *const OSVERSIONINFOEXW = version_info;
unsafe {
VerifyVersionInfoW(
version_info_ptr as *mut OSVERSIONINFOEXW, type_mask,
condition_mask,
)
}
}
#[allow(non_snake_case)]
pub fn WinAPI_VerQueryValueW<'a, S: AsRef<str>>(
version_info: &'a [BYTE],
query: S,
info_view: &'a mut LPVOID,
info_view_length: &'a mut UINT,
) -> BOOL {
let version_info_ptr = version_info.as_ptr() as LPCVOID;
unsafe {
VerQueryValueW(
version_info_ptr,
to_c_wstring(query.as_ref()).as_ptr(),
info_view,
info_view_length,
)
}
}
#[allow(non_snake_case)]
pub fn WinAPI_VerSetConditionMask(
condition_mask: ULONGLONG,
type_mask: DWORD,
condition: BYTE,
) -> ULONGLONG {
unsafe { VerSetConditionMask(condition_mask, type_mask, condition) }
}
#[allow(non_snake_case)]
pub fn WinOsFileVersionInfoQuery_root(
version_info: &WinApiFileVersionInfo,
) -> Result<&VS_FIXEDFILEINFO, WinOSError> {
let version_info_data = &version_info.data;
let mut data_view = ptr::null_mut(); let mut data_view_size = 0;
let query = "\\"; let fixed_file_info_size = UINT::try_from(mem::size_of::<VS_FIXEDFILEINFO>())?; if WinAPI_VerQueryValueW(
version_info_data,
query,
&mut data_view,
&mut data_view_size,
) == 0
|| (data_view_size != fixed_file_info_size)
{
return Err(Box::new(io::Error::last_os_error()));
}
assert!(version_info_data.len() >= usize::try_from(data_view_size)?);
assert!(data_view_size == fixed_file_info_size);
assert!(!data_view.is_null());
Ok(unsafe { &*(data_view as *const VS_FIXEDFILEINFO) })
}
#[allow(dead_code)] #[allow(non_snake_case)]
pub fn KERNEL32_IsWow64Process(process: HANDLE) -> Result<bool, WinOSError> {
let module_file = "kernel32.dll";
let symbol_name = "IsWow64Process";
let module_path = super::WinOsGetSystemDirectory()?.join(module_file);
let module = WinAPI_LoadLibrary(module_path);
let func = match WinAPI_GetProcAddress(module, symbol_name) {
Some(f) => f,
None => {
return Err(Box::from(format!(
"Unable to find DLL procedure '{}' within '{}'",
symbol_name, module_file
)));
}
};
let func: extern "system" fn(HANDLE, *mut BOOL) -> BOOL = unsafe { mem::transmute(func) };
let mut is_wow64: BOOL = FALSE;
let result: BOOL = func(process, &mut is_wow64);
let _ = WinAPI_FreeLibrary(module);
Ok((result != FALSE) && (is_wow64 != FALSE))
}
#[allow(non_snake_case)]
pub fn NTDLL_RtlGetVersion() -> Result<OSVERSIONINFOEXW, WinOSError> {
let module_file = "ntdll.dll";
let symbol_name = "RtlGetVersion";
let module_path = super::WinOsGetSystemDirectory()?.join(module_file);
let module = WinAPI_LoadLibrary(module_path);
let func = match WinAPI_GetProcAddress(module, symbol_name) {
Some(f) => f,
None => {
return Err(Box::from(format!(
"Unable to find DLL procedure '{}' within '{}'",
symbol_name, module_file
)));
}
};
let func: extern "system" fn(*mut RTL_OSVERSIONINFOEXW) -> NTSTATUS =
unsafe { mem::transmute(func) };
let mut os_version_info = match create_OSVERSIONINFOEXW() {
Ok(value) => value,
Err(_) => return Err(Box::from("Unable to create OSVERSIONINFOEXW".to_string())),
};
let result: NTSTATUS = func(&mut os_version_info);
let _ = WinAPI_FreeLibrary(module);
if result == STATUS_SUCCESS {
Ok(os_version_info)
} else {
Err(Box::from(format!(
"RtlGetVersion() failed (result/status: {})",
result
)))
}
}
#[test]
fn structure_clone() {
let ffi = VS_FIXEDFILEINFO {
dwSignature: 0,
dwStrucVersion: 0,
dwFileVersionMS: 0,
dwFileVersionLS: 0,
dwProductVersionMS: 0,
dwProductVersionLS: 0,
dwFileFlagsMask: 0,
dwFileFlags: 0,
dwFileOS: 0,
dwFileType: 0,
dwFileSubtype: 0,
dwFileDateMS: 0,
dwFileDateLS: 0,
};
println!("{:?}", ffi);
#[allow(clippy::clone_on_copy)] let ffi_clone = ffi.clone();
assert_eq!(ffi_clone, ffi);
}