Mise à jour : ajout d'un échantillon
Si vous êtes prêt à faire un peu de P/Invoke, cela pourrait vous aider.
En fait, si vous obtenez un identifiant pour le tampon de la console, vous pouvez utiliser les API Win32 standard pour manipuler le tampon, et même construire l'intégralité du tampon en dehors de l'écran et le transmettre à la console.
La seule partie délicate est d'obtenir la poignée du tampon de la console. Je n'ai pas essayé cela dans .NET, mais dans les années passées, vous pouviez obtenir le handle de la console courante en utilisant CreateFile (vous aurez besoin de P/Invoke ceci) et ouvrir "CONOUT$" puis vous pouvez utiliser le handle qui est retourné pour passer aux autres APIs.
P/Invocation pour CreateFile
http://www.pinvoke.net/default.aspx/kernel32/CreateFile.html
Et vous pouvez utiliser WriteConsoleOutput pour déplacer tous les caractères et leurs attributs d'un tampon mémoire vers le tampon de la console.
http://msdn.microsoft.com/en-us/library/ms687404(VS.85).aspx
Vous pourriez probablement mettre en place une belle bibliothèque pour fournir un accès de bas niveau au tampon de la console.
Comme j'essaie de remettre mon .NET à niveau, je me suis dit que j'allais m'y essayer et voir si je pouvais le faire fonctionner. Voici un exemple qui remplira l'écran avec toutes les lettres de A à Z et parcourra tous les attributs de terrain de 0 à 15. Je pense que vous serez impressionné par les performances. Je vais être honnête, je n'ai pas passé beaucoup de temps à réviser ce code, donc la vérification des erreurs est nulle et il pourrait y avoir un petit bug ici ou là, mais cela devrait vous permettre d'utiliser le reste des 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();
}
}
}