Найти тему
Василий Волченко

На пути к "продвинутому пользователю": ещё раз об архитектурах - Win16, Win32, Win64, и немного - о совместимости

Итак, ещё раз остановимся на архитектурах программного обеспечения, на этот раз будем говорить, преимущественно, о ПО для Windows.

Сейчас мы не будем обсуждать версии Windows for ARM(64) - это большая и отдельная тема, хоть и не так часто с ними можно столкнуться, также обойдём стороной виртуальные машины (.NET, JVM), оставим в покое универсальные приложения (Metro, ModernAPP, UWP, Appx - как их ни называй). DOS тоже оставим в покое.

Что мы можем встретить на сегодня? Допустим, есть какая-то программа, которую Вы скачали, предназначена она для Windows. Запускаем... А не запускается. Надо выяснить, почему. Кто-то скажет: "просто не установлены библиотеки", и процентах в 60 случаев будет прав. Ещё процентов 20 отведём на банальную несовместимость, особенно в случае с играми: приложение разработано для одной ОС, и даже не предполагает, как надо себя вести на другой. Режим совместимости иногда помогает, иногда - не особо, но этот случай тоже оставим в покое. И тогда остаётся лишь вариант с архитектурой.

Понятно, что архитектура Windows предполагает, что программа когда-то была написана под Windows, ПО для Mac, Linux и всяких телефонов мы скачивать не будем. Если таки скачали - отправляем туда, для чего оно предназначено, ну или в эмулятор, если таковой есть. Но может быть, что на нашем ПК (включая ноутбуки и планшеты с Windows, кроме RT) просто другая архитектура. Какие же они бывают?

1. Win16. ПО создано под 16-разрядную Windows. То есть, Windows 3.x (более старое - совсем уже экзотика, и шансов запустить мало). Казалось бы, древность древностью, актуально в первой половине 90-х. Причём должно встречаться ещё реже, чем DOS. Но не совсем так... То тут, то там всплывает что-то из начала "нулевых", а то и вообще единственно актуальное, что до сих пор имеет эту архитектуру. Давайте поговорим о ней подробнее.

Итак, Windows 3.x. Три режима: реальный (существовал только в 3.0, редкий и мало чего поддерживает, так что оставим его), стандартный (работал на i286 и выше) и 386-расширенный (очевидно, требовал не ниже чем i386). Тем не менее, большинство приложений разрабатывались именно в виде Win16 (в конце эры Windows 3.x всё больше появлялось приложений Win32s, но они уже относятся к другой архитектуре). Что это такое?

Приложение Win16 предполагает, что процессор находится в защищённом режиме, то есть, в принципе, все команды оперируют 16-разрядными данными. А вот адрес не совсем 16-разрядный. Да, основная его часть именно 16-разрядная (это адресация только 64 килобайт адреса, ну плюс столько же данных), но есть ещё сегментные регистры. Не будем говорить о том, как "криво" расширили адресное пространство в i8086, в данном случае эта одномегабайтная модель почти не работает (кроме селектора 0040h). Адресация идёт в режиме селектор:смещение, то есть, теоретически, с точки зрения программы адресуется столько же памяти, что и в 32-разрядном режиме (4 Гб). Практически, конечно, этого нет (тогда о таких объёмах на пользовательских компьютерах речь и не шла!), защищённый режим ограничен 16 Мб памяти, а 386 расширенный в Win3x не давал адресовать больше 64 Мб физической памяти (но и это тогда было не просто много, а очень много). Но факт остаётся фактом: у приложений Win16 данные были, преимущественно, 16-разрядными (т.е., "родной" целочисленный тип int16 был от -32768 до 32767). Впрочем, это у приложений Win16 было не главным. Главной особенностью, которая позже уже почти нигде не встречалась, была кооперативная многозадачность. Что это значит? А вот что. Программа Win16 запускается, рисует окошки (через функции WinAPI, разумеется) и в какой-то момент получает управление. Ну, пользователь нажал на кнопку, например. Это управление она не потеряет, пока не закончит обрабатывать событие. Ну или специально не скажет WinAPI дать и остальным поработать. Если реакция на нажатие этой кнопки была бы мгновенной - ну, выдать там сообщение на экран, или же рассчитать что-то очень простое - никто ничего и не заметит. А вот если необходимо провести серьёзную обработку данных, сложные расчёты, работу с файлами или вообще управление каким-то оборудованием - это может создать проблемы. Нет, прерывания никто не отменял, мышка будет ездить по экрану, щелчки будут собираться - и всё. Ничего более длительного. Все остальные приложения должны будут подождать. Иногда - долго, пока программа не удосужится вернуть управление системе. Иногда - навсегда, если возникнет бесконечный цикл. Да, грамотные программисты в большой цикл встраивали цикл обработки сообщений (MessageLoop), и система жила - но кто привык писать для DOSа, или кто не ожидал зависания в каком-то месте - легко одной программой вешал систему. Причём вешалась и Windows 3.1 (в стандартном режиме - с концами, в расширенном - с шансом снять приложение), и последующие Windows 95, 98, Me. С другой стороны, те, кто писали программы для сложного управления оборудованием (например, хроматографами), мог быть уверен, что в критический момент система не займётся чем-то более "важным", вытеснив управляющую программу на несколько секунд (мало ли чего наоткрывал пользователь, а слабые ПК тогда были не редкостью). Вот и писали такие вот управляющие программы как приложения Win16 (иногда - DOS, но там разговор особый). В Windows NT (а также 2000, XP, Vista, 7, 8, 10) в 32-разрядной системе подсистема Win16 - вполне вытесняема, поэтому приложение Win16 сможет повесить только остальные приложения Win16, но не всю систему.

