SetProcessDpiAwareness没有效果

12

我一直在尝试禁用ClickOnce应用程序的DPI感知功能。
我很快发现,无法在清单中指定它,因为ClickOnce不支持清单文件中的asm.v3。

我找到的下一个选项是调用新的Windows函数SetProcessDpiAwareness

根据教程,

在创建应用程序窗口之前调用SetProcessDpiAwareness。

以及教程,

在进行任何Win32API调用之前,必须调用SetProcessDpiAwareness。

你必须尽早调用该函数。因此,为了测试,我创建了完全空白的WPF应用程序,并将其作为整个App类:

[DllImport("SHCore.dll", SetLastError = true)]
private static extern bool SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness);

[DllImport("SHCore.dll", SetLastError = true)]
private static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness);

private enum PROCESS_DPI_AWARENESS
{
    Process_DPI_Unaware = 0,
    Process_System_DPI_Aware = 1,
    Process_Per_Monitor_DPI_Aware = 2
}

static App()
{
    var result = SetProcessDpiAwareness(PROCESS_DPI_AWARENESS.Process_DPI_Unaware);
    var setDpiError = Marshal.GetLastWin32Error();
    MessageBox.Show("Dpi set: " + result.ToString());

    PROCESS_DPI_AWARENESS awareness;
    GetProcessDpiAwareness(Process.GetCurrentProcess().Handle, out awareness);
    var getDpiError = Marshal.GetLastWin32Error();
    MessageBox.Show(awareness.ToString());

    MessageBox.Show("Set DPI error: " + new Win32Exception(setDpiError).ToString());
    MessageBox.Show("Get DPI error: " + new Win32Exception(getDpiError).ToString());
}

这三个消息框显示了以下内容:

Dpi设置:True
Process_System_DPI_Aware
设置DPI错误:System.ComponentModel.Win32Exception (0x80004005):拒绝访问
System.ComponentModel.Win32Exception (0x80004005):操作成功完成

为什么应用程序仍然设置为DPI_Aware?这个调用不够早吗?
该应用程序确实经历了DPI缩放。

当我使用清单定义时:

<application xmlns="urn:schemas-microsoft-com:asm.v3">
  <windowsSettings>
    <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
  </windowsSettings>
</application>

它确实返回Process_DPI_Unaware。

编辑1:
现在在调用PInvoke方法后直接获取Marshal.GetLastWin32Error(),这样就会返回一个错误。

1个回答

12

当使用SetLastErrorGetLastWin32Error时需要小心,它们之间的任何调用(如MessageBox.Show)都会影响其结果。确保在调用本机方法后立即获取最后一个错误。

因此,你可能得到了预期的行为,但被错误代码误导了。

查看这篇博客文章以获得完整解释:http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

编辑

不太确定是什么原因导致了访问被拒绝...但有一个简单而有效的技巧可以禁用DPI感知:

编辑你的AssemblyInfo.cs文件并添加以下内容:

[assembly: DisableDpiAwareness]

来源: https://code.msdn.microsoft.com/windowsdesktop/Per-Monitor-Aware-WPF-e43cde33(在PerMonitorAwareWPFWindow.xaml.cs文件的注释中)


啊!当然!请看我编辑后的代码,返回“设置 DPI 错误:System.ComponentModel.Win32Exception (0x80004005):拒绝访问”。 - René Sackers
你非常接近解决方案了!在你提供的最后两个链接中,有一个“高 DPI”部分的第三篇文章(针对 WPF),里面有一个示例应用程序:D - aybe
这太奇怪了。我正在使用System.Windows.Forms.Screen.PrimaryScreen获取屏幕大小。使用这种方法,它显示“错误”的缩放分辨率,但是使用其他清单选项,则显示正确的2160x1440分辨率,但是使用PresentationSource TransformFromDevice获取缩放时,缩放为1.0 :| - René Sackers
  1. 你已经删除了调用函数的先前代码,只使用了这种方法吗?
  2. 你尝试过微软提供的那个示例吗?我猜应该可以工作 :D
- aybe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接