From 5bf79ff27f88ce222424167ed9beeca3db9f3135 Mon Sep 17 00:00:00 2001 From: sivadeilra Date: Tue, 11 Jun 2024 15:06:06 -0700 Subject: [PATCH] Allow `windows-result` to work on non-Windows platforms (#3082) --- crates/libs/result/src/error.rs | 134 ++++++++++++++++++---------- crates/libs/result/src/hresult.rs | 77 +++++++++------- crates/libs/result/src/lib.rs | 5 ++ crates/tests/linux/tests/hresult.rs | 34 +++++++ 4 files changed, 168 insertions(+), 82 deletions(-) create mode 100644 crates/tests/linux/tests/hresult.rs diff --git a/crates/libs/result/src/error.rs b/crates/libs/result/src/error.rs index ed28d975d2d..88a2c697a5a 100644 --- a/crates/libs/result/src/error.rs +++ b/crates/libs/result/src/error.rs @@ -5,6 +5,7 @@ use core::ffi::c_void; #[derive(Clone, PartialEq, Eq)] pub struct Error { code: HRESULT, + #[cfg(windows)] info: Option, } @@ -13,6 +14,7 @@ impl Error { pub const fn empty() -> Self { Self { code: HRESULT(0), + #[cfg(windows)] info: None, } } @@ -20,28 +22,46 @@ impl Error { /// Creates a new error object, capturing the stack and other information about the /// point of failure. pub fn new>(code: HRESULT, message: T) -> Self { - let message: Vec<_> = message.as_ref().encode_utf16().collect(); - - if message.is_empty() { - Self::from_hresult(code) - } else { - unsafe { - RoOriginateErrorW(code.0, message.len() as u32, message.as_ptr()); + #[cfg(windows)] + { + let message: Vec<_> = message.as_ref().encode_utf16().collect(); + if message.is_empty() { + Self::from_hresult(code) + } else { + unsafe { + RoOriginateErrorW(code.0, message.len() as u32, message.as_ptr()); + } + code.into() } - code.into() + } + #[cfg(not(windows))] + { + let _ = message; + Self::from_hresult(code) } } /// Creates a new error object with an error code, but without additional error information. pub fn from_hresult(code: HRESULT) -> Self { - Self { code, info: None } + Self { + code, + #[cfg(windows)] + info: None, + } } /// Creates a new `Error` from the Win32 error code returned by `GetLastError()`. pub fn from_win32() -> Self { - Self { - code: HRESULT::from_win32(unsafe { GetLastError() }), - info: None, + #[cfg(windows)] + { + Self { + code: HRESULT::from_win32(unsafe { GetLastError() }), + info: None, + } + } + #[cfg(not(windows))] + { + unimplemented!() } } @@ -52,42 +72,45 @@ impl Error { /// The error message describing the error. pub fn message(&self) -> String { - if let Some(info) = &self.info { - let mut message = BasicString::default(); - - // First attempt to retrieve the restricted error information. - if let Some(info) = info.cast(&IID_IRestrictedErrorInfo) { - let mut fallback = BasicString::default(); - let mut code = 0; - - unsafe { - com_call!( - IRestrictedErrorInfo_Vtbl, - info.GetErrorDetails( - &mut fallback as *mut _ as _, - &mut code, - &mut message as *mut _ as _, - &mut BasicString::default() as *mut _ as _ - ) - ); + #[cfg(windows)] + { + if let Some(info) = &self.info { + let mut message = BasicString::default(); + + // First attempt to retrieve the restricted error information. + if let Some(info) = info.cast(&IID_IRestrictedErrorInfo) { + let mut fallback = BasicString::default(); + let mut code = 0; + + unsafe { + com_call!( + IRestrictedErrorInfo_Vtbl, + info.GetErrorDetails( + &mut fallback as *mut _ as _, + &mut code, + &mut message as *mut _ as _, + &mut BasicString::default() as *mut _ as _ + ) + ); + } + + if message.is_empty() { + message = fallback + }; } + // Next attempt to retrieve the regular error information. if message.is_empty() { - message = fallback - }; - } - - // Next attempt to retrieve the regular error information. - if message.is_empty() { - unsafe { - com_call!( - IErrorInfo_Vtbl, - info.GetDescription(&mut message as *mut _ as _) - ); + unsafe { + com_call!( + IErrorInfo_Vtbl, + info.GetDescription(&mut message as *mut _ as _) + ); + } } - } - return String::from_utf16_lossy(wide_trim_end(message.as_wide())); + return String::from_utf16_lossy(wide_trim_end(message.as_wide())); + } } // Otherwise fallback to a generic error code description. @@ -95,6 +118,7 @@ impl Error { } /// The error object describing the error. + #[cfg(windows)] pub fn as_ptr(&self) -> *mut c_void { self.info .as_ref() @@ -109,9 +133,12 @@ unsafe impl Sync for Error {} impl From for HRESULT { fn from(error: Error) -> Self { - if let Some(info) = error.info { - unsafe { - SetErrorInfo(0, info.as_raw()); + #[cfg(windows)] + { + if let Some(info) = error.info { + unsafe { + SetErrorInfo(0, info.as_raw()); + } } } error.code @@ -120,9 +147,15 @@ impl From for HRESULT { impl From for Error { fn from(code: HRESULT) -> Self { - let mut info = None; - unsafe { GetErrorInfo(0, &mut info as *mut _ as _) }; - Self { code, info } + Self { + code, + #[cfg(windows)] + info: { + let mut info = None; + unsafe { GetErrorInfo(0, &mut info as *mut _ as _) }; + info + }, + } } } @@ -147,6 +180,7 @@ impl From for Error { fn from(_: alloc::string::FromUtf16Error) -> Self { Self { code: HRESULT::from_win32(ERROR_NO_UNICODE_TRANSLATION), + #[cfg(windows)] info: None, } } @@ -156,6 +190,7 @@ impl From for Error { fn from(_: alloc::string::FromUtf8Error) -> Self { Self { code: HRESULT::from_win32(ERROR_NO_UNICODE_TRANSLATION), + #[cfg(windows)] info: None, } } @@ -165,6 +200,7 @@ impl From for Error { fn from(_: core::num::TryFromIntError) -> Self { Self { code: HRESULT::from_win32(ERROR_INVALID_DATA), + #[cfg(windows)] info: None, } } diff --git a/crates/libs/result/src/hresult.rs b/crates/libs/result/src/hresult.rs index fe69ee29f3b..f881bc6cf2a 100644 --- a/crates/libs/result/src/hresult.rs +++ b/crates/libs/result/src/hresult.rs @@ -64,41 +64,52 @@ 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); + #[cfg(windows)] + { + 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( + flags, + module as _, + code as _, + 0, + &mut message.0 as *mut _ as *mut _, + 0, + core::ptr::null(), + ); + + if !message.0.is_null() && size > 0 { + String::from_utf16_lossy(wide_trim_end(core::slice::from_raw_parts( + message.0, + size as usize, + ))) + } else { + String::default() + } } + } - let size = FormatMessageW( - flags, - module as _, - code as _, - 0, - &mut message.0 as *mut _ as *mut _, - 0, - core::ptr::null(), - ); - - if !message.0.is_null() && size > 0 { - String::from_utf16_lossy(wide_trim_end(core::slice::from_raw_parts( - message.0, - size as usize, - ))) - } else { - String::default() - } + #[cfg(not(windows))] + { + return format!("0x{:08x}", self.0 as u32); } } diff --git a/crates/libs/result/src/lib.rs b/crates/libs/result/src/lib.rs index 7e6601a2f3a..df5cd6d97fd 100644 --- a/crates/libs/result/src/lib.rs +++ b/crates/libs/result/src/lib.rs @@ -7,6 +7,7 @@ Learn more about Rust for Windows here: