Программа из девяностых отказывается ставиться на свежую систему и жалуется на нехватку места на терабайтном диске? Чаще всего файл цел, а сломан диалог: программа задаёт системе вопросы, рассчитанные на версию Windows тридцатилетней давности. Шим совместимости перехватывает эти вопросы и подставляет удобные ответы, после чего программа живёт так, будто никуда не переезжала. Код менять не нужно: система подстраивается сама, в момент запуска.

Механизм шима подменяет ответы системы в момент запуска программы

Пользователь дважды щёлкает значок, и в эти доли секунды загрузчик Windows сверяет файл с базой данных совместимости. Главный такой файл называется sysmain.sdb и лежит в папке C:\Windows\AppPatch; в обычной системе в нём тысячи записей, и каждая привязана к конкретному .exe. Совпадение ищется не по имени, а по набору признаков: имя, размер, контрольная сумма, номер версии, сведения о производителе. Поэтому шим не цепляется к соседям по папке, он срабатывает строго на тот бинарник, для которого создан.

При совпадении в новый процесс подгружаются библиотеки вида AcLayers.dll и AcGenral.dll из той же папки AppPatch. Они встраиваются между программой и системными функциями: каждый вызов сначала проходит через прослойку, и прослойка решает, передать ли настоящий ответ или отдать выдуманный. Программа спрашивает версию Windows, получает ту, на которой умеет работать. Пытается записать настройки в защищённую папку, и запись уходит туда, где ей разрешено. Сам файл не меняется ни на байт, меняется среда, в которой он выполняется.

Исправления собраны в готовые наборы, которые называются режимами совместимости. Режим WinXPSP3 объединяет сразу несколько заплаток: WinXPSP3VersionLie подменяет номер версии, DirectXVersionLie подделывает версию DirectX, VirtualRegistry перенаправляет обращения к реестру, ElevateCreateProcess поднимает права при запуске дочерних программ, CustomNCRender отдаёт программе рамки окон в стиле XP. Готовый набор экономит время, ведь составляющие не нужно подбирать по одной.

С версиями у Windows вообще особые отношения. Начиная с Windows 8.1 система и сама врёт в обратную сторону: без специальной пометки в манифесте функция GetVersionEx докладывает номер 6.2, то есть Windows 8, какой бы файл ни спрашивал. Зато функции-помощники вроде IsWindows7OrGreater учитывают включённый режим совместимости и отвечают так, как требует шим. По сути, номер версии давно превратился в договорную величину.

Вкладка Совместимость в свойствах файла подбирает заплатку за минуту

Самый короткий путь вообще не требует команд. Щелчок правой кнопкой по файлу .exe → Свойства → вкладка Совместимость. Флажок "Запустить программу в режиме совместимости с:" открывает список систем от Windows 95 до Windows 8. Ниже блок "Параметры" с флажками "Режим пониженной цветности", "Использовать разрешение экрана 640 × 480", "Отключить оптимизацию во весь экран", "Запускать эту программу от имени администратора". Каждая галочка здесь является настоящим шимом: пониженная цветность включает набор Force8BitColor и DisableThemes, разрешение 640 × 480 – Force640x480, а отключение полноэкранной оптимизации – слой DisableDXMaximizedWindowedMode, собранный из DXMaximizedWindowedMode и DXGICompat.

Рядом находится кнопка "Запустить средство устранения проблем с совместимостью". Мастер сам прогоняет программу через несколько настроек, сначала предлагает "Рекомендуемые параметры", затем проверяет работу и предлагает сохранить то, что помогло. Тот же мастер доступен и без свойств файла: Пуск → Параметры → Система → Устранение неполадок → Другие средства устранения неполадок → Программа совместимости → Запустить. В актуальных сборках Windows 11 его открывает утилита csdt.exe, а в Windows 10 и более ранних версиях тот же сценарий вызывался командой из командной строки:

