1
Fork 0

Windows: Use WriteFile to write to a UTF-8 console

This commit is contained in:
Chris Denton 2024-12-13 17:31:46 +00:00
parent 9bd5f3387d
commit 1e3ecd5e4d
No known key found for this signature in database
GPG key ID: 713472F2F45627DE
3 changed files with 26 additions and 1 deletions

View file

@ -2425,6 +2425,7 @@ Windows.Win32.System.Console.ENABLE_VIRTUAL_TERMINAL_PROCESSING
Windows.Win32.System.Console.ENABLE_WINDOW_INPUT
Windows.Win32.System.Console.ENABLE_WRAP_AT_EOL_OUTPUT
Windows.Win32.System.Console.GetConsoleMode
Windows.Win32.System.Console.GetConsoleOutputCP
Windows.Win32.System.Console.GetStdHandle
Windows.Win32.System.Console.ReadConsoleW
Windows.Win32.System.Console.STD_ERROR_HANDLE

View file

@ -34,6 +34,7 @@ windows_targets::link!("kernel32.dll" "system" fn FreeEnvironmentStringsW(penv :
windows_targets::link!("kernel32.dll" "system" fn GetActiveProcessorCount(groupnumber : u16) -> u32);
windows_targets::link!("kernel32.dll" "system" fn GetCommandLineW() -> PCWSTR);
windows_targets::link!("kernel32.dll" "system" fn GetConsoleMode(hconsolehandle : HANDLE, lpmode : *mut CONSOLE_MODE) -> BOOL);
windows_targets::link!("kernel32.dll" "system" fn GetConsoleOutputCP() -> u32);
windows_targets::link!("kernel32.dll" "system" fn GetCurrentDirectoryW(nbufferlength : u32, lpbuffer : PWSTR) -> u32);
windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcess() -> HANDLE);
windows_targets::link!("kernel32.dll" "system" fn GetCurrentProcessId() -> u32);
@ -3317,6 +3318,7 @@ pub struct XSAVE_FORMAT {
pub XmmRegisters: [M128A; 8],
pub Reserved4: [u8; 224],
}
#[cfg(target_arch = "arm")]
#[repr(C)]
pub struct WSADATA {

View file

@ -84,21 +84,43 @@ fn is_console(handle: c::HANDLE) -> bool {
unsafe { c::GetConsoleMode(handle, &mut mode) != 0 }
}
/// Returns true if the attached console's code page is currently UTF-8.
#[cfg(not(target_vendor = "win7"))]
fn is_utf8_console() -> bool {
unsafe { c::GetConsoleOutputCP() == c::CP_UTF8 }
}
#[cfg(target_vendor = "win7")]
fn is_utf8_console() -> bool {
// Windows 7 has a fun "feature" where WriteFile on a console handle will return
// the number of UTF-16 code units written and not the number of bytes from the input string.
// So we always claim the console isn't UTF-8 to trigger the WriteConsole fallback code.
false
}
fn write(handle_id: u32, data: &[u8], incomplete_utf8: &mut IncompleteUtf8) -> io::Result<usize> {
if data.is_empty() {
return Ok(0);
}
let handle = get_handle(handle_id)?;
if !is_console(handle) {
if !is_console(handle) || is_utf8_console() {
unsafe {
let handle = Handle::from_raw_handle(handle);
let ret = handle.write(data);
let _ = handle.into_raw_handle(); // Don't close the handle
return ret;
}
} else {
write_console_utf16(data, incomplete_utf8, handle)
}
}
fn write_console_utf16(
data: &[u8],
incomplete_utf8: &mut IncompleteUtf8,
handle: c::HANDLE,
) -> io::Result<usize> {
if incomplete_utf8.len > 0 {
assert!(
incomplete_utf8.len < 4,