Ещё один аспект, который нужно учитывать при использовании приложений Win16 - они не видят и никак не понимают длинные имена файлов. Возможно, сейчас кто-то уже вообще о них не знает, а раньше они были серьёзной проблемой. Ведь DOS работает только с короткими именами в формате 8+3 (имя файла не длиннее 8 символов, расширение - не длиннее 3). Windows 3.x, как, по сути, надстройка над DOS, тоже работала в том же режиме. Но, начиная с Windows 95, создаваемой изначально не только (и не столько) для IT-шников, в Microsoft сделали вывод, что этого мало. Что домохозяйке будет лучше назвать файл со своим любимым рецептом не RCPT_034.DOC, а "Мой любимый рецепт пирога.doc". Вот именно так, с пробелами.

Это создало немало проблем потом, многие приложения не понимали, что путь "C:\Program Files\MySoft\MyProg.exe" - это один файл, а не два разных параметра... Но это - отдельный разговор, как и дискуссия о том, в чём легче запутаться. Главное - в файловую систему FAT встроили (достаточно криво) в дополнение к короткому имени длинное имя файла (получив VFAT). Сколько с этим было пороки - когда нарушалось соответствие, когда шла проверка Scandisc'ом и т.д. Так вот: приложение Win16 видит только короткие имена файлов. И если с имеющимися длинными оно как-то ещё может сработать, то новых не создаст (разве что нештатным образом через командную строку). А короткие имена в верхнем регистре могут казаться "белыми воронами" на фоне имеющихся. Кстати, система NTFS коротких имён не имеет. Но правило преобразования никуда не делось, поэтому приложения Win16 будут "видеть" несуществующие короткие имена файлов и на NTFS.

2. Платформа Win32. Впервые платформа появилась в той же Windows 3.x, но уже только для 386 расширенного режима, и только при установке пакета Win32s. Система была достаточно "убогой", поэтому запустить что-то серьёзное на Win32s не получится, полноценное WinAPI было уже в Windows 95 и в линейке Windows NT. Более того, с каждой новой системой WinAPI серьёзно дорабатывалось, поэтому в конце "нулевых"-начале "десятых" большинство актуальных (на тот момент) программ не запускалось под Windows 2000, сейчас большинство не запустится и под XP.

Адресное пространство - 32-разрядное, данные - преимущественно 32-разрядные. Программа безусловно адресует 4 Гб адресного пространства (хотя не всё оно может быть именно памятью, могут быть и служебные участки для драйверов). Как следствие, если у Вас 64-разрядная система и 16+ Гб оперативной памяти, но Вы запускаете тяжёлое приложение Win32 (например, одна из последних 32-разрядных игр - TESV: Skyrim), это приложение будет "ютиться" в 4 Гб.

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

Архитектура актуальна и широко используется, приложения могут запускаться (при условии совместимости версии WinAPI и наличия необходимых библиотек, ну и инструкций процессора, разумеется) на любой 32-разрядной и 64-разрядной ОС семейства Windows для процессоров Intel. Исключения: установщик Windows x64 (в нём урезана подсистема Win32), специальные версии Windows (например, Windows S), где запуск приложений WinAPI ограничен, ну и системы для других платформ, разумеется. Хотя Windows 10 ARM64 запускает приложения Win32, эмулируя подсистему x86.

3. Win64. Ну, здесь всё понятно. Архитектура максимально совместима с Win32, но использует архитектуру AMD64. Есть один нюанс: использование сопроцессора становится лотереей, ОС не отвечает за сохранность его регистров. Отсюда проблема для программиста-любителя: типа Extended (FLOAT80) в Win64 нет, он приравнен к Double. Это может создать проблемы при портировании старых программ. Понятно, что приложение Win64 запустить под 32-разрядной системой без эмулятора не получится.

Впрочем, для 64-разрядных Windows есть ещё одна проблема: драйвера. Если обычные приложения Win32 запускаются под x64 почти как родные, проблем не наблюдается, то эмуляцией слоя драйверов в Microsoft не заморачивались. Впрочем, и в Linux тоже, за исключением отдельных проектов, держащихся на энтузиастах-одиночках. То есть, при переходе к Win64 все драйвера были переписаны. Которые не были - не заработали. Впрочем, не привыкать - переход от Win9x к 2000-XP тоже сопровождался 100%-й заменой драйверов.

И ещё одна проблема Win64, которая сначала не была очевидна. Microsoft не удосужилась встроить подсистему Win16 в системы Win64 (от XP до 10). Отсюда возникли проблемы. Первая, весьма неожиданная - инсталляторы и самораспаковывающиеся архивы. К началу нулевых Win16 большей частью устарело, но поддерживалось везде, поэтому разработчики по привычке инсталлятор писали в виде кода Win16. То есть, сама программа под Win32 запустится, но установить её штатным образом не выходит.

Второй аспект - специализированное ПО "реального режима". Как я уже сказал, его писали под Win16. Но здесь особого выбора нет.

Как запустить ПО Win16 под Windows x64?

1. Запустив в эмуляторе Windows 3.1. Можно взять хоть DOSBox. Проблема № 1 - нет взаимодействия с Win32. Проблема № 2 - лицензия. Без комментариев.

2. Запустить в эмуляторе любую более актуальную систему Windows x86 (от 95 до 10). Проблемы № 1 нет, проблема № 2 осталась (хотя решения есть).

3. Для последних сборок Windows 10 с WSL2 - установить подсистему Linux, перевести её в WSL2, установить сервер X (например, MobaXTerm), совместимый Wine (у Wine 5.x есть проблемы, у Wine 3 - нет). Linux для AMD64 позволяет запускать в Wine приложения Win16. Вот так вот. Хотя WSL2 - уже эмуляция. Кто не понял - может, ему это и не надо, используйте п.2.