SetProcessDpiAwareness not having effect
Asked Answered
P

1

12

I've been trying to disable the DPI awareness on a ClickOnce application.
I quickly found out, it is not possible to specify it in the manifest, because ClickOnce does not support asm.v3 in the manifest file.

The next option I found was calling the new Windows function SetProcessDpiAwareness.

According to this tutorial,

Call SetProcessDpiAwareness before you create the application window.

And this tutorial,

you must call SetProcessDpiAwareness prior to any Win32API call

You have to call the function pretty early on. So, to test, I have created an entirely blank WPF application, and made this my entire App 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());
}

The 3 message boxes show this content:

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

Why is the application still set to DPI_Aware? Is this call not early enough?
The application does indeed experience DPI scaling.

When I use the manifest definition:

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

It does return Process_DPI_Unaware.

EDIT 1:
Now grabbing Marshal.GetLastWin32Error() directly after pInvoke methods, this now actually returns an error.

Prescind answered 21/8, 2015 at 19:41 Comment(0)
S
12

Beware with SetLastError and GetLastWin32Error, any call in between such as MessageBox.Show will affect its result. Make sure to always get the last error right after calling your native method.

So it could be very well that you are getting the expected behavior but being misled by the error code.

See this blog post for a complete explanation : http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

EDIT

Not quite sure about what's causing access denied ...but there's a simple and effective trick that disables DPI awareness :

Edit your AssemblyInfo.cs and add the following:

[assembly: DisableDpiAwareness]

Source: https://code.msdn.microsoft.com/windowsdesktop/Per-Monitor-Aware-WPF-e43cde33 (comments in PerMonitorAwareWPFWindow.xaml.cs)

Sharkey answered 21/8, 2015 at 20:14 Comment(4)
Ah! Ofcourse! Please see my edited code, returns "Set DPI error: System.ComponentModel.Win32Exception (0x80004005): Access is denied"Darlington
You were very close to the solution ! In the last 2 links you've provided there was a 3rd article (for WPF) in the 'High DPI' section, and it's the sample application in it:DSharkey
This is so weird. I am getting the size of the screen using System.Windows.Forms.Screen.PrimaryScreen. Using this solution, it shows the "wrong", scaled resolution, but using the other manifest option, it shows the correct 2160x1440 resolution, but getting the scaling with PresentationSource TransformFromDevice gives 1.0 for scaling :|Darlington
1. have you removed previous code calling the function and only used this approach ? 2. have you tried that sample from MS ? I guess it should work :DSharkey

© 2022 - 2024 — McMap. All rights reserved.