我试图让Windows8.1识别我一直在尝试构建的Delphi应用程序(一个演示程序),并让它识别我的应用程序是Per-Monitor XE6感知的,完全是通过Manifest技术。Delphi XE6 (以及所有其他类似的最新版本的Delphi)使得在项目选项中添加清单变得很容易,我已经这样做了。
这是我使用MSDN资源确定的.manifest内容。我怀疑这可能有点不正确。
如果要尝试此清单,请创建一个空的VCL应用程序,使用此内容作为清单,并添加代码(代码当前附加到我对此问题的回答中)。
<?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。
最新情况:
这是另一次对舱单的攻击:
<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语法与上面的语法混合在一起会导致并行启动错误。您可以看到,微软一直在他们的清单上搅乱了很多。请注意,以下内容实际上并不能解决我的问题,但它提供了另一个可能接近实际解决方案的“潜在基本形式”:
<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}"/>
。微软已经打破了鼠标捕捉行为,打破了我甚至无法猜到的可怕的窗口绘画方式。打开此标志会在我的应用程序中造成非常微妙的错误,包括绘制问题、无法单击控件(鼠标向下的消息由于鼠标捕获丢失而无法到达控件),以及许多其他问题。
发布于 2014-11-10 23:01:14
它被记录在MSDN主题Writing DPI-Aware Desktop and Win32 Applications上。
通过修改应用程序清单或调用SetProcessDpiAwarenessAPI来标记应用程序。我们建议您使用应用程序清单,因为这将在应用程序启动时设置DPI意识级别。仅在以下情况下使用API:
如果使用SetProcessDpiAwareness方法设置DPI感知级别,则必须在强制系统开始虚拟化的任何Win32API调用之前调用Win32API。
新闻部感知显式值,描述
False将应用程序设置为不知道新闻部。
True将应用程序设置为系统DPI感知。
Windows8.1上的每个监视器,将应用程序设置为每个监视器-新闻部感知.在Windows上通过Windows 8,将应用程序设置为“不了解新闻部”.
Windows8.1上的True/PM,将应用程序设置为每个监视器-新闻部感知。在Windows上通过Windows 8,将应用程序设置为system感知。
您只需使用标准DPI感知清单,但指定True/PM或每个监视器,而不是True。
同样的主题使新闻部了解到以下情况:
<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。
发布于 2014-11-10 22:24:21
此清单有效,但有一些警告:
True/PM
值,而不是True
,造成了所有的不同。微软显然确实将其记录在案。(咧嘴笑)<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
示例!这是XML。我在StackOverflow损坏这个XML的过程中遇到了一些麻烦,所以如果它看起来很糟糕,您就会看到StackOverflow错误。
<?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>
你也可以有:
代码示例:
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.
发布于 2014-11-10 20:51:35
要么修改应用程序中指向的清单,要么使用$R指令在.dpr文件中包含一个额外的清单。
另外,asmv3 3:application部分看起来也不错,但我认为您需要用小写t拼写"true“,如"True”。
https://stackoverflow.com/questions/26852150
复制相似问题