Как работает совместимость приложений Windows — режим совместимости, шимы и Compatibility Administrator

· · Windows, Режим совместимости, Шимы, Совместимость приложений, Compatibility Administrator, Использование существующих активов, Разработка под Windows, Существующие системы

«Десятилетнее бизнес-приложение, исходников которого уже нет, не стартует на новом ПК с Windows 11. Я поставил галочку “Windows XP” на вкладке “Совместимость” диалога свойств — и оно просто заработало. — Что это на самом деле делает? Можно ли и дальше на это опираться?» Такой запрос мы слышим часто.

Когда одна галочка заставляет что-то работать, беспокойство естественно. Настоящая сущность режима совместимости, похожего на магию, — набор маленьких кусков кода, называемых шимами, которые встают между приложением и Windows API и возвращают «ложь». Сама Windows использует эту временную меру в больших масштабах, чтобы держать живыми приложения многих поколений, и открывает часть механизма пользователям и администраторам.

Без понимания механизма продление жизни становится нестабильным «нельзя трогать, потому что не знаем, почему работает». Поняв механизм, вы решаете с основаниями, насколько далеко можно спокойно опираться, что его сломает и когда стоит переписать.

Понимание механизма меняет качество продления жизниИспользование режима совместимости без понимания механизма ведёт к нестабильному продлению, которое боятся трогать; понимание механизма позволяет решать с основаниями, насколько можно опираться, что сломает и когда переписыватьИспользовать, не понимая механизмНестабильное продление, которое боятся трогатьИспользовать, поняв механизмРешения с основаниямиНасколько можно опиратьсяЧто его сломаетКогда стоит переписать

Рис. 1: Даже при одном и том же продлении качество различается между тревогой из-за незнания механизма и решением на основе понимания.

Статья для ИТ-сотрудников малого и среднего бизнеса и разработчиков Windows-приложений, которые ведут старые бизнес-приложения. По первичным источникам Microsoft Learn она собирает механизм шимов — настоящую сущность режима совместимости, — что умеют типичные шимы, как применять их в организации через Compatibility Administrator, пределы, которые шимы не спасают, и как решать между продлением жизни и миграцией.

1. Сначала вывод

  • Настоящая сущность режима совместимости — шимы (слой совместимости). Настройки вкладки «Совместимость» пишутся в HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers, и при старте к процессу применяется набор шимов.12
  • Шим — это перехват API в пользовательском режиме, переписывающий таблицу адресов импорта (IAT). Он перехватывает путь, по которому приложение вызывает Windows API, и возвращает те же ответы, что давала старая Windows. Саму ОС он не меняет.3
  • То, что умеет шим, совпадает с тем, что умеет правка кода в приложении. Он не обходит механизмы безопасности и не чинит проблемы режима ядра (драйверы устройств).3
  • Microsoft поставляет много готовых шимов — ложь о версии, переназначение путей файлов, подмена реестра, подмена проверок администратора и другое. Их можно применять к отдельным EXE из Compatibility Administrator.4
  • Сама Windows по умолчанию использует шимы. Стандартная база совместимости ОС (.sdb) сопоставляется при каждом запуске, а PCA (Program Compatibility Assistant) может обнаружить проблему и автоматически применить настройку совместимости.15
  • «Отвечать так, будто это более старая Windows» теперь поведение по умолчанию. Начиная с Windows 8.1 GetVersionEx не возвращает версию ОС, которую приложение не объявило в манифесте. Режим совместимости — расширение этого механизма.67
  • Шимы не работают с 16-разрядными приложениями, зависимостями от драйверов ядра и прямым доступом к оборудованию. В частности, 16-разрядные приложения на 64-разрядной Windows вообще не запускаются.8
  • Для приложений, которые «требуют администратора, но на самом деле не нуждаются», стандартный ход — RunAsInvoker. __COMPAT_LAYER=RunAsInvoker подавляет запрос повышения и даёт приложению обычные права.9
  • Работа под шимом значит, что жизнь можно продлить пока, но настоящий путь — «сделать так, чтобы работало без шима». Если решили продлевать, зафиксируйте, какие шимы дают работу, и ведите это как материал для решения о переписывании.

2. Общая картина совместимости приложений — слои обратной совместимости, которые у Windows уже есть

Прежде чем говорить о шимах, перечислим механизмы, которые Windows уже имеет для старых приложений. Даже когда говорят «заработало в режиме совместимости», приложение на самом деле спасает один из этих слоёв или их сочетание.

Слой Что делает Типичная цель
Шимы (режим совместимости) Перехватывает вызовы API и подменяет те же ответы, что давала старая Windows Приложения, написанные под более старую ОС, в целом
Виртуализация UAC (файлы / реестр) Перенаправляет записи без прав в HKLM\Software или Program Files в пользовательский VirtualStore 32-разрядные приложения, написанные в расчёте на права администратора
WOW64 Запускает 32-разрядные приложения как есть на 64-разрядной Windows (даёт 32-разрядные представления реестра и файловой системы) 32-разрядные приложения в целом
Виртуализация DPI Заставляет приложение без поддержки DPI рисовать при 96 DPI и показывает его, растягивая растр Старые приложения на дисплеях с высокой плотностью

Виртуализация UAC — переходная мера для интерактивных 32-разрядных процессов без манифеста, и сама Microsoft называет её «временной технологией, которую мы намерены убрать из будущей версии Windows».10 Реальный вред перенаправления Wow6432Node и VirtualStore и как с ним жить подробно разобраны в «Registry 32-bit/64-bit Redirection and Virtualization Pitfalls»; эта статья держит шимы в центре и упоминает остальные слои только по необходимости.

