//! This module contains some logic for working with the console handle. 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}, }; use std::io::{self, Result}; use std::ops::Deref; use std::ptr::null_mut; /// This enum represents the different handles that could be requested. /// /// Some more details could be found [here](https://docs.microsoft.com/en-us/windows/console/getstdhandle#parameters) pub enum HandleType { /// This represents the `STD_OUTPUT_HANDLE` OutputHandle, /// This represents the `STD_INPUT_HANDLE` InputHandle, /// This represents the `CONOUT$` file handle /// When using multiple screen buffers this will always point to the to the current screen output buffer. CurrentOutputHandle, /// This represents the `CONIN$` file handle. /// When using multiple screen buffers this will always point to the to the current screen input buffer. CurrentInputHandle, } /// This abstracts away some WinaApi calls to set and get some console handles. /// // Wraps the underlying WinApi type: [HANDLE] pub struct Handle { handle: HANDLE, } impl Handle { pub fn new(handle: HandleType) -> Result { 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 }) } /// Get the handle of the active screen buffer. /// When using multiple screen buffers this will always point to the to the current screen output buffer. /// /// On success this function returns the `HANDLE` to `STD_OUTPUT_HANDLE`. /// /// This function uses `CONOUT$` to create a file handle to the current output buffer. /// /// Wraps the underlying function call: [CreateFileW] /// link: [https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilew] pub fn current_out_handle() -> Result { let utf16: Vec = "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) } /// Get the handle of the active input screen buffer. /// When using multiple screen buffers this will always point to the to the current screen input buffer. /// /// On success this function returns the `HANDLE` to `STD_INPUT_HANDLE`. /// /// This function uses `CONIN$` to create a file handle to the current input buffer. /// /// Wraps the underlying function call: [CreateFileW] /// link: [https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-createfilew] pub fn current_in_handle() -> Result { let utf16: Vec = "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) } /// Get the handle of the output screen buffer. /// /// On success this function returns the `HANDLE` to `STD_OUTPUT_HANDLE`. /// /// Wraps the underlying function call: [GetStdHandle] whit argument `STD_OUTPUT_HANDLE` /// link: [https://docs.microsoft.com/en-us/windows/console/getstdhandle] pub fn output_handle() -> Result { unsafe { let handle = GetStdHandle(STD_OUTPUT_HANDLE); if !Handle::is_valid_handle(&handle) { return Err(io::Error::last_os_error()); } Ok(handle) } } /// Get the handle of the input screen buffer. /// /// On success this function returns the `HANDLE` to `STD_INPUT_HANDLE`. /// /// Wraps the underlying function call: [GetStdHandle] whit argument `STD_INPUT_HANDLE` /// link: [https://docs.microsoft.com/en-us/windows/console/getstdhandle] pub fn input_handle() -> Result { unsafe { let handle = GetStdHandle(STD_INPUT_HANDLE); if !Handle::is_valid_handle(&handle) { return Err(io::Error::last_os_error()); } Ok(handle) } } /// Checks if the console handle is an invalid handle value. /// /// This is done by checking if the passed `HANDLE` is equal to `INVALID_HANDLE_VALUE` 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) -> &::Target { &self.handle } } impl From for Handle { fn from(handle: HANDLE) -> Self { Handle { handle } } } #[cfg(test)] mod test { use super::{Handle, HandleType}; #[test] fn get_handle() { let out_put_handle = Handle::new(HandleType::OutputHandle).unwrap(); let out_put_handle = Handle::new(HandleType::InputHandle).unwrap(); let curr_out_put_handle = Handle::new(HandleType::CurrentOutputHandle).unwrap(); let curr_out_put_handle = Handle::new(HandleType::CurrentInputHandle).unwrap(); } }