首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我如何使Windows8.1意识到我的Delphi应用程序想要支持每个显示器新闻部?

我如何使Windows8.1意识到我的Delphi应用程序想要支持每个显示器新闻部?
EN

Stack Overflow用户
提问于 2014-11-10 20:10:02
回答 3查看 5.5K关注 0票数 22

我试图让Windows8.1识别我一直在尝试构建的Delphi应用程序(一个演示程序),并让它识别我的应用程序是Per-Monitor XE6感知的,完全是通过Manifest技术。Delphi XE6 (以及所有其他类似的最新版本的Delphi)使得在项目选项中添加清单变得很容易,我已经这样做了。

这是我使用MSDN资源确定的.manifest内容。我怀疑这可能有点不正确。

如果要尝试此清单,请创建一个空的VCL应用程序,使用此内容作为清单,并添加代码(代码当前附加到我对此问题的回答中)。

代码语言:javascript
运行
复制
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
  <!-- Per Monitor DPI Awareness in Windows 8.1 uses asmv3:application + asmv3:windowsSettings -->
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>

  <!-- Dear Microsoft, Don't Lie to Me About What Version of Windows I am On -->
  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
      <!-- Windows Vista and Windows Server 2008 -->
      <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
      <!-- Windows 7 and Windows Server 2008 R2 -->
      <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
      <!-- Windows 8 and Windows Server 2012 -->
      <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
      <!-- Windows 8.1 and Windows Server 2012 R2 -->
      <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
    </application>
  </compatibility>
  <dependency>
    <dependentAssembly>
      <assemblyIdentity
        type="win32"
        name="Microsoft.Windows.Common-Controls"
        version="6.0.0.0"
        processorArchitecture="*"
        publicKeyToken="6595b64144ccf1df"
        language="*"
        />
    </dependentAssembly>
  </dependency>
</assembly>

有人成功了吗?我所发现的是,上述情况并没有得到承认。如果我先调用SetProcessDPIAwareness(Process_Per_Monitor_DPI_Aware),然后调用GetProcessDPIAwareness(hProc,Awareness),我会得到必要的Awareness = Process_Per_Monitor_DPI_Aware,但我已经读到了该方法可能存在的缺陷,因此我更喜欢只使用工作报表的方法。

如果我调用GetProcessDPIAwareness(hProc,Awareness),就会得到‘感知=Process_DPI_ `Awareness’。

我的另一个担心是,在MSDN源中,他们指定添加一个额外的清单。然而,我使用Delphi 6的IDE功能将一个也是唯一一个清单链接到我的应用程序中。我从未注意到添加任何额外的清单与只有一个清单是一个问题,除此之外,Visual 2010中的.manifest管理系统可能很差劲,这就是为什么存在提示,因此与其他IDE/语言无关。

在Visual 2013中,项目选项中有一个复选框,但我没有Visual 2013,因此无法检查工作的.manifest。

最新情况:

这是另一次对舱单的攻击:

代码语言:javascript
运行
复制
<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>

上面的小清单改变了应用程序的行为,但并不完全是我想要的方式。使用上述微小的清单,将检测到旧的Windows 8.0/Windows 7/Vista DPI感知级别。

更新2:

谢谢雷米的想法。有趣的是,下面的内容似乎足够有效,可以启动应用程序。但是,将SMI/2005语法与上面的语法混合在一起会导致并行启动错误。您可以看到,微软一直在他们的清单上搅乱了很多。请注意,以下内容实际上并不能解决我的问题,但它提供了另一个可能接近实际解决方案的“潜在基本形式”:

代码语言:javascript
运行
复制
 <assembly xmlns="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0" >
  <application>
    <windowsSettings xmlns="http://schemas.microsoft.com/SMI/2011/WindowsSettings">
      <dpiAware>true</dpiAware>
    </windowsSettings>
  </application>
</assembly>

更新3:

代码红色警报!在任何Delphi应用程序中都不使用以下操作系统兼容性标志:<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>。微软已经打破了鼠标捕捉行为,打破了我甚至无法猜到的可怕的窗口绘画方式。打开此标志会在我的应用程序中造成非常微妙的错误,包括绘制问题、无法单击控件(鼠标向下的消息由于鼠标捕获丢失而无法到达控件),以及许多其他问题。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-11-10 23:01:14

它被记录在MSDN主题Writing DPI-Aware Desktop and Win32 Applications上。

通过修改应用程序清单或调用SetProcessDpiAwarenessAPI来标记应用程序。我们建议您使用应用程序清单,因为这将在应用程序启动时设置DPI意识级别。仅在以下情况下使用API:

  • 您的代码位于通过rundll32.exe运行的dll中。这是一种不支持应用程序清单的启动机制。
  • 您需要根据OS版本或其他考虑因素做出复杂的运行时决策。例如,如果您需要应用程序在Windows 7上具有system感知,而在Windows8.1上需要动态识别,请使用True/PM清单设置。

如果使用SetProcessDpiAwareness方法设置DPI感知级别,则必须在强制系统开始虚拟化的任何Win32API调用之前调用Win32API。

新闻部感知显式值,描述

False将应用程序设置为不知道新闻部。

True将应用程序设置为系统DPI感知。

Windows8.1上的每个监视器,将应用程序设置为每个监视器-新闻部感知.在Windows上通过Windows 8,将应用程序设置为“不了解新闻部”.

Windows8.1上的True/PM,将应用程序设置为每个监视器-新闻部感知。在Windows上通过Windows 8,将应用程序设置为system感知。

您只需使用标准DPI感知清单,但指定True/PM或每个监视器,而不是True。

同样的主题使新闻部了解到以下情况:

代码语言:javascript
运行
复制
<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>

所以,用您选择的值替换True。

票数 12
EN

Stack Overflow用户

发布于 2014-11-10 22:24:21

此清单有效,但有一些警告:

  • 注意有关asmv1、asm.v2和asmv3的各种“元数据”差异。可能不重要。
  • 正如David所指出的,可能是True/PM值,而不是True,造成了所有的不同。微软显然确实将其记录在案。(咧嘴笑)
  • 一些SMI/2011变体将在没有可怕的SxS启动错误的情况下启动,但我还没有找到一个能够工作的SMI/2011版本。
  • 在使用了一个既启用了每个Monitor API又将操作系统兼容性定义为Windows8.1的应用程序之后,我在我的应用程序中发现了一些可怕的回归。Microsoft已经更改了Windows8.1级别应用程序中的鼠标焦点行为。我不建议这样做。选择via代码而不是via清单,不要使用下面的<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>示例!

这是XML。我在StackOverflow损坏这个XML的过程中遇到了一些麻烦,所以如果它看起来很糟糕,您就会看到StackOverflow错误。

代码语言:javascript
运行
复制
<?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>

你也可以有:

代码示例:

代码语言:javascript
运行
复制
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.
票数 6
EN

Stack Overflow用户

发布于 2014-11-10 20:51:35

要么修改应用程序中指向的清单,要么使用$R指令在.dpr文件中包含一个额外的清单。

另外,asmv3 3:application部分看起来也不错,但我认为您需要用小写t拼写"true“,如"True”。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26852150

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档