How Windows App Compatibility Works — Keeping Old Apps Alive with Compatibility Mode, Shims, and Compatibility Administrator

· Updated: · · Windows, Compatibility Mode, Shims, Application Compatibility, Compatibility Administrator, Legacy Asset Reuse, Windows Development, Existing Systems

Revision history (first version, published Aug 20, 2026)
First published
Cite this article(DOI (registered archive): 10.5281/zenodo.22170873)

The DOIs below refer to previously archived versions and may not match the current text. Use this page’s URL to reference the current text.

Go Komura (2026). How Windows App Compatibility Works — Keeping Old Apps Alive with Compatibility Mode, Shims, and Compatibility Administrator. KomuraSoft LLC. https://comcomponent.com/en/blog/windows-appcompat-shims-compatibility-mode/

DOI (registered archive)
10.5281/zenodo.22170873
DOI (last registered version)
10.5281/zenodo.22170874

“A ten-year-old business app whose source code no longer exists will not start on a new Windows 11 PC. But when I select ‘Windows XP’ on the Compatibility tab, it runs. Is it all right to keep using it this way?” Teams that look after old business apps bring us questions like this.

Compatibility mode is not a feature that turns the whole OS back into an older Windows. It is a mechanism that supplements, for that app alone, the behavior the app expects from an older Windows. At its center are small compatibility fixes that intercept calls between the app and the Windows API: shims.1

This article is written for IT staff at small and mid-sized companies and for Windows app developers. It works through the topic in the order what can be fixed → why it runs → how to apply and distribute it → how to decide between life-extension and migration, using primary sources on Microsoft Learn to confirm what happens beyond the checkbox.

1. The Conclusion First — Compatibility Mode Is Fine to Use, but Manage It as Life-Extension

Keeping the business running on Compatibility mode for the time being is a reasonable choice in itself; it uses a mechanism that Windows provides officially. Windows itself applies compatibility fixes to known apps.1 The app has not been fixed, though. The real goal is eventually to fix it so that it runs without shims.

Whether to use it is easiest to decide in the following order.

Order of decision What to check Where to read
1. Determine whether it is in scope Is the problem in how the app uses the API? Or is it a driver, 16-bit, or dedicated-hardware problem? Sections 2 and 3
2. Choose the fix you need What has to be supplemented for it to run: the version check, paths, privilege requests, and so on Sections 4 and 5. Ready-made settings in Section 6, RunAsInvoker in Section 7, distributing individual shims in Section 8
3. Decide how to operate it once it runs Can you record the settings and verify them at each Windows update? How long will you extend its life? Section 9

In particular, returning success to an “is this an administrator?” check and granting administrator privileges are two different things. A shim is subject to the same security constraints as the app and does not bypass the OS’s protections.12 RunAsInvoker, likewise, suppresses the elevation request and starts the app with the same privileges as the caller; it is not a feature that adds privileges.3

Once you understand the mechanism, you can turn “we cannot touch it because nobody knows why it works” into life-extension where you can explain how far you can rely on it, under what conditions it breaks, and when to rewrite.

Understanding the mechanism changes the quality of life-extensionUsing Compatibility mode without knowing the mechanism leads to unstable life-extension nobody dares touch, while understanding the mechanism lets you decide with reasons how far you can rely on it, what will break it, and when you should rewriteUse it without knowing the mechanismUnstable life-extension nobody dares touchUse it after understanding the mechanismDecisions backed by reasonsHow far you can rely on itWhat will break itWhen you should rewrite

Figure 1: The same life-extension differs in quality between unease without knowing the mechanism and decisions grounded in understanding.

In the diagram a solid line marks a relation that always holds and a dashed line marks a conditional one (the conditions are given per relation on the detail page). The full list of relations (16 in total, with evidence and certainty) and the definitions of the main concepts are collected on the knowledge map detail page (in Japanese). Data: JSON-LD / Turtle

2. The First Triage — Is It a Problem a Shim Can Fix?

2.1. What Can Be Fixed Is a User-Mode Problem on the App Side

What a shim can do stays within the range that a code fix in the app could also achieve. It is an alternative for when the source code is gone, the vendor’s support has ended, or the app cannot be fixed right now; it is not more powerful than fixing the code.1

Problems such as refusing to start after looking at the OS version, assuming an old write location, or requesting administrator privileges that are not actually needed are candidates. Section 5 looks at the specific shims.

2.2. Cases That No Amount of Trying Settings Will Solve

The following problems need a remedy other than Compatibility mode.

Problem Why a shim cannot solve it
Kernel-mode incompatibility A shim runs inside a user-mode process, so it cannot fix a device driver. The same applies to unsupported drivers for old measuring instruments, USB dongles, and printers, and to the parts of antivirus software that run in the kernel
16-bit apps on 64-bit Windows The OS does not support running 16-bit apps, so startup itself fails
Direct hardware access An app that assumes it can touch I/O ports or physical memory directly from user mode is beyond what a shim can fake
Bypassing security mechanisms A shim cannot turn an operation the app is not allowed to perform into a permitted one

