В начале 1990-х самым популярным расширителем DOS был DOS/4GW. Во время разработки Windows 95 я очень много времени тратил на решение задачи совместимости с играми под MS-DOS, поэтому видел много баннеров расширителей DOS, и чаще всего это был DOS/4GW.

Вы можете задаться вопросом: «Как эти игры вообще запускались в Windows 95, если они поставлялись с расширителем DOS? Разве расширитель не пытался бы безуспешно перейти в защищённый режим, потому что Windows уже управляла защищённым режимом?»

Хитрость заключалась в том, что эти расширители на самом деле были двумя связанными друг с другом программами. Одна использовалась как сервер защищённого режима, а другая была клиентской библиотекой защищённого режима.

В начале существовал Virtual Control Program Interface (VCPI), который поддерживался менеджерами расширенной памяти наподобие EMM386. Эти менеджеры расширенной памяти практически не использовали защищённый режим: единственное, что им было важно — получение доступа к памяти выше границы в 1МБ, чтобы они могли создать таблицы страниц для отображения дополненной памяти (extended memory) в кадр страницы расширенной памяти (expanded memory), но никакой другой виртуализации они не выполняли. MS-DOS работала в виртуальной машине с полным доступом к оборудованию, а интерфейс VCPI позволял приложению MS-DOS сказать: «Сейчас мне нужно получить полный контроль над системой», после чего VCPI отвечал: «Конечно, без проблем!»

Интерфейс VCPI быстро потерял свою популярность, потому что ни одна операционная система защищённого режима (например, Windows 3.0 в расширенном режиме) не позволила бы какой-то программе получать полный контроль над системой. По сути, это бы приостанавливало работу старой операционной системы, чтобы позволить программе MS-DOS перехватить управление как новой. В Windows 3.0 появился новый интерфейс под названием DOS Protected Mode Interface (DPMI), позволявший программам MS-DOS запрашивать исполнение их кода в защищённом режиме, но только в пользовательском режиме. Драйвер доступа DPMI при этом продолжал управлять режимом ядра.

Итак, вернёмся к DOS/4GW. При запуске расширитель DOS/4GW искал запущенный DPMI-сервер. Если он не находил его, то устанавливался сам в качестве DPMI-сервера. Но если DPMI-сервер уже работал, то он позволял этому DPMI-серверу оставаться в работе.

Игра общалась только с частью библиотеки, относящейся к DPMI-клиенту, которую использовала для перехода в 32-битный режим, распределения памяти и выполнения всех 32-битных задач, которые требовались этой 32-битной игре от 32 битов.

Иными словами, получается следующая блок-схема:

И DPMI-серверы, и Windows, и DOS/4GW реализуют интерфейс DPMI, поэтому DPMI-клиент DOS/4GW использовал для общения с обоими серверами стандартные вызовы DPMI.

Это прекрасно обеспечивало совместимость приложений, потому что в случае возникновения проблем в общении клиента DOS/4GW с сервером DOS/4GW нам достаточно было устранить их один раз и сразу для всех игр. С другой стороны, если проблему нельзя было устранить, это бы сломало множество игр.

Высокие риски, большая награда.

