Rollup merge of #103637 - ChrisDenton:stdio-uwp, r=thomcc

Use stdio in UWP apps

Fixes #103233

This has been supported since Windows 10.0.16299. See https://learn.microsoft.com/en-us/uwp/win32-and-com/win32-apis#apis-from-api-ms-win-core-console-l1-1-0dll
This commit is contained in:
Manish Goregaokar 2022-11-01 20:00:38 -04:00 committed by GitHub
commit 65d63caf8d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 28 additions and 120 deletions

View File

@ -56,6 +56,7 @@ pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES; pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
pub type LPSTARTUPINFO = *mut STARTUPINFO; pub type LPSTARTUPINFO = *mut STARTUPINFO;
pub type LPVOID = *mut c_void; pub type LPVOID = *mut c_void;
pub type LPCVOID = *const c_void;
pub type LPWCH = *mut WCHAR; pub type LPWCH = *mut WCHAR;
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
pub type LPWSADATA = *mut WSADATA; pub type LPWSADATA = *mut WSADATA;
@ -773,6 +774,16 @@ pub struct timeval {
pub tv_usec: c_long, pub tv_usec: c_long,
} }
#[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;
// Desktop specific functions & types // Desktop specific functions & types
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] { if #[cfg(not(target_vendor = "uwp"))] {
@ -801,17 +812,6 @@ if #[cfg(not(target_vendor = "uwp"))] {
pub type PVECTORED_EXCEPTION_HANDLER = pub type PVECTORED_EXCEPTION_HANDLER =
extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
#[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)] #[repr(C)]
pub struct BY_HANDLE_FILE_INFORMATION { pub struct BY_HANDLE_FILE_INFORMATION {
pub dwFileAttributes: DWORD, pub dwFileAttributes: DWORD,
@ -827,7 +827,6 @@ if #[cfg(not(target_vendor = "uwp"))] {
} }
pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION; pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
pub type LPCVOID = *const c_void;
pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
@ -855,24 +854,6 @@ if #[cfg(not(target_vendor = "uwp"))] {
#[link(name = "kernel32")] #[link(name = "kernel32")]
extern "system" { extern "system" {
// Functions forbidden when targeting UWP
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 // Allowed but unused by UWP
pub fn GetFileInformationByHandle( pub fn GetFileInformationByHandle(
hFile: HANDLE, hFile: HANDLE,
@ -914,6 +895,22 @@ if #[cfg(target_vendor = "uwp")] {
extern "system" { extern "system" {
pub fn GetCurrentProcessId() -> DWORD; pub fn GetCurrentProcessId() -> DWORD;
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 GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT; pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL; pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL; pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL;

View File

@ -29,6 +29,7 @@ pub mod path;
pub mod pipe; pub mod pipe;
pub mod process; pub mod process;
pub mod rand; pub mod rand;
pub mod stdio;
pub mod thread; pub mod thread;
pub mod thread_local_dtor; pub mod thread_local_dtor;
pub mod thread_local_key; pub mod thread_local_key;
@ -36,12 +37,9 @@ pub mod thread_parker;
pub mod time; pub mod time;
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] { if #[cfg(not(target_vendor = "uwp"))] {
pub mod stdio;
pub mod stack_overflow; pub mod stack_overflow;
} else { } else {
pub mod stdio_uwp;
pub mod stack_overflow_uwp; pub mod stack_overflow_uwp;
pub use self::stdio_uwp as stdio;
pub use self::stack_overflow_uwp as stack_overflow; pub use self::stack_overflow_uwp as stack_overflow;
} }
} }

View File

@ -1,87 +0,0 @@
#![unstable(issue = "none", feature = "windows_stdio")]
use crate::io;
use crate::mem::ManuallyDrop;
use crate::os::windows::io::FromRawHandle;
use crate::sys::c;
use crate::sys::handle::Handle;
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)?;
// SAFETY: The handle returned from `get_handle` must be valid and non-null.
let handle = unsafe { Handle::from_raw_handle(handle) };
ManuallyDrop::new(handle).write(data)
}
impl Stdin {
pub const fn new() -> Stdin {
Stdin {}
}
}
impl io::Read for Stdin {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let handle = get_handle(c::STD_INPUT_HANDLE)?;
// SAFETY: The handle returned from `get_handle` must be valid and non-null.
let handle = unsafe { Handle::from_raw_handle(handle) };
ManuallyDrop::new(handle).read(buf)
}
}
impl Stdout {
pub const fn new() -> Stdout {
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 const fn new() -> Stderr {
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> {
Some(Stderr::new())
}