The kernel-mode problems and the security constraints are limits that come from where a shim runs.1 ForceAdminAccess and WRPMitigation only fake the success of a check or a write so that the app can proceed; they do not actually modify the protected resource.2

For the 16-bit problem, check the installer as well as the app itself. Even if the app is 32-bit, an old package whose launcher (stub) alone is 16-bit ends up as “the app runs but cannot be installed.” On 64-bit Windows, handles have 32 significant bits and cannot be truncated to 16 bits when passed, among other reasons, so 16-bit apps are not supported and startup fails with ERROR_BAD_EXE_FORMAT.4

Cases where shims do not workA shim runs inside a user-mode process, so it does not work on kernel-mode driver problems, 16-bit apps, direct hardware access, or bypassing security mechanismsno effectno effectno effectno effectShim (runs in user mode)Kernel driver16-bit appDirect hardware accessBypassing security mechanismsStartup itself fails on 64-bitOnly fakes success to let the app proceed

Figure 2: Shims are limited to user mode and do not reach the kernel, 16-bit apps, direct hardware access, or security bypasses.

Also, an app with self-integrity checks, such as old copy protection or tamper detection, may treat the API hook itself as an anomaly. It is not the case that every user-mode app can be rescued by a shim.

3. Telling Similar Features Apart — Shims, UAC Virtualization, WOW64, and DPI Virtualization

When “the old app ran,” the mechanism at work is not necessarily just a shim. Let us separate the backward-compatibility layers Windows has. In practice, several of them may be combined.

Layer What it does Main targets
Shims (Compatibility mode) Intercept API calls and fake the same responses an older Windows would give Apps in general written against an older OS
UAC virtualization (file/registry) Redirect writes to HKLM\Software or Program Files that lack permission into a per-user VirtualStore 32-bit apps written on the assumption of administrator privileges
WOW64 Run 32-bit apps as they are on 64-bit Windows (provides 32-bit views of the registry and files) 32-bit apps in general
DPI virtualization Have a non-DPI-aware app render at 96 DPI and display it with bitmap stretching Old apps on high-DPI displays

3.1. UAC Virtualization: Diverting Writes to a Per-User Location

UAC virtualization is a transitional measure that works on 32-bit interactive processes without a manifest. Microsoft itself positions it as an interim technology that it intends to remove from a future Windows.5 WOW64, which runs 32-bit apps, and UAC virtualization, which redirects writes to per-user locations, are separate mechanisms.

Redirection to Wow6432Node and the real-world harm and remedies of VirtualStore are covered in Registry 32-bit/64-bit Redirection and Virtualization Pitfalls. This article stays within what is needed to distinguish them from shims.

Where UAC virtualization fitsUAC virtualization is a transitional measure that works on 32-bit interactive processes without a manifest and redirects writes to a per-user VirtualStore, but Microsoft itself states that it is an interim technology it intends to remove from a future Windows32-bit interactive process without a manifestUAC virtualization takes effectWrites redirected to a per-user VirtualStoreInterim technology slated for removal

Figure 3: UAC virtualization is a transitional measure for 32-bit processes without a manifest and cannot be relied on permanently.

3.2. DPI Virtualization: Stretching Old Rendering

An app that does not declare DPI awareness is treated as rendering at 96 DPI (100%). Because Windows stretches that bitmap, the display looks blurry on a high-DPI monitor. “Override high DPI scaling behavior” on the Compatibility tab is the switch that changes the behavior of this virtualization.6

How DPI virtualization worksAn app that does not declare DPI awareness is treated as rendering at 96 DPI and Windows stretches the bitmap for display, so it looks blurry, and Override high DPI scaling behavior on the Compatibility tab switches the behavior of this virtualizationswitches the virtualization behaviorApp that does not declare DPI awarenessTreated as rendering at 96 DPIBitmap stretched for displayBlurry on a high-DPI monitorOverride high DPI scaling behavior

Figure 4: A non-DPI-aware app is treated as 96 DPI and stretched, and the override on the Compatibility tab is the switch for this virtualization.

4. Why Compatibility Mode Makes It Run — Shims and Their Application at Startup

4.1. Replacing the Destination of API Calls

The path by which a Windows executable (PE format) calls an API in an external DLL goes through the import address table (IAT). When the app calls GetVersionEx, for example, execution jumps to the address recorded in the IAT.

When the app is loaded, the shim rewrites this IAT entry to the address of the shim code. This is the API hook. APIs obtained dynamically through GetProcAddress are handled by hooking GetProcAddress itself.1

The interposed shim returns an old OS version, reroutes file access, and so on, and calls the real API when needed. It shows the app “the Windows behavior it expects” and hands the OS a call that fits the current mechanism: an interpreter, so to speak.

How a shim intercepts an API callThe app's API calls go through the IAT, and rewriting the IAT entry to point at the shim at load time lets the shim intercept, fake the same response an older Windows would give, and then call the real API when neededAPI callrewritten at load time to point at the shimwhen neededhandled by a hookAppIAT entryShim (interpreter)Real Windows APIFakes the same response an older Windows would giveCall through GetProcAddress

