1use std::error::Error;
2use std::ffi::OsString;
3use std::fmt;
4use std::mem::MaybeUninit;
5use std::os::windows::ffi::OsStringExt;
6use std::ptr;
7use std::slice;
8
9use winapi::shared::ntdef::HRESULT;
10use winapi::shared::winerror::FACILITY_WIN32;
11use winapi::um::winbase::{
12 FormatMessageW, LocalFree, FORMAT_MESSAGE_ALLOCATE_BUFFER, FORMAT_MESSAGE_FROM_SYSTEM,
13};
14
15#[derive(Clone, Debug)]
17pub struct Win32Error {
18 pub code: HRESULT,
20}
21
22impl Win32Error {
23 pub fn new(code: HRESULT) -> Win32Error {
32 Win32Error { code }
33 }
34}
35
36impl fmt::Display for Win32Error {
37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 match (self.code >> 16) & 0x1fff {
39 facility if facility == FACILITY_WIN32 => unsafe {
41 let mut buffer = MaybeUninit::<*mut u16>::uninit();
42 let len = FormatMessageW(
43 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
44 ptr::null(),
45 (self.code & 0xffff) as u32,
46 0,
47 buffer.as_mut_ptr() as *mut _,
48 0,
49 ptr::null_mut(),
50 );
51 match len {
52 0 => write!(f, "Unexpected HRESULT: {:X}", self.code),
53 len => {
54 let buffer = buffer.assume_init();
55 let str: OsString =
56 OsStringExt::from_wide(slice::from_raw_parts(buffer, len as usize));
57 LocalFree(buffer as *mut _);
58 write!(
59 f,
60 "Unexpected HRESULT: {:X}: {}",
61 self.code,
62 str.to_string_lossy()
63 )
64 }
65 }
66 },
67 _ => write!(f, "Unexpected HRESULT: {:X}", self.code),
68 }
69 }
70}
71
72impl Error for Win32Error {
73 fn cause(&self) -> Option<&dyn Error> {
74 None
75 }
76}
77
78#[inline]
88pub fn check(result: HRESULT) -> Result<HRESULT, Win32Error> {
89 match result {
90 err if err < 0 => Err(Win32Error::new(err)),
91 success => Ok(success),
92 }
93}