SetProcessDpiAwareness 没有效果
SetProcessDpiAwareness not having effect
我一直在尝试禁用 ClickOnce 应用程序的 DPI 感知。
我很快发现,无法在清单中指定它,因为 ClickOnce 不支持清单文件中的 asm.v3。
我发现的下一个选项是调用新的 Windows 函数 SetProcessDpiAwareness。
根据this教程,
Call SetProcessDpiAwareness before you create the application window.
和this教程,
you must call SetProcessDpiAwareness prior to any Win32API call
您必须尽早调用该函数。因此,为了测试,我创建了一个完全空白的 WPF 应用程序,并将其作为我的整个应用程序 class:
[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());
}
3个消息框显示以下内容:
Dpi set: True
Process_System_DPI_Aware
Set DPI error: System.ComponentModel.Win32Exception (0x80004005): Access is denied
System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully
为什么应用程序仍然设置为 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>
确实如此 return Process_DPI_Unaware。
编辑 1:
现在在 pInvoke 方法之后直接获取 Marshal.GetLastWin32Error(),这实际上 return 是一个错误。
注意 SetLastError
和 GetLastWin32Error
,任何介于两者之间的调用(例如 MessageBox.Show
)都会影响其结果。确保始终在调用本机方法后立即获取最后一个错误。
因此,您得到预期的行为但被错误代码误导了,这可能很好。
查看此博客 post 以获得完整的解释: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 中的评论)
我一直在尝试禁用 ClickOnce 应用程序的 DPI 感知。
我很快发现,无法在清单中指定它,因为 ClickOnce 不支持清单文件中的 asm.v3。
我发现的下一个选项是调用新的 Windows 函数 SetProcessDpiAwareness。
根据this教程,
Call SetProcessDpiAwareness before you create the application window.
和this教程,
you must call SetProcessDpiAwareness prior to any Win32API call
您必须尽早调用该函数。因此,为了测试,我创建了一个完全空白的 WPF 应用程序,并将其作为我的整个应用程序 class:
[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());
}
3个消息框显示以下内容:
Dpi set: True
Process_System_DPI_Aware
Set DPI error: System.ComponentModel.Win32Exception (0x80004005): Access is denied
System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully
为什么应用程序仍然设置为 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>
确实如此 return Process_DPI_Unaware。
编辑 1:
现在在 pInvoke 方法之后直接获取 Marshal.GetLastWin32Error(),这实际上 return 是一个错误。
注意 SetLastError
和 GetLastWin32Error
,任何介于两者之间的调用(例如 MessageBox.Show
)都会影响其结果。确保始终在调用本机方法后立即获取最后一个错误。
因此,您得到预期的行为但被错误代码误导了,这可能很好。
查看此博客 post 以获得完整的解释: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 中的评论)