[Q]: Как Win32-EXE переносятся в OS/2? Что такое Odin, Open32, INNOWIN?

[A]: Andrew Belov (2:5020/181.2)

Попытаемся вспомнить несколько технологий:

1. IBM Open32 (в прошлом DAPIE или DAX)

В эпоху NT v 3.5 задачу совместимости с Win32 начали решать с помощью Developer API Extensions (DAX). Было решено продолжить опыт проектов WLO и MIRRORS (библиотеки для миграции из Win16 в PM) и рассчитывать на инициативу разработчиков конкретных приложений. Ближе к XR_W017 внутри PMMERGE.DLL выросла стопка функций, дополняющих PM API некоторыми Win32-понятиями (Caret'ы и т.п.), и появились PMWINX/PMDDEML - сборники Win32-API.

Ресурсы GUI при таком подходе должны были приводиться к PM'мному формату (поэтому внешний вид и поведение перенесенного софта слабо отличались от PM'ного), хранение настроек поощрялось в стандартных *.INI. Сам софт целиком пересобирался OS/2-компиляторами, при этом все API, не охваченные Open32, например, WINMM, оставались на совести программиста.

LX-EXE Open32 OS/2
+---------------+ +--------------+
| Вызовы W32 API| -> [PMWINX.DLL, PMDDEML.DLL] -> | ... |
+---------------+ | PMMERGE.DLL |
|Вызовы OS/2 API| ------------------------------> | |
+---------------+ | DOSCALL1.DLL |
| PM-ресурсы | | ... |
+---------------+ +--------------+

По этой технологии перенесены все SmartSuite после 1996 г. и мифический MGI PhotoSuite. Оверхед - 1M памяти для PMWINX.

2. Довески - REGISTRY.DLL и WGSS4?.DLL

В конце 1997 г. IBM слегка дополнил мерлиновский PMWINX.DLL и выпустил два “довеска”, архитектурно независимых от Open32.

REGISTRY.DLL - воспроизводит Win32'шные API Reg*, позволяя любой OS/2'шной программе работать с древовидным “реестром” (физически он находится в \OS2\SYSTEM\*.DAT) и не прибегать к “родным” Prf*. Изначально реестр был центральной концепцией в OS/2 for PowerPC (configuration namespace), но на i386 он оказался полезным для портирования из Win32.

WGSS4?.DLL - были придуманы для собственных нужд портирования Netscape 4.xx (первые альфы 4.03/4.04 еще использовали PMWINX.DLL). Они содержат только ограниченное подмножество функций Gpi*, оверхед - сотни килобайт.

LX-EXE OS/2
+-----------------+ +--------------+
| Вызовы GDI32, | --------> WGSS46.DLL -------> | PMMERGE.DLL |
| ADVAPI32 | --------> REGISTRY.DLL -------> | DOSCALL1.DLL |
+-----------------+ +--------------+
| Вызовы OS/2 API | ------------------------------> | |
+-----------------+ | *.DLL |
| PM-ресурсы | | |
+-----------------+ +--------------+

3. Win32-OS/2

В 1997 г. несколько энтузиастов развили идею Open32: заметив, что формат EXE и DLL в Win32 (Portable Executable - PE) не успел далеко уйти от OS/2 (Linear eXecutable - LX), они выпустили конвертор - PE2LX.EXE. Win32-программа превращалась в OS/2-программу, импортировавшую библиотеки под теми же именами, но в OS/2'шном формате. Ресурсы по возможности/необходимости приводились конвертором к формату PM.

Соответственно, были написаны LX-аналоги USER32.DLL, KERNEL32.DLL и прочей системщины, составившие рантайм Win32-OS/2. Отсутствующие в PMWINX.DLL интерфейсы были доделаны вручную - появились WINMM, TAPI32, DDRAW, … Некоторые “несистемные” DLL, например, COMCTL32.DLL, предлагалось конвертировать из ближайшего дистрибутива WinNT. Все PE-библиотеки из комплекта устанавливаемого Win32-софта также подлежали конвертации.

