Exécutez le jeu en C # sur MS-DOS

J'ai toujours été ennuyé de ne pas pouvoir exécuter un jeu 64 bits en C # sous MS-DOS. Aujourd'hui, je l'ai réparé.



Les exécutables Windows se composent de deux parties:

  1. Un programme pour DOS qui affiche «Ce programme ne peut pas ĂȘtre dĂ©marrĂ© en mode DOS»
  2. En- tĂȘte exĂ©cutable Windows

Dans un sens, tous les fichiers .exe sont des programmes DOS, mais ne font rien d'utile. Alors un jour, j'ai trouvé un projet sur Github qui mérite beaucoup plus de stars qu'il n'en a:

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

Dos64-stub est un petit programme qui remplace le message inutile «ne peut pas ĂȘtre dĂ©marrĂ© sous DOS» en chargeant la section Windows du fichier exĂ©cutable et en tĂ©lĂ©portant le processus au 21e siĂšcle. Par «tĂ©lĂ©portation», j'entends la configuration de la mĂ©moire des pages et la mise du processeur en mode 64 bits («long»).

Pour commencer, j'ai pris mon jeu "Snake" sous Windows, qui a récemment piqué jusqu'à 8 ko sans dépendances:



Bien sûr, les méthodes habituelles de l'API Windows ne sont pas disponibles sous DOS, j'ai donc dû réécrire la couche de communication du jeu avec le monde extérieur. Voici à quoi ressemble 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; } } 

Lorsque nous avons le nombre de ticks, vous pouvez faire du 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;)); } } 

Et puis 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++; } 

Eh bien, alors tout est simple: compilateur C # -> compilateur CoreRT AOT -> Ă©diteur de liens. Nous indiquons Ă  l'Ă©diteur de liens d'utiliser Dosub-stub au lieu de gĂ©nĂ©rer un en-tĂȘte par dĂ©faut inutile.



Et voici l'intégralité du code source sous forme de pull request .

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


All Articles