Figure 5: The shim sits between the app and the Windows API. What is rewritten is the app’s IAT; the OS itself is unchanged.

What changes is the call path on the app side, not the OS itself. Because a shim runs under the same security constraints as the app, there is no need to relax the OS’s security settings in order to use one.1

4.2. The .sdb Decides Which EXE Gets What

The shim database is a binary file with the .sdb extension. It identifies executables by matching attributes such as file name, size, checksum, and version, and is consulted when a process starts. The terms used here break down as follows.7

Term Role
Appfix (shim) Applies compatibility fixes such as API hooks
Apphelp Displays a message such as “This app has a compatibility problem”
Compatibility layer (Compatibility mode) Bundles several shims and flags and applies them together

It is not only apps for which the user has set Compatibility mode that are matched. Every process start is checked against the OS’s standard database. Windows ships with fixes for thousands of known apps, stored under %WINDIR%\AppPatch. The compatibility fixes Microsoft provides ship as part of Windows and are updated through Windows Update.1

Shim database matching at process startEvery process start is matched against the shim database, and if an entry matches the matching attributes, an Appfix injects shims or Apphelp displays a message, otherwise the process starts as isYesYesNobundle of several shims and flagsProcess startMatched against the shim database (.sdb)Matched by file name, size, and so onEntry found?Appfix (inject shims)Apphelp (display a message)Start as isCompatibility layer (Compatibility mode)

Figure 6: Matching happens on every process start, not only for apps with Compatibility mode set.

A compatibility layer contains not only API hooks but also startup flags. RunAsInvoker in Section 7 is a compatibility fix that does not intercept an API; it acts on the execution level at startup as a loader flag.3

4.3. PCA May Also Detect a Problem and Apply a Fix

Even when no administrator sets anything by hand, the Program Compatibility Assistant (PCA) may apply compatibility settings. PCA monitors app execution and, when it detects signs of a known problem, either proposes a fix or, in some cases, applies it automatically.8

For example, a compatibility mode such as PINDLL is used for an app that crashes by calling code in an already-unloaded DLL, and WRPMITIGATION for an app that fails to write to protected Windows files.8

How PCA applies compatibility settings automaticallyPCA monitors app execution and, when it detects signs of a known compatibility problem, either proposes applying a fix to the user or, in some cases, applies the compatibility setting automaticallyYeshandled by a proposalsome casesNoApp executionPCA monitorsSigns of a known problem?Which case?Proposes applying a fixApplies the compatibility setting automaticallyRuns as isExamples such as PINDLL and WRPMITIGATION

Figure 7: PCA monitors app execution and, when it detects signs of a known problem, proposes a fix or applies it automatically.

“I never set it, but the Compatibility mode box was checked” is, in most cases, this path. It is not necessarily a fault or a mis-click; it can also be the result of Windows responding to a problem.

5. Choosing a Fix from the Symptom — Representative Shims and Version Checks

5.1. What Ready-Made Shims Can Supplement

Of the ready-made shims Microsoft publishes, these are the ones often used to extend the life of business apps.2

Shim What it can do (summary)
WinXPSP3VersionLie and other VersionLie-family shims Return a specified older version to OS-version queries (version spoofing)
CorrectFilePaths Reroute access to an unwritable or nonexistent file path to another location
VirtualRegistry Redirect or spoof registry reads and writes (including version spoofing and simulating nonexistent keys)
ForceAdminAccess Temporarily return True to an “is the user a member of the Administrators group?” check
RunAsAdmin / RunAsHighest / RunAsInvoker Give, from the outside, an execution level equivalent to the manifest’s requireAdministrator / highestAvailable / asInvoker setting
WRPMitigation Fake success for writes to protected OS files and registry keys so that the app can proceed
EmulateGetDiskFreeSpace Report free disk space as at most 2 GB (for apps that overflow on large disks)
GlobalMemoryStatusLie Spoof the reported memory-status values (for apps that fail a memory check at startup)
LoadLibraryRedirect Load the current DLL on the Windows side instead of an old system DLL bundled with the app

What most shims do is return the answer the old app expects. They reproduce, inside that process only, the assumptions of the era when the app was written: “disk capacity tops out at 2 GB,” “the OS is XP,” “the administrator check succeeds.” As Section 2 showed, faking an answer and actually changing privileges or resources are different things.

5.2. The Value of GetVersionEx Changes Even Without Selecting Compatibility Mode

Version spoofing is not only a matter of selecting Compatibility mode by hand. Since Windows 8.1, the value GetVersionEx returns depends on the app’s manifest. Without a <supportedOS> declaration inside <compatibility>, it returns 6.2, the Windows 8 value, even when the app is actually running on a newer Windows. With a declaration, it returns a value up to the highest OS declared. An app that declares GUIDs up through Windows 8.1, for example, sees 6.3 even on Windows 11.910

If a VersionLie-family shim is applied on top of that, it reports the version of the OS selected in Compatibility mode. You need to look at the default response determined by the manifest and then at the replacement made by the shim, in that order.9

