我想了解是否有另一种(更快)方式使用C#.net将文本输出到控制台应用程序窗口,而不是简单的写入, BackgroundColor 和 ForegroundColor 方法和属性?我了解到每个单元格都有背景颜色和前景色,我想比使用上面提到的方法更快地缓存/缓冲/写入。
也许使用Out缓冲区有一些帮助,但我不知道如何将颜色编码到流中,如果这是颜色数据所在的位置。
这是一个基于retrostyle文本的游戏,我想要实现,我使用标准颜色和ascii字符来布局游戏。
请帮助:)
更新
Out和buffer可能不是我需要弄乱的东西。似乎有一个控制台拥有的屏幕缓冲区。我不知道如何访问它,也许我只是运气不好,除非我导入一些dll。
答案 0 :(得分:43)
更新:添加了样本
如果你准备做一些P / Invoke的东西,这可能会有所帮助。
基本上,如果您获得控制台缓冲区的句柄,那么您可以使用标准的Win32 API来操作缓冲区,甚至可以在屏幕上构建整个缓冲区并将其blit到控制台。
唯一棘手的部分是获取控制台缓冲区的句柄。我没有在.NET中试过这个,但是在过去的几年里,你可以通过使用CreateFile来获取当前控制台的句柄(你需要P / Invoke这个)并打开“CONOUT $”然后你可以使用那个句柄返回传递给其他API。
P / Invoke for CreateFile
http://www.pinvoke.net/default.aspx/kernel32/CreateFile.html
您可以使用WriteConsoleOutput将所有字符及其属性从内存缓冲区移动到控制台缓冲区。
http://msdn.microsoft.com/en-us/library/ms687404(VS.85).aspx
你可以组建一个很好的库来提供对控制台缓冲区的低级访问。
由于我试图让我的.NET重新开始,我想我会尝试一下,看看我是否可以让它工作。这是一个示例,它将使用所有字母A-Z填充屏幕,并贯穿所有forground属性0-15。我认为你会对表现印象深刻。老实说,我没有花太多时间查看这段代码,所以错误检查是零,这里或那里可能会有一些小错误但它应该让你继续使用其他的API。
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace ConsoleApplication1
{
class Program
{
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
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 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)
{
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;
}
[STAThread]
static void Main(string[] args)
{
SafeFileHandle h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
if (!h.IsInvalid)
{
CharInfo[] buf = new CharInfo[80 * 25];
SmallRect rect = new SmallRect() { Left = 0, Top = 0, Right = 80, Bottom = 25 };
for (byte character = 65; character < 65 + 26; ++character)
{
for (short attribute = 0; attribute < 15; ++attribute)
{
for (int i = 0; i < buf.Length; ++i)
{
buf[i].Attributes = attribute;
buf[i].Char.AsciiChar = character;
}
bool b = WriteConsoleOutput(h, buf,
new Coord() { X = 80, Y = 25 },
new Coord() { X = 0, Y = 0 },
ref rect);
}
}
}
Console.ReadKey();
}
}
}
答案 1 :(得分:5)
如果您查看Console
的属性实现以更改控制台颜色,他们会委托kernel32.dll
中的SetConsoleTextAttribute方法。此方法将character attributes作为输入来设置前景色和背景色。
从几个MSDN文档页面中,每个屏幕缓冲区(控制台都有一个)具有二维数组信息记录,每个记录由CHAR_INFO表示。这决定了每个角色的颜色。您可以使用SetConsoleTextAttribute
方法对此进行操作,但这适用于写入控制台的任何新文本 - 您无法操作控制台上已有的现有文本。
除非控制台文本颜色属性中存在较低级别的挂钩(看起来不太可能),否则我认为您使用这些方法时会遇到困难。
您可以尝试的一件事是创建一个新的屏幕缓冲区,写入该缓冲区,然后使用SetConsoleActiveScreenBuffer将其切换为控制台的当前缓冲区。 可能产生更快的输出,因为您将所有输出写入非活动缓冲区。
答案 2 :(得分:0)
我使用
成功type barConst = 'bar';
type Foo<K extends string> = Record<K, number>;
function test3(foo?: Foo<barConst>) {
if (typeof foo !== 'undefined') {
foo['bar']++;
}
}
let x: Foo<barConst> = { bar: 2 };
test3(x);
console.log(x);
但是,如果有人能建议我如何编写扩展ASCII码,我将不胜感激