3

Having looked at this question and modifying the code to print characters like '☺', '☻' or '█', I can't see how to get these characters to actually draw properly with WriteConsoleOutput. (There is no problem when using a stream or Console.Write but I can't individually control the character colour with these solutions so they're unsuitable.)

It seems there was a solution here for C++ but the "L" macro they talk about down the bottom does not apply to C#.

Finally, having checked the suggestions here, I can't see anything wrong with the code I ended up with:

class Program
{
    [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
    static extern SafeFileHandle CreateFile(
        string fileName,
        [MarshalAs(UnmanagedType.U4)] uint fileAccess,
        [MarshalAs(UnmanagedType.U4)] uint fileShare,
        IntPtr securityAttributes,
        [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition,
        [MarshalAs(UnmanagedType.U4)] int flags,
        IntPtr template
    );

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool WriteConsoleOutputW(
        SafeFileHandle hConsoleOutput,
        CharInfo[] lpBuffer,
        Coord dwBufferSize,
        Coord dwBufferCoord,
        ref SmallRect lpWriteRegion
    );

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool SetConsoleOutputCP(uint wCodePageID);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool SetConsoleCP(uint wCodePageID);

    [StructLayout(LayoutKind.Sequential)]
    public struct Coord
    {
        public short X;
        public short Y;

        public Coord(short X, short Y)
        {
            this.X = X;
            this.Y = Y;
        }
    };

    [StructLayout(LayoutKind.Explicit)]
    public struct CharUnion
    {
        [FieldOffset(0)] public char UnicodeChar;
        [FieldOffset(0)] public byte AsciiChar;
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct CharInfo
    {
        [FieldOffset(0)] public CharUnion Char;
        [FieldOffset(2)] public short Attributes;
    }

    [StructLayout(LayoutKind.Sequential)]
    public struct SmallRect
    {
        public short Left;
        public short Top;
        public short Right;
        public short Bottom;
    }

    static void Main(string[] args)
    {
        //SetConsoleOutputCP(65001);
        //SetConsoleCP(65001);
        SafeFileHandle fileHandle = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
        Console.TreatControlCAsInput = true;
        //Console.OutputEncoding = Encoding.UTF8;
        Console.OutputEncoding = System.Text.Encoding.Unicode;
        Console.CursorVisible = false;
        short screenWidth = 40;
        short screenHeight = 20;
        Console.SetWindowSize(screenWidth + 1, screenHeight + 1);
        Console.SetBufferSize(screenWidth + 1, screenHeight + 1);
        bool running = true;
        while (running)
        {
            CharInfo[] buf = new CharInfo[screenWidth * screenHeight];
            SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = screenWidth, Bottom = screenHeight };
            for (int i = 0; i < buf.Length; ++i)
            {
                buf[i].Attributes = 6;
                buf[i].Char.UnicodeChar = '☺';
            }
            bool b = WriteConsoleOutputW(
                fileHandle,
                buf,
                new Coord() { X = screenWidth, Y = screenHeight },
                new Coord() { X = 0, Y = 0 },
                ref rect
            );
            Console.SetCursorPosition(0, 0);
        }
    }
}

I seem to have ruled out all combinations of CharSet, A/W DLLImport suffixes, code pages, Console properties & source-file encoding.

(Surely it can't be impossible to fast-print coloured smiley-face characters to a C# console. Somebody tell me I've missed something silly here; I've spent about 2 hours Googling & trying to emulate something Castle Adventure managed in 1984 with ease.)

How can I get the aforementioned '☺' to print anything other than a '?' or a ':'?

Rogod
  • 188
  • 1
  • 13
  • 1
    Console.OutputEncoding = System.Text.Encoding.UTF8; – Mikael Jun 02 '20 at 20:12
  • @Mikael sadly this does not change anything for me - whether it's set to Unicode or UTF8, it's printing a screen full of ':' – Rogod Jun 02 '20 at 20:14
  • 1
    Interesting. I loaded up a new console app in visual studio and it prints the smiley face either way for me – Mikael Jun 02 '20 at 20:15
  • There is no problem for Console.Write - but using WriteConsoleOutput (in order to have control of colour per character) seems to ignore these encoding settings to some degree. – Rogod Jun 02 '20 at 20:28
  • https://stackoverflow.com/questions/2743260/is-it-possible-to-write-to-the-console-in-colour-in-net <- You may like the last answer as it colors certain parts of a string. Also, check this plugin: https://github.com/silkfire/Pastel – Mikael Jun 02 '20 at 21:20
  • Both of these options sacrifice the speed gained from using WriteConsoleOutput or a stream. Currently with the code snippet in my question, text would render in the same time regardless of how convoluted the characters or colours are - this is something I am keen to keep – Rogod Jun 02 '20 at 21:38

1 Answers1

1

This seems to be a duplicate of Using WriteConsoleOutput to write Unicode with c#

The solution to that was to add the CharSet = CharSet.Unicode attribute to both the CharInfo and CharUnion structs.

  • Yes I hadn't realised the significance of those parameters - this does indeed solve the problem. Thanks :3 – Rogod Jun 02 '20 at 22:16