Skip to main content

ferroui_microcom/
hresult.rs

1use std::fmt;
2
3/// `HRESULT` as it crosses the ABI (`typedef unsigned int HRESULT` in `com.h`).
4pub type RawHResult = u32;
5
6pub const S_OK: RawHResult = 0;
7pub const E_NOTIMPL: RawHResult = 0x8000_4001;
8pub const E_NOINTERFACE: RawHResult = 0x8000_4002;
9pub const E_POINTER: RawHResult = 0x8000_4003;
10pub const E_ABORT: RawHResult = 0x8000_4004;
11pub const E_FAIL: RawHResult = 0x8000_4005;
12pub const E_UNEXPECTED: RawHResult = 0x8000_FFFF;
13pub const E_HANDLE: RawHResult = 0x8007_0006;
14pub const E_INVALIDARG: RawHResult = 0x8007_0057;
15pub const COR_E_INVALIDOPERATION: RawHResult = 0x8013_1509;
16pub const COR_E_OBJECTDISPOSED: RawHResult = 0x8013_1622;
17
18/// A failed (or, rarely, non-`S_OK` success) `HRESULT`; the error type of
19/// every generated method whose IDL signature returns `HRESULT`.
20#[derive(Clone, Copy, PartialEq, Eq, Hash)]
21pub struct HResult(pub RawHResult);
22
23impl HResult {
24    pub const NOTIMPL: HResult = HResult(E_NOTIMPL);
25    pub const NOINTERFACE: HResult = HResult(E_NOINTERFACE);
26    pub const POINTER: HResult = HResult(E_POINTER);
27    pub const ABORT: HResult = HResult(E_ABORT);
28    pub const FAIL: HResult = HResult(E_FAIL);
29    pub const UNEXPECTED: HResult = HResult(E_UNEXPECTED);
30    pub const HANDLE: HResult = HResult(E_HANDLE);
31    pub const INVALIDARG: HResult = HResult(E_INVALIDARG);
32    pub const INVALIDOPERATION: HResult = HResult(COR_E_INVALIDOPERATION);
33    pub const OBJECTDISPOSED: HResult = HResult(COR_E_OBJECTDISPOSED);
34
35    /// Maps a raw `HRESULT` to `Ok(())` for `S_OK` and `Err` for anything
36    /// else. This mirrors the native sources and MicroCom's C# proxies, which
37    /// test `hr != S_OK` rather than the sign bit.
38    #[inline]
39    pub fn check(raw: RawHResult) -> Result<(), HResult> {
40        if raw == S_OK {
41            Ok(())
42        } else {
43            Err(HResult(raw))
44        }
45    }
46
47    /// Converts a callback result back to the raw value handed to native code.
48    #[inline]
49    pub fn from_result(r: Result<(), HResult>) -> RawHResult {
50        match r {
51            Ok(()) => S_OK,
52            Err(e) => e.0,
53        }
54    }
55
56    pub fn name(self) -> Option<&'static str> {
57        Some(match self.0 {
58            S_OK => "S_OK",
59            E_NOTIMPL => "E_NOTIMPL",
60            E_NOINTERFACE => "E_NOINTERFACE",
61            E_POINTER => "E_POINTER",
62            E_ABORT => "E_ABORT",
63            E_FAIL => "E_FAIL",
64            E_UNEXPECTED => "E_UNEXPECTED",
65            E_HANDLE => "E_HANDLE",
66            E_INVALIDARG => "E_INVALIDARG",
67            COR_E_INVALIDOPERATION => "COR_E_INVALIDOPERATION",
68            COR_E_OBJECTDISPOSED => "COR_E_OBJECTDISPOSED",
69            _ => return None,
70        })
71    }
72}
73
74impl fmt::Debug for HResult {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match self.name() {
77            Some(n) => write!(f, "HResult({n} 0x{:08X})", self.0),
78            None => write!(f, "HResult(0x{:08X})", self.0),
79        }
80    }
81}
82
83impl fmt::Display for HResult {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        match self.name() {
86            Some(n) => write!(f, "COM call failed: {n} (0x{:08X})", self.0),
87            None => write!(f, "COM call failed: HRESULT 0x{:08X}", self.0),
88        }
89    }
90}
91
92impl std::error::Error for HResult {}