Где стоит виртуализация UACВиртуализация UAC — переходная мера для интерактивных 32-разрядных процессов без манифеста; она перенаправляет записи в пользовательский VirtualStore, но сама Microsoft называет её временной технологией, предназначенной к удалению из будущей WindowsИнтерактивный 32-разрядный процесс без манифестаПрименяется виртуализация UACПеренаправлено в пользовательский VirtualStoreВременная технология, предназначенная к удалению

Рис. 2: Виртуализация UAC — переходная мера для 32-разрядных процессов без манифеста, и на неё нельзя опираться постоянно.

Заметка о виртуализации DPI: приложение, не объявившее осведомлённость о DPI, считается рисующим при 96 DPI (100%), и Windows растягивает растр для показа. Поэтому старые приложения выглядят «размытыми» на мониторе с высокой плотностью, а «Переопределить поведение масштабирования при высокой плотности» на вкладке «Совместимость» — переключатель этого поведения виртуализации.11

Как работает виртуализация DPIПриложение, не объявившее осведомлённость о DPI, считается рисующим при 96 DPI; Windows растягивает растр, поэтому оно выглядит размытым, а переопределение настроек высокой плотности на вкладке «Совместимость» переключает это поведение виртуализацииПереключает поведение виртуализацииПриложение, не объявляющее осведомлённость о DPIСчитается рисующим при 96 DPIРастр растягивается для показаВыглядит размытым на мониторе с высокой плотностьюПереопределить поведение масштабирования при высокой плотности

Рис. 3: Приложение без поддержки DPI считается 96 DPI и растягивается; переопределение на вкладке «Совместимость» — переключатель этой виртуализации.

3. Чем шим является на самом деле — перехват между API через перепись IAT

3.1. «Переводчик», который стоит между приложением и ОС

Исполняемый файл Windows (формат PE) вызывает API во внешних DLL через таблицу адресов импорта (IAT). Когда приложение вызывает GetVersionEx, оно лишь прыгает по адресу, записанному в IAT. Механизм шимов этим пользуется. При загрузке он переписывает запись IAT целевого API на адрес кода шима и вставляет себя между приложением и Windows. API, полученные динамически через GetProcAddress, обрабатываются перехватом самого GetProcAddress.3

Перехватив, шим может вернуть старый номер версии на «какая сейчас версия ОС?» или переназначить доступ к файлу в незаписываемое место куда-то ещё, а затем при необходимости вызвать настоящий API. Со стороны приложения кажется, что оно «работает на старой Windows»; со стороны ОС — что «работает воспитанное приложение». Шим — переводчик между ними.

Путь, по которому шим перехватывает вызов APIВызов API приложения идёт через IAT; перепись записи IAT на шим при загрузке позволяет шиму перехватить, подменить тот же ответ, что давала старая Windows, и затем при необходимости вызвать настоящий APIВызов APIПереписана на шим при загрузкеЕсли нужноОбрабатываются перехватомПриложениеЗапись IATШим (переводчик)Настоящий Windows APIПодменяет тот же ответ, что давала старая WindowsВызовы через GetProcAddress

Рис. 4: Шим перехватывает между приложением и Windows API. Переписывается IAT на стороне приложения; сама ОС не меняется.

Из этой конструкции следуют три важных свойства.3

  1. Шим выполняется как код на стороне приложения. Он не часть ОС, поэтому подчиняется тем же ограничениям безопасности, что и приложение. Шим не обходит механизмы безопасности ОС, и ослаблять настройки безопасности ради шима не нужно.
  2. То, что шим может исправить, может исправить и правка кода на стороне приложения. Шим — замена для случаев «нет исходников / не можем править»; он не сильнее правки кода.
  3. Только пользовательский режим. Проблемы совместимости драйверов устройств в режиме ядра шим не чинит.

3.2. База шимов (.sdb) и сопоставление

Таблица соответствия «какой шим применять к какому EXE» — это база шимов, двоичный файл с расширением .sdb. Целевые исполняемые файлы регистрируются в базе по атрибутам вроде имени файла, размера, контрольной суммы и версии (атрибуты сопоставления) и сопоставляются при старте процесса. Средства включают Appfix (шим), который внедряет перехват API, и Apphelp, который показывает сообщение «у этого приложения проблема совместимости». Набор нескольких шимов и флагов — это слой совместимости (режим совместимости).1

Легко упустить: это сопоставление идёт не только у приложений с включённым режимом совместимости, а при каждом запуске процесса. Windows поставляет стандартную базу ОС с исправлениями для тысяч известных приложений (файлы лежат в %WINDIR%\AppPatch), и на вашем ПК сегодня почти наверняка какое-то старое приложение стартует с прикреплённым шимом незаметно. Исправления совместимости от Microsoft поставляются как часть Windows и обновляются через Windows Update.3

Сопоставление базы шимов при старте процессаКаждый запуск процесса сопоставляется с базой шимов; если регистрация совпадает с атрибутами сопоставления, Appfix внедряет шим или Apphelp показывает сообщение, иначе процесс стартует как естьДаДаНетНабор шимов и флаговСтарт процессаСопоставить с .sdbИмя файла, размер и т. д.Есть регистрация?Appfix: внедрить шимApphelp: сообщениеСтартовать как естьСлой совместимости

Рис. 5: Сопоставление идёт при каждом запуске процесса, не только у приложений с включённым режимом совместимости.

3.3. PCA — механизм, который применяет шимы автоматически

Другой путь, по которому шим может примениться без намерения администратора, — PCA (Program Compatibility Assistant). PCA следит за выполнением приложений и, обнаружив признаки известной проблемы совместимости, предлагает пользователю применить исправление или в некоторых случаях применяет настройку совместимости автоматически. Например, приложению, которое падает, вызывая код в освобождённой DLL, назначают PINDLL, а приложению, которое не может писать в защищённый файл Windows, — WRPMITIGATION.5