How the OS version an app sees is determinedThe value GetVersionEx returns depends on whether the manifest has a supportedOS declaration, returning the Windows 8 value 6.2 without one and a value up to the highest declared OS with one, and if a VersionLie-family shim is applied it is overridden with the version of the selected OSNoYesYesNoGetVersionEx querysupportedOS declared?Windows 8 value (6.2) returnedValue up to the highest declared OSVersionLie shim applied?Version of the OS selected in Compatibility modeValue returned as is

Figure 8: The Windows version an app sees is determined in stages by the manifest and the shim.

So where to look also depends on the symptom. If your own app is misidentifying Windows 11 as Windows 8 and that is causing trouble, check the supportedOS declaration first. If, on the other hand, an old app refuses to start solely because of a version check, VersionLie is worth trying. Its actual behavior is often fine on the newer OS, so this type has a high chance of having its startup refusal resolved by a shim.

Two version-related symptoms and their remediesIf your own app identifies Windows 11 as Windows 8, suspect the manifest's supportedOS declaration, and an old app that refuses to start because of a version check can very likely be gotten past with a VersionLie shimWindows 11 identified as Windows 8Suspect the supportedOS declarationRefuses to start on a version checkTry getting past it with VersionLieActual behavior is often fine on the newer OS

Figure 9: Suspect the manifest when the version comes out old, and VersionLie when startup is refused.

6. Check on One Machine First — The Compatibility Tab and the Layers Key

6.1. Look at Where the Checkboxes Are Saved

Settings saved on the Compatibility tab of the Properties dialog are written to the AppCompatFlags\Layers key in the registry. This is where compatibility layers are specified, and DXGI’s app-compatibility settings use it too.11

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

For an EXE with “Windows XP (Service Pack 3),” “Run this program as an administrator,” and “Override high DPI scaling behavior” set, you see a value like the following.

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

Representative correspondences between items and values are as follows. These are Windows 11 examples; item names and values can differ by OS version.

Compatibility tab item Value written (example) What it actually is
Compatibility mode: Windows XP (Service Pack 3) WINXPSP3 A compatibility layer bundling version spoofing and several other shims
Reduced color mode: 8-bit (256) color 256COLOR Relaxation for the old color mode
Run in 640 x 480 screen resolution 640X480 Run at a low resolution
Disable fullscreen optimizations DISABLEDXMAXIMIZEDWINDOWEDMODE Disable rendering optimizations when in full screen
Override high DPI scaling behavior (Application) HIGHDPIAWARE Stop DPI virtualization (bitmap stretching)6
Run this program as an administrator RUNASADMIN Request elevation at startup

6.2. Separate Which User It Applies To from When It Applies

The HKCU side is a setting for that user only. If you save through “Change settings for all users,” it is written to the key of the same name on the HKLM side and applies to all users. When provisioning PCs, check which of the two you are saving to.

Also, the setting is applied to the process the next time that EXE starts. The loader reads the saved value and applies the corresponding compatibility layer.

How a Compatibility tab setting takes effectA Compatibility tab setting is saved to the Layers key under AppCompatFlags as the EXE path and a value, and the next time that EXE starts the loader reads the value and applies the corresponding compatibility layer to the processSet on the Compatibility tabEXE path and value saved to the Layers keyNext start of the EXELoader reads the valueCompatibility layer applied to the processHKCU is for that user onlyHKLM applies to all users

Figure 10: The checkbox is really a write to the Layers key, and it is applied at the next startup.

6.3. Do Not Confuse Compatibility Mode with the Elevation Setting

RUNASADMIN lives in the same Layers key as WINXPSP3. When it looks as though “setting Compatibility mode added or removed elevation as well,” checking the value directly lets you separate the compatibility-layer setting from the elevation setting.

The Compatibility tab is the entry point to the representative ready-made layers. Selecting and combining individual shims is the job of Compatibility Administrator in Section 8. Before that, let us look at RunAsInvoker, which comes up often in day-to-day operations.

7. RunAsInvoker — Suppressing Only the Unnecessary Elevation Requests

7.1. Separate “Requests Administrator” from “Needs Administrator Privileges”

Some old business apps request UAC elevation every time they start, because of a requireAdministrator setting in the manifest or because the EXE name or contents cause them to be misdetected as an installer. Many of them, however, request it only because they inherited an XP-era design, and do not actually use administrator privileges.

RunAsInvoker overrides both installer detection and manifest processing and starts the app with the token inherited from the parent process. If the caller has standard-user privileges, it keeps those privileges.3

How RunAsInvoker suppresses elevation requestsA requireAdministrator declaration in the manifest or misdetection as an installer causes a UAC elevation request at startup, but applying RunAsInvoker overrides both and starts the app with the token inherited from the parent processNoYesrequireAdministrator declarationRunAsInvoker applied?Misdetected as an installerUAC elevation request at every startStarts with the parent's tokenWork that needs administrator fails inside the app

Figure 11: RunAsInvoker only overrides the cause of the elevation request; it does not add privileges.

7.2. Try It Temporarily with an Environment Variable

