Do you play the odds?

If you are a developer, the odds are that all things being equal you are not nearly as smart now before you read this blog as you will be once you have read it....

Back in the middle of February I mentioned in The real problem(s) with all of these console "fallback" discussions that, of the many people talking about the console these days, most of them are wrong.

Solving problems that don't exist, incorrectly impacting problems that do exist, and just generally making the situation worse overall....

But I didn't really finish the work there; the blog was merely armchair criticisms of bugs, design flaws, mistaken assumptions spoken as fact, documentation problems, etc.

100% accurate, but not described in a way that can help you move to the next step (getting it done right, in either native or managed code).

Today's blog is going to change all that. :-)

All of this and much more will be covered in the upcoming training on the World-Ready Console, if you are on the Windows team....

After showing how the console could be 100% Unicode, which I did in March of 2008 after STL showed me, as I talked about in Conventional wisdom is retarded, aka What the @#%&* is _O_U16TEXT?, there is one piece of the puzzle still missing.

I mean it is all well and good to show it in just a few lines of native code using the CRT.

But the truth is that this problem exists in managed code too (some of which actually uses the CRT, and Win32), and also in native code that has no heavy CRT dependency or doesn't take one on.

Behind the scenes, the CRT is doing all the right work in those circumstances to e.g. call WriteConsoleW or WriteFile (depending on whether the console's output streams are redirected or not).

So anyone trying to do the same thing in native Win32 would have to do that same work.

And although the CRT and .NET are both being developed in the same division of Microsoft, and .Net has its own internal CRT dependencies (it depends on .Net's version even when it ships with the OS), the managed Console class is not using this CRT functionality. And they are not doing it the hard way themselves, either.

Now calling the CRT from VB.Net or C# (or other non-C++ languages) has some interesting challenges that I am not going to get into here (if someone wants to go that way they can). I thought instead I'd just give you the code really quick so you can do it in whatever language, without the version or CRT dependencies.

Now this is C# code, this WriteLineRight sample function.

But it is pretty much Win32 code written in C#. So Win32 developers should have no trouble grokking it or what it is doing:

using System;
using System.Runtime.InteropServices;

public class Test {
    public static void Main() {
        string st = "\u0627\u0628\u0629 \u043a\u043e\u0448\u043a\u0430 \u65e5\u672c\u56fd\n\n";

    internal static bool IsConsoleFontTrueType(IntPtr std) {
        cfie.cbSize = (uint)Marshal.SizeOf(cfie);
        if(GetCurrentConsoleFontEx(std, false, ref cfie)) {
            return(((cfie.FontFamily & TMPF_TRUETYPE) == TMPF_TRUETYPE));
        return false;

    public static void WriteLineRight(string st) {
        IntPtr stdout = GetStdHandle(STD_OUTPUT_HANDLE);
        if(stdout != INVALID_HANDLE_VALUE) {
            uint filetype = GetFileType(stdout);
            if(! ((filetype == FILE_TYPE_UNKNOWN) && (Marshal.GetLastWin32Error() != ERROR_SUCCESS))) {
                bool fConsole;
                uint mode;
                uint written;
                filetype &= ~(FILE_TYPE_REMOTE);
                if (filetype == FILE_TYPE_CHAR) {
                    bool retval = GetConsoleMode(stdout, out mode);
                    if ((retval == false) && (Marshal.GetLastWin32Error() == ERROR_INVALID_HANDLE)) {
                        fConsole = false;
                    } else {
                        fConsole = true;
                } else {
                    fConsole = false;

                if (fConsole) {
                    if (IsConsoleFontTrueType(stdout)) {
                        WriteConsoleW(stdout, st, st.Length, out written, IntPtr.Zero);
                    } else {
                        // Not a TrueType font, so the output may have trouble here
                        // Need to check the codepage settings
                        // TODO: Add the old style GetConsoleFallbackUICulture code here!!!
                } else {
                    // Write out a Unicode BOM to ensure proper processing by text readers
                    WriteFile(stdout, BOM, 2, out written, IntPtr.Zero);
                    WriteFile(stdout, st, st.Length * 2, out written, IntPtr.Zero);

    [DllImport("kernel32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
    internal static extern bool WriteConsoleW(IntPtr hConsoleOutput, 
string lpBuffer,
int nNumberOfCharsToWrite, out uint lpNumberOfCharsWritten,
IntPtr lpReserved); [DllImport("kernel32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)] internal static extern bool WriteFile(IntPtr hFile,
string lpBuffer,
int nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
IntPtr lpOverlapped); [DllImport("kernel32.dll", ExactSpelling=true, SetLastError=true)] internal static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); [DllImport("kernel32.dll", ExactSpelling=true)] internal static extern bool GetCurrentConsoleFontEx(IntPtr hConsoleOutput,
bool bMaximumWindow,
ref CONSOLE_FONT_INFO_EX lpConsoleCurrentFontEx); [DllImport("Kernel32.DLL", ExactSpelling=true, SetLastError=true)] internal static extern uint GetFileType(IntPtr hFile); [DllImport("Kernel32.DLL", ExactSpelling=true)] internal static extern IntPtr GetStdHandle(int nStdHandle); internal struct COORD { internal short X; internal short Y; internal COORD(short x, short y) { X = x; Y = y; } } [StructLayout(LayoutKind.Sequential)] internal unsafe struct CONSOLE_FONT_INFO_EX { internal uint cbSize; internal uint nFont; internal COORD dwFontSize; internal int FontFamily; internal int FontWeight; fixed char FaceName[LF_FACESIZE]; } internal const int TMPF_TRUETYPE = 0x4; internal const int LF_FACESIZE = 32; internal const string BOM = "\uFEFF"; internal const int STD_OUTPUT_HANDLE = -11; // Handle to the standard output device. internal const int ERROR_INVALID_HANDLE = 6; internal const int ERROR_SUCCESS = 0; internal const uint FILE_TYPE_UNKNOWN = 0x0000; internal const uint FILE_TYPE_DISK = 0x0001; internal const uint FILE_TYPE_CHAR = 0x0002; internal const uint FILE_TYPE_PIPE = 0x0003; internal const uint FILE_TYPE_REMOTE = 0x8000; internal static IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1); }

And there you go!

A few things to note here:

I know the last point because I used to say that, when I was not as smart as I am now.

In fact, as I said way back in the beginning, the odds are in favor of the fact that you yourself were not nearly as smart before you read this blog as you are now that you have read it! :-)

And now if you will excuse me, I have to start conversations with the gazillion console applications in Windows that routinely punt bugs in console apps talking about their lack of Unicode support....