Skip to content

Commit

Permalink
std: win: Don't use console APIs on UWP
Browse files Browse the repository at this point in the history
  • Loading branch information
chouquette committed Jul 25, 2019
1 parent 4c05073 commit 668f0d3
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 26 deletions.
51 changes: 26 additions & 25 deletions src/libstd/sys/windows/c.rs
Expand Up @@ -35,7 +35,6 @@ pub type ULONG = c_ulong;
pub type LPBOOL = *mut BOOL;
pub type LPBYTE = *mut BYTE;
pub type LPCSTR = *const CHAR;
pub type LPCVOID = *const c_void;
pub type LPCWSTR = *const WCHAR;
pub type LPDWORD = *mut DWORD;
pub type LPHANDLE = *mut HANDLE;
Expand Down Expand Up @@ -609,16 +608,6 @@ pub enum EXCEPTION_DISPOSITION {
ExceptionCollidedUnwind
}

#[repr(C)]
#[derive(Copy, Clone)]
pub struct CONSOLE_READCONSOLE_CONTROL {
pub nLength: ULONG,
pub nInitialChars: ULONG,
pub dwCtrlWakeupMask: ULONG,
pub dwControlKeyState: ULONG,
}
pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;

#[repr(C)]
#[derive(Copy)]
pub struct fd_set {
Expand All @@ -642,6 +631,17 @@ pub struct timeval {
// Functions forbidden when targeting UWP
cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] {
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CONSOLE_READCONSOLE_CONTROL {
pub nLength: ULONG,
pub nInitialChars: ULONG,
pub dwCtrlWakeupMask: ULONG,
pub dwControlKeyState: ULONG,
}

pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;

#[repr(C)]
pub struct BY_HANDLE_FILE_INFORMATION {
pub dwFileAttributes: DWORD,
Expand All @@ -657,6 +657,7 @@ if #[cfg(not(target_vendor = "uwp"))] {
}

pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
pub type LPCVOID = *const c_void;

pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;

Expand All @@ -666,6 +667,20 @@ if #[cfg(not(target_vendor = "uwp"))] {
#[link_name = "SystemFunction036"]
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;

pub fn ReadConsoleW(hConsoleInput: HANDLE,
lpBuffer: LPVOID,
nNumberOfCharsToRead: DWORD,
lpNumberOfCharsRead: LPDWORD,
pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;

pub fn WriteConsoleW(hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
nNumberOfCharsToWrite: DWORD,
lpNumberOfCharsWritten: LPDWORD,
lpReserved: LPVOID) -> BOOL;

pub fn GetConsoleMode(hConsoleHandle: HANDLE,
lpMode: LPDWORD) -> BOOL;
// Allowed but unused by UWP
pub fn OpenProcessToken(ProcessHandle: HANDLE,
DesiredAccess: DWORD,
Expand Down Expand Up @@ -752,20 +767,6 @@ extern "system" {
pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);

pub fn ReadConsoleW(hConsoleInput: HANDLE,
lpBuffer: LPVOID,
nNumberOfCharsToRead: DWORD,
lpNumberOfCharsRead: LPDWORD,
pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;

pub fn WriteConsoleW(hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
nNumberOfCharsToWrite: DWORD,
lpNumberOfCharsWritten: LPDWORD,
lpReserved: LPVOID) -> BOOL;

pub fn GetConsoleMode(hConsoleHandle: HANDLE,
lpMode: LPDWORD) -> BOOL;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn SetFileAttributesW(lpFileName: LPCWSTR,
dwFileAttributes: DWORD) -> BOOL;
Expand Down
9 changes: 8 additions & 1 deletion src/libstd/sys/windows/mod.rs
Expand Up @@ -37,7 +37,14 @@ pub mod stack_overflow;
pub mod thread;
pub mod thread_local;
pub mod time;
pub mod stdio;
cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] {
pub mod stdio;
} else {
pub mod stdio_uwp;
pub use self::stdio_uwp as stdio;
}
}

#[cfg(not(test))]
pub fn init() {
Expand Down
85 changes: 85 additions & 0 deletions src/libstd/sys/windows/stdio_uwp.rs
@@ -0,0 +1,85 @@
#![unstable(issue = "0", feature = "windows_stdio")]

use crate::io;
use crate::sys::c;
use crate::sys::handle::Handle;
use crate::mem::ManuallyDrop;

pub struct Stdin {
}
pub struct Stdout;
pub struct Stderr;

const MAX_BUFFER_SIZE: usize = 8192;
pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3;

pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
let handle = unsafe { c::GetStdHandle(handle_id) };
if handle == c::INVALID_HANDLE_VALUE {
Err(io::Error::last_os_error())
} else if handle.is_null() {
Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
} else {
Ok(handle)
}
}

fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> {
let handle = get_handle(handle_id)?;
let handle = Handle::new(handle);
ManuallyDrop::new(handle).write(data)
}

impl Stdin {
pub fn new() -> io::Result<Stdin> {
Ok(Stdin { })
}
}

impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let handle = get_handle(c::STD_INPUT_HANDLE)?;
let handle = Handle::new(handle);
ManuallyDrop::new(handle).read(buf)
}
}

impl Stdout {
pub fn new() -> io::Result<Stdout> {
Ok(Stdout)
}
}

impl io::Write for Stdout {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
write(c::STD_OUTPUT_HANDLE, buf)
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

impl Stderr {
pub fn new() -> io::Result<Stderr> {
Ok(Stderr)
}
}

impl io::Write for Stderr {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
write(c::STD_ERROR_HANDLE, buf)
}

fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

pub fn is_ebadf(err: &io::Error) -> bool {
err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32)
}

pub fn panic_output() -> Option<impl io::Write> {
Stderr::new().ok()
}

0 comments on commit 668f0d3

Please sign in to comment.