LX-EXE (полученный из PE) LX-DLL (полученная из PE)
+--------------+ +--------------------+
|Вызовы несист.| ----> |Выз. сист. Win32-DLL|
| Win32-DLL | +----------||--------+ OS/2
| Вызовы сист. | +------\/----------+ Open32 +-----+
| Win32-DLL | --------> | Вызовы OS/2-DLL | -->[PMWINX]--> |*.DLL|
+--------------+ +------------------+ -------------> +-----+
| PM-ресурсы + | Рантайм Win32-OS/2
|Win32-ресурсы | (KERNEL32, USER32, GDI32...)
+--------------+

Благодаря конвертору требование перекомпиляции исчезло - первым примером работы Win32-OS/2 стал Quake II-OS/2, сделанный из Win32-бинарников. Оверхед - больший в сравнении с перекомпиляцией под Open32 (1.5-4M), но главное - принципиальная невозможность конвертации многих (например, сжатых) PE-EXE и отсутствие перспектив из-за прекращения развития Open32 API.

4. Project Odin

Для оживления Win32-OS/2 пришлось наращивать уровни абстракции. USER32.DLL и COMCTL32.DLL были перестроены на исходниках проекта WINE - элементы GUI отныне отрисовываются “с нуля”, и сходство с PM'ом было восстановлено только путем ручной имитации PM'ного оформления. Примером нового подхода был RealPlayer/Win32 из комплекта eComStation v 1.00.

PE2LX.EXE был официально заменен WIN32K.SYS и PE.EXE. Преобразование PE → LX происходит “на лету” внутри KERNEL32.DLL. Впоследствии команда выпустила новый PE2LX (XX2LX.EXE), который вместо полноценной конвертации порождал суррогат (грубо говоря, результатом был упрощенный LX-загрузчик с прикрепленным в “хвосте” слегка переваренным имиджем исходного PE-файла). Вопрос “какие DLL вызываются и надо ли их перегонять в LX?” быстро отошел на второй план.

По мере того, как проект переезжал на рельсы WINE, за Open32 остался только минимум API. В 2001 г. Innotek GmbH получил от IBM исходники WGSS46.DLL и части PMWINX.DLL, объединив их в closed-source модуль WGSS50.DLL. В результате проект Odin ныне упирается только в фундаментальные ограничения OS/2 и PM.

PE-EXE: Odin-рантайм: OS/2:

+———+ +-+——–++——–++ +———-+ |Win32-код|\→ PE.EXE/WIN32K.SYS → |K| USER32 || WGSS50 | → | PMMERGE | +———+ \ |E| GDI32 ++========++ | PMGPI |

\ +-PE-DLL:-+ |R| WINMM | | MDM |

LX (из PE): > |Win32-код| ←—> |N| DDRAW | | DIVE | +———+ / +———+ |E| ADVAPI32 | → | REGISTRY | |OS/2-stub| ———————→ |L| WSOCK32 | | SO32DLL | +———+/ |3| NTDLL ++========++ | DOSCALL1 | |модиф.код| ←——————–> |2| … || ODINCRT | → | … | +———+ +-+——–++———+ +———-+

Оверхед при такой схеме заметно вырос (4-10M + перерасход памяти на 10-20% по сравнению с NT), Помимо этого, многообразие “прослоек” сильно сказалось на быстродействии и стабильности.

5. Odin Custom-Build (INNOWIN.DLL, OPODIN32.DLL, VPCWIN32.DLL, …)

Поскольку PE.EXE отменил необходимость наличия отдельных USER32.DLL/GDI32.DLL и т.д., появилась возможность собирать требуемые модули в одну общую DLL и загружать с ней как OS/2'шные (перекомпилированные) приложения, так и исходные Win32'шные. При этом новому билду можно назначить собственную ветку в Registry, которую не затронут эксперименты юзера с “общим” Odin'ом.

