/// An error object consists of both an error code and optional detailed error information for debugging. /// /// # Extended error info and the `windows_slim_errors` configuration option /// /// `Error` contains an [`HRESULT`] value that describes the error, as well as an optional /// `IErrorInfo` COM object. The `IErrorInfo` object is a COM object that can provide detailed information /// about an error, such as a text string, a `ProgID` of the originator, etc. If the error object /// was originated in an WinRT component, then additional information such as a stack track may be /// captured. /// /// However, many systems based on COM do not use `IErrorInfo`. For these systems, the optional error /// info within `Error` has no benefits, but has substantial costs because it increases the size of /// the `Error` object, which also increases the size of `Result<T>`. /// /// This error information can be disabled at compile time by setting `RUSTFLAGS=--cfg=windows_slim_errors`. /// This removes the `IErrorInfo` support within the [`Error`] type, which has these benefits: /// /// * It reduces the size of [`Error`] to 4 bytes (the size of [`HRESULT`]). /// /// * It reduces the size of `Result<(), Error>` to 4 bytes, allowing it to be returned in a single /// machine register. /// /// * The `Error` (and `Result<T, Error>`) types no longer have a [`Drop`] impl. This removes the need /// for lifetime checking and running drop code when [`Error`] and [`Result`] go out of scope. This /// significantly reduces code size for codebase that make extensive use of [`Error`]. /// /// Of course, these benefits come with a cost; you lose extended error information for those /// COM objects that support it. /// /// This is controlled by a `--cfg` option rather than a Cargo feature because this compilation /// option sets a policy that applies to an entire graph of crates. Individual crates that take a /// dependency on the `windows-result` crate are not in a good position to decide whether they want /// slim errors or full errors. Cargo features are meant to be additive, but specifying the size /// and contents of `Error` is not a feature so much as a whole-program policy decision. /// /// # References /// /// * [`IErrorInfo`](https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-ierrorinfo) #[derive(Clone)] pubstruct Error { /// The `HRESULT` error code, but represented using [`NonZeroI32`]. [`NonZeroI32`] provides /// a "niche" to the Rust compiler, which is a space-saving optimization. This allows the /// compiler to use more compact representation for enum variants (such as [`Result`]) that /// contain instances of [`Error`].
code: NonZeroI32,
/// Contains details about the error, such as error text.
info: ErrorInfo,
}
/// We remap S_OK to this error because the S_OK representation (zero) is reserved for niche /// optimizations. const S_EMPTY_ERROR: NonZeroI32 = const_nonzero_i32(u32::from_be_bytes(*b"S_OK") as i32);
/// Converts an HRESULT into a NonZeroI32. If the input is S_OK (zero), then this is converted to /// S_EMPTY_ERROR. This is necessary because NonZeroI32, as the name implies, cannot represent the /// value zero. So we remap it to a value no one should be using, during storage. constfn const_nonzero_i32(i: i32) -> NonZeroI32 { iflet Some(nz) = NonZeroI32::new(i) {
nz
} else {
panic!();
}
}
impl Error { /// Creates an error object without any failure information. pubconstfn empty() -> Self { Self {
code: S_EMPTY_ERROR,
info: ErrorInfo::empty(),
}
}
/// Creates a new error object, capturing the stack and other information about the /// point of failure. pubfn new<T: AsRef<str>>(code: HRESULT, message: T) -> Self { #[cfg(windows)]
{ let message: &str = message.as_ref(); if message.is_empty() { Self::from_hresult(code)
} else {
ErrorInfo::originate_error(code, message);
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. pubfn from_hresult(code: HRESULT) -> Self { Self {
code: nonzero_hresult(code),
info: ErrorInfo::empty(),
}
}
/// Creates a new `Error` from the Win32 error code returned by `GetLastError()`. pubfn from_win32() -> Self { #[cfg(windows)]
{ let error = unsafe { GetLastError() }; Self::from_hresult(HRESULT::from_win32(error))
} #[cfg(not(windows))]
{
unimplemented!()
}
}
impl core::hash::Hash for Error { fn hash<H: core::hash::Hasher>(&self, state: &mut H) { self.code.hash(state); // We do not hash the error info.
}
}
// Equality tests only the HRESULT, not the error info (if any). impl PartialEq for Error { fn eq(&self, other: &Self) -> bool { self.code == other.code
}
}
// First attempt to retrieve the restricted error information. iflet Some(info) = ptr.cast(&IID_IRestrictedErrorInfo) { letmut fallback = BasicString::default(); letmut 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() { unsafe {
com_call!(
IErrorInfo_Vtbl,
ptr.GetDescription(&mut message as *mut _ as _)
);
}
}
unsafeimpl Send for ErrorInfo {} unsafeimpl Sync for ErrorInfo {}
}
#[cfg(not(all(windows, not(windows_slim_errors))))] mod error_info { usesuper::*;
// We use this name so that the NatVis <Type> element for ErrorInfo does *not* match this type. // This prevents the NatVis description from failing to load. #[derive(Clone, Default)] pub(crate) struct EmptyErrorInfo;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.