Как PCA автоматически применяет настройку совместимостиPCA следит за выполнением приложений и, обнаружив признаки известной проблемы совместимости, предлагает пользователю применить исправление или в некоторых случаях применяет настройку совместимости автоматическиДаЧерез предложениеНекоторые случаиНетВыполнение приложенияPCA следитПризнаки известной проблемы?Какой случай?Предложить применить исправлениеПрименить настройку совместимости автоматическиВыполнить как естьПример: PINDLL или WRPMITIGATION

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

Сущность «я ничего не настраивал, но в какой-то момент флажок режима совместимости оказался включён» во многих случаях именно это. Это не сбой и не промах; Windows ведёт себя как задумано.

4. Что умеют типичные шимы

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

Шим Что умеет (кратко)
WinXPSP3VersionLie и другие шимы семейства VersionLie Возвращать указанную более старую версию на запросы версии ОС (подмена версии)
CorrectFilePaths Переназначать доступ к незаписываемому или несуществующему пути файла в другое место
VirtualRegistry Перенаправлять или подменять чтение и запись реестра (включая подмену версии и имитацию несуществующих ключей)
ForceAdminAccess Временно возвращать True на проверку «вы член группы Administrators?»
RunAsAdmin / RunAsHighest / RunAsInvoker Снаружи дать уровень выполнения, равный requireAdministrator / highestAvailable / asInvoker в манифесте
WRPMitigation Подменять успех записи в защищённые файлы ОС и ключи реестра, чтобы приложение могло продолжить
EmulateGetDiskFreeSpace Сообщать свободное место на диске максимум 2 ГБ (для приложений, которые переполняются на больших дисках)
GlobalMemoryStatusLie Подменять сообщаемые значения состояния памяти (для приложений, которые не проходят проверку памяти при старте)
LoadLibraryRedirect Загружать текущую DLL Windows вместо старой системной DLL, которую приложение несёт с собой

Глядя на список, большинство шимов — это «ложь, которая возвращает ответ, которого ждёт старое приложение». Диск не больше 2 ГБ, ОС — XP, вы администратор: они воссоздают, только внутри этого процесса, картину мира эпохи, в которой приложение родилось.

Подмена версии стала «официальным поведением по умолчанию»

Подмена версии — не особый хак. Начиная с Windows 8.1 значение, которое возвращает GetVersionEx, зависит от манифеста приложения. Приложению без объявления <supportedOS> в разделе <compatibility> манифеста всегда дают эквивалент Windows 8 (6.2), какая бы ни была фактическая ОС. Если объявление есть, возвращается значение до самой высокой ОС среди объявленных (например, если объявлено до GUID Windows 8.1, вы получаете 6.3 даже на Windows 11).67

Итак, «версия Windows, которую видит приложение», решается в этих наложенных ступенях.

  1. Возвращается значение до ОС, объявленной в манифесте (6.2, если объявления нет)
  2. Если применён режим совместимости (шим семейства VersionLie), возвращается версия выбранной ОС6
Как решается версия ОС, которую видит приложениеЗначение, которое возвращает GetVersionEx, решается наличием объявления supportedOS в манифесте; без объявления возвращается эквивалент Windows 8 6.2, с объявлением — значение до самой высокой объявленной ОС, а если применён шим семейства VersionLie, оно перезаписывается версией выбранной ОСНетДаДаНетЗапрос GetVersionExЕсть объявление supportedOS?Возвращается эквивалент Windows 8 (6.2)Значение до самой высокой объявленной ОСПрименён шим семейства VersionLie?Значение ОС, выбранное в режиме совместимостиЗначение возвращается как есть

Рис. 7: Версия Windows, которую видит приложение, решается наложенными ступенями манифеста и шимов.

Если внутреннее приложение «ветвится по версии ОС и, путано, считается восьмёркой, хотя это Windows 11», сначала подозревайте объявление supportedOS в манифесте. Наоборот, старое приложение, которое отказывается стартовать из-за проверки версии, с высокой вероятностью можно провести шимом VersionLie. Во многих случаях оно смотрит только на номер версии, а фактическое поведение на более новой ОС нормально.

Два симптома из-за версии и как с ними бытьЕсли внутреннее приложение считается восьмёркой, хотя это Windows 11, подозревайте объявление supportedOS в манифесте; старое приложение, которое отказывается стартовать из-за проверки версии, с высокой вероятностью можно провести шимом VersionLieСчитается восьмёркой, хотя это Windows 11Подозревать объявление supportedOSСтарт отказан из-за проверки версииПопробовать пройти VersionLieФактическое поведение на более новой ОС часто нормально

Рис. 8: Если суждение устарело — подозревайте манифест; если старт отказан — подозревайте VersionLie.

5. Что делает флажок режима совместимости

Настройки «Свойства → вкладка “Совместимость”» хранятся в ключе реестра AppCompatFlags\Layers. Настройки совместимости приложений DXGI и подобные используют тот же ключ как место указания слоя совместимости.2 Посмотрим на деле.

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

Для EXE, на котором на вкладке «Совместимость» заданы «Windows XP (Service Pack 3)», «Запускать эту программу от имени администратора» и «Переопределить поведение масштабирования при высокой плотности», вы увидите значение вроде следующего.

HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers
    C:\LegacyApp\Gyomu.exe    REG_SZ    ~ WINXPSP3 RUNASADMIN HIGHDPIAWARE

Типичные соответствия пунктов флажка и значений (проверено на Windows 11; имена пунктов и значения могут меняться по версии ОС).

Пункт вкладки «Совместимость» Записанное значение (пример) Что это на самом деле
Режим совместимости: Windows XP (Service Pack 3) WINXPSP3 Слой совместимости, который связывает подмену версии и несколько других шимов
Пониженный цветовой режим (8 бит / 256 цветов) 256COLOR Ослабление для старого цветового режима
Запускать в разрешении экрана 640 × 480 640X480 Запускать в низком разрешении
Отключить оптимизации полноэкранного режима DISABLEDXMAXIMIZEDWINDOWEDMODE Отключить оптимизации рисования в полноэкранном режиме
Переопределить поведение масштабирования при высокой плотности (Приложение) HIGHDPIAWARE Остановить виртуализацию DPI (растяжение растра)11
Запускать эту программу от имени администратора RUNASADMIN Запрашивать повышение при старте