Without creating an .sdb, you can apply the same layer temporarily with the __COMPAT_LAYER environment variable. The following examples apply it to child processes started from that Command Prompt or PowerShell session.

:: 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'

Adopt it only after confirming, with the same standard privileges as the actual users, that everything the business needs works.2 If the app does not need administrator privileges, putting the commands in a batch file and distributing it in place of a shortcut reduces both the handing out of local administrator rights and the calls to IT every time UAC asks for a password. It is a compatibility technique that moves in the direction of the principle of least privilege.

What distributing a RunAsInvoker batch file achievesDistributing a two-line batch file that sets RunAsInvoker in place of a shortcut means standard users do not need local administrator rights and IT is no longer called for UAC password prompts, an operation in line with the principle of least privilegeDistribute a two-line batch fileNo need to hand out administrator rightsIT not called for UAC promptsOperation in line with least privilege

Figure 12: Distributing a batch file alone reduces both the handing out of administrator rights and the calls for UAC help.

7.3. Distinguish the Scope of Effect, Permanent Application, and Fixing the App

RunAsInvoker does not add privileges. Writes to HKLM or updates under Program Files that truly need administrator privileges fail inside the app. When the conditions are met, they may instead be redirected to VirtualStore by UAC virtualization. If saving settings appears to have “stopped working,” suspect virtualization.5

The environment-variable approach affects only child processes that start with that environment inherited. For permanent application, set the Layers key directly or distribute an .sdb. There is no item on the Compatibility tab for selecting RUNASINVOKER.

Temporary and permanent application of RunAsInvokerApplication through the COMPAT_LAYER environment variable affects only child processes started from there, and permanent application uses a direct setting in the Layers key or distribution through an .sdbSet via environment variableAffects child processes onlyTemporary applicationSet directly in the Layers keyPermanent applicationDistribute via sdb

Figure 13: The environment-variable approach is a temporary application limited to child processes; make it permanent with the Layers key or an .sdb.

If you can modify the app, the proper fix is to move the settings file location under %APPDATA% and declare asInvoker in the manifest, rather than piling on compatibility settings.3

8. Rolling Out to the Organization — Compatibility Administrator and sdbinst

8.1. Match the Tool’s 32-bit/64-bit Edition to the App

Compatibility Administrator is included in the Windows ADK (Windows Assessment and Deployment Kit).12 Both a 32-bit and a 64-bit edition are installed; use the 32-bit edition to fix 32-bit apps and the 64-bit edition for 64-bit apps.13

The other caution is not to conclude “it is fixed” from a test run as administrator. In an elevated state, UAC virtualization and redirection do not work as they normally would, and you can misjudge the result. Confirm the effect of a fix with the same account and privileges as the actual users.2

Two cautions when using Compatibility AdministratorUse the 32-bit edition to fix 32-bit apps and the 64-bit edition for 64-bit apps, and confirm the effect of a fix not in an elevated state but with the same account and privileges as the actual users32-bit appFix with the 32-bit edition64-bit appFix with the 64-bit editionTest in an elevated stateRisk of misjudging it as fixedTest with the actual users' privilegesEffect confirmed correctly

Figure 14: Choosing between the 32-bit and 64-bit editions and testing with the actual users’ privileges are the cautions at the entrance.

8.2. Try a Layer First, Then Narrow Down to the Shims You Need and the Target EXE

Creating a custom compatibility database proceeds in the following order.14

  1. Create a new database under “Custom Databases” in the left pane, then choose “Create New” → “Application Fix.”
  2. Enter the app name and vendor name, and specify the target EXE file.
  3. Select a compatibility mode (layer) such as “Windows XP compatibility” and try the bundle of shims first.
  4. If necessary, select individual compatibility fixes. You can narrow it down to a minimal configuration such as VersionLie only or CorrectFilePaths only.
  5. Check the matching conditions such as file size, checksum, and version, then save.

Both “choose a shim that works” and “make it take effect only on the right EXE” are necessary. The default basic conditions are usually enough for matching, but keep a condition that identifies the app’s version. That way, once the vendor releases a fixed version, the old fix does not keep being applied to the new version.1415

Steps for creating a custom compatibility databaseCreate an Application Fix in a new database, specify the app name and target EXE, try the Compatibility mode bundle, narrow down to individual shims if necessary, then check the matching conditions and saveCreate a new databaseChoose Application FixSpecify the app name and target EXETry the Compatibility mode bundleNarrow down to individual shims if neededCheck the matching conditions and saveKeep a version-identifying condition

Figure 15: An Application Fix starts with the Compatibility mode bundle, is narrowed to a minimal configuration, and is limited to its target by matching conditions.

Try the .sdb you created on a test machine, confirm that it works as intended, and only then proceed to distribution.

8.3. Apply and Remove with sdbinst, and Manage Updates by GUID

To apply it on each PC, run sdbinst.exe with administrator privileges. Besides installing, you can uninstall by specifying the file or the database GUID.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}

