使用 WriteConsoleOutput 使用 c# 编写 Unicode



我正在尝试使用 kernel32.dll 中的WriteConsoleOutput函数,但是我无法正确显示 unicode 字符,它们总是显示为错误的字符。

我尝试使用:

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 代码。

我知道在物理上可以输出这些字符,因为Console.Write("┬┬┬┬")正常工作。我正在从Console.Write切换到WriteConsoleOutput,因为性能显着提高。

以下是 im 用于设置代码页的代码:

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修复了它

简单的解决方案,更改

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

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

这是因为它将默认为 ANSI,这意味着您的 unicode 字符会自动转换为 ANSI,因此 ┬ 变为 ,

最新更新