Три пункта запомнить.

  • «Запускать эту программу от имени администратора» пишется в то же место. Режим совместимости и флаг повышения живут вместе в одном ключе Layers, и отсюда путаница «я включил режим совместимости, и повышение пришло / пропало». Прямой взгляд на значение разделяет их.
  • То, что записано в HKCU, — «настройка этого пользователя». Если задать через «Изменить параметры для всех пользователей» вкладки, пишется в одноимённый ключ на стороне HKLM и действует на всех пользователей. При раздаче в imaging сознавайте, на какую сторону пишете.
  • Флажок — только вход в готовые слои. Вкладка даёт выбрать лишь типичные слои; отдельные шимы выбрать и скомбинировать нельзя. Это делает Compatibility Administrator в следующей главе.
Путь от настройки вкладки «Совместимость» до действияНастройки вкладки «Совместимость» хранятся как путь EXE и значение в ключе AppCompatFlags Layers; при следующем старте этого EXE загрузчик читает значение и применяет соответствующий слой совместимости к процессуЗадать на вкладке «Совместимость»Сохранить путь EXE и значение в ключе LayersСледующий старт EXEЗагрузчик читает значениеПрименить слой совместимости к процессуHKCU только этот пользовательHKLM действует на всех пользователей

Рис. 9: Флажок на деле — запись в ключ Layers, а применение происходит при следующем старте.

6. Compatibility Administrator на практике — собрать и раздать пользовательский .sdb

6.1. Как получить и оговорки

Compatibility Administrator — инструмент из Windows ADK (Windows Assessment and Deployment Kit).12 После установки есть и 32-, и 64-разрядные издания, и для 32-разрядных приложений нужно 32-разрядное издание, для 64-разрядных — 64-разрядное.13

Есть ещё важная оговорка. Если запускать Compatibility Administrator с повышением (от имени администратора) и тестировать, виртуализация UAC и перенаправление ведут себя не как у реального пользователя, и можно ошибочно решить, что «исправлено». Всегда подтверждайте эффект исправления той же учётной записью и теми же правами, что у реального пользователя.4

Две оговорки при работе с Compatibility AdministratorИспользуйте 32-разрядное издание для 32-разрядных приложений и 64-разрядное для 64-разрядных и подтверждайте эффект исправления той же учётной записью и теми же правами, что у реального пользователя, а не в повышенном состоянии32-разрядное приложениеИспользовать 32-разрядное издание64-разрядное приложениеИспользовать 64-разрядное изданиеТест в повышенном состоянииМожно ошибочно оценить исправлениеТест с правами реального пользователяПодтвердить эффект

Рис. 10: Выбор 32- или 64-разрядного издания и подтверждение теми же правами, что у реального пользователя, — оговорки на входе.

6.2. Порядок сборки пользовательской базы совместимости

Схема такова.14

  1. В левой панели Compatibility Administrator создайте новую базу в «Custom Databases» и выберите «Create New» → «Application Fix»
  2. Введите имя приложения и имя поставщика и укажите целевой EXE
  3. Выберите применяемый режим совместимости (слой) — сначала попробовать набор вроде «совместимость с Windows XP» короче
  4. При необходимости добавьте отдельные исправления совместимости (шимы) — можно сузить до минимума вроде только VersionLie или только CorrectFilePaths
  5. Подтвердите условия сопоставления (размер файла, контрольная сумма, версия и так далее) и сохраните

Условия сопоставления — ключ к «применять это только к этому EXE». Базовых условий по умолчанию обычно хватает, но мы рекомендуем оставить условие, которое идентифицирует версию приложения. Это предотвращает аварию, когда старая ложь продолжает применяться к новой версии, когда поставщик позже выпустит исправленное издание.1415

Порядок сборки пользовательской базы совместимостиСоздайте Application Fix в новой базе, укажите имя приложения и целевой EXE, сначала попробуйте набор режима совместимости, затем при необходимости сузьте до отдельных шимов, подтвердите условия сопоставления и сохранитеСоздать новую базуВыбрать Application FixУказать имя приложения и целевой EXEПопробовать набор режима совместимостиПри необходимости сузить до отдельных шимовПодтвердить условия сопоставления и сохранитьОставить условие, которое идентифицирует версию

Рис. 11: Для Application Fix сначала пробуйте набор режима совместимости, сужайте до минимума и ограничивайте цель условиями сопоставления.

Сначала протестируйте созданный .sdb на проверочной машине. Когда работает как задумано, разворачиваете в организации.

6.3. Раздача через sdbinst

Команда, которая применяет пользовательский .sdb на каждом ПК, — sdbinst.exe (нужны права администратора).15

:: Install (-q is silent with no confirmation)
sdbinst -q "C:\Deploy\MyCorpFixes.sdb"

:: Uninstall (by file)
sdbinst -q -u "C:\Deploy\MyCorpFixes.sdb"

:: Uninstall (by database GUID)
sdbinst -q -u -g {database GUID}

Как стратегию организационного развёртывания Microsoft рекомендует свести в одну общефирменную (или ведомственную) пользовательскую базу и вести её централизованно, а не возить отдельный .sdb с установщиком каждого приложения. Чем больше исправлений, тем проще обновлять и перераздавать одну базу, чем раздавать много однострочных. У пользовательской базы свой GUID, и установка новой версии с тем же GUID автоматически заменяет старую, поэтому операции обновления тоже остаются простыми. Саму раздачу положите на существующий путь, который может идти с правами администратора, например упаковку в MSI или сценарий автозагрузки.15

