I'm currently writing a small utility library to help improve performance when writing to the console, and I'm facing an issue where it fails to actually output any text. Below is my code:
public static class QuickDraw
{
private static short Width => (short)Console.WindowWidth;
private static short Height => (short)Console.WindowHeight;
private static SafeFileHandle Handle =>
Kernel32.CreateFile("$CONOUT", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
private static Kernel32.Coord Cursor =>
new Kernel32.Coord((short)Console.CursorLeft, (short)Console.CursorTop);
private static Kernel32.SmallRect WriteRegion =>
new Kernel32.SmallRect() { Left = 0, Top = 0, Right = Width, Bottom = Height };
private static Kernel32.Coord BufferSize =>
new Kernel32.Coord(Width, Height);
private static Kernel32.Coord BufferCoord =>
new Kernel32.Coord(0, 0);
public static void Write(char[] text, ConsoleColor fg, ConsoleColor bg)
{
Kernel32.CharInfo[] buffer = new Kernel32.CharInfo[Width * Height];
Kernel32.Coord cursor = Cursor;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == '\n')
{
cursor.X = 0;
cursor.Y++;
}
else
{
int index = (cursor.Y * Width) + cursor.X;
// Set character
buffer[index].Char.AsciiChar = (byte)text[i];
// Set color
// (Crazy heckin bitwise crap, don't touch.)
buffer[index].Attributes = (short)((int)fg | ((int)bg | (2 << 4)));
// Increment cursor
cursor.X++;
}
// Make sure that cursor does not exceed bounds of window
if (cursor.X >= Width)
{
cursor.X = 0;
cursor.Y++;
}
if (cursor.Y >= Height)
{
cursor.Y = 0;
}
}
var writeRegion = WriteRegion;
Kernel32.WriteConsoleOutput(Handle, buffer, BufferSize, BufferCoord, ref writeRegion);
Console.SetCursorPosition(cursor.X, cursor.Y);
}
}
// Taken from https://stackoverflow.com/a/2754674/7937949
internal static class Kernel32
{
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public 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)]
public static extern bool WriteConsoleOutput(
SafeFileHandle hConsoleOutput,
CharInfo[] lpBuffer,
Coord dwBufferSize,
Coord dwBufferCoord,
ref SmallRect lpWriteRegion);
[StructLayout(LayoutKind.Sequential)]
public struct Coord
{
public short X;
public short Y;
public Coord(short x, short y)
{
X = x;
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(2)] 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;
}
}
I've mostly taken the implementation from this post, adding a new class to simplify its use. I'm not entirely sure where my issue is, as my debugger is not working right, but I'm pretty sure it's in my implementation in QuickDraw
.
When I try to use QuickDraw.Write()
, the cursor moves to the end of whatever string it was trying to print, but nothing actually shows up. What am I doing wrong?