Как работает совместимость приложений Windows — режим совместимости, шимы и Compatibility Administrator
· Го Комура · Windows, Режим совместимости, Шимы, Совместимость приложений, Compatibility Administrator, Использование существующих активов, Разработка под Windows, Существующие системы
«Десятилетнее бизнес-приложение, исходников которого уже нет, не стартует на новом ПК с Windows 11. Я поставил галочку “Windows XP” на вкладке “Совместимость” диалога свойств — и оно просто заработало. — Что это на самом деле делает? Можно ли и дальше на это опираться?» Такой запрос мы слышим часто.
Когда одна галочка заставляет что-то работать, беспокойство естественно. Настоящая сущность режима совместимости, похожего на магию, — набор маленьких кусков кода, называемых шимами, которые встают между приложением и Windows API и возвращают «ложь». Сама Windows использует эту временную меру в больших масштабах, чтобы держать живыми приложения многих поколений, и открывает часть механизма пользователям и администраторам.
Без понимания механизма продление жизни становится нестабильным «нельзя трогать, потому что не знаем, почему работает». Поняв механизм, вы решаете с основаниями, насколько далеко можно спокойно опираться, что его сломает и когда стоит переписать.
flowchart TB
accTitle: Понимание механизма меняет качество продления жизни
accDescr: Использование режима совместимости без понимания механизма ведёт к нестабильному продлению, которое боятся трогать; понимание механизма позволяет решать с основаниями, насколько можно опираться, что сломает и когда переписывать
unknown["Использовать, не понимая механизм"] --> fear["Нестабильное продление, которое боятся трогать"]
known["Использовать, поняв механизм"] --> judge["Решения с основаниями"]
judge -.-> j1["Насколько можно опираться"]
judge -.-> j2["Что его сломает"]
judge -.-> j3["Когда стоит переписать"]
Рис. 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»; эта статья держит шимы в центре и упоминает остальные слои только по необходимости.
flowchart TB
accTitle: Где стоит виртуализация UAC
accDescr: Виртуализация UAC — переходная мера для интерактивных 32-разрядных процессов без манифеста; она перенаправляет записи в пользовательский VirtualStore, но сама Microsoft называет её временной технологией, предназначенной к удалению из будущей Windows
proc["Интерактивный 32-разрядный процесс без манифеста"] --> uacv["Применяется виртуализация UAC"]
uacv --> vs["Перенаправлено в пользовательский VirtualStore"]
uacv -.-> tmp["Временная технология, предназначенная к удалению"]
Рис. 2: Виртуализация UAC — переходная мера для 32-разрядных процессов без манифеста, и на неё нельзя опираться постоянно.
Заметка о виртуализации DPI: приложение, не объявившее осведомлённость о DPI, считается рисующим при 96 DPI (100%), и Windows растягивает растр для показа. Поэтому старые приложения выглядят «размытыми» на мониторе с высокой плотностью, а «Переопределить поведение масштабирования при высокой плотности» на вкладке «Совместимость» — переключатель этого поведения виртуализации.11
flowchart TB
accTitle: Как работает виртуализация DPI
accDescr: Приложение, не объявившее осведомлённость о DPI, считается рисующим при 96 DPI; Windows растягивает растр, поэтому оно выглядит размытым, а переопределение настроек высокой плотности на вкладке «Совместимость» переключает это поведение виртуализации
app["Приложение, не объявляющее осведомлённость о DPI"] --> treat["Считается рисующим при 96 DPI"]
treat --> stretch["Растр растягивается для показа"]
stretch --> blur["Выглядит размытым на мониторе с высокой плотностью"]
tab["Переопределить поведение масштабирования при высокой плотности"] -.->|Переключает поведение виртуализации| treat
Рис. 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»; со стороны ОС — что «работает воспитанное приложение». Шим — переводчик между ними.
flowchart TB
accTitle: Путь, по которому шим перехватывает вызов API
accDescr: Вызов API приложения идёт через IAT; перепись записи IAT на шим при загрузке позволяет шиму перехватить, подменить тот же ответ, что давала старая Windows, и затем при необходимости вызвать настоящий API
app["Приложение"] -->|Вызов API| iat["Запись IAT"]
iat -->|Переписана на шим при загрузке| shim["Шим (переводчик)"]
shim -->|Если нужно| api["Настоящий Windows API"]
shim -.-> lie["Подменяет тот же ответ, что давала старая Windows"]
gpa["Вызовы через GetProcAddress"] -.->|Обрабатываются перехватом| shim
Рис. 4: Шим перехватывает между приложением и Windows API. Переписывается IAT на стороне приложения; сама ОС не меняется.
Из этой конструкции следуют три важных свойства.3
- Шим выполняется как код на стороне приложения. Он не часть ОС, поэтому подчиняется тем же ограничениям безопасности, что и приложение. Шим не обходит механизмы безопасности ОС, и ослаблять настройки безопасности ради шима не нужно.
- То, что шим может исправить, может исправить и правка кода на стороне приложения. Шим — замена для случаев «нет исходников / не можем править»; он не сильнее правки кода.
- Только пользовательский режим. Проблемы совместимости драйверов устройств в режиме ядра шим не чинит.
3.2. База шимов (.sdb) и сопоставление
Таблица соответствия «какой шим применять к какому EXE» — это база шимов, двоичный файл с расширением .sdb. Целевые исполняемые файлы регистрируются в базе по атрибутам вроде имени файла, размера, контрольной суммы и версии (атрибуты сопоставления) и сопоставляются при старте процесса. Средства включают Appfix (шим), который внедряет перехват API, и Apphelp, который показывает сообщение «у этого приложения проблема совместимости». Набор нескольких шимов и флагов — это слой совместимости (режим совместимости).1
Легко упустить: это сопоставление идёт не только у приложений с включённым режимом совместимости, а при каждом запуске процесса. Windows поставляет стандартную базу ОС с исправлениями для тысяч известных приложений (файлы лежат в %WINDIR%\AppPatch), и на вашем ПК сегодня почти наверняка какое-то старое приложение стартует с прикреплённым шимом незаметно. Исправления совместимости от Microsoft поставляются как часть Windows и обновляются через Windows Update.3
flowchart TB
accTitle: Сопоставление базы шимов при старте процесса
accDescr: Каждый запуск процесса сопоставляется с базой шимов; если регистрация совпадает с атрибутами сопоставления, Appfix внедряет шим или Apphelp показывает сообщение, иначе процесс стартует как есть
start["Старт процесса"] --> db["Сопоставить с .sdb"]
db -.-> attr["Имя файла, размер и т. д."]
db --> hit{"Есть регистрация?"}
hit -->|Да| appfix["Appfix: внедрить шим"]
hit -->|Да| apphelp["Apphelp: сообщение"]
hit -->|Нет| plain["Стартовать как есть"]
layer["Слой совместимости"] -.->|Набор шимов и флагов| appfix
Рис. 5: Сопоставление идёт при каждом запуске процесса, не только у приложений с включённым режимом совместимости.
3.3. PCA — механизм, который применяет шимы автоматически
Другой путь, по которому шим может примениться без намерения администратора, — PCA (Program Compatibility Assistant). PCA следит за выполнением приложений и, обнаружив признаки известной проблемы совместимости, предлагает пользователю применить исправление или в некоторых случаях применяет настройку совместимости автоматически. Например, приложению, которое падает, вызывая код в освобождённой DLL, назначают PINDLL, а приложению, которое не может писать в защищённый файл Windows, — WRPMITIGATION.5
flowchart TB
accTitle: Как PCA автоматически применяет настройку совместимости
accDescr: PCA следит за выполнением приложений и, обнаружив признаки известной проблемы совместимости, предлагает пользователю применить исправление или в некоторых случаях применяет настройку совместимости автоматически
run["Выполнение приложения"] --> pca["PCA следит"]
pca --> sign{"Признаки известной проблемы?"}
sign -->|Да| resp{"Какой случай?"}
resp -->|Через предложение| suggest["Предложить применить исправление"]
resp -->|Некоторые случаи| auto["Применить настройку совместимости автоматически"]
sign -->|Нет| none["Выполнить как есть"]
auto -.-> ex["Пример: 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, которую видит приложение», решается в этих наложенных ступенях.
- Возвращается значение до ОС, объявленной в манифесте (6.2, если объявления нет)
- Если применён режим совместимости (шим семейства VersionLie), возвращается версия выбранной ОС6
flowchart TB
accTitle: Как решается версия ОС, которую видит приложение
accDescr: Значение, которое возвращает GetVersionEx, решается наличием объявления supportedOS в манифесте; без объявления возвращается эквивалент Windows 8 6.2, с объявлением — значение до самой высокой объявленной ОС, а если применён шим семейства VersionLie, оно перезаписывается версией выбранной ОС
q["Запрос GetVersionEx"] --> m{"Есть объявление supportedOS?"}
m -->|Нет| v62["Возвращается эквивалент Windows 8 (6.2)"]
m -->|Да| decl["Значение до самой высокой объявленной ОС"]
v62 --> lie{"Применён шим семейства VersionLie?"}
decl --> lie
lie -->|Да| fake["Значение ОС, выбранное в режиме совместимости"]
lie -->|Нет| asis["Значение возвращается как есть"]
Рис. 7: Версия Windows, которую видит приложение, решается наложенными ступенями манифеста и шимов.
Если внутреннее приложение «ветвится по версии ОС и, путано, считается восьмёркой, хотя это Windows 11», сначала подозревайте объявление supportedOS в манифесте. Наоборот, старое приложение, которое отказывается стартовать из-за проверки версии, с высокой вероятностью можно провести шимом VersionLie. Во многих случаях оно смотрит только на номер версии, а фактическое поведение на более новой ОС нормально.
flowchart TB
accTitle: Два симптома из-за версии и как с ними быть
accDescr: Если внутреннее приложение считается восьмёркой, хотя это Windows 11, подозревайте объявление supportedOS в манифесте; старое приложение, которое отказывается стартовать из-за проверки версии, с высокой вероятностью можно провести шимом VersionLie
sym1["Считается восьмёркой, хотя это Windows 11"] --> fix1["Подозревать объявление supportedOS"]
sym2["Старт отказан из-за проверки версии"] --> fix2["Попробовать пройти VersionLie"]
fix2 -.-> why["Фактическое поведение на более новой ОС часто нормально"]
Рис. 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 в следующей главе.
flowchart TB
accTitle: Путь от настройки вкладки «Совместимость» до действия
accDescr: Настройки вкладки «Совместимость» хранятся как путь EXE и значение в ключе AppCompatFlags Layers; при следующем старте этого EXE загрузчик читает значение и применяет соответствующий слой совместимости к процессу
tab["Задать на вкладке «Совместимость»"] --> reg["Сохранить путь EXE и значение в ключе Layers"]
reg --> boot["Следующий старт EXE"]
boot --> loader["Загрузчик читает значение"]
loader --> apply["Применить слой совместимости к процессу"]
reg -.-> hkcu["HKCU только этот пользователь"]
reg -.-> hklm["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
flowchart TB
accTitle: Две оговорки при работе с Compatibility Administrator
accDescr: Используйте 32-разрядное издание для 32-разрядных приложений и 64-разрядное для 64-разрядных и подтверждайте эффект исправления той же учётной записью и теми же правами, что у реального пользователя, а не в повышенном состоянии
app32["32-разрядное приложение"] --> tool32["Использовать 32-разрядное издание"]
app64["64-разрядное приложение"] --> tool64["Использовать 64-разрядное издание"]
elev["Тест в повышенном состоянии"] -.-> wrong["Можно ошибочно оценить исправление"]
user["Тест с правами реального пользователя"] --> ok["Подтвердить эффект"]
Рис. 10: Выбор 32- или 64-разрядного издания и подтверждение теми же правами, что у реального пользователя, — оговорки на входе.
6.2. Порядок сборки пользовательской базы совместимости
Схема такова.14
- В левой панели Compatibility Administrator создайте новую базу в «Custom Databases» и выберите «Create New» → «Application Fix»
- Введите имя приложения и имя поставщика и укажите целевой EXE
- Выберите применяемый режим совместимости (слой) — сначала попробовать набор вроде «совместимость с Windows XP» короче
- При необходимости добавьте отдельные исправления совместимости (шимы) — можно сузить до минимума вроде только VersionLie или только CorrectFilePaths
- Подтвердите условия сопоставления (размер файла, контрольная сумма, версия и так далее) и сохраните
Условия сопоставления — ключ к «применять это только к этому EXE». Базовых условий по умолчанию обычно хватает, но мы рекомендуем оставить условие, которое идентифицирует версию приложения. Это предотвращает аварию, когда старая ложь продолжает применяться к новой версии, когда поставщик позже выпустит исправленное издание.1415
flowchart TB
accTitle: Порядок сборки пользовательской базы совместимости
accDescr: Создайте Application Fix в новой базе, укажите имя приложения и целевой EXE, сначала попробуйте набор режима совместимости, затем при необходимости сузьте до отдельных шимов, подтвердите условия сопоставления и сохраните
new["Создать новую базу"] --> fix["Выбрать Application Fix"]
fix --> info["Указать имя приложения и целевой EXE"]
info --> layer["Попробовать набор режима совместимости"]
layer --> single["При необходимости сузить до отдельных шимов"]
single --> match["Подтвердить условия сопоставления и сохранить"]
match -.-> ver["Оставить условие, которое идентифицирует версию"]
Рис. 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
flowchart TB
accTitle: Путь от создания пользовательского .sdb до раздачи
accDescr: Создайте пользовательскую базу совместимости в Compatibility Administrator, протестируйте на проверочной машине, примените на каждом ПК через sdbinst и при обновлении установите новую версию с тем же GUID, чтобы старая заменилась автоматически
make["Создать в Compatibility Administrator"] --> test["Протестировать на проверочной машине"]
test --> deploy["Применить на каждом ПК через sdbinst"]
deploy --> update["Установить новую версию с тем же GUID"]
update -.-> replace["Старая версия заменяется автоматически"]
deploy -.-> inv["Регистрируется в «Программы и компоненты»"]
Рис. 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 аномалией и перестать работать.
flowchart TB
accTitle: Случаи, когда шим не работает
accDescr: Шим выполняется внутри процесса пользовательского режима, поэтому не работает на проблемах драйверов режима ядра, 16-разрядных приложениях, прямом доступе к оборудованию и обходе механизмов безопасности
shim["Шим (выполняется в пользовательском режиме)"] -->|Не работает| drv["Драйвер ядра"]
shim -->|Не работает| b16["16-разрядное приложение"]
shim -->|Не работает| hw["Прямой доступ к оборудованию"]
shim -->|Не работает| sec["Обход механизмов безопасности"]
b16 -.-> fmt["На 64 разрядах падает уже сам старт"]
sec -.-> fake["Лишь подменяет успех, чтобы приложение продолжило"]
Рис. 13: Шим только в пользовательском режиме и не достаёт до ядра, 16-разрядных приложений, прямого доступа к оборудованию и обхода безопасности.
И существенный предел, общий для каждого шима: это временная мера. Шим — ложь, заточенная под конкретное использование конкретного API, и если реализация на стороне ОС меняется, предпосылка рушится. Шимы от Microsoft поддерживаются как часть Windows через Windows Update,3 но ухаживать за ложью, которую вы применили пользовательской базой, — работа вашей организации. Заложите в бюджет, как стоимость продления жизни, операцию, которая проверяет «список приложений, которых держат живыми шимы» при каждом обновлении функций.
flowchart TB
accTitle: Шимы как временная мера и кто отвечает за поддержку
accDescr: Шим — ложь, заточенная под конкретное использование API, и предпосылка рушится, если меняется реализация на стороне ОС; шимы Microsoft поддерживаются через Windows Update, но ухаживать за ложью, применённой пользовательской базой, — работа организации, а проверка при каждом обновлении функций — стоимость продления жизни
shim["Шим = временная ложь"] --> break["Изменение ОС ломает"]
ms["Шимы Microsoft"] --> wu["Через Windows Update"]
own["Ложь пользовательской базы"] --> self["Организация ухаживает"]
self --> cost["Проверка каждого обновления — стоимость продления жизни"]
Рис. 14: Ответственность за поддержку лжи шима делится между набором от Microsoft и пользовательским набором вашей организации.
8. Практическая ценность RunAsInvoker — заглушить только запрос повышения
Среди шимов чаще всего в повседневной ИТ-работе встречается RunAsInvoker.
Некоторые старые бизнес-приложения объявляют requireAdministrator в манифесте или ошибочно детектируются как установщик по имени или содержимому EXE и запрашивают повышение UAC при каждом старте. Многие из них, однако, просят администратора лишь по инерции эпохи XP и не используют права администратора. Применение шима RunAsInvoker перезаписывает и детекцию установщика, и манифест, и приложение стартует с токеном, унаследованным от родительского процесса (= обычные права пользователя).9
flowchart TB
accTitle: Как RunAsInvoker подавляет запрос повышения
accDescr: Объявление requireAdministrator в манифесте или ошибочная детекция как установщик вызывает запрос повышения UAC при старте, но применение RunAsInvoker перезаписывает оба и приложение стартует с токеном, унаследованным от родителя
manifest["Объявление requireAdministrator"] --> shim{"Применён RunAsInvoker?"}
detect["Ошибочно детектировано как установщик"] --> shim
shim -->|Нет| uac["Запрос повышения UAC при каждом старте"]
shim -->|Да| token["Стартует с токеном родителя"]
token -.-> limit["Работа, которой действительно нужен администратор, падает внутри приложения"]
Рис. 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. Это техника совместимости, которая укрепляет защиту, в духе наименьших привилегий.
flowchart TB
accTitle: Эффект раздачи пакета RunAsInvoker
accDescr: Раздача двухстрочного пакета, который задаёт RunAsInvoker, как ярлыка значит, что можно не раздавать локальные права администратора обычным пользователям, ИТ не вызывают из-за пароля UAC, а эксплуатация следует наименьшим привилегиям
bat["Раздать двухстрочный пакет"] --> noadmin["Можно не раздавать права администратора"]
bat --> nocall["ИТ не вызывают из-за UAC"]
noadmin --> lp["Эксплуатация, которая следует наименьшим привилегиям"]
nocall --> lp
Рис. 16: Одна раздача пакета может сократить и раздачу прав администратора, и вызовы из-за UAC.
Оговорки тоже, ясно.
- Права не растут. Работа, которой действительно нужны права администратора (запись в HKLM, обновления под Program Files и так далее), даст ошибку внутри приложения или, если условия выполнены, будет перенаправлена в VirtualStore виртуализацией UAC.10 Если сохранение настроек вдруг «перестало работать», подозревайте виртуализацию.
- Метод переменной окружения действует только на дочерние процессы. Для постоянного применения надёжны прямая настройка в ключе Layers (у RUNASINVOKER нет пункта на вкладке) или раздача через .sdb.
- Исправить место записи — настоящий путь. Если приложение можно менять, перенесите файл настроек под
%APPDATA%и объявитеasInvokerв манифесте — это правильная форма.9
flowchart TB
accTitle: Временное и постоянное применение RunAsInvoker
accDescr: Применение через переменную окружения COMPAT_LAYER действует только на дочерние процессы, запущенные оттуда; для постоянного применения используйте прямую настройку в ключе Layers или раздачу через .sdb
env["Задать через переменную окружения"] --> child["Действует только на дочерние процессы"]
child -.-> tmp["Временное применение"]
layers["Задать напрямую в ключе Layers"] --> always["Постоянное применение"]
sdb["Раздать через sdb"] --> always
Рис. 17: Метод переменной окружения — временное применение, ограниченное дочерними процессами; постоянным его делают ключ Layers или .sdb.
9. Решение между продлением жизни и миграцией — о чём думать после того, как заработало под шимом
Момент, когда заработало под шимом, — облегчение, но важно не останавливать мысль там. Работа под шимом значит лишь, что случайно подошло гнездо, которое Windows подготовила. Оси решения — таблицей.
| Ось решения | Условия в пользу продления жизни (шим) | Условия в пользу миграции / переписывания |
|---|---|---|
| Оставшийся срок использования | Планируется вывести вместе с бизнесом за 1–2 года | Предполагается использовать ещё 5 лет и больше |
| Исходный код | Нет (поставщик исчез или потерян) | Есть, или актив можно восстановить |
| Глубина зависимости | Только проблема совместимости API в пользовательском режиме | Зависит от драйвера, 16 бит или специализированного оборудования |
| Альтернативы | Нет коробочного продукта или новой версии | Целевой продукт и технология ясны |
| Влияние при отказе | Бизнес может идти по запасной процедуре | Ядро бизнеса бьёт напрямую |
| Ёмкость проверки | Можно подтверждать поведение при каждом обновлении функций | Нет ресурса проверки, и это склонно замораживаться |
Если решили продлевать жизнь, внесите в эксплуатацию следующие три пункта комплектом.
- Зафиксировать. Какой EXE, какой шим/слой и почему. Оставьте значение ключа Layers и GUID .sdb в реестре учёта. «Никто не знает, почему работает» — самый большой долг следующей смене. Это та же установка на сохранение, что в «Если вам досталась система без исходного кода и без документации — практический план, как сопровождать её, не останавливая работу».
- Проверять. Включите старт и основные операции приложений, которых держат живыми шимы, в пункты проверки обновления функций Windows. Свяжите и с планом замены ОС (Practical Options After Windows 10 End of Support).
- Поставить срок. Решите конец продления — «до следующего обновления ядра системы», «до марта 2028» — и параллельно ведите рассмотрение миграции.
flowchart TB
accTitle: Комплект эксплуатации из трёх пунктов после решения продлевать жизнь
accDescr: Зафиксируйте в реестре учёта, какой шим даёт работу, проверяйте поведение приложений, которых держат живыми шимы, при каждом обновлении функций, поставьте срок конца продления и параллельно ведите рассмотрение миграции
decide["Решить продлевать жизнь"] --> rec["Зафиксировать: какой шим даёт работу, в реестр учёта"]
rec --> verify["Проверять: подтверждать поведение при каждом обновлении функций"]
verify --> deadline["Срок: решить конец продления"]
deadline --> mig["Параллельно вести рассмотрение миграции"]
Рис. 18: Продление жизни ведётся комплектом из трёх пунктов — зафиксировать, проверять и срок, включая параллельное рассмотрение миграции.
На стороне миграции стандартные варианты меняются с технологией приложения. Для VB6 — тройной выбор полной переписки, автоматического преобразования и поэтапной миграции, собранный в «До каких пор будут работать приложения VB6 ── состояние поддержки среды выполнения и практичный путь миграции на .NET»; для зависимости от ActiveX/OCX — таблица решений оставить / обернуть / заменить в «Как сегодня поступать с ActiveX / OCX - таблица решений: оставить, обернуть или заменить». Здоровое место шима — покупать время, чтобы период рассмотрения и подготовки этого проекта миграции шёл безопасно.
flowchart TB
accTitle: Варианты на стороне миграции и где стоит шим
accDescr: Стандартные варианты миграции меняются с технологией приложения; для VB6 тройной выбор — переписать, автоматически преобразовать и поэтапная миграция, для зависимости ActiveX действует таблица оставить / обернуть / заменить, а шим стоит как покупка времени на рассмотрение и подготовку проекта миграции
tech{"Какая технология приложения?"} -->|VB6| vb["Переписать, автоматически преобразовать или поэтапная миграция"]
tech -->|Зависимость ActiveX| ax["Оставить, обернуть или заменить"]
shim["Продление жизни через шим"] -.->|Покупает время на рассмотрение и подготовку| tech
Рис. 19: Стандартные варианты миграции решает технология приложения, а шим стоит как покупка времени на это рассмотрение.
10. Итог
- Настоящая сущность режима совместимости — шимы. Настройки вкладки «Совместимость» пишутся в ключ AppCompatFlags\Layers и при старте внедряются в процесс как перехват API через перепись IAT.
- Шимы — набор «лжи, которая возвращает ответ, которого ждёт старое приложение». Готовые шимы для подмены версии, переназначения путей, подмены реестра, подмены проверок администратора и подобного предоставляются.
- Сама Windows по умолчанию использует много шимов, и PCA может применять их автоматически. Опираться на режим совместимости само по себе разумный выбор, который едет на официальном механизме ОС.
- Есть принципиальный предел только пользовательского режима и без обхода безопасности, и драйверы ядра, 16-разрядные приложения и прямой доступ к оборудованию спасти нельзя.
- Организационное развёртывание — собрать пользовательский .sdb в Compatibility Administrator (Windows ADK) и раздать через sdbinst. Выбор 32-/64-разрядного издания, тест с реальной учётной записью пользователя и ведение обновлений по GUID — практические точки.
- Приложения, которые «требуют администратора, но на самом деле не нуждаются», можно опустить до обычных прав через
__COMPAT_LAYER=RunAsInvoker. Это защитная техника, которая глушит запрос повышения, а не раздаёт права. - Работа под шимом — продление жизни, не решение. Зафиксировать, что даёт работу, проверять при каждом обновлении функций и поставить срок, чтобы миграция шла параллельно, — этот комплект из трёх пунктов входит в решение «опираться на режим совместимости».
В следующий раз, когда старое приложение заработает после галочки режима совместимости, спросите снова. «Благодаря какой лжи это приложение работает? Как долго эта ложь ещё будет действовать?» Если можете ответить, продление жизни — почтенная стратегия.
Похожие статьи
- Registry 32-bit/64-bit Redirection and Virtualization Pitfalls — Wow6432Node and the “The Value I Wrote Isn’t There” Problem
- До каких пор будут работать приложения VB6 ── состояние поддержки среды выполнения и практичный путь миграции на .NET
- Как сегодня поступать с ActiveX / OCX - таблица решений: оставить, обернуть или заменить
- Practical Options After Windows 10 End of Support — A Decision Table for ESU, LTSC, and Replacement
- Если вам досталась система без исходного кода и без документации — практический план, как сопровождать её, не останавливая работу
- Интеграция с оболочкой Windows сегодня — контекстные меню, сопоставления файлов и что изменилось в Windows 11
Смежные области консультирования
Компания KomuraSoft LLC занимается исследованием поведения старых бизнес-приложений без исходного кода и проектированием продления их жизни (выбор шимов и режима совместимости, сборка и развёртывание пользовательского .sdb), проверкой совместимости существующих приложений для миграции на Windows 11 и планированием переписывания или миграции, идущих параллельно с продлением. Консультация уже со стадии «заработало в режиме совместимости, но нормально ли так оставлять?» уместна.
- Использование и перенос существующих активов
- Разработка приложений для Windows
- Технические консультации и ревью дизайна
- Связаться с нами
Справочные ссылки
-
Microsoft Learn, Application Compatibility Database. О том, что инфраструктура совместимости ведёт проблемы и средства в базе формата .sdb, сопоставление по атрибутам исполняемого файла, Apphelp (показ сообщения) и Appfix (перехват API через шим), а также слой совместимости (режим), который связывает несколько шимов и флагов. ↩ ↩2 ↩3
-
Microsoft Learn, DXGI overview. О том, что настройки совместимости приложений хранятся в ключе реестра HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers (на примере настроек совместимости DXGI). ↩ ↩2
-
Microsoft Learn, Understanding and Using Compatibility Fixes. О том, что исправление совместимости (шим) перенаправляет вызовы API, переписывая IAT (таблицу адресов импорта), что динамическая компоновка обрабатывается перехватом GetProcAddress, что шим подчиняется тем же ограничениям безопасности, что и приложение, и не обходит механизмы безопасности ОС, что он только в пользовательском режиме и не чинит проблемы драйверов, что исправление, возможное шимом, возможно и правкой кода, сценарии вроде приложений, у которых кончилась поддержка поставщика, и что исправления совместимости от Microsoft поставляются как часть Windows и обновляются через Windows Update. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
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
-
Microsoft Learn, Program Compatibility Assistant scenarios for Windows 8. О том, что PCA следит за выполнением приложений, обнаруживает признаки известной проблемы совместимости и предлагает применить рекомендованное исправление или применяет его автоматически (PINDLL, DISABLEUSERCALLBACKEXCEPTION, VIRTUALIZEDELETE, WRPMITIGATION и подобные), а также применение исправления с вкладки «Совместимость» и Program Compatibility Troubleshooter. ↩ ↩2
-
Microsoft Learn, GetVersionExW function. О том, что начиная с Windows 8.1 значение, которое возвращает GetVersionEx, зависит от манифеста, что приложению без манифеста для Windows 8.1/10 дают значение версии Windows 8 (6.2), и что при включённом режиме совместимости сообщается версия выбранной ОС. ↩ ↩2 ↩3
-
Microsoft Learn, Targeting your application for Windows. Как объявлять GUID поддерживаемых ОС элементом supportedOS в разделе compatibility манифеста приложения, поведение без объявления и то, что интерактивное 32-разрядное x86-приложение без trustInfo попадает под виртуализацию файлов UAC (перенаправление записи в VirtualStore). ↩ ↩2
-
Microsoft Learn, Running 32-bit Applications. О том, что WOW64 — слой эмуляции, который запускает 32-разрядные приложения на 64-разрядной Windows и изолирует столкновения файлов и реестра, и что 64-разрядная Windows не поддерживает выполнение 16-разрядных приложений, а старт падает с ERROR_BAD_EXE_FORMAT из-за числа действительных бит в дескрипторе. ↩ ↩2
-
Microsoft Learn, Using the RunAsInvoker Fix. О том, что исправление совместимости RunAsInvoker стартует приложение с токеном, унаследованным от родительского процесса, что оно перезаписывает и детекцию установщика, и обработку манифеста, что применяется как флаг загрузчика без перехвата API, и что когда код можно править, правильное исправление — объявить asInvoker в манифесте. ↩ ↩2 ↩3
-
Microsoft Learn, Registry Virtualization. О том, что виртуализация реестра — технология совместимости, которая прозрачно перенаправляет глобальные записи в HKLM\Software в пользовательский VirtualStore, что в охвате только интерактивные 32-разрядные процессы и она отключена для процессов, которые задают requestedExecutionLevel в манифесте, и для 64-разрядных процессов, и что её ставят как временную технологию, предназначенную к удалению из будущей Windows. ↩ ↩2
-
Microsoft Learn, High DPI Desktop Application Development on Windows. О том, что приложение без поддержки DPI считается рисующим при фиксированных 96 DPI и на дисплее с высокой плотностью Windows растягивает растр, поэтому оно выглядит размытым, а также различия режимов осведомлённости о DPI (Unaware/System/Per-Monitor). ↩ ↩2
-
Microsoft Learn, Download and install the Windows ADK. О том, что Windows ADK включает Compatibility Administrator и Standard User Analyzer, и как думать о выборе версии ADK и как скачивать и устанавливать. ↩
-
Microsoft Learn, Compatibility Administrator User’s Guide. О том, что Compatibility Administrator даёт применение исправлений совместимости, режимов совместимости и сообщений AppHelp и создание пользовательской базы, и что ставятся и 32-, и 64-разрядные издания и для 32-разрядных приложений нужно 32-разрядное издание, для 64-разрядных — 64-разрядное. ↩
-
Microsoft Learn, Creating a Custom Compatibility Fix in Compatibility Administrator. О том, что исправление совместимости (раньше называлось шимом) — маленький кусок кода, который перехватывает вызов API; порядок создания Application Fix в пользовательской базе (указать имя приложения, поставщика и целевой EXE, выбрать режим совместимости, выбрать дополнительные шимы, задать условия сопоставления); и что следует оставить условия, которые верно идентифицируют приложение, сужая сведения сопоставления. ↩ ↩2
-
Microsoft Learn, Compatibility Fix Database Management Strategies and Deployment. О том, что централизованно ведомая база рекомендуется как стратегия управления пользовательской базой совместимости, что исправление совместимости должно включать проверку версии (условие сопоставления), чтобы не применяться к новой версии, локальная установка через Sdbinst.exe (параметры -q, -u, -g), что установка новой версии с тем же GUID базы автоматически удаляет старую, и способы раздачи через MSI или сценарий. ↩ ↩2 ↩3
Похожие статьи
Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.
Win32 Thread Pool API — параллелизм без создания потоков через CreateThreadpoolWork
По всему нативному коду разбросаны вызовы CreateThread? Статья разбирает Thread Pool API Win32, переработанный в Vista, — четыре объекта ...
Именованные каналы на практике — стандартный IPC Windows: от проектирования до безопасности
Практическое руководство по именованным каналам — стандартному межпроцессному взаимодействию Windows. Статья по первичным источникам разб...
Приложения, которые ломаются после выхода из сна — как работают события питания Windows и как строить бизнес-приложения, которые это переживают
Открыли ноутбук — и соединения бизнес-приложения мертвы: причина в проекте, который не учитывал сон. Статья разбирает поток уведомлений W...
DllMain и блокировка загрузчика — настоящая причина, почему говорят «ничего не делай в инициализации DLL»
Почему из DllMain нельзя вызывать LoadLibrary и синхронизироваться с другими потоками. Статья по первичным источникам объясняет, как блок...
Что на самом деле значит «Не отвечает» — как Windows решает, что приложение зависло, и как проектировать приложения, которые не зависают
«Не отвечает» в Windows — механизм, в котором ОС судит, что окно не извлекало сообщение 5 секунд, и подменяет его окном-призраком. Статья...
Связанные темы
Эти страницы показывают тему статьи в более широком контексте услуг и решений.
Технические темы Windows
Раздел о разработке Windows, расследовании сбоев и использовании существующих активов.
Услуги по этой теме
Статья напрямую связана со следующими услугами.
Разработка приложений для Windows
Бизнес-приложения, интеграция оборудования и средства связи — от требований до разработки.
Частые вопросы
Вопросы, которые часто возникают при консультациях по теме статьи.
- Если приложение заработало после галочки в режиме совместимости, можно ли так и пользоваться?
- Чтобы бизнес не встал в короткой перспективе — да. Режим совместимости — это перехват 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, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.