Windows Shortcuts and Compatibility

Shortcuts

There is no legal way to change the shortcut's (.lnk) tech properties except the well-known ones like TargetPath or Arguments.

The usual code for shortcut creation on C# is:

        WshShell shell = new WshShell();
        try
        {
          IWshShortcut link = (IWshShortcut)shell.CreateShortcut(myShortCutPath), 
          link.TargetPath = myExecutablePath, 
          link.Description = "Run my awesome app", 
          link.Arguments = myExecutableArgs, 
          link.Save(), 
        }
        finally
        {
          Marshal.ReleaseComObject(shell); 
        }

This code will require adding COM dependency from Windows Script Host Object Model to your project.

But you can read about it in MSDN and StackOverflow.

What else we can do for the shortcut? With Windows Explorer UI we can set different compatiblity settings for our executable. But changing them does not changes the shortcut file. Moreover, if we change it for some shortcut, it changes for all of shortcuts for this executable. These settings are related to the exectuable itself and not to the shortcut.

What else we can do? We can create the Admin Shortcut. It will not apply on our executable, but will allow to run it from admin with this shortcut. There is no legal options to do this from code except byte hack. Binary comparison of two shortcuts with and without this checkbox on gives us the clue.

The 21th (0x15) byte from the beginning changes:

  • the value of 0 is default and means that checkbox is disabled
  • the value of 32 (0x20) means that shortcut will run our executable from admin.

With knowing so we can use binary patching to alter this setting from code how we want.

0x20 is a single bit set in byte. What do the other ones mean? No answer. This is the weirdness of WinAPI.

Combatibility

SO gives us a clue of how we can change the executable's compatibility settings. All of them are stored in:

HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers

or (machine-wide, not only current user)

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AppCompatFlags\Layers

There are a few values there with name of absolute executable's path, type of String and different values. Layers key may be missing, so if we want to set up settings for some executable, we should create it.

Let's check them:

  • Compatiblity with Windows 8 gives us ~ WIN8RTM value.
  • Compatiblity with Windows 7 gives us ~ WIN7RTM value.
  • Compatiblity with Windows Vista (Service Pack 2) gives us ~ VISTASP2 value.
  • Compatiblity with Windows Vista (Service Pack 1) gives us ~ VISTASP1 value.
  • Compatiblity with pure Windows Vista gives us ~ VISTARTM value.
  • Compatiblity with Windows XP SP3 gives us ~ WINXPSP3 value.
  • Compatiblity with Windows XP SP2 gives us ~ WINXPSP2 value.
  • Compatiblity with Windows 98/ME gives us ~ WIN98 value.
  • Compatiblity with Windows 95 gives us ~ WIN95 value.

Disabling the compatibility setting will remove the record from the registry.

Let's check the other checkboxes:

  • 640x480 resolution gives us ~ 640X480 value.
  • Disable display scaling gives us ~ HIGHDPIAWARE value.
  • Run from admin gives us ~ RUNASADMIN value.
  • Run app from non-elevated user (not admin) ~ RUNASINVOKER value (update from 2 Jun 2021).
  • Reduced to 8-bit color gives us ~ 256COLOR value.
  • Reduced to 16-bit color gives us ~ 16BITCOLOR value.

Windows 10 Spring Update also added a few more settings:

  • Fix scaling problems on sign in gives us ~ PERPROCESSSYSTEMDPIFORCEOFF value.
  • Fix scaling problems on open app gives us ~ PERPROCESSSYSTEMDPIFORCEON value.
  • Disable fullscreen optimizations gives us ~ DISABLEDXMAXIMIZEDWINDOWEDMODE value.
  • Override scaling with application gives us ~ HIGHDPIAWARE value (same as previous Disable display scaling).
  • Override scaling with system gives us ~ DPIUNAWARE value.
  • Override scaling with system (enhanced) gives us ~ GDIDPISCALING DPIUNAWARE value.

Combination of the flags gives as combined value like:

~ DISABLEDXMAXIMIZEDWINDOWEDMODE RUNASADMIN PERPROCESSSYSTEMDPIFORCEON HIGHDPIAWARE 640X480 16BITCOLOR WIN8RTM.

Don't know if order is meaningful, so here they are in order of Explorer created them. It seems, that tilda in the beginning is not critical, Explorer sets it, but it will work without it.

If you are really get confused with all of these flags - just open properties of the executable file and explore the Compatibility tab.

There are some another hacks (DWM8And16BitMitigation for example), they are related to DirectDraw and should be obtained from the appropriate documentation.

P.S. Complete list of compatibility flags can be obtained in MSDN.