Write extended ASCII to Windows console

I have a byte array that includes the extended ASCII character with byte value 248 (appears as °). All other bytes are printable ASCII. When I attempt to write this array to the console, I get a panic: 'failed printing to stdout: Windows stdio in console mode does not support writing non-UTF-8 byte sequences'. However, I can pipe the output to a file, and then display the contents of that file using type without issue.

For example, if I have a file whose contents are exactly the bytes (in decimal) [56, 53, 46, 51, 50, 248, 70], I can execute type myfile and 85.32°F is displayed. This would seem to indicate that the Windows console supports extended ASCII, which is non-UTF-8.

The panic message refers to "Windows stdio". What is it that type does that Windows stdio doesn't do?
Aside from converting my string to UTF-8, is there a way to display my string in the console, in Rust?

Thank you

//mystr is a Vec<u8>
stdout().write_all(&mystr).unwrap()

There's no such single thing as "extended ASCII". There are literally hundreds of possible character sets, and Windows supports a huge set of them with it's codepage support, which is used by all the system APIs with the A suffix, like WriteConsoleA. But that means you can get different output on different systems, or not be able to output a certain character. So Rust instead uses WriteConsoleW which takes UTF-16 so you can write any character identically on any platform, but it needs to therefore convert the text you are writing from whatever encoding it is in. Since it wants to work the same across different platforms, they chose to enforce that that single encoding is UTF-8.

What type does depends on what the current code page is set to - try it again after running chcp with some other code page.

You can do this, but be aware that's writing to the attached console, not any redirected output:

use std::io::Write;

fn main() -> std::io::Result<()> {
    let mut console = std::fs::File::create("CONOUT$")?;
    console
        .write_all(&[56, 00, 53, 46, 51, 50, 248, 70, 0xd, 0xa])
        .unwrap();
    console.flush().unwrap();
    Ok(())
}

I'm not aware of any simple options for getting the raw file handle for stdout without falling back to unsafe native APIs using e.g. the windows crate, which is way more work than just converting to UTF-8 (which, really, you should absolutely be using)

4 Likes