قم بتشغيل اللعبة في C # على MS-DOS

كنت دائمًا منزعجًا من أنني لا أستطيع تشغيل لعبة 64 بت في C # ضمن MS-DOS. اليوم أنا إصلاحه.



تتكون الملفات التنفيذية لـ Windows من جزأين:

  1. برنامج لـ DOS يعرض "لا يمكن بدء تشغيل هذا البرنامج في وضع DOS"
  2. رأس قابل للتنفيذ ويندوز

بمعنى ما ، جميع ملفات exe هي برامج DOS ، لكن لا تفعل شيئًا مفيدًا. في أحد الأيام وجدت مشروعًا على جيثب يستحق نجومًا أكثر بكثير مما لديه:

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

Dos64-stub هو برنامج صغير يستبدل الرسالة عديمة الفائدة "لا يمكن بدء تشغيلها تحت DOS" عن طريق تحميل قسم Windows من الملف القابل للتنفيذ ونقل العملية إلى القرن الحادي والعشرين. يعني "النقل عن بُعد" إعداد ذاكرة الصفحة ووضع المعالج في وضع 64 بت ("طويل").

للبدء ، أخذت لعبتي "Snake" ضمن Windows ، والتي وصلت إلى 8 كيلوبايت مؤخرًا دون تبعية:



بالطبع ، لا تتوفر طرق Windows API المعتادة في DOS ، لذلك اضطررت إلى إعادة كتابة طبقة اتصال اللعبة مع العالم الخارجي. هذا هو ما يبدو عليه 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; } } 

عندما يكون لدينا عدد من علامات التجزئة ، يمكنك القيام 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;)); } } 

ثم 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++; } 

حسنًا ، كل شيء بسيط: C # compiler -> CoreRT AOT compiler -> linker. نقول للرابط استخدام Dos64-stub بدلاً من إنشاء رأس افتراضي عديم الفائدة.



وهنا هو مصدر شفرة كاملة في شكل طلب سحب .

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


All Articles