1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#![cfg(windows)]
//! Windows Error
//!
//! This crate provide simple means to operate WinAPI errors.
//!


extern crate winapi;
extern crate kernel32;

use winapi::{DWORD};
use winapi::winbase::{
    FORMAT_MESSAGE_ARGUMENT_ARRAY,
    FORMAT_MESSAGE_FROM_SYSTEM,
    FORMAT_MESSAGE_IGNORE_INSERTS
};
use kernel32::{
    FormatMessageW,
    GetLastError
};

fn format_message_error(buff: &[u16]) -> String {
    match unsafe {GetLastError()} {
        122 => String::from_utf16_lossy(buff), //Insufficient memory
        _ => "Unknown Error.".to_string()
    }
}

fn format_message_ok(buff: &[u16]) -> String {
    String::from_utf16_lossy(&buff[0..buff.len()-2])
}

///Returns description of error code.
///
///`Unknown Error.` is returned in case of bad error code.
pub fn format_error(errno: u32) -> String {
    const BUF_SIZE: usize = 512;
    const FMT_FLAGS: DWORD = FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY;
    let mut format_buff: [u16; BUF_SIZE] = [0; BUF_SIZE];

    let num_chars: u32 = unsafe { FormatMessageW(FMT_FLAGS,
                                                 std::ptr::null(), errno,
                                                 0, format_buff.as_mut_ptr(),
                                                 BUF_SIZE as u32, std::ptr::null_mut()) };

    if num_chars == 0 {
        format_message_error(&format_buff)
    } else {
        format_message_ok(&format_buff[0..num_chars as usize])
    }
}

use std::error::Error;
use std::fmt;

#[derive(Clone)]
///Represents Windows error code.
pub struct WindowsError(u32);

impl WindowsError {
    ///Constructs new error.
    pub fn new(errno: u32) -> WindowsError {
        WindowsError(errno)
    }

    ///Constructs new error from last happened one via ```GetLastError``` call.
    pub fn from_last_err() -> WindowsError {
        unsafe { WindowsError(GetLastError()) }
    }

    #[inline(always)]
    ///Returns underlying error code.
    pub fn errno(&self) -> u32 {
        self.0
    }

    ///Returns description of underlying error code.
    pub fn errno_desc(&self) -> String {
        format_error(self.0)
    }
}

//Own debug as derive one is a bit lame
impl fmt::Debug for WindowsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "WinAPI Error({})", self.errno())
    }
}

impl fmt::Display for WindowsError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "WinAPI Error({})", self.errno())
    }
}

impl Error for WindowsError {
    fn description(&self) -> &str {
        "WinAPI Error"
    }
}

impl PartialEq for WindowsError {
    fn eq(&self, right: &WindowsError) -> bool {
        self.0 == right.0
    }

    fn ne(&self, right: &WindowsError) -> bool {
        self.0 != right.0
    }
}

macro_rules! impl_traits
{
    ($($t:ty), +) => {
        $(
            impl From<$t> for WindowsError {
                fn from(num: $t) -> Self {
                    WindowsError(num as u32)
                }
            }

            impl Into<$t> for WindowsError {
                fn into(self) -> $t {
                    self.0 as $t
                }
            }

            impl PartialEq<$t> for WindowsError {
                fn eq(&self, right: &$t) -> bool {
                    self.0 == *right as u32
                }

                fn ne(&self, right: &$t) -> bool {
                    self.0 != *right as u32
                }
            }
        )+
    };
}

impl_traits!(u32, u16, u8, usize, i32, i16, i8, isize);