Чудесным образом большинство игр просто работало, несмотря на то, что они запускались не под тем DPMI-сервером, для которого разрабатывались изначально. Иногда возникали проблемы с отдельными играми. Самыми частыми оказывались проблемы с играми, предполагавшими, что вся память была физической и с играми, предполагавшими, что флаг прерываний был невиртуализированным, однако по большей мере всё работало достаточно хорошо, чтобы оставшиеся проблемы можно было решать как баги конкретных приложений.

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


  1. ciuafm
    31.08.2023 12:05
    +2

    Так получилось что никогда не программировал под DOS/4GW, но играл как и все. Можете рассказать подробнее и с примерами как это выглядело со стороны программы?


    1. Zara6502
      31.08.2023 12:05
      +1

      Присоединяюсь к просьбе, интересно как приходилось программисту напрягаться чтобы сделать что-то больше одной страницы.


      1. da-nie
        31.08.2023 12:05
        +4

        На Си или на асме? На Си это было прозрачно совершенно. Хотите мегабайт для массива? Просто выделяете этот мегабайт. Компилятор Watcom всё остальное делал сам.


        А вот так на Watcom делались вставки на асме в 32-битном режиме:


        pragma aux putscreen parm[]=\

        "mov esi,dpt"\
        "mov ecx,16000"\
        "mov eax,ecx"\
        "mov edi,0xa0000"\
        "rep movsd"\
        modify [esi edi ecx eax];


        1. Zara6502
          31.08.2023 12:05

          не хотелось бы спорить, но я писал на Watcom (пытался), еще в 1994-1996, но в силу отсутствии документации лично у меня я не мог писать что-то больше чем стандартные программы на 640 Кб ОЗУ, при запросе памяти просто была ошибка и никакой расширитель не приклеивался. Вероятно сам процесс сборки требовал настройки под такие условия, что я не делал конечно же. Собственно в свое время я и хотел на ваткоме писать код именно что с применением большего количества памяти.


          1. da-nie
            31.08.2023 12:05
            +1

            Я на Watcom написал аналог DooM.
            Посмотрите, там есть все настройки компилятора.


      1. aamonster
        31.08.2023 12:05

        Да никак. У вас просто было 32-битное адресное пространство без всего этого геморроя со страницами.


        1. Zara6502
          31.08.2023 12:05

          это вы про что? стандартное приложение DOS работает в 640Кб пространстве. Сколько писал на Turbo C. Потом полез в Watcom чтобы этот вопрос закрыть, но не получилось.


          1. aamonster
            31.08.2023 12:05
            +1

            Так вся фишка dos4gw (во всяком случае, при использовании wacom c с дефолтными настройками) – что вам dos4gw прямо на старте программы проц переводит в защищённый режим и делает плоское адресное пространство (с известными адресами видеопамяти и т.п.). Вы просто работаете на всём готовом (и модель памяти – "самая маленькая", cs/ds/es/ss назначены на одно и то же и не трогаются никогда).


            1. Zara6502
              31.08.2023 12:05

              значит я не раскурил ватком, потому что на нём я не смог делать такие приложения.


    1. VelocidadAbsurda
      31.08.2023 12:05
      +19

      В простейшем случае программа просто писалась с расчётом на 32-битность и плоскую модель, собиралась Watcom C(++), компоновщик которого сам ваш код компоновал в формат LE (OS/2 Linear Executable), затем добавлял к нему DOS MZ заголовок и сам DOS/4GW как DOS stub. При запуске получившегося ехе первым получал управление DOS/4GW (т.к. DOS не понимал формат LE и видел только MZ часть), который, как и описано в статье, искал уже работающий DPMI-сервер (через прерывание INT 2F, закреплённое за DPMI), при отсутствии оного сам «вешался» на это прерывание, а дальше через функцию того же INT 2F (обрабатываемую либо самим DOS/4GW, либо «чужим» DPMI-сервером) переходил в защищённый режим, через функции INT 31 (DPMI API уже в 32-битном режиме, DPMI-сервер и его должен обрабатывать) выделял память под пользовательскую программу, загружал её туда (разбирая уже LE-часть) и в конце концов «прыгал» на пользовательскую точку входа, указанную в LE-заголовке.

      Другая часть «магии» Watcom находилась в его стандартной библиотеке, которая «заворачивала» работу с файлами/консолью в вызовы DOS через функции всё того же INT 31, выделяла/освобождала память опять же через INT 31 итд.

      Если программе не требовалось что-нибудь низкоуровневое вроде установки обработчика прерывания, прямого доступа к видеобуферу и подобного, она выглядела как самый обычный С/С++. Для низкоуровневых же вещей требовалось уже вручную вызывать всё тот же INT 31.

      Как-то так.


      1. joedm
        31.08.2023 12:05
        +3

        И этот dos/4gw стаб можно было тупо оторвать, оставив остальное, положить рядом отдельностоящий dos4gw.exe, положить ему конфиг (.ini кажется), а в конфиге прописать свап-файл - и гонять в игры, которым не хватало установленной физической памяти.


        1. buran_ded
          31.08.2023 12:05
          +1

          Для включения виртуальной памяти достаточно было задать переменную среды SET DOS4GVM=1


          1. buran_ded
            31.08.2023 12:05

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

            И вот какой парадокс - спасал Windows 95, именно 95, в нём была лучшая поддержка DOS/4GW, в Windows 98 такой уже не было.

            То есть я хотел поиграть в свою любимую игру Blood, а она требовала 16 МБ, а у меня было всего 8 МБ, я просто запускал её под Windows 95.

            И всё прекрасно работало и не крешилось на звуке. Только частый своп иногда притормаживал игру.


  1. perfect_genius
    31.08.2023 12:05

    Интересно, как расширитель определял, что запущенная именно игра. Или же программы тоже шли хорошо.


    1. da-nie
      31.08.2023 12:05
      +1

      В смысле, именно игра? А какая разница с не игрой?


      1. perfect_genius
        31.08.2023 12:05

        По тексту кажется, что приоритет был на игры:


        нам достаточно было устранить их один раз и сразу для всех игр. С другой стороны, если проблему нельзя было устранить, это бы сломало множество игр.
        Чудесным образом большинство игр просто работало, несмотря на то, что они запускались не под тем DPMI-сервером, для которого разрабатывались изначально. Иногда возникали проблемы с отдельными играми. Самыми частыми оказывались проблемы с играми...


        1. da-nie
          31.08.2023 12:05

          Просто почти все современные на тот момент игры использовали dos/4gw. Но точно так же это могли быть совершенно любые приложения.
          Кстати, буковка w означала версию для watcom.


    1. Gummilion
      31.08.2023 12:05

      Интересно, а был вообще какой-нибудь более-менее популярный софт под DOS/4GW? В 90-е уже все под Windows переползали, чтобы была потребность в защищенном режиме, но именно под ДОС - это что-то специфическое должно быть...


      1. da-nie
        31.08.2023 12:05
        +2

        Вряд ли он был. Дело в том, что этот софт не требовал выжимать от аппаратуры всё, а потому гораздо лучше его писать с использованием Windows API. А вот игры требовали максимума отдачи от оборудования (в Windows первые Direct-X были кривыми и тормознутыми по сравнению с прямой работой с аппаратурой, да и от COM-модели разработчиков игр тошнило), потому даже в 1997 тот же Duke Nukem 3D шёл под MS-DOS.


        1. cdriper
          31.08.2023 12:05

          Duke Nukem 3D это начало 96-го

          игра -- одногодка первого Quake


          1. da-nie
            31.08.2023 12:05

            Да. Перепутал с Blood, которая как раз 1997 и на том же движке.


      1. vitalyvitaly
        31.08.2023 12:05
        +1

        Под Clipper 5, насколько помню, такие расширения были


      1. aamonster
        31.08.2023 12:05
        +1

        Игры же.


        1. Gummilion
          31.08.2023 12:05

          Игры - это само собой, я имел в виду - для чего-то помимо игр


          1. aamonster
            31.08.2023 12:05

            Числяк. Ну в смысле когда надо много считать, а данные не помещаются в 64k (а использование указателей вида сегмент:смещение создаёт лишние тормоза). Хотя этот софт трудно назвать популярным, это для единиц)

            Ну и довольно долго винду недолюбливали всё-таки. Когда ресурсов у компа не так много – не хочется тратить их зазря.


      1. Zara6502
        31.08.2023 12:05

        у каждого свои 90-е, я от MS-DOS Config.sys (менюшка с emm386, himem.sys и всякими вариантами под разные игры, как мне помнится Worms и Doom 2 Plutonia Experiment дольше всего у меня держали DOS) избавился только в 2001 году перейдя на WinMe, NT/2000 по сути мимо прошли и где-то в 2004 я на XP перешёл, в 2007 на Виста и в 2009 на 7, в 2014 на 8/8.1 и через год кажется на 10 инсайдер. На 10 до сих пор.


  1. Maximuzz
    31.08.2023 12:05
    +2

    В те времена, видев на экране надпись DOS/4GW я знал, что игра будет хорошей, даже не понимая, что это и зачем. Вот такие забавные ассоциации у меня)