Путь от создания пользовательского .sdb до раздачиСоздайте пользовательскую базу совместимости в Compatibility Administrator, протестируйте на проверочной машине, примените на каждом ПК через sdbinst и при обновлении установите новую версию с тем же GUID, чтобы старая заменилась автоматическиСоздать в Compatibility AdministratorПротестировать на проверочной машинеПрименить на каждом ПК через sdbinstУстановить новую версию с тем же GUIDСтарая версия заменяется автоматическиРегистрируется в «Программы и компоненты»

Рис. 12: Пользовательский .sdb разворачивается через создание, проверку и раздачу sdbinst, а обновления ведутся по GUID.

Установленная пользовательская база регистрируется как пункт в «Программы и компоненты (Установленные приложения)», поэтому инвентарь и удаление можно подтверждать и оттуда. Какие ПК имеют какой .sdb — сведения для реестра учёта активов.

7. Случаи, когда не работает, и пределы

Шимы — не серебряная пуля. По конструкции они не работают в следующих случаях.

  • Проблемы режима ядра. Шим выполняется внутри процесса пользовательского режима, поэтому несовместимость драйвера устройства не исправить. Если драйвер старого измерительного прибора, USB-донгла или принтера не поддерживает Windows 11, что бы вы ни применили на стороне приложения, это не решит. Код в ядре, например части антивируса, то же самое.3
  • 16-разрядные приложения. 64-разрядная Windows не поддерживает выполнение 16-разрядных приложений. У дескрипторов на 64-разрядной Windows 32 действительных бита, и их нельзя обрезать, чтобы передать 16-разрядному приложению, поэтому старт падает с ERROR_BAD_EXE_FORMAT.8 Даже если само приложение 32-разрядное, у пакетов той эпохи бывает 16-разрядная заглушка установщика, и это выглядит как «приложение бы работало, но установить нельзя».
  • Прямой доступ к оборудованию. Промышленные приложения, которые предполагают прямое обращение к портам ввода-вывода или физической памяти, в современном Windows из пользовательского режима на это не имеют права, и это за пределами того, что шим может подменить.
  • Обход механизмов безопасности. Поскольку шим идёт под теми же ограничениями безопасности, что и приложение, он не делает возможным «то, чего нельзя из-за нехватки прав». ForceAdminAccess и WRPMitigation лишь подменяют успех проверки или записи, чтобы приложение могло продолжить; они не переписывают защищённый ресурс по-настоящему.34
  • Приложения, которые проверяют свою целостность. Приложения со старой защитой от копирования или обнаружением подделки могут счесть сам перехват API аномалией и перестать работать.
Случаи, когда шим не работаетШим выполняется внутри процесса пользовательского режима, поэтому не работает на проблемах драйверов режима ядра, 16-разрядных приложениях, прямом доступе к оборудованию и обходе механизмов безопасностиНе работаетНе работаетНе работаетНе работаетШим (выполняется в пользовательском режиме)Драйвер ядра16-разрядное приложениеПрямой доступ к оборудованиюОбход механизмов безопасностиНа 64 разрядах падает уже сам стартЛишь подменяет успех, чтобы приложение продолжило

Рис. 13: Шим только в пользовательском режиме и не достаёт до ядра, 16-разрядных приложений, прямого доступа к оборудованию и обхода безопасности.

И существенный предел, общий для каждого шима: это временная мера. Шим — ложь, заточенная под конкретное использование конкретного API, и если реализация на стороне ОС меняется, предпосылка рушится. Шимы от Microsoft поддерживаются как часть Windows через Windows Update,3 но ухаживать за ложью, которую вы применили пользовательской базой, — работа вашей организации. Заложите в бюджет, как стоимость продления жизни, операцию, которая проверяет «список приложений, которых держат живыми шимы» при каждом обновлении функций.

Шимы как временная мера и кто отвечает за поддержкуШим — ложь, заточенная под конкретное использование API, и предпосылка рушится, если меняется реализация на стороне ОС; шимы Microsoft поддерживаются через Windows Update, но ухаживать за ложью, применённой пользовательской базой, — работа организации, а проверка при каждом обновлении функций — стоимость продления жизниШим = временная ложьИзменение ОС ломаетШимы MicrosoftЧерез Windows UpdateЛожь пользовательской базыОрганизация ухаживаетПроверка каждого обновления — стоимость продления жизни

Рис. 14: Ответственность за поддержку лжи шима делится между набором от Microsoft и пользовательским набором вашей организации.

8. Практическая ценность RunAsInvoker — заглушить только запрос повышения

Среди шимов чаще всего в повседневной ИТ-работе встречается RunAsInvoker.

Некоторые старые бизнес-приложения объявляют requireAdministrator в манифесте или ошибочно детектируются как установщик по имени или содержимому EXE и запрашивают повышение UAC при каждом старте. Многие из них, однако, просят администратора лишь по инерции эпохи XP и не используют права администратора. Применение шима RunAsInvoker перезаписывает и детекцию установщика, и манифест, и приложение стартует с токеном, унаследованным от родительского процесса (= обычные права пользователя).9

Как RunAsInvoker подавляет запрос повышенияОбъявление requireAdministrator в манифесте или ошибочная детекция как установщик вызывает запрос повышения UAC при старте, но применение RunAsInvoker перезаписывает оба и приложение стартует с токеном, унаследованным от родителяНетДаОбъявление requireAdministratorПрименён RunAsInvoker?Ошибочно детектировано как установщикЗапрос повышения UAC при каждом стартеСтартует с токеном родителяРабота, которой действительно нужен администратор, падает внутри приложения

Рис. 15: RunAsInvoker перезаписывает только причину запроса повышения; права не растут.

Даже не собирая .sdb в Compatibility Administrator, ту же слой можно временно применить переменной окружения __COMPAT_LAYER.