Первый пример - Opera/2 v 5.12 (1999-2002) - тщательно проработанный порт браузера в OS/2, собранный VisualAge C++ в родной LX-EXE и использующий Odin наравне с некоторыми нативными API. Имея внутри Odin'овскую KERNEL32.DLL, порт может подгружать Win32-плагины в неизменном виде.

OPERA*.EXE (LX) OPODIN32.DLL OS/2

+————–+ +——–++——–+ +—————–+ | | ————> | USER32 ||OPWGSS50| → | | | | | GDI32 |+========+ | | |Портированная | PE-DLL | … || OPCRT | | | | часть | +———–+ | … ++======+-+ | Системные | | | | Win32- | | KERNEL32 + | → | *.DLL | | | | плагины |↔| PE-загрузчик | | | | | +———–+ +—————-+ | | +————–+ | | | OS/2-код | ————————————–> | | +————–+ +—————–+

“Новый” XX2LX.EXE нашел применение в Innotek Virtual PC for OS/2 (2001-2002), где исходники собирались уже Visual C++ v 6.0, а результирующий PE-EXE переводился под OS/2 с помощью конвертора. Этот же проект привнес в KERNEL32 роутер запросов к драйверам - для портирования софта, где часть операций выполнялась в привилегированном режиме через драйвер (драйвер, естественно, переписывался с нуля).

VPC.EXE (PE→LX) VPCWIN.DLL OS/2 +————–+ +——–++——–+ +—————–+ | OS/2-stub | ————> | USER32 ||VPCWGSS | → | | +————–+ | GDI32 |+========+ | Системные | | Модифицир. | +———-+ |KERNEL32|| VPCCRT | → | | | | | R0-helper| | … ++=======++ | *.DLL | | Win32-код | |VPCAPP.SYS|←-| роутер IOCtl'ов | | | +————–+ +———-+ +—————–+ +—————–+

В последующих проектах (2004 г.) Innotek окончательно спрямил XX2LX.EXE до формулы “PE.EXE + Win32-модуль в одном бинарнике”. В Java и OpenOffice соответствующие *.EXE состоят из типового LX-загрузчика, следом за которым идет полная копия исходного Win32-EXE и указатель на его начало.

Заодно был введен единый closed-source рантайм INNOWIN.DLL, поглотивший WGSS и ODINCRT (рантайм VisualAge), а вся специфика конкретных портов при необходимости выносилась в мелкие “объединительные” модули.

SOFFICE.EXE, JAVA.EXE OS/2

+———————+ Запрос путей к DLL через Registry +————–+ | Универсальный |———————————–> | | | OS/2-stub |-+ | | +———————+ | Объединительный модуль | | | | | +———————-+ | | | | +→| OOWIN.DLL, J2WIN.DLL | | Системные | | Немодифицированный | +———-||———-+ | *.DLL | | Win32-код | || | | | | +———-\/———-+ | | | |←→| INNOWIN.DLL | —→ | | | | +———————-+ | | +———————+ Innotek Win32 Runtime +————–+

Параллельно были изобретены врапперы для плагинов к Netscape (Java, Acrobat Reader и Flash 7). Они базируются на общем прототипе под названием NPOdin и обращаются через INNOWIN-рантайм к Win32-плагину для Netscape, который в свою очередь может взаимодействовать с любыми PE-DLL из Win32-мира:

LX : PE
Flash 6/Flash 7: :
+------------+-------------------------+--------------+
| NPSWF2.DLL | FLASHWIN.DLL | NPSWF32.DLL |
+------------+-------------------------+--------------+
:
Innotek Kit for Java: :
+------------+-----------+-------------+--------------+
| NPJ2.DLL | J2WIN.DLL | INNOWIN.DLL | NPOJI610.DLL | -> Sun JRE/Win32
+------------+-----------+-------------+--------------+
:

Yuri Dario выпустил комплект для самостоятельного изготовления врапперов к Win32-плагинам - NpWrap. Врапперы работают с обычным Odin (не с INNOWIN), по архитектуре NpWrap аналогичен NPOdin, но объединительные модули здесь не требуются.