I have tried to make Windows 8.1 recognize a Delphi XE6 application (a demo program) that I have been trying to build, and have it recognize my application is Per-Monitor DP
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".
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;
interface
const
Process_DPI_Unaware = 0;
Process_System_DPI_Aware = 1; // Old windows 8.0
Process_Per_Monitor_DPI_Aware = 2; // Windows 8.1
function 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;
implementation
uses
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.