Führen Sie das Spiel in C # unter MS-DOS aus

Ich habe mich immer geärgert, dass ich unter MS-DOS kein 64-Bit-Spiel in C # ausführen kann. Heute habe ich es behoben.



Windows-Programmdateien bestehen aus zwei Teilen:

  1. Ein Programm für DOS mit der Meldung "Dieses Programm kann nicht im DOS-Modus gestartet werden"
  2. Ausführbarer Windows- Header

In gewisser Weise sind alle .exe-Dateien DOS-Programme, tun aber nichts Nützliches. Also habe ich eines Tages ein Projekt auf Github gefunden, das viel mehr Sterne verdient als es hat:

github.com/Baron-von-Riedesel/Dos64-stub

Dos64-stub ist ein kleines Programm, das die nutzlose Meldung "Kann unter DOS nicht gestartet werden" ersetzt, indem der Windows-Abschnitt der ausführbaren Datei geladen und der Prozess in das 21. Jahrhundert teleportiert wird. Mit "Teleportation" meine ich das Einrichten des Seitenspeichers und das Versetzen des Prozessors in den 64-Bit-Modus ("lang").

Als Einstieg nahm ich mein Spiel "Snake" unter Windows, das kürzlich ohne Abhängigkeiten bis zu 8 kb stach:



Natürlich sind die üblichen Windows-API-Methoden in DOS nicht verfügbar, daher musste ich die Ebene der Kommunikation des Spiels mit der Außenwelt neu schreiben. So sieht Environment.TickCount jetzt aus:

 public static unsafe long TickCount64 { [MethodImpl(MethodImplOptions.NoInlining)] get { //    BIOS -   1AH. // ,         "" . //   BIOS -   , //  BIOS    . //   DOS   . //   0x46C       55. uint timerTicks = * (uint *) 0x46C; return (long) timerTicks * 55; } } 

Wenn wir die Anzahl der Ticks haben, können Sie Thread.Sleep tun:

 public static unsafe void Sleep(int delayMs) { //     : 0xF4 0xC3 //     : // // hlt // ret ushort hlt = 0xc3f4; long expected = Environment.TickCount64 + delayMs; while(Environment.TickCount64 < expected) { //  ,     ,   //     // (    ) ClassConstructorRunner.Call<int>(new IntPtr(&hlt;)); } } 

Und dann Console.WriteLine :

 public static unsafe void Write(char c) { byte* biosDataArea = (byte*)0x400; //   VRAM,    BIOS byte* vram = (byte*)0xB8000; if(*(biosDataArea + 0x63) == 0xB4) vram = (byte*)0xB0000; //     vram += * (ushort*)(biosDataArea + 0x4E); //        IBM byte b = c switch { '│' => (byte)0xB3, '┌' => (byte)0xDA, '┐' => (byte)0xBF, '─' => (byte)0xC4, '└' => (byte)0xC0, '┘' => (byte)0xD9, _ => (byte)c, }; // TODO:     BIOS vram[(s_cursorY * 80 * 2) + (s_cursorX * 2)] = b; vram[(s_cursorY * 80 * 2) + (s_cursorX * 2) + 1] = (byte)s_consoleAttribute; // TODO:      ? s_cursorX++; } 

Dann ist alles ganz einfach: C # -Compiler -> CoreRT AOT-Compiler -> Linker. Wir weisen den Linker an, Dos64-stub zu verwenden, anstatt einen nutzlosen Standardheader zu generieren.



Und hier ist der gesamte Quellcode in Form einer Pull-Anfrage .

Source: https://habr.com/ru/post/de484854/


All Articles