:: Apply RunAsInvoker to child processes started from this command prompt
set __COMPAT_LAYER=RunAsInvoker
start "" "C:\LegacyApp\Gyomu.exe"
# In PowerShell
$env:__COMPAT_LAYER = 'RunAsInvoker'
Start-Process 'C:\LegacyApp\Gyomu.exe'

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

Эффект раздачи пакета RunAsInvokerРаздача двухстрочного пакета, который задаёт RunAsInvoker, как ярлыка значит, что можно не раздавать локальные права администратора обычным пользователям, ИТ не вызывают из-за пароля UAC, а эксплуатация следует наименьшим привилегиямРаздать двухстрочный пакетМожно не раздавать права администратораИТ не вызывают из-за UACЭксплуатация, которая следует наименьшим привилегиям

Рис. 16: Одна раздача пакета может сократить и раздачу прав администратора, и вызовы из-за UAC.

Оговорки тоже, ясно.

  • Права не растут. Работа, которой действительно нужны права администратора (запись в HKLM, обновления под Program Files и так далее), даст ошибку внутри приложения или, если условия выполнены, будет перенаправлена в VirtualStore виртуализацией UAC.10 Если сохранение настроек вдруг «перестало работать», подозревайте виртуализацию.
  • Метод переменной окружения действует только на дочерние процессы. Для постоянного применения надёжны прямая настройка в ключе Layers (у RUNASINVOKER нет пункта на вкладке) или раздача через .sdb.
  • Исправить место записи — настоящий путь. Если приложение можно менять, перенесите файл настроек под %APPDATA% и объявите asInvoker в манифесте — это правильная форма.9
Временное и постоянное применение RunAsInvokerПрименение через переменную окружения COMPAT_LAYER действует только на дочерние процессы, запущенные оттуда; для постоянного применения используйте прямую настройку в ключе Layers или раздачу через .sdbЗадать через переменную окруженияДействует только на дочерние процессыВременное применениеЗадать напрямую в ключе LayersПостоянное применениеРаздать через sdb

Рис. 17: Метод переменной окружения — временное применение, ограниченное дочерними процессами; постоянным его делают ключ Layers или .sdb.

9. Решение между продлением жизни и миграцией — о чём думать после того, как заработало под шимом

Момент, когда заработало под шимом, — облегчение, но важно не останавливать мысль там. Работа под шимом значит лишь, что случайно подошло гнездо, которое Windows подготовила. Оси решения — таблицей.

Ось решения Условия в пользу продления жизни (шим) Условия в пользу миграции / переписывания
Оставшийся срок использования Планируется вывести вместе с бизнесом за 1–2 года Предполагается использовать ещё 5 лет и больше
Исходный код Нет (поставщик исчез или потерян) Есть, или актив можно восстановить
Глубина зависимости Только проблема совместимости API в пользовательском режиме Зависит от драйвера, 16 бит или специализированного оборудования
Альтернативы Нет коробочного продукта или новой версии Целевой продукт и технология ясны
Влияние при отказе Бизнес может идти по запасной процедуре Ядро бизнеса бьёт напрямую
Ёмкость проверки Можно подтверждать поведение при каждом обновлении функций Нет ресурса проверки, и это склонно замораживаться

Если решили продлевать жизнь, внесите в эксплуатацию следующие три пункта комплектом.

  1. Зафиксировать. Какой EXE, какой шим/слой и почему. Оставьте значение ключа Layers и GUID .sdb в реестре учёта. «Никто не знает, почему работает» — самый большой долг следующей смене. Это та же установка на сохранение, что в «Если вам досталась система без исходного кода и без документации — практический план, как сопровождать её, не останавливая работу».
  2. Проверять. Включите старт и основные операции приложений, которых держат живыми шимы, в пункты проверки обновления функций Windows. Свяжите и с планом замены ОС (Practical Options After Windows 10 End of Support).
  3. Поставить срок. Решите конец продления — «до следующего обновления ядра системы», «до марта 2028» — и параллельно ведите рассмотрение миграции.
Комплект эксплуатации из трёх пунктов после решения продлевать жизньЗафиксируйте в реестре учёта, какой шим даёт работу, проверяйте поведение приложений, которых держат живыми шимы, при каждом обновлении функций, поставьте срок конца продления и параллельно ведите рассмотрение миграцииРешить продлевать жизньЗафиксировать: какой шим даёт работу, в реестр учётаПроверять: подтверждать поведение при каждом обновлении функцийСрок: решить конец продленияПараллельно вести рассмотрение миграции

Рис. 18: Продление жизни ведётся комплектом из трёх пунктов — зафиксировать, проверять и срок, включая параллельное рассмотрение миграции.

На стороне миграции стандартные варианты меняются с технологией приложения. Для VB6 — тройной выбор полной переписки, автоматического преобразования и поэтапной миграции, собранный в «До каких пор будут работать приложения VB6 ── состояние поддержки среды выполнения и практичный путь миграции на .NET»; для зависимости от ActiveX/OCX — таблица решений оставить / обернуть / заменить в «Как сегодня поступать с ActiveX / OCX - таблица решений: оставить, обернуть или заменить». Здоровое место шима — покупать время, чтобы период рассмотрения и подготовки этого проекта миграции шёл безопасно.

Варианты на стороне миграции и где стоит шимСтандартные варианты миграции меняются с технологией приложения; для VB6 тройной выбор — переписать, автоматически преобразовать и поэтапная миграция, для зависимости ActiveX действует таблица оставить / обернуть / заменить, а шим стоит как покупка времени на рассмотрение и подготовку проекта миграцииVB6Зависимость ActiveXПокупает время на рассмотрение и подготовкуКакая технология приложения?Переписать, автоматически преобразовать или поэтапная миграцияОставить, обернуть или заменитьПродление жизни через шим

Рис. 19: Стандартные варианты миграции решает технология приложения, а шим стоит как покупка времени на это рассмотрение.

