Ejecuta el juego en C # en MS-DOS

Siempre me molestó que no pueda ejecutar un juego de 64 bits en C # bajo MS-DOS. Hoy lo arreglé.



Los ejecutables de Windows constan de dos partes:

  1. Un programa para DOS que muestra "Este programa no se puede iniciar en modo DOS"
  2. Encabezado ejecutable de Windows

En cierto sentido, todos los archivos .exe son programas de DOS, pero no hacen nada útil. Entonces, un día encontré un proyecto en Github que merece muchas más estrellas de las que tiene:

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

Dos64-stub es un pequeño programa que reemplaza el mensaje inútil "no se puede iniciar en DOS" al cargar la sección de Windows del archivo ejecutable y teletransportar el proceso al siglo XXI. Por "teletransportación" me refiero a configurar la memoria de página y poner el procesador en modo de 64 bits ("largo").

Para comenzar, tomé mi juego "Snake" en Windows, que recientemente picó hasta 8 kb sin dependencias:



Por supuesto, los métodos habituales de la API de Windows no están disponibles en DOS, así que tuve que reescribir la capa de comunicación del juego con el mundo exterior. Así es como se ve ahora Environment.TickCount :

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

Cuando tenemos el número de ticks, puedes hacer Thread.Sleep :

 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;)); } } 

Y luego 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++; } 

Bueno, entonces todo es simple: compilador C # -> compilador CoreRT AOT -> enlazador. Le decimos al enlazador que use Dos64-stub en lugar de generar un encabezado predeterminado inútil.



Y aquí está todo el código fuente en forma de una solicitud de extracción .

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


All Articles