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

后端 未结 3 710
攒了一身酷
攒了一身酷 2020-12-31 00:21

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

3条回答
  •  灰色年华
    2020-12-31 00:55

    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 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.

    
    
      
      
        
          
            
          
        
      
    
      
        
          
        
      
    
      
        
          True/PM
        
      
    
    

    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.
    

提交回复
热议问题