10. Итог

  • Настоящая сущность режима совместимости — шимы. Настройки вкладки «Совместимость» пишутся в ключ AppCompatFlags\Layers и при старте внедряются в процесс как перехват API через перепись IAT.
  • Шимы — набор «лжи, которая возвращает ответ, которого ждёт старое приложение». Готовые шимы для подмены версии, переназначения путей, подмены реестра, подмены проверок администратора и подобного предоставляются.
  • Сама Windows по умолчанию использует много шимов, и PCA может применять их автоматически. Опираться на режим совместимости само по себе разумный выбор, который едет на официальном механизме ОС.
  • Есть принципиальный предел только пользовательского режима и без обхода безопасности, и драйверы ядра, 16-разрядные приложения и прямой доступ к оборудованию спасти нельзя.
  • Организационное развёртывание — собрать пользовательский .sdb в Compatibility Administrator (Windows ADK) и раздать через sdbinst. Выбор 32-/64-разрядного издания, тест с реальной учётной записью пользователя и ведение обновлений по GUID — практические точки.
  • Приложения, которые «требуют администратора, но на самом деле не нуждаются», можно опустить до обычных прав через __COMPAT_LAYER=RunAsInvoker. Это защитная техника, которая глушит запрос повышения, а не раздаёт права.
  • Работа под шимом — продление жизни, не решение. Зафиксировать, что даёт работу, проверять при каждом обновлении функций и поставить срок, чтобы миграция шла параллельно, — этот комплект из трёх пунктов входит в решение «опираться на режим совместимости».

В следующий раз, когда старое приложение заработает после галочки режима совместимости, спросите снова. «Благодаря какой лжи это приложение работает? Как долго эта ложь ещё будет действовать?» Если можете ответить, продление жизни — почтенная стратегия.

Похожие статьи

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

Компания KomuraSoft LLC занимается исследованием поведения старых бизнес-приложений без исходного кода и проектированием продления их жизни (выбор шимов и режима совместимости, сборка и развёртывание пользовательского .sdb), проверкой совместимости существующих приложений для миграции на Windows 11 и планированием переписывания или миграции, идущих параллельно с продлением. Консультация уже со стадии «заработало в режиме совместимости, но нормально ли так оставлять?» уместна.

Справочные ссылки

  1. Microsoft Learn, Application Compatibility Database. О том, что инфраструктура совместимости ведёт проблемы и средства в базе формата .sdb, сопоставление по атрибутам исполняемого файла, Apphelp (показ сообщения) и Appfix (перехват API через шим), а также слой совместимости (режим), который связывает несколько шимов и флагов.  2 3

  2. Microsoft Learn, DXGI overview. О том, что настройки совместимости приложений хранятся в ключе реестра HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers (на примере настроек совместимости DXGI).  2

  3. Microsoft Learn, Understanding and Using Compatibility Fixes. О том, что исправление совместимости (шим) перенаправляет вызовы API, переписывая IAT (таблицу адресов импорта), что динамическая компоновка обрабатывается перехватом GetProcAddress, что шим подчиняется тем же ограничениям безопасности, что и приложение, и не обходит механизмы безопасности ОС, что он только в пользовательском режиме и не чинит проблемы драйверов, что исправление, возможное шимом, возможно и правкой кода, сценарии вроде приложений, у которых кончилась поддержка поставщика, и что исправления совместимости от Microsoft поставляются как часть Windows и обновляются через Windows Update.  2 3 4 5 6 7 8

  4. Microsoft Learn, Compatibility Fixes for Windows 10, Windows 8, Windows 7, and Windows Vista. Список и описание известных исправлений совместимости, включая CorrectFilePaths, VirtualRegistry, ForceAdminAccess, RunAsAdmin/RunAsHighest/RunAsInvoker, WRPMitigation, EmulateGetDiskFreeSpace, GlobalMemoryStatusLie, LoadLibraryRedirect и семейство VersionLie; выбор 32-/64-разрядного издания Compatibility Administrator; и что тест в повышенном состоянии значит, что виртуализация и перенаправление ведут себя не как ожидается, поэтому проверять нужно реальной учётной записью пользователя.  2 3 4

  5. Microsoft Learn, Program Compatibility Assistant scenarios for Windows 8. О том, что PCA следит за выполнением приложений, обнаруживает признаки известной проблемы совместимости и предлагает применить рекомендованное исправление или применяет его автоматически (PINDLL, DISABLEUSERCALLBACKEXCEPTION, VIRTUALIZEDELETE, WRPMITIGATION и подобные), а также применение исправления с вкладки «Совместимость» и Program Compatibility Troubleshooter.  2

  6. Microsoft Learn, GetVersionExW function. О том, что начиная с Windows 8.1 значение, которое возвращает GetVersionEx, зависит от манифеста, что приложению без манифеста для Windows 8.1/10 дают значение версии Windows 8 (6.2), и что при включённом режиме совместимости сообщается версия выбранной ОС.  2 3

  7. Microsoft Learn, Targeting your application for Windows. Как объявлять GUID поддерживаемых ОС элементом supportedOS в разделе compatibility манифеста приложения, поведение без объявления и то, что интерактивное 32-разрядное x86-приложение без trustInfo попадает под виртуализацию файлов UAC (перенаправление записи в VirtualStore).  2

  8. Microsoft Learn, Running 32-bit Applications. О том, что WOW64 — слой эмуляции, который запускает 32-разрядные приложения на 64-разрядной Windows и изолирует столкновения файлов и реестра, и что 64-разрядная Windows не поддерживает выполнение 16-разрядных приложений, а старт падает с ERROR_BAD_EXE_FORMAT из-за числа действительных бит в дескрипторе.  2

  9. Microsoft Learn, Using the RunAsInvoker Fix. О том, что исправление совместимости RunAsInvoker стартует приложение с токеном, унаследованным от родительского процесса, что оно перезаписывает и детекцию установщика, и обработку манифеста, что применяется как флаг загрузчика без перехвата API, и что когда код можно править, правильное исправление — объявить asInvoker в манифесте.  2 3

  10. Microsoft Learn, Registry Virtualization. О том, что виртуализация реестра — технология совместимости, которая прозрачно перенаправляет глобальные записи в HKLM\Software в пользовательский VirtualStore, что в охвате только интерактивные 32-разрядные процессы и она отключена для процессов, которые задают requestedExecutionLevel в манифесте, и для 64-разрядных процессов, и что её ставят как временную технологию, предназначенную к удалению из будущей Windows.  2

  11. Microsoft Learn, High DPI Desktop Application Development on Windows. О том, что приложение без поддержки DPI считается рисующим при фиксированных 96 DPI и на дисплее с высокой плотностью Windows растягивает растр, поэтому оно выглядит размытым, а также различия режимов осведомлённости о DPI (Unaware/System/Per-Monitor).  2

  12. Microsoft Learn, Download and install the Windows ADK. О том, что Windows ADK включает Compatibility Administrator и Standard User Analyzer, и как думать о выборе версии ADK и как скачивать и устанавливать. 

  13. Microsoft Learn, Compatibility Administrator User’s Guide. О том, что Compatibility Administrator даёт применение исправлений совместимости, режимов совместимости и сообщений AppHelp и создание пользовательской базы, и что ставятся и 32-, и 64-разрядные издания и для 32-разрядных приложений нужно 32-разрядное издание, для 64-разрядных — 64-разрядное. 

  14. Microsoft Learn, Creating a Custom Compatibility Fix in Compatibility Administrator. О том, что исправление совместимости (раньше называлось шимом) — маленький кусок кода, который перехватывает вызов API; порядок создания Application Fix в пользовательской базе (указать имя приложения, поставщика и целевой EXE, выбрать режим совместимости, выбрать дополнительные шимы, задать условия сопоставления); и что следует оставить условия, которые верно идентифицируют приложение, сужая сведения сопоставления.  2

  15. Microsoft Learn, Compatibility Fix Database Management Strategies and Deployment. О том, что централизованно ведомая база рекомендуется как стратегия управления пользовательской базой совместимости, что исправление совместимости должно включать проверку версии (условие сопоставления), чтобы не применяться к новой версии, локальная установка через Sdbinst.exe (параметры -q, -u, -g), что установка новой версии с тем же GUID базы автоматически удаляет старую, и способы раздачи через MSI или сценарий.  2 3

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

