Witam
chyba wypłynąłem na za głębokie wody jak dla mnie :)
Ogólnie staram się napisać grę w konsoli i potrzebne mi szybkie rysowanie po niej.
Znalazłem kod który działa dobrze :
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();
}
}
}
Kod przeniosłem do klasy gdzie rysuje główne okno. Rysowanie trochę zmieniłem i wszystko ok.
Tylko teraz fajnie było by i w innych klasach użyć tego kodu. I chciałem spakować ten kod w jedną klasę.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace unicodes
{
class BuforKonsoli
{
public SafeFileHandle h;
public CharInfo[] buf;
public SmallRect rect;
public BuforKonsoli(short x, short y, short dx, short dy)
{
h = CreateFile("CONOUT$", 0x40000000, 2, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
buf = new CharInfo[x * y];
rect = new SmallRect() { Left = dx, Top = dy, Right = x, Bottom = y };
}
// BRZYDKI KOD //
[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)
{
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;
}
// BRZYDKI KOD //
}
}
I w innych klasach korzystać z tego mniej więcej tak :
public BuforKonsoli bufor;
bufor = new BuforKonsoli(81,40,0,0);
//i gdzieś w funkcji rysującej
bufor.WriteConsoleOutput(bufor.h, bufor.buf, new Coord() { X = 81, Y = 40 }, new Coord() { X = 0, Y = 0 }, ref bufor.rect);
jak mam operatorem new stworzyć obiekt z innej klasy ? chodzi dokładnie o Coord.
a pierwszego błędu nie rozumiem (dlaczego tak nie może być)
Błędy :
Member 'BuforKonsoli.WriteConsoleOutput(Microsoft.Win32.SafeHandles.SafeFileHandle, unicodes.BuforKonsoli.CharInfo[], unicodes.Coord, unicodes.Coord, ref unicodes.BuforKonsoli.SmallRect)' cannot be accessed with an instance reference; qualify it with a type name instead
cannot convert from 'unicodes.Coord' to 'unicodes.BuforKonsoli.Coord'
C# uczę się od paru tygodni, więc to trochę mnie przerasta ale chcę pisać w miarę poprawnie i mieć szybką konsole :)
Ogólnie mógłbym ten 'brzydki' kod umieścić w każdej klasie gdzie będzie mi potrzebny ale wiem że to złe rozwiązanie.