- PVSM.RU - https://www.pvsm.ru -
Это могла бы быть рождественская история со счастливым концом, но он не такой.
В канун рождества 2018 года заметил в списке проверенных приложений для ReactOS установщик .NET 4.0 и был приятно удивлён, что он успешно устанавливается и приложения запускаются. Но так как 4.0 давно не актуален меня посетила безумная идея — а что будет если попытаться установить версию 4.5?
Установщик сразу заявил что версия ОС не подходит. Запуск в режиме совместимости так же определялся им и устанавливаться отказался. Дела, всё закончилось не начавшись…
ReactOS разрабатывается как аналог Windows 2003 и версию он сообщает как 5.2. Для установки требуется как минимум 6.0, но тогда я решил что целиться лучше сразу на Windows 7 и стал искать как менять версию на 6.1. В коде по словам version/MajorVersion/MinorVersion нашлось несколько мест по всей системе, даже там где не ожидаешь. Заменив все пары 5.2 на 6.1 результат был нулевой — не стартовал даже установщик ОС. Дальнейший поиск вывел на freeldr и ntldr в boot — в 4 местах надо было заменить _WIN32_WINNT_WS03 на _WIN32_WINNT_WIN7. ОС установилась и сообщает нам что это 6.1. Отлично?! Нет. Почему-то с такой заменой ничего толком не устанавливается — ни VirtualBox Guest Additions, ни Firefox, ни .NET 4.0 и даже проводник падает через раз. Окей, значит надо создать ISO со всем необходимым и подключить его к виртуалке. Слава байтам, привод ещё работает и снова стартуем установщик с него. Ура! Он хотя бы стартует, но жалуется на отсутствие неких компонентов ОС:
Первый это сервис автоматических обновлений, второй — Trusted Installer. Ничего подобного у нас нет — действительно, зачем в ReactOS обновления Windows, а Trusted Installer не может быть по определению ибо он появился вместе с Windows 7. Так же в логе нашлась строка, что отсутствует некий wusa.exe. Ок, создаём заглушки для wusa.exe и wuauserv.dll для сервиса обновлений PR 355 [1]. Trusted Installer просто скопировал из Windows 7 32bit вместе с ключами реестра. Теперь установщик определяет наличие всего необходимого и остаётся лишь скрепить договор капелькой крови.
Процесс верификации файлов проходит успешно и стартует установка. Сразу получаем сообщение, что не хватает функции LCMapStringEx в модуле kernel32.
Ок, ищу функцию в коде и, вы удивитесь, она есть но почему-то не добавлена в экспорт-лист (spec-файлы рядом с CMakeLists.txt в корне каждой DLL). Сборка/Установка/Запуск и опять подобная ошибка. Что же, сценарий известен. После повторения этой процедуры 5-10 раз от прощёлкивания Enter-ом установщика нагугливается, что у ОС есть режим unattend-установки. Для этого нужно в файле bootbootdatabootcdunattend.inf включить UnattendSetupEnabled = yes. Супер, сани едут сами! Едут так быстро, что за чаем не успеваешь сходить — минуты две вся установка.
Так как ReactOS пишется как 2003, то код для 6.0+ никто особо не поддерживает. Такие места закрыты условиями #if _WIN32_WINNT >= 0x600, а то и вовсе #if 0 и их приходится приводить в рабочий вид. Недостающую функцию (хотя код её есть @$&^%!) добавить в экспорт (SleepConditionVariableCS требует RtlSleepConditionVariableCS) или где-то в SDK-заголовках разблокировать структуры/поля. Ещё более странный костыль с ntdll, kernel32 и advapi32 — для них зачем-то созданы дополнения в виде ntdll_vista, kernel32_vista и advapi32_vista в каждой из которых максимум 10-15 процедур, при этом в kernel32 есть целых два файла vista.c. Лебедь, рак и щука, не иначе, принимали такие решения. Сейчас определённости так же нет — при выкладке ПРа на гитхабе один просит вынести код в *_vista-либу, второй пишет что достаточно закрыть экспорт условием -version=0x600+ в spec-файле. Больше всего тут удивляет то, что все такие функции это новое API и вполне могут мирно сосуществовать с основным кодом, непонятно зачем городить такой огород.
Продолжались эти попытки на протяжении пары месяцев, но в итоге всё остановилось на том, что установщик зависал в середине процесса ни ругаясь, ни падая.
Летом решил вернуться к снаряду. Всё-таки столько времени потрачено, а результат нулевой. На этот раз решил делать всё иначе — раз при подмене сообщаемой версии с 5.2 на 6.1 всё работает вкривь и вкось, то надо менять версию совсем с другой стороны — попытаться собрать ReactOS полностью в режиме NT6.
Для этого надо в корневом CMakeLists.txt заменить следующие условия 0x502 на 0x600. Да, тут уже не до жиру, хотя бы 6.0 получить на выходе.
# Version Options
add_definitions(-DWINVER=0x502
-D_WIN32_IE=0x600
-D_WIN32_WINNT=0x502
-D_WIN32_WINDOWS=0x502
-D_SETUPAPI_VER=0x502)
Ожидания успеха от этой затеи изначально были так себе, хотя идея в целом верная.
Суть проблемы в том, что в ядре NT6 многие функции изменили сигнатуры, структуры данных отличаются составом и порядком полей.
#if (_WIN32_WINNT >= 0x600)
NTSTATUS
RxConstructSrvCall(
_In_ PRX_CONTEXT RxContext,
_In_ PIRP Irp,
_In_ PSRV_CALL SrvCall,
_Out_ PLOCK_HOLDING_STATE LockHoldingState);
#else
NTSTATUS
RxConstructSrvCall(
_In_ PRX_CONTEXT RxContext,
_In_ PSRV_CALL SrvCall,
_Out_ PLOCK_HOLDING_STATE LockHoldingState);
#endif
Ошибки сборки сыпались как из рога изобилия, самые простые из которых были в том что в CMake-файлах некоторых dll WINVER и _WIN32_WINNT явно переназначались на иные значения, например 0x602. При этом в ReactOS полно dll, у которых и сейчас WINVER переопределён с 0х502 на 0х600. Нашлось и несколько настоящих багов #356 [2] #359 [2] #747 [3] #814 [4] #815 [5].
Длилось это так же месяц-два и в итоге со всеми костылями образ собрался, но вот установщик не подавал признаков жизни совсем. Помучавшись немного ещё запал пропал
Грядёт новое рождество, а .NET 4.5 не даёт покоя. Вновь возвращаюсь к первому варианту, повторяются все правки, но с некоторыми изменениями. Если раньше вместо недостающих функций (для которых нет кода в ОС) делал просто заглушки, то теперь решил поискать их в коде Wine и, о чудо, там они были. Перенести, адаптировать под ReactOS, к следующей #1045 [6]. Где-то вместо заглушки можно и настоящего кода написать :) #1046 [7]. С такими правками установщик работал уже по-бодрее и даже завершался «успешно», но в отличие установщика .NET 4.0 не предлагал выполнить перезагрузку после установки — я списал на то, что все таки софт для нового поколения ОС и нет нужды перезагружаться каждый раз (ха ха, святая наивность). При попытке запустить helloWorld-приложение на экране не происходило ничего, в task manager тоже не успевал заметить какую-то активность.
Немного позже решил покопаться в ресурсах установщика, где нашел текст сообщений об ошибках и ВОТ СЮРПРИЗ — все ограничения указаны в файле ParameterInfo.xml! Достаточно было закомментировать StopBlockers-условие IsInOSCompatibilityMode и всё стартует без проблем. Убираю правки, которые меняют версию ОС с 5.2 на 6.0, включаю в ярлыке к setup-у режим совместимости с Vista (так он не ожидает наличие Trusted Installer) и добавив ещё немного функций установщик завершался так же «успешно». Однако если сперва установить 4.0 и потом запустить установщик 4.5, то процесс завершился уже с просьбой перезагрузиться! Победа!? Нет. Я же говорил что это сказ без хэппи-энда. При попытке запустить HelloWorld результат немного отличается, но не сильно — процесс занимает 11-12МБ памяти и, повисев секунд 20, завершается. Запуск в режиме совместимости не помогает (всё-таки CLR-runtime запускается в каждом процессе отдельно, а не одна общесистемная среда, которая стартует вместе с ОС с версией ОС 5.2).
В логе видим вызовы на определение версии:
Добавил в RtlVerifyVersionInfo хак, что если запрашивается версия 6.*, то подменить версию ОС на 6.0. Отмеченные стрелкой строки ушли, но результат тот же.
Не хэппи-энд.
Возможно до успеха осталось совсем немного и вы, вдохновились этим рассказом, готовы подхватить флаг и закончить начатое скачав код ReactOS и собрав её? Не так быстро. Почти по всем ПР на сделанные изменения при их выкладке сперва идёт какое-то обсуждение, но потом они висят без внимания основных разрабов ОС.
Для того что бы повторить описанное надо на мастер-ветку накатить ПРы по ссылкам в тексте, разблокировать пачку функций в spec-файлах (заменить версию в условии -version на 0x500+) и несколько 0x600-условий в заголовках
msvcrt
kernel32
Если вы следите на развитием ReactOS и пробуете установить свежее приложение, то наверняка сталкивались с тем, что не хватает каких-то функций либо интересный/полезный ПР висит бесконечно. Мне это тоже знакомо и потому решил регулярно составлять сборку ОС с недостающими кусками и ПРами (хочу держать график еженедельно или раз в две недели). Попробуйте эту сборку, возможно она будет полезна! Пишите если столкнётесь с очередной отсутствующей функцией — высока вероятность что она уже лежит в коде ReactOS или есть в Wine. USB-драйвера в ней пока нет.
Скачать можно здесь [8]
С новым годом и стабильного ReactOS-а!
Автор: Getequ
Источник [9]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/open-source/304103
Ссылки в тексте:
[1] PR 355: https://github.com/reactos/reactos/pull/355
[2] #356: https://github.com/reactos/reactos/pull/356
[3] #747: https://github.com/reactos/reactos/pull/747
[4] #814: https://github.com/reactos/reactos/pull/814
[5] #815: https://github.com/reactos/reactos/pull/815
[6] #1045: https://github.com/reactos/reactos/pull/1045
[7] #1046: https://github.com/reactos/reactos/pull/1046
[8] здесь: https://getequ.000webhostapp.com/2018/12/first-build
[9] Источник: https://habr.com/post/435050/?utm_source=habrahabr&utm_medium=rss&utm_campaign=435050
Нажмите здесь для печати.