Приложения, которые ломаются после выхода из сна — как работают события питания Windows и как строить бизнес-приложения, которые это переживают

Открыли ноутбук — и соединения бизнес-приложения мертвы: причина в проекте, который не учитывал сон. Статья разбирает поток уведомлений W...

Что на самом деле значит «Не отвечает» — как Windows решает, что приложение зависло, и как проектировать приложения, которые не зависают

«Не отвечает» в Windows — механизм, в котором ОС судит, что окно не извлекало сообщение 5 секунд, и подменяет его окном-призраком. Статья...

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Если приложение заработало после галочки в режиме совместимости, можно ли так и пользоваться?
Чтобы бизнес не встал в короткой перспективе — да. Режим совместимости — это перехват API в пользовательском режиме, называемый шимом, официальный механизм ОС. Шим всё же временная мера, чтобы приложение работало без исправления, и другое обновление ОС может сменить предпосылки и снова его сломать. Зафиксируйте в реестре учёта факт работы в режиме совместимости и считайте эту запись частью решения: переписывать приложение или продлевать жизнь целенаправленно.
Что на самом деле делает флажок режима совместимости?
Когда вы сохраняете настройки на вкладке «Совместимость» диалога свойств, Windows записывает путь целевого EXE и значение вроде "WINXPSP3" или "HIGHDPIAWARE" в ключ HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers. При следующем запуске этого EXE загрузчик Windows читает значение и применяет к процессу соответствующий слой совместимости (набор шимов). Режим Windows XP, например, подменяет версию ОС, возвращая старое значение из API запроса версии. Сама ОС не меняется; только этому процессу показывают притворную старую Windows.
Можно ли запускать приложения эпохи 16 бит в режиме совместимости на 64-разрядной Windows?
Нет. 64-разрядная Windows запускает 32-разрядные приложения через WOW64, но не поддерживает выполнение 16-разрядных; попытка старта завершается ERROR_BAD_EXE_FORMAT. Это архитектурный предел, который шим не обойдёт. Старые пакеты, у которых заглушка установщика 16-разрядная, падают по той же причине. Если они действительно нужны, смотрите вне режима совместимости — например виртуальную машину с 32-разрядной Windows.
Можно ли запустить приложение, которое «не стартует без прав администратора», под учётной записью обычного пользователя?
RunAsInvoker стоит попробовать. Если выполнить set __COMPAT_LAYER=RunAsInvoker в командной строке и затем запустить приложение, запросы повышения из манифеста requireAdministrator или из детекции установщика подавляются, и приложение стартует с теми же (обычными) правами, что и вызывающий процесс. Для приложения, которое только просит права администратора и не использует их, этого достаточно, чтобы убрать повышение из повседневной работы. Права не растут, поэтому работа, которой действительно нужны права администратора, упадёт внутри приложения. Принимайте только после проверки поведения.
Где взять Compatibility Administrator?
Он входит в Windows ADK (Windows Assessment and Deployment Kit). Скачайте ADK с сайта Microsoft и при установке выберите функции Application Compatibility Tools. Ставятся и 32-, и 64-разрядные издания; для 32-разрядных приложений нужно 32-разрядное издание, для 64-разрядных — 64-разрядное. Пользовательскую базу совместимости (.sdb) применяют командой sdbinst на каждом ПК.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог