diff options
Diffstat (limited to 'src/win_err.rs')
-rw-r--r-- | src/win_err.rs | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/src/win_err.rs b/src/win_err.rs new file mode 100644 index 0000000..f3a675b --- /dev/null +++ b/src/win_err.rs @@ -0,0 +1,103 @@ +#![allow(non_snake_case)] + +use std::ptr; + +mod c { + use std::ffi::c_void; + use std::os::raw::{c_ulong}; + + pub type DWORD = c_ulong; + pub type HANDLE = LPVOID; + pub type LPVOID = *mut c_void; + pub type HINSTANCE = HANDLE; + pub type HMODULE = HINSTANCE; + pub type WCHAR = u16; + pub type LPCWSTR = *const WCHAR; + pub type LPWSTR = *mut WCHAR; + + pub const FACILITY_NT_BIT: DWORD = 0x1000_0000; + pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800; + pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; + pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; + + extern "system" { + pub fn GetLastError() -> DWORD; + pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + pub fn FormatMessageW( + flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const c_void, + ) -> DWORD; + } +} + +pub fn errno() -> i32 { + unsafe { c::GetLastError() as i32 } +} + +/// Gets a detailed string description for the given error number. +pub fn error_string(mut errnum: i32) -> String { + // This value is calculated from the macro + // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) + let langId = 0x0800 as c::DWORD; + + let mut buf = [0 as c::WCHAR; 2048]; + + unsafe { + let mut module = ptr::null_mut(); + let mut flags = 0; + + // NTSTATUS errors may be encoded as HRESULT, which may returned from + // GetLastError. For more information about Windows error codes, see + // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx + if (errnum & c::FACILITY_NT_BIT as i32) != 0 { + // format according to https://support.microsoft.com/en-us/help/259693 + const NTDLL_DLL: &[u16] = &[ + 'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _, + 'L' as _, 0, + ]; + module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); + + if module != ptr::null_mut() { + errnum ^= c::FACILITY_NT_BIT as i32; + flags = c::FORMAT_MESSAGE_FROM_HMODULE; + } + } + + let res = c::FormatMessageW( + flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, + module, + errnum as c::DWORD, + langId, + buf.as_mut_ptr(), + buf.len() as c::DWORD, + ptr::null(), + ) as usize; + if res == 0 { + // Sometimes FormatMessageW can fail e.g., system doesn't like langId, + let fm_err = errno(); + return format!( + "OS Error {} (FormatMessageW() returned error {})", + errnum, fm_err + ); + } + + match String::from_utf16(&buf[..res]) { + Ok(mut msg) => { + // Trim trailing CRLF inserted by FormatMessageW + let len = msg.trim_end().len(); + msg.truncate(len); + msg + } + Err(..) => format!( + "OS Error {} (FormatMessageW() returned \ + invalid UTF-16)", + errnum + ), + } + } +} |