Я пытаюсь использовать функцию WriteConsoleOutput
из kernel32.dll, однако мне не удается правильно отобразить символы Юникода, они всегда отображаются как неправильные символы.
Я пытался использовать:
Console.OutputEncoding = System.Text.Encoding.UTF8;
Изменение этого значения на Encoding.Unicode
также не работает.
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleOutputCP(uint wCodePageID);
public void SetCP(){
SetConsoleOutputCP(65001);
}
Я попытался использовать оба из вышеперечисленных, каждый по отдельности, и ни один из них не содержал почти все комбинации значений.
Я также переключился между всеми шрифтами (включая шрифты истинного типа), однако ни один из них, кажется, не отображает символы правильно.
Вот код, который я использую для использования WriteConsoleOutput
[DllImport("kernel32.dll", SetLastError = true, EntryPoint = "WriteConsoleOutputW", CharSet = CharSet.Unicode)]
static extern bool WriteConsoleOutputW(SafeFileHandle hConsoleOutput, CharInfo[] lpBuffer, Coord dwBufferSize, Coord dwBufferCoord, ref SmallRect lpWriteRegion);
[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);
private static readonly SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
public static void RegionWrite(string s, int x, int y, int width, int height)
{
if (!h.IsInvalid)
{
int length = width * height;
// Pad any extra space we have
string fill = s + new string(' ', length - s.Length);
// Grab the background and foreground as integers
int bg = (int) Console.BackgroundColor;
int fg = (int) Console.ForegroundColor;
// Make background and foreground into attribute value
short attr = (short)(fg | (bg << 4));
CharInfo[] buf = fill.Select(c =>
{
CharInfo info = new CharInfo();
// Give it our character to write
info.Char.UnicodeChar = c;
// Use our attributes
info.Attributes = attr;
// Return info for this character
return info;
}).ToArray();
// Make everything short so we don't have to cast all the time
short sx = (short) x;
short sy = (short) y;
short swidth = (short) width;
short sheight = (short) height;
// Make a buffer size out our dimensions
Coord bufferSize = new Coord(swidth, sheight);
// Not really sure what this is but its probably important
Coord pos = new Coord(0, 0);
// Where do we place this?
SmallRect rect = new SmallRect() { Left = sx, Top = sy, Right = (short) (sx + swidth), Bottom = (short) (sy + sheight) };
bool b = WriteConsoleOutputW(h, buf, bufferSize, pos, ref rect);
}
else
{
throw new Exception("Console handle is invalid.");
}
}
Использование этого со стандартными символами ASCII прекрасно работает:
RegionWrite("Hello world", 4, 4, 10, 10);
Однако, когда я использую что-либо выше стандартного диапазона ASCII, оно не отображается правильно:
RegionWrite("┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬", 4, 4, 10, 10);
Это выводит в виде двух строк символов ',', это имеет некоторый смысл, так как символ "┬" имеет значение 9516, 9516% 128 равно 44, что является кодом ascii для ','. * 102 6 *
Я знаю, что физически возможно вывести эти символы, так как Console.Write("┬┬┬┬")
работает правильно. Я переключаюсь с Console.Write
на WriteConsoleOutput
, поскольку наблюдается значительное повышение производительности.
Вот код, который я использую для установки кодовых страниц:
public void Setup()
{
Console.BufferHeight = Console.WindowHeight;
Console.BufferWidth = Console.WindowWidth;
Console.OutputEncoding = System.Text.Encoding.UTF8;
SetConsoleOutputCP(65001);
DefaultColor();
Console.Clear();
Console.ReadLine();
RegionWrite("┬┬┬┬", 4, 4, 10, 10);
Console.WriteLine("┬┬┬┬");
Console.ReadLine();
}
Вот мои структуры:
[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;
}
Я предполагаю, что облажался с одной из переменных WriteConsoleOutput
, но после нескольких часов поиска ответов я действительно не уверен, где я ошибся. Есть ли какая-то внутренняя функция кодирования набора, которую мне нужно использовать?
nvm исправил это