In an organization where compatibility fixes keep growing, rather than giving each app installer its own .sdb, the recommended approach is to consolidate them into one custom database per company, or one per department, and manage them centrally. Updating and redistributing a consolidated database is easier to manage than tracking many one-line databases.15

A custom database has its own GUID. Installing a new version with the same GUID automatically replaces the old version. For distribution, use an existing channel that can run with administrator privileges, such as an MSI package or a startup script.15

From creating a custom .sdb to distributing itCreate a custom compatibility database with Compatibility Administrator, test it on a test machine, apply it to each PC with sdbinst, and when updating, install a new version with the same GUID so that the old version is replaced automaticallyCreate with Compatibility AdministratorTest on a test machineApply to each PC with sdbinstInstall a new version with the same GUIDOld version replaced automaticallyRegistered in Programs and Features

Figure 16: A custom .sdb is rolled out through creation, testing, and sdbinst distribution, and updates are managed by GUID.

An installed custom database is also registered in “Programs and Features” (Installed apps), which you can use for inventory and to confirm removal. Record which .sdb went onto which PC in the asset-management ledger as well.

9. Decide After It Runs — Maintaining the Life-Extension and Setting a Migration Deadline

9.1. Separate the Fixes the OS Provides from Your Own Organization’s Decisions to Apply Them

Even once a shim makes the app run, the app’s problem itself has not been fixed. A shim is a stopgap tailored to a specific way of using an API, and if the OS implementation changes, its premise can collapse.

The shims Microsoft provides are themselves maintained through Windows Update as part of Windows.1 On the other hand, managing what you applied through a custom database, and whether the business can continue on that combination, is your own organization’s job. Include verification at every feature update in the cost of life-extension.

Shims as a stopgap and the responsibility for maintaining themA shim is a lie tailored to a specific way of using an API and its premise collapses if the OS implementation changes, the shims Microsoft provides are maintained through Windows Update, but the lies applied through a custom database are looked after by your own organization, and verification at every feature update is the cost of life-extensionA shim is a stopgap liePremise collapses if the OS implementation changesShims provided by MicrosoftMaintained through Windows UpdateLies in a custom databaseLooked after by your own organizationVerification at every feature update is the cost of life-extension

Figure 17: Responsibility for maintaining the lie that is a shim is split between what Microsoft provides and your own custom part.

9.2. Decide by Remaining Period of Use, Dependencies, and Verification Capacity

It is important not to decide on long-term use from the mere fact that “it ran under Compatibility mode.” Running on a shim means the app happened to fit into the safety net Windows provides. Decide by combining the following axes.

Decision axis Conditions leaning toward life-extension (shim) Conditions leaning toward migration or rewrite
Remaining period of use The business process itself is to be retired in 1 to 2 years Expected to stay in use for 5 years or more
Source code None (vendor gone or code lost) Exists, or the asset can be recovered
Depth of dependencies Only a user-mode API-compatibility problem Depends on a driver, 16-bit code, or dedicated hardware
Alternatives No packaged product or new version exists The destination product or technology is clear
Impact of a failure The business can continue on a fallback procedure even if it stops Core business takes a direct hit
Verification capacity Behavior can be checked at every feature update No verification resources, so it tends to be left frozen

9.3. If You Extend Its Life, Make Recording, Verification, and a Deadline a Set

  1. Record. Keep a record of which shim or layer was applied to which EXE, and why. Put the Layers key value and the .sdb GUID in the ledger as well. The idea of not handing a “nobody knows why it works” state to the next person in charge is the same preservation covered in When You Inherit a System With No Source Code and No Documentation.
  2. Verify. At each Windows feature update, confirm that the life-extended app starts and that its main operations work. Tie this to the OS replacement planning covered in Practical Options After Windows 10 End of Support.
  3. Set a deadline. Decide when the life-extension ends, such as “until the next core-system replacement” or “until March 2028,” and run the migration study in parallel.
The three-part operating set once you decide on life-extensionRecord in a ledger which shims the app runs on, verify the behavior of shim-extended apps at every feature update, set a deadline for the life-extension, and run the migration study in parallelDecide on life-extensionRecord in a ledger which shims it runs onVerify behavior at every feature updateSet a deadline for ending the life-extensionRun the migration study in parallel

Figure 18: Life-extension is operated as a three-part set of recording, verification, and a deadline, with the migration study running in parallel.

9.4. Use Shims to Buy Time for Studying and Preparing the Migration

The migration options depend on the app’s technology. For a VB6 app, the starting point is the three choices laid out in How Long Will VB6 Apps Keep Running?: full rewrite, automated conversion, or phased migration. For an app that depends on ActiveX/OCX, the “keep, wrap, or replace” decision table in How to Handle ActiveX / OCX Today applies.

The healthy way to position shims is as a means of safely buying the time to study and prepare such a migration project.

Migration options and where shims fitThe standard migration approach depends on the app's technology, with the three choices of full rewrite, automated conversion, and phased migration for VB6 and the keep, wrap, or replace decision table for ActiveX dependencies, while shims are positioned as a way to safely buy time for studying and preparing the migration projectVB6ActiveX dependencybuys time to study and prepareWhat is the app's technology?Rewrite, automated conversion, or phased migrationKeep, wrap, or replaceLife-extension with shims

Figure 19: The standard migration approach is set by the app’s technology, and shims are positioned as a way to buy time for that study.

10. Summary

Compatibility mode is a mechanism that supplements, for the app alone, the behavior it expects from an older Windows. The shims at its center intercept API calls by replacing IAT entries and the like, and supplement version checks and access destinations. Windows itself uses them through its default database and PCA.

Think of the response in this order: first determine whether the problem is within a shim’s scope, confirm the settings you need with the Compatibility tab or RunAsInvoker, and for organization-wide rollout manage them with Compatibility Administrator and sdbinst. Choosing the 32-bit or 64-bit tool, verifying with the actual users’ privileges, and managing targets and versions through matching conditions and GUIDs are the practical essentials.

They are limited to user mode, however, and do not bypass security mechanisms. Kernel drivers, 16-bit apps on 64-bit Windows, and direct hardware access need other remedies. RunAsInvoker, too, only suppresses unnecessary elevation requests and does not add privileges.

Once it runs, record the settings, verify at every feature update, set a deadline, and run the migration in parallel. The decision to rely on Compatibility mode includes all of this.

The next time a single checkbox makes an old app run, ask yourself this: “Which lie is this app running on, and how long will that lie hold?” If you can answer, life-extension is a perfectly respectable strategy.

KomuraSoft LLC handles behavior investigation and life-extension design for old business apps without source code (selecting shims and compatibility modes, creating and rolling out custom .sdb files), compatibility verification of existing apps for Windows 11 migration, and planning the rewrite or migration that runs alongside the life-extension. It is fine to consult us from the stage of “it ran under Compatibility mode, but is it all right to leave it this way?”

References

  1. Microsoft Learn, Understanding and Using Compatibility Fixes. On compatibility fixes (shims) redirecting API calls by rewriting the IAT (import address table), dynamic linking being handled by hooking GetProcAddress, shims being subject to the same security constraints as the app and unable to bypass the OS’s security mechanisms, shims being limited to user mode and unable to fix driver problems, fixes possible with shims also being possible with code changes, usage scenarios such as apps whose vendor support has ended, and Microsoft-provided compatibility fixes shipping as part of Windows and being updated through Windows Update. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9

  2. Microsoft Learn, Compatibility Fixes for Windows 10, Windows 8, Windows 7, and Windows Vista. A list and descriptions of known compatibility fixes such as CorrectFilePaths, VirtualRegistry, ForceAdminAccess, RunAsAdmin/RunAsHighest/RunAsInvoker, WRPMitigation, EmulateGetDiskFreeSpace, GlobalMemoryStatusLie, LoadLibraryRedirect, and the VersionLie family; the choice between the 32-bit and 64-bit editions of Compatibility Administrator; and the need to verify with the actual user account because virtualization and redirection do not work as expected when testing in an elevated state. ↩ ↩2 ↩3 ↩4 ↩5

  3. Microsoft Learn, Using the RunAsInvoker Fix. On the RunAsInvoker compatibility fix starting the app with the token inherited from the parent process, overriding both installer detection and manifest processing, being applied as a loader flag without intercepting APIs, and declaring asInvoker in the manifest being the proper fix when the code can be changed. ↩ ↩2 ↩3 ↩4

  4. Microsoft Learn, Running 32-bit Applications. On WOW64 being the emulation layer that runs 32-bit apps on 64-bit Windows and isolates file and registry conflicts, and on 64-bit Windows not supporting the execution of 16-bit apps, whose startup fails with ERROR_BAD_EXE_FORMAT because of the number of significant bits in handles. ↩

  5. Microsoft Learn, Registry Virtualization. On registry virtualization being a compatibility technology that transparently redirects global writes to HKLM\Software into a per-user VirtualStore, applying only to 32-bit interactive processes and being disabled for processes whose manifest specifies requestedExecutionLevel and for 64-bit processes, and being positioned as an interim technology to be removed from a future version of Windows. ↩ ↩2

  6. Microsoft Learn, High DPI Desktop Application Development on Windows. On non-DPI-aware apps being treated as rendering at a fixed 96 DPI and looking blurry on high-DPI displays because Windows stretches the bitmap, and on the differences between the DPI awareness modes (Unaware/System/Per-Monitor). ↩ ↩2

  7. Microsoft Learn, Application Compatibility Database. On the compatibility infrastructure managing problems and solutions in a database in .sdb format, matching by executable attributes, Apphelp (message display) and Appfix (API hooks by shims), and compatibility layers (modes) that bundle several shims and flags. ↩

  8. Microsoft Learn, Program Compatibility Assistant scenarios for Windows 8. On PCA monitoring app execution to detect signs of known compatibility problems and proposing or automatically applying recommended fixes (PINDLL, DISABLEUSERCALLBACKEXCEPTION, VIRTUALIZEDELETE, WRPMITIGATION, and others), and on applying fixes from the Compatibility tab and the Program Compatibility Troubleshooter. ↩ ↩2

  9. Microsoft Learn, GetVersionExW function. On the value returned by GetVersionEx depending on the manifest from Windows 8.1 onward, apps not manifested for Windows 8.1/10 receiving the Windows 8 version value (6.2), and the selected OS version being reported when a compatibility mode is in effect. ↩ ↩2

  10. Microsoft Learn, Targeting your application for Windows. On how to declare the GUIDs of supported OS versions with the supportedOS element in the compatibility section of the app manifest, the behavior when there is no declaration, and 32-bit x86 apps that do not include trustInfo being subject to UAC file virtualization (redirection of writes to VirtualStore). ↩

  11. Microsoft Learn, DXGI overview. On application compatibility settings being stored in the HKCU\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers registry key (using DXGI’s compatibility settings as the example). ↩

  12. Microsoft Learn, Download and install the Windows ADK. On the Windows ADK including Compatibility Administrator and the Standard User Analyzer, how to think about choosing an ADK version, and how to download and install it. ↩

  13. Microsoft Learn, Compatibility Administrator User’s Guide. On Compatibility Administrator providing the ability to apply compatibility fixes, compatibility modes, and AppHelp messages and to create custom databases, and on both a 32-bit and a 64-bit edition being installed, with the 32-bit edition required for 32-bit apps and the 64-bit edition for 64-bit apps. ↩

  14. Microsoft Learn, Creating a Custom Compatibility Fix in Compatibility Administrator. On a compatibility fix (formerly called a shim) being a small piece of code that intercepts API calls, the procedure for creating an Application Fix in a custom database (specifying the app name, vendor, and target EXE, selecting a compatibility mode, selecting additional shims, and setting matching conditions), and keeping conditions that correctly identify the app while narrowing the matching information. ↩ ↩2

  15. Microsoft Learn, Compatibility Fix Database Management Strategies and Deployment. On a centralized database being recommended as the management strategy for custom compatibility databases, including a version check (matching conditions) in a compatibility fix so that it is not applied to new versions, local installation with Sdbinst.exe (the -q, -u, and -g options), the automatic uninstallation of the old version when a new version with the same database GUID is installed, and distribution methods using MSI or scripts. ↩ ↩2 ↩3 ↩4

Recent articles sharing the same tags. Deepen your understanding with closely related topics.

These topic pages place the article in a broader service and decision context.

This article connects naturally to the following service pages.

Frequently Asked Questions

Common questions about the topic of this article.

If an app started working after I checked Compatibility mode, is it all right to keep using it that way?
For keeping the business running for the time being, yes. Compatibility mode is really a user-mode API hook called a shim, a mechanism that Windows provides officially as an OS setting. A shim is still only a stopgap for running an app without fixing it, though, and an OS update that changes its premise can break the app again. Record the fact that it runs under Compatibility mode in a ledger, and operate it together with a decision on whether to rewrite the app or to extend its life deliberately.
What does the Compatibility mode checkbox actually do?
When you save settings on the Compatibility tab of the Properties dialog, the path of the target EXE and a value such as "WINXPSP3" or "HIGHDPIAWARE" are written to the HKCU\Software\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers key. The next time that EXE starts, the Windows loader reads the value and applies the corresponding compatibility layer (a bundle of shims) to the process. Under Windows XP compatibility mode, for example, version spoofing returns old values to the APIs that query the OS version. The behavior of the OS itself is not changed; only that process is shown a pretend older Windows.
Can old 16-bit-era apps be run under Compatibility mode on 64-bit Windows?
No. 64-bit Windows runs 32-bit apps through a mechanism called WOW64, but it does not support running 16-bit apps, and an attempt to start one fails with ERROR_BAD_EXE_FORMAT. This is an architectural limit that a shim cannot work around. Old packages in which only the launcher part of the installer is 16-bit fail for the same reason. If you truly need one, consider means other than Compatibility mode, such as a virtual machine containing 32-bit Windows.
Can an app that "will not start unless run as administrator" be run with standard-user privileges?
RunAsInvoker is worth trying. If you run set __COMPAT_LAYER=RunAsInvoker at a Command Prompt and then start the app, elevation requests caused by a requireAdministrator setting in the manifest or by installer detection are suppressed, and the app starts with the same (standard-user) privileges as the caller. For an app that only requests administrator privileges without actually using them, this alone removes elevation from day-to-day operation. Privileges do not increase, however, so work that truly needs administrator privileges fails inside that app. Adopt it after verifying the behavior.
Where can I get Compatibility Administrator?
It is included in the Windows ADK (Windows Assessment and Deployment Kit). Download the ADK from Microsoft's site and select the Application Compatibility Tools features during installation. Note that both a 32-bit and a 64-bit edition are installed, and you must use the 32-bit edition to fix 32-bit apps and the 64-bit edition for 64-bit apps. Apply a custom compatibility database (.sdb) you have created by running the sdbinst command on each PC.

Author Profile

Profile page for the article author.

Go Komura

Representative of KomuraSoft LLC

Focused on Windows software development, technical consulting, and investigations into failures that are difficult to reproduce.

Back to the Blog