use std::io::{self, Result};
use std::ops::Deref;
use std::ptr::null_mut;
use winapi::um::{
fileapi::{CreateFileW, OPEN_EXISTING},
handleapi::INVALID_HANDLE_VALUE,
processenv::GetStdHandle,
winbase::{STD_INPUT_HANDLE, STD_OUTPUT_HANDLE},
winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE},
};
pub enum HandleType {
OutputHandle,
InputHandle,
CurrentOutputHandle,
CurrentInputHandle,
}
pub struct Handle {
handle: HANDLE,
}
impl Handle {
pub fn new(handle: HandleType) -> Result<Handle> {
let handle = match handle {
HandleType::OutputHandle => Handle::output_handle(),
HandleType::InputHandle => Handle::input_handle(),
HandleType::CurrentOutputHandle => Handle::current_out_handle(),
HandleType::CurrentInputHandle => Handle::current_in_handle(),
}?;
Ok(Handle { handle })
}
pub fn current_out_handle() -> Result<HANDLE> {
let utf16: Vec<u16> = "CONOUT$\0".encode_utf16().collect();
let utf16_ptr: *const u16 = utf16.as_ptr();
let handle = unsafe {
CreateFileW(
utf16_ptr,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
null_mut(),
OPEN_EXISTING,
0,
null_mut(),
)
};
if !Handle::is_valid_handle(&handle) {
println!("invalid!!");
return Err(io::Error::last_os_error());
}
Ok(handle)
}
pub fn current_in_handle() -> Result<HANDLE> {
let utf16: Vec<u16> = "CONIN$\0".encode_utf16().collect();
let utf16_ptr: *const u16 = utf16.as_ptr();
let handle = unsafe {
CreateFileW(
utf16_ptr,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
null_mut(),
OPEN_EXISTING,
0,
null_mut(),
)
};
if !Handle::is_valid_handle(&handle) {
return Err(io::Error::last_os_error());
}
Ok(handle)
}
pub fn output_handle() -> Result<HANDLE> {
unsafe {
let handle = GetStdHandle(STD_OUTPUT_HANDLE);
if !Handle::is_valid_handle(&handle) {
return Err(io::Error::last_os_error());
}
Ok(handle)
}
}
pub fn input_handle() -> Result<HANDLE> {
unsafe {
let handle = GetStdHandle(STD_INPUT_HANDLE);
if !Handle::is_valid_handle(&handle) {
return Err(io::Error::last_os_error());
}
Ok(handle)
}
}
pub fn is_valid_handle(handle: &HANDLE) -> bool {
if *handle == INVALID_HANDLE_VALUE {
false
} else {
true
}
}
}
impl Deref for Handle {
type Target = HANDLE;
fn deref(&self) -> &<Self as Deref>::Target {
&self.handle
}
}
impl From<HANDLE> for Handle {
fn from(handle: HANDLE) -> Self {
Handle { handle }
}
}
#[cfg(test)]
mod tests {
use super::{Handle, HandleType};
#[test]
fn test_get_handle() {
assert!(Handle::new(HandleType::OutputHandle).is_ok());
assert!(Handle::new(HandleType::InputHandle).is_ok());
assert!(Handle::new(HandleType::CurrentOutputHandle).is_ok());
assert!(Handle::new(HandleType::CurrentInputHandle).is_ok());
}
}