How to Configure an App to Run Correctly on a Machine With a High Dpi Setting (E.G. 150%)

How to configure an app to run correctly on a machine with a high DPI setting (e.g. 150%)?

Once you go past 100% (or 125% with the "XP-style DPI scaling" checkbox ticked), Windows by default takes over the scaling of your UI. It does so by having your app render its output to a bitmap and drawing that bitmap to the screen. The rescaling of that bitmap makes the text inevitably look fuzzy. A feature called "DPI virtualization", it keeps old programs usable on high resolution monitors.

You have to explicitly let it know that you can handle higher DPI settings by adding the <dpiAware> element to your manifest. The MSDN page is here but it isn't complete since it is omitting the UAC settings. Project + Add New Item, pick "Application Manifest File". Edit the manifest text or copy/paste this:

<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<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>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

You can also pinvoke SetProcessDPIAware() in your Main() method, necessary for example if you deploy with ClickOnce:

    [STAThread]
static void Main() {
if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // Edit as needed
}

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();

UPDATE, this common need is finally a bit easier if you use VS2015 Update 1 or higher. The added manifest already has the relevant directive, just remove the comments.


Keyword for search so I can find this post back: dpiAware

Metafile size incorrect in console app, correct in Windows Forms

Thanks to Hans Passant. His link was super helpful.

So even if EMF is a resolution-independent graphics file format, the resolution and DPI of your screen (likely the main screen) will influence the result. Basically, EMF uses the physical units of your screen. So for HiDPI screens, it depends on the screen scaling.

To fix it, the application needs to run in DPI aware mode. See below, for how to achieve it.

If run in the DPI virtualization mode instead, the EMF frame behaves differently from the EMF content and the result is incorrect. That's strange, likely a bug.

I've also noted that none of the results are in line with the EMF and EMF+ standards published by Microsoft. If they were, they wouldn't properly work in Microsoft Office. Now it nicely works in Microsoft Word.

DPI aware mode

Either call this SetProcessDPIAware() at the start of your application:

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();

Or use an application manifest:

<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

How to configure an app to run correctly on a machine with a high DPI setting (e.g. 150%)?

Once you go past 100% (or 125% with the "XP-style DPI scaling" checkbox ticked), Windows by default takes over the scaling of your UI. It does so by having your app render its output to a bitmap and drawing that bitmap to the screen. The rescaling of that bitmap makes the text inevitably look fuzzy. A feature called "DPI virtualization", it keeps old programs usable on high resolution monitors.

You have to explicitly let it know that you can handle higher DPI settings by adding the <dpiAware> element to your manifest. The MSDN page is here but it isn't complete since it is omitting the UAC settings. Project + Add New Item, pick "Application Manifest File". Edit the manifest text or copy/paste this:

<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
<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>
<asmv3:application>
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>true</dpiAware>
</asmv3:windowsSettings>
</asmv3:application>
</assembly>

You can also pinvoke SetProcessDPIAware() in your Main() method, necessary for example if you deploy with ClickOnce:

    [STAThread]
static void Main() {
if (Environment.OSVersion.Version.Major >= 6) SetProcessDPIAware();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); // Edit as needed
}

[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern bool SetProcessDPIAware();

UPDATE, this common need is finally a bit easier if you use VS2015 Update 1 or higher. The added manifest already has the relevant directive, just remove the comments.


Keyword for search so I can find this post back: dpiAware

Windows Forms DPI scaling

Creating a DPI-Aware Application

All containers must use the same AutoScaleMode - this part fixed my problem

It is required that windows app should have same layout at different resolutions means there should be no effect on layout of app on changing resolution. Here are the steps to do this.

  1. Use table layout panel
  2. Drag control in cell of tablelayoutpanel and set anchor and dock property.
  3. Set rowspan and colspan properties of dragged control to merge cells
  4. Set margin and padding of dragged control with respect to cell.
  5. drag all controls and follow same steps, complete design using tablelayoutpanel
  6. Now set all columns and rows size of tablelayoutpanel = autosize (or in %)
  7. Set tablelayoutpanel properties autosize = true,autosizemode = grow and shrink
  8. Set Forms properties autosize = true,autosizemode = grow and shrink
  9. Run windows app If your windows app opens in maximum state then set tablelayoutpanel dock property =fill.


Related Topics



Leave a reply



Submit