Execute o jogo em c # no MS-DOS

Sempre fiquei irritado por não conseguir executar um jogo de 64 bits em C # no MS-DOS. Hoje eu consertei.



Os executáveis ​​do Windows consistem em duas partes:

  1. Um programa para DOS que exibe "Este programa não pode ser iniciado no modo DOS"
  2. Cabeçalho executável do Windows

De certa forma, todos os arquivos .exe são programas DOS, mas não fazem nada útil. Então, um dia, encontrei um projeto no Github que merece muito mais estrelas do que tem:

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

O Dos64-stub é um pequeno programa que substitui a mensagem inútil "não pode ser iniciada no DOS" carregando a seção Windows do arquivo executável e teleportando o processo para o século XXI. Por "teletransporte", quero dizer configurar a memória da página e colocar o processador no modo de 64 bits ("longo").

Para começar, peguei meu jogo "Snake" no Windows, que doeu até 8 kb sem dependências:



Obviamente, os métodos usuais da API do Windows não estão disponíveis no DOS, então tive que reescrever a camada de comunicação do jogo com o mundo exterior. Agora é assim que o Environment.TickCount se parece:

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

Quando temos o número de ticks, você pode fazer 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;)); } } 

E então 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++; } 

Bem, então tudo é simples: compilador C # -> compilador CoreRT AOT -> vinculador. Dizemos ao vinculador para usar o Dos64-stub em vez de gerar um cabeçalho padrão inútil.



E aqui está o código fonte inteiro na forma de uma solicitação pull .

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


All Articles