msdt.exe -id PCWDiagnostic

Команду вводят в окне командной строки, и после запуска откроется то же окно мастера с выбором программы и подбором настроек.

Результат любого из этих действий оседает в реестре. Ветка HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers хранит настройки текущего пользователя, ветка HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers – настройки для всей машины. Параметр в них называется полным путём к программе, а значение выглядит как строка "~ WINXPSP3 256COLOR 640X480": тильда помечает настройки, поставленные через интерфейс, дальше идут коды режимов. Посмотреть накопившееся можно командой, выполненной в командной строке:

reg query "HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers"

На экране появится перечень программ со всеми включёнными флагами совместимости. Значения удобно переносить на другой компьютер или раздавать скриптом, например так:

reg add "HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers" /v "C:\Games\oldgame.exe" /t REG_SZ /d "~ WINXPSP3 256COLOR 640X480" /f

Путь к программе и коды режимов здесь меняют под себя, а после выполнения команды настройки появятся на вкладке Совместимость при следующем открытии свойств файла.

Встроенные исправления VersionLie и VirtualRegistry врут программе в её же интересах

Каталог готовых заплаток у Windows огромный, и у каждой есть история, похожая на анекдот из жизни старого софта. Целое семейство VersionLie – Win95VersionLie, Win98VersionLie, WinXPSP3VersionLie, VistaRTMVersionLie – просто выдаёт программе выдуманный номер версии. Установщик 1997 года при виде современной системы заявляет "Эта программа требует Windows 95" и бросает работу; после включения соответствующей заплатки он видит привычные цифры и спокойно доходит до финала. Похожим образом Win7RTMVersionLie отдаёт строку версии Windows 7 на любой запрос GetVersion, а DirectXVersionLie принимает параметр вроде 9.0.c.

Есть заплатки почти на любую фобию старого кода. EmulateGetDiskFreeSpace отвечает ровно 2 ГБ свободного места, если места больше: первые установщики не умели считать огромные диски и вопили о нехватке гигабайт там, где свободны сотни. GlobalMemoryStatusLie докладывает о файле подкачки размером 400 МБ, потому что старая программа отказывается верить большим цифрам. FakeLunaTheme на запрос темы оформления отвечает названием Luna из Windows XP. ForceAdminAccess отвечает "да" на проверку прав администратора, IgnoreMessageBox глушит назойливые окна с отладочными сообщениями, SystemMetricsLie подсовывает размеры элементов интерфейса из прежних версий.

Третий пласт касается запуска и прав. ElevateCreateProcess ловит ошибку ERROR_ELEVATION_REQUIRED и повторяет вызов CreateProcess с запросом повышения, из-за чего старые установщики перестают падать на жёстких проверках UAC. WRPMitigation имитирует успешную запись в защищённые системные файлы, VirtualizeHKCRLite переадресует регистрацию компонентов в личную ветку пользователя, CorrectFilePaths переправляет файловые операции туда, где программе разрешено писать, – для установочных файлов его включают в паре с CorrectFilePathsUninstall. Игровой набор тоже серьёзный: DXMaximizedWindowedMode переводит полноэкранные игры на DirectX 8 и 9 в развёрнутое окно, IgnoreAltTab убирает зависания на Alt+Tab, PopCapGamesForceResPerf чинит производительность в Bejeweled 2, а SecuROM7 разгребает последствия одной из самых капризных защит дисков.

Compatibility Administrator собирает личную базу исправлений для конкретной программы

Для самописной бухгалтерии или древнего складского клиента готового шима может не найтись. Тогда в дело идёт Compatibility Administrator из комплекта Application Compatibility Toolkit, который устанавливается вместе с Windows ADK. Инструмент ставится в двух версиях, 32-разрядной и 64-разрядной, и путать их нельзя: базу для 32-разрядной программы собирают в 32-разрядной версии, иначе утилита откажется работать и выдаст ошибку. Рядом устанавливается Standard User Analyzer, который показывает, к каким системным ресурсам программа тянется без спроса.

Собственная база собирается за несколько минут:

  1. в левой панели Compatibility Administrator щёлкнуть правой кнопкой по строке новой базы в разделе Custom Databases и выбрать Create New → Application Fix;
  2. ввести название программы и производителя, указать путь к .exe и нажать Next;
  3. на странице выбора системы отметить готовый режим совместимости или оставить None;
  4. на странице исправлений отметить отдельные заплатки вроде VirtualRegistry и CorrectFilePaths;
  5. на шаге matching information оставить минимальный набор признаков, по которым файл будет узнаваться;
  6. сохранить базу через File → Save.

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

Утилита sdbinst устанавливает базу совместимости тихо и без окон

Свежесохранённый файл .sdb сам по себе ничего не меняет: пока база не зарегистрирована, загрузчик о ней даже не догадывается. Регистрация выполняется щелчком по файлу или утилитой sdbinst.exe из командной строки, запущенной от имени администратора. Ключ -q делает установку тихой, без единого окна и предупреждения, и в этом случае ошибка видна только в Просмотре событий. Ключ -u снимает базу, причём удалять можно и по пути к файлу, и по идентификатору GUID, и по внутреннему имени. Типовые вызовы выглядят так:

sdbinst.exe "C:\Distrib\oldapp_fix.sdb"
sdbinst.exe -q "C:\Distrib\oldapp_fix.sdb"
sdbinst.exe -u "C:\Distrib\oldapp_fix.sdb"
sdbinst.exe -g {6586cd8f-edc9-4ea8-ad94-afabea7f62e3}

Первая команда ставит базу с обычным подтверждением, вторая делает то же молча, третья снимает её по пути к файлу, четвёртая удаляет по GUID. После установки база прописывается в ветке HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Custom, а сам файл оседает в папке C:\Windows\AppPatch\Custom. На сотню рабочих станций такое решение раскатывают сценарием входа или групповой политикой: скопировать файл и один раз вызвать sdbinst.exe, остальное система сделает при ближайшем запуске программы.

Список установленных баз удобно снимать через PowerShell перед ревизией. Команда читает ветку Custom и перечисляет имена баз:

Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Custom" | Select-Object PSChildName

Лишнюю базу из списка снимают командой -u, и следы эксперимента исчезают.

Границы шимов и ошибки, которые ломают программы вместо лечения

Шим чинит разговор с системой, но не сам код. Если программе нужен отсутствующий драйвер, если она несёт в себе 16-разрядный код, который 64-разрядная Windows не запустит в принципе, или если она рушится из-за собственных повреждённых данных, никакая подмена ответов не спасёт. Вторая ловушка – жадность: дюжина галочек, поставленных разом, иногда добивает программу окончательно, поэтому заплатки проверяют по одной и фиксируют рабочую комбинацию. Полезно помнить и про проверку результата: если собирать исправления с повышенными правами, тестировать их нужно под учётной записью обычного пользователя, иначе виртуализация и перенаправление работают иначе и показывают лучшее, чем есть на деле.

Следы таких экспериментов в системе заметны невооружённым глазом. Ветки Layers перечисляют настройки с тильдой, ветка Custom хранит установленные базы, а в HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\AppCompatCache копятся записи о файлах, которые система проверяла при запуске. По этим трём местам легко восстановить, что и когда меняли на рабочей станции, и это выручает при разборе давних загадок.

По сути, шимы – это признание в простом факте: операционная система помнит, как разговаривать с софтом из прошлых десятилетий, и хранит эти знания в штатных, документированных механизмах. Старая программа получает право на жизнь без единой правки её файлов, а тот, кто поддерживает парк машин, – спокойные ночи. Папка AppPatch на собственном компьютере тому подтверждение: система, скорее всего, уже давно незаметно подкручивает несколько программ за спиной владельца.