diff --git a/crates/libs/bindgen/src/rust/extensions/mod/Win32/Foundation/NTSTATUS.rs b/crates/libs/bindgen/src/rust/extensions/mod/Win32/Foundation/NTSTATUS.rs index 324b4e3d58..a5edfa21da 100644 --- a/crates/libs/bindgen/src/rust/extensions/mod/Win32/Foundation/NTSTATUS.rs +++ b/crates/libs/bindgen/src/rust/extensions/mod/Win32/Foundation/NTSTATUS.rs @@ -9,7 +9,7 @@ impl NTSTATUS { } #[inline] pub const fn to_hresult(self) -> ::windows_core::HRESULT { - ::windows_core::HRESULT(self.0 | 0x1000_0000) + ::windows_core::HRESULT::from_nt(self.0) } #[inline] pub fn ok(self) -> ::windows_core::Result<()> { diff --git a/crates/libs/result/src/bindings.rs b/crates/libs/result/src/bindings.rs index dc24fe0ff3..f4e8fc38f7 100644 --- a/crates/libs/result/src/bindings.rs +++ b/crates/libs/result/src/bindings.rs @@ -12,6 +12,7 @@ ::windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); ::windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE); ::windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const ::core::ffi::c_void) -> BOOL); +::windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE); ::windows_targets::link!("oleaut32.dll" "system" fn GetErrorInfo(dwreserved : u32, pperrinfo : *mut * mut::core::ffi::c_void) -> HRESULT); ::windows_targets::link!("oleaut32.dll" "system" fn SetErrorInfo(dwreserved : u32, perrinfo : * mut::core::ffi::c_void) -> HRESULT); ::windows_targets::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR)); @@ -23,6 +24,7 @@ pub const ERROR_NO_UNICODE_TRANSLATION: WIN32_ERROR = 1113u32; pub const E_INVALIDARG: HRESULT = 0x80070057_u32 as _; pub const E_UNEXPECTED: HRESULT = 0x8000FFFF_u32 as _; pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32; +pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32; pub const FORMAT_MESSAGE_FROM_SYSTEM: FORMAT_MESSAGE_OPTIONS = 4096u32; pub const FORMAT_MESSAGE_IGNORE_INSERTS: FORMAT_MESSAGE_OPTIONS = 512u32; pub type FORMAT_MESSAGE_OPTIONS = u32; @@ -51,6 +53,7 @@ impl GUID { } pub type HANDLE = isize; pub type HEAP_FLAGS = u32; +pub type HMODULE = isize; pub type HRESULT = i32; pub const IID_IErrorInfo: GUID = GUID::from_u128(0x1cf2b120_547d_101b_8e65_08002b2bd119); #[repr(C)] @@ -86,6 +89,9 @@ pub struct IUnknown_Vtbl { pub AddRef: unsafe extern "system" fn(this: *mut ::core::ffi::c_void) -> u32, pub Release: unsafe extern "system" fn(this: *mut ::core::ffi::c_void) -> u32, } +pub type LOAD_LIBRARY_FLAGS = u32; +pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 4096u32; +pub type PCSTR = *const u8; pub type PCWSTR = *const u16; pub type PWSTR = *mut u16; pub type WIN32_ERROR = u32; diff --git a/crates/libs/result/src/hresult.rs b/crates/libs/result/src/hresult.rs index d51bafe031..273c698f27 100644 --- a/crates/libs/result/src/hresult.rs +++ b/crates/libs/result/src/hresult.rs @@ -65,14 +65,26 @@ impl HRESULT { /// The error message describing the error. pub fn message(&self) -> String { let mut message = HeapString::default(); + let mut code = self.0; + let mut module = 0; + + let mut flags = FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS; unsafe { + if self.0 & 0x1000_0000 == 0x1000_0000 { + code ^= 0x1000_0000; + flags |= FORMAT_MESSAGE_FROM_HMODULE; + + module = + LoadLibraryExA(b"ntdll.dll\0".as_ptr(), 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); + } + let size = FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM - | FORMAT_MESSAGE_IGNORE_INSERTS, - std::ptr::null(), - self.0 as u32, + flags, + module as _, + code as _, 0, &mut message.0 as *mut _ as *mut _, 0, @@ -98,6 +110,15 @@ impl HRESULT { (error & 0x0000_FFFF) | (7 << 16) | 0x8000_0000 } as i32) } + + /// Maps an NT error code to an HRESULT value. + pub const fn from_nt(error: i32) -> Self { + Self(if error >= 0 { + error + } else { + error | 0x1000_0000 + }) + } } impl From> for HRESULT { diff --git a/crates/libs/result/tests/bindings.txt b/crates/libs/result/tests/bindings.txt index 845ff1828b..135752da86 100644 --- a/crates/libs/result/tests/bindings.txt +++ b/crates/libs/result/tests/bindings.txt @@ -13,9 +13,12 @@ Windows.Win32.System.Com.IErrorInfo Windows.Win32.System.Com.SetErrorInfo Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_ALLOCATE_BUFFER + Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_FROM_HMODULE Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_FROM_SYSTEM Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_IGNORE_INSERTS Windows.Win32.System.Diagnostics.Debug.FormatMessageW + Windows.Win32.System.LibraryLoader.LOAD_LIBRARY_SEARCH_DEFAULT_DIRS + Windows.Win32.System.LibraryLoader.LoadLibraryExA Windows.Win32.System.Memory.GetProcessHeap Windows.Win32.System.Memory.HeapFree Windows.Win32.System.WinRT.IRestrictedErrorInfo diff --git a/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs b/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs index 33517ea1eb..57701734a3 100644 --- a/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs +++ b/crates/libs/windows/src/Windows/Win32/Foundation/mod.rs @@ -11689,7 +11689,7 @@ impl NTSTATUS { } #[inline] pub const fn to_hresult(self) -> ::windows_core::HRESULT { - ::windows_core::HRESULT(self.0 | 0x1000_0000) + ::windows_core::HRESULT::from_nt(self.0) } #[inline] pub fn ok(self) -> ::windows_core::Result<()> { diff --git a/crates/tests/error/tests/test.rs b/crates/tests/error/tests/test.rs index f9fdca0296..1f42b4b434 100644 --- a/crates/tests/error/tests/test.rs +++ b/crates/tests/error/tests/test.rs @@ -46,6 +46,7 @@ fn ntstatus() -> Result<()> { let hresult: HRESULT = STATUS_NOT_FOUND.into(); assert_eq!(error.code(), hresult); + assert_eq!(error.message(), "The object was not found."); assert_eq!(STATUS_NOT_FOUND.is_ok(), false); assert_eq!(STATUS_NOT_FOUND.is_err(), true); assert_eq!(STATUS_SUCCESS.is_ok(), true); diff --git a/crates/tests/result/tests/hresult.rs b/crates/tests/result/tests/hresult.rs index 74aee0a485..51d8f3cd4d 100644 --- a/crates/tests/result/tests/hresult.rs +++ b/crates/tests/result/tests/hresult.rs @@ -3,9 +3,13 @@ use windows_result::*; const S_OK: HRESULT = HRESULT(0); const S_FALSE: HRESULT = HRESULT(1); const E_INVALIDARG: HRESULT = HRESULT(-2147024809i32); + const ERROR_CANCELLED: u32 = 1223; const E_CANCELLED: HRESULT = HRESULT::from_win32(ERROR_CANCELLED); +const STATUS_NOT_FOUND: i32 = -1073741275; +const E_STATUS_NOT_FOUND: HRESULT = HRESULT::from_nt(STATUS_NOT_FOUND); + #[test] fn is_ok() { assert!(S_OK.is_ok()); @@ -53,6 +57,7 @@ fn message() { "The operation was canceled by the user." ); + assert_eq!(E_STATUS_NOT_FOUND.message(), "The object was not found."); assert_eq!(HRESULT(-1).message(), ""); } @@ -60,6 +65,14 @@ fn message() { fn from_win32() { assert_eq!(E_INVALIDARG, HRESULT::from_win32(E_INVALIDARG.0 as u32)); assert_eq!(E_CANCELLED, HRESULT::from_win32(ERROR_CANCELLED)); + assert_eq!(HRESULT(0), HRESULT::from_win32(0)); +} + +#[test] +fn from_nt() { + assert_eq!(E_STATUS_NOT_FOUND, HRESULT::from_nt(STATUS_NOT_FOUND)); + assert_eq!(S_OK, HRESULT::from_nt(0)); + assert_eq!(HRESULT(1), HRESULT::from_nt(1)); } #[test]