1#![cfg(windows)]
2use std::os::raw::{
8 c_ulong,
9 c_void,
10 c_ushort,
11 c_char
12};
13
14type DWORD = c_ulong;
15
16const FORMAT_MESSAGE_ARGUMENT_ARRAY: DWORD = 0x00002000;
17const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
18const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
19
20extern "system" {
21 fn GetLastError() -> DWORD;
22 fn FormatMessageW(dwFlags: DWORD,
23 lpSource: *const c_void,
24 dwMessageId: DWORD,
25 dwLanguageId: DWORD,
26 lpBuffer: *mut c_ushort,
27 nSize: DWORD,
28 Arguments: *mut c_char) -> DWORD;
29}
30
31fn format_message_error(buff: &[u16]) -> String {
32 match unsafe {GetLastError()} {
33 122 => String::from_utf16_lossy(buff), _ => "Unknown Error.".to_string()
35 }
36}
37
38fn format_message_ok(buff: &[u16]) -> String {
39 String::from_utf16_lossy(&buff[0..buff.len()-2])
40}
41
42pub fn format_error(errno: u32) -> String {
46 const BUF_SIZE: usize = 512;
47 const FMT_FLAGS: DWORD = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY;
48 let mut format_buff: [u16; BUF_SIZE] = [0; BUF_SIZE];
49
50 let num_chars: u32 = unsafe { FormatMessageW(FMT_FLAGS,
51 std::ptr::null(), errno,
52 0, format_buff.as_mut_ptr(),
53 BUF_SIZE as u32, std::ptr::null_mut()) };
54
55 if num_chars == 0 {
56 format_message_error(&format_buff)
57 } else {
58 format_message_ok(&format_buff[0..num_chars as usize])
59 }
60}
61
62use std::error::Error;
63use std::fmt;
64
65#[derive(Clone)]
66pub struct WindowsError(u32);
68
69impl WindowsError {
70 pub fn new(errno: u32) -> WindowsError {
72 WindowsError(errno)
73 }
74
75 pub fn from_last_err() -> WindowsError {
77 unsafe { WindowsError(GetLastError()) }
78 }
79
80 #[inline(always)]
81 pub fn errno(&self) -> u32 {
83 self.0
84 }
85
86 #[inline(always)]
87 pub fn errno_desc(&self) -> String {
89 format_error(self.0)
90 }
91}
92
93impl fmt::Debug for WindowsError {
95 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
96 write!(f, "WinAPI Error({})", self.errno())
97 }
98}
99
100impl fmt::Display for WindowsError {
101 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
102 write!(f, "WinAPI Error({})", self.errno())
103 }
104}
105
106impl Error for WindowsError {
107 fn description(&self) -> &str {
108 "WinAPI Error"
109 }
110}
111
112impl PartialEq for WindowsError {
113 fn eq(&self, right: &WindowsError) -> bool {
114 self.0 == right.0
115 }
116
117 fn ne(&self, right: &WindowsError) -> bool {
118 self.0 != right.0
119 }
120}
121
122macro_rules! impl_traits
123{
124 ($($t:ty), +) => {
125 $(
126 impl From<$t> for WindowsError {
127 fn from(num: $t) -> Self {
128 WindowsError(num as u32)
129 }
130 }
131
132 impl Into<$t> for WindowsError {
133 fn into(self) -> $t {
134 self.0 as $t
135 }
136 }
137
138 impl PartialEq<$t> for WindowsError {
139 fn eq(&self, right: &$t) -> bool {
140 self.0 == *right as u32
141 }
142
143 fn ne(&self, right: &$t) -> bool {
144 self.0 != *right as u32
145 }
146 }
147 )+
148 };
149}
150
151impl_traits!(u32, u16, u8, usize, i32, i16, i8, isize);