windows_error/
lib.rs

1#![cfg(windows)]
2//! Windows Error
3//!
4//! This crate provide simple means to operate WinAPI errors.
5//!
6
7use 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), //Insufficient memory
34        _ => "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
42///Returns description of error code.
43///
44///`Unknown Error.` is returned in case of bad error code.
45pub 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)]
66///Represents Windows error code.
67pub struct WindowsError(u32);
68
69impl WindowsError {
70    ///Constructs new error.
71    pub fn new(errno: u32) -> WindowsError {
72        WindowsError(errno)
73    }
74
75    ///Constructs new error from last happened one via ```GetLastError``` call.
76    pub fn from_last_err() -> WindowsError {
77        unsafe { WindowsError(GetLastError()) }
78    }
79
80    #[inline(always)]
81    ///Returns underlying error code.
82    pub fn errno(&self) -> u32 {
83        self.0
84    }
85
86    #[inline(always)]
87    ///Returns description of underlying error code.
88    pub fn errno_desc(&self) -> String {
89        format_error(self.0)
90    }
91}
92
93//Own debug as derive one is a bit lame
94impl 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);