Начало поисков

Меня давно занимал один несерьёзный вопрос: какая самая старая программа с графическим интерфейсом до сих пор запускается на Windows 11 без доработок и без эмуляции?

Обратная совместимость у Windows отличная, так что я ожидал найти что-нибудь впечатляюще древнее.

Увы, 16-битные программы для Windows сама Windows 11 запускать не умеет: в 64-битной Windows нет NTVDM. Значит, искать придётся среди программ ранней эпохи NT.

Когда-то я задал этот вопрос на анонимном форуме, и мне посоветовали посмотреть на Win32s: найти одну из первых его версий, в комплекте с которой шёл FREECELL.exe.

Так я и сделал. И правда: FREECELL.EXE с датой изменения 22-Feb-93 запускается на последней версии Windows 11 без каких-либо правок, и в него можно полноценно играть:

FREECELL.EXE 1993 года
FREECELL.EXE 1993 года

На момент написания поста этой программе 33 года и 8 месяцев. Она почти моя ровесница, и это впечатляет.

Я подумал «прикольно», счёл загадку разгаданной и вскоре о ней забыл. Но недавно вопрос почему-то снова всплыл в голове, и на этот раз я решил копнуть глубже: вдруг найдётся что-нибудь старше.

Копаем дальше

Я перебирал старые версии Windows в Internet Archive и нашёл несколько ранних предрелизных сборок NT 3.1, которые выглядели многообещающе. Но основная проблема, по-видимому, заключалась либо в несовместимости с нынешним форматом исполняемых файлов, либо в изменениях API, сделанных позже в ходе разработки.

Самые ранние версии 1991 года использовали черновой вариант формата PE, несовместимый с современной Windows. А сборки до середины 1992 года при вызовах Windows API рассчитывали на соглашение о вызовах cdecl, а не stdcall. Из-за этого аргументы снимались со стека дважды:

push hwnd          ; 4 bytes of args
call [ShowWindow]  ; Win11 ShowWindow is stdcall, ends with "ret 4" and removes them
add  esp, 4        ; the 1992 caller removes them again

Прим. пер.: в комментариях к коду сказано, что вызывающий код кладёт на стек 4 байта аргументов, ShowWindow в Windows 11 следует stdcall и сама убирает их инструкцией ret 4, а код 1992 года после возврата снимает те же байты ещё раз. Пример у автора упрощён: на самом деле ShowWindow принимает два аргумента, то есть 8 байт на 32-битном x86, и заканчивается ret 8. Суть от этого не меняется: аргументы со стека снимаются дважды, и указатель стека после вызова оказывается не там, где его ждёт программа.

Понятно, что программа от такого падает.

Одно приложение всё же привлекло моё внимание. Это CDPLAYER.EXE из сборки 347, собранный (слинкованный) 16-Nov-1992. К тому времени соглашение о вызовах уже исправили, но остальные программы из этой сборки падают внутри своей встроенной библиотеки времени выполнения C. CDPLAYER.EXE этой участи избегает: он пользуется системной crtdll.dll, а Windows 11 до сих пор поставляет crtdll.dll в SysWOW64.

Если запустить программу, вы увидите примерно такое:

CDPLAYER.EXE: привод CD-ROM не найден
CDPLAYER.EXE: привод CD-ROM не найден

Ну да, конечно: в моём компьютере нет привода CD-ROM. Но его можно сэмулировать небольшой DLL (cdemu.dll), которая подсовывает поддельные аудиоданные, и тогда программа действительно играет звук:

CDPLAYER.EXE с эмулированным CD-ROM
CDPLAYER.EXE с эмулированным CD-ROM

Неплохо для программы, которой почти 34 года!

А если схитрить?

Выше я говорил, что 16-битные программы выбывают из игры, потому что их больше не поддерживают.

Но при желании старые программы для Windows можно запустить через что-нибудь вроде otvdm.

Вот, полюбуйтесь: на Windows 11 работает полностью играбельный REVERSI.EXE с датой 15-Nov-1985, взятый из Windows 1.01:

REVERSI.EXE из Windows 1.01 на Windows 11
REVERSI.EXE из Windows 1.01 на Windows 11

Использовать otvdm — это, конечно, немного жульничество, но результат показался мне слишком классным, чтобы не включить его в пост.

Комментарии (0)