How can I make Windows 8.1 aware that my Delphi application wants to support Per Monitor DPI? How can I make Windows 8.1 aware that my Delphi application wants to support Per Monitor DPI? windows windows

How can I make Windows 8.1 aware that my Delphi application wants to support Per Monitor DPI?


It is documented on the MSDN topic Writing DPI-Aware Desktop and Win32 Applications:

Mark the application as per monitor-DPI aware by modifying the application manifest or by calling the SetProcessDpiAwarenessAPI. We recommend that you use the application manifest because that sets the DPI awareness level when the application is launched. Use the API only in the following cases:

  • Your code is in a dll that runs via rundll32.exe. This is a launch mechanism that does not support the application manifest.
  • You need to make complex run-time decisions based on OS version or other considerations. For example, if you need the application to be system-DPI aware on Windows 7 and dynamically aware on Windows 8.1, use the True/PM manifest setting.

If you use the SetProcessDpiAwareness method to set the DPI awareness level, you must call SetProcessDpiAwareness prior to any Win32API call that forces the system to begin virtualization.

DPI awareness manifest value, Description

False Sets the application to not DPI-aware.

True Sets the application to system DPI–aware.

Per-monitor On Windows 8.1, sets the application to per monitor-DPI aware. On Windows Vista through Windows 8, sets the application to not DPI–aware.

True/PM On Windows 8.1, sets the application to per monitor-DPI aware. On Windows Vista through Windows 8, sets the application to system-DPI aware.

You just use the standard DPI aware manifest but specify True/PM or Per-monitor instead of True.

The same topic gives the DPI aware manifest as follows:

<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >  <asmv3:application>    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">      <dpiAware>true</dpiAware>    </asmv3:windowsSettings>  </asmv3:application></assembly>

So, replace True with your chosen value.


This manifest works but with some warnings:

  • Note the various "metadata" differences about asmv1, and asm.v2 and asmv3. Probably not important.

  • As David pointed out probably its the True/PM value, instead of True that makes all the difference. Microsoft apparently DID document it. (grins)

  • Some SMI/2011 variants WILL launch WITHOUT dread SxS launch errors, but I haven't found an SMI/2011 variant that WORKS.

  • After using an application that both enabled Per Monitor API, and defined OS compatibility as Windows 8.1, I found some HORRIBLE regressions in my application. Microsoft has changed the mouse focus behaviour in Windows 8.1 level applications. I do NOT RECOMMEND THIS APPROACH. Opt in via CODE instead of via MANIFEST, and DO NOT USE the <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/> example below!

Here is the XML. I am having some trouble with StackOverflow mangling this XML, so if it looks bad, you're seeing StackOverflow bugs.

<?xml version="1.0" encoding="utf-8" ?><asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">    <security>      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">        <requestedExecutionLevel level="asInvoker" uiAccess="false" />      </requestedPrivileges>    </security>  </trustInfo>  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">    <application>      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>    </application>  </compatibility>  <asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">    <asmv3:windowsSettings         xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">      <dpiAware>True/PM</dpiAware>    </asmv3:windowsSettings>  </asmv3:application></asmv1:assembly>

And you can has teh codez too:

Code sample:

unit PerMonitorApi;interfaceconst   Process_DPI_Unaware = 0;   Process_System_DPI_Aware = 1;    // Old windows 8.0   Process_Per_Monitor_DPI_Aware = 2; // Windows 8.1function SystemCanSupportPerMonitorDpi(AutoEnable: Boolean): Boolean; // New Windows 8.1 dpi awareness available?function SystemCanSupportOldDpiAwareness(AutoEnable: Boolean): Boolean; // Windows Vista/ Windows 7 Global System DPI functional level.var   _RequestedLevelOfAwareness:LongInt;   _ProcessDpiAwarenessValue:LongInt;implementationuses   System.SysUtils,   WinApi.Windows;type   TGetProcessDPIAwarenessProc = function(const hprocess: THandle; var ProcessDpiAwareness: LongInt): HRESULT; stdcall;   TSetProcessDPIAwarenessProc = function(const ProcessDpiAwareness: LongInt): HRESULT; stdcall;const   E_ACCESSDENIED = $80070005;function _GetProcessDpiAwareness(AutoEnable: Boolean): LongInt;var   hprocess: THandle;   HRESULT: DWORD;   BAwareness: Integer;   GetProcessDPIAwareness: TGetProcessDPIAwarenessProc;   LibHandle: THandle;   PID: DWORD;   function ManifestOverride: Boolean;   var      HRESULT: DWORD;      SetProcessDPIAwareness: TSetProcessDPIAwarenessProc;   begin      Result := False;      SetProcessDPIAwareness := TSetProcessDPIAwarenessProc(GetProcAddress(LibHandle, 'SetProcessDpiAwareness'));      if Assigned(SetProcessDPIAwareness) and (_RequestedLevelOfAwareness>=0) then      begin         HRESULT := SetProcessDPIAwareness(_RequestedLevelOfAwareness ); // If we do this we don't need the manifest change.         Result := (HRESULT = 0) or (HRESULT = E_ACCESSDENIED)         // if Result = 80070005 then ACESS IS DENIED, means already set.      end   end;begin   Result := _ProcessDpiAwarenessValue;   if (Result = -1) then   begin      BAwareness := 3;      LibHandle := LoadLibrary('shcore.dll');      if LibHandle <> 0 then      begin         if (not AutoEnable) or ManifestOverride then         begin            // This supercedes the Vista era IsProcessDPIAware api, and is available in Windows 8.0 and 8.1,although only            // windows 8.1 and later will return a per-monitor-dpi-aware result.            GetProcessDPIAwareness := TGetProcessDPIAwarenessProc(GetProcAddress(LibHandle, 'GetProcessDpiAwareness'));            if Assigned(GetProcessDPIAwareness) then            begin               PID := WinApi.Windows.GetCurrentProcessId;               hprocess := OpenProcess(PROCESS_ALL_ACCESS, False, PID);               if hprocess > 0 then               begin                  HRESULT := GetProcessDPIAwareness(hprocess, BAwareness);                  if HRESULT = 0 then                     Result := BAwareness;               end;            end;         end;      end;   end;end;// If this returns true, this is a windows 8.1 system that has Per Monitor DPI Awareness enabled// at a system level.function SystemCanSupportPerMonitorDpi(AutoEnable: Boolean): Boolean;begin   if AutoEnable then   begin    _RequestedLevelOfAwareness := Process_Per_Monitor_DPI_Aware;    _ProcessDpiAwarenessValue := -1;   end;   Result := _GetProcessDpiAwareness(AutoEnable) = Process_Per_Monitor_DPI_Aware;end;// If this returns true, This is either a Windows 7 machine, or a Windows 8 machine, or a// Windows 8.1 machine where the Per-DPI Monitor Awareness feature has been disabled.function SystemCanSupportOldDpiAwareness(AutoEnable: Boolean): Boolean;begin   if AutoEnable then   begin     _RequestedLevelOfAwareness := Process_Per_Monitor_DPI_Aware;     _ProcessDpiAwarenessValue := -1;   end;   Result := _GetProcessDpiAwareness(AutoEnable) = Process_System_DPI_Aware;end;initialization   _ProcessDpiAwarenessValue := -1;// not yet determined.   _RequestedLevelOfAwareness := -1;end.


Either modify the manifest pointed to in Project | Options | Application or include an additional manifest using the $R directive in the .dpr file.

Also your asmv3:application section looks fine except that I think you need to spell "True" with a lower case t as in "true".