Windows Display Setting at 150% still shows 96 DPI

后端 未结 2 1192
南笙
南笙 2020-12-30 09:31

On my laptop running Win7, when I set the display setting to 125%, the DPI shows up as 120 (using both graphics.DpiX and GetDeviceCaps) as expected. However, with the displ

相关标签:
2条回答
  • 2020-12-30 10:04

    I've just struggled the same problem, and though there are a lot of DPI-related questions on StackOverflow, I did not find all the answers in one place.

    The answer to question a) is the easier one: Starting with Windows Vista, Windows supports two kinds of DPI-related resizing. If you click on "Set custom text size (DPI)" on Display settings, you can see that by default, 125% uses the Windows XP-compatible resizing, while 150% doesn't.

    Custom DPI Settings


    Question b) is a trickier one. If you search StackOverflow, usually you can find the following answer:

        using (Graphics screen = Graphics.FromHwnd(IntPtr.Zero))
        {
            IntPtr hdc = screen.GetHdc();
            int dpiX = GetDeviceCaps(hdc, DeviceCaps.LOGPIXELSX);
            screen.ReleaseHdc(hdc);
        }
    

    However, it will return always 96, regardless of actual DPI settings, unless...
    - You use Windows XP or the compatibility mode is checked in at DPI settings. Problem: you cannot enforce it at the users.
    - DWM is turned off (you use Basic or Classic themes). Problem: same as above.
    - You call SetProcessDPIAware function before using GetDeviceCaps. Problem: This function should be called once, before all other rendering. If you have an existing DPI-unaware app, changing the awareness will ruin the whole appearance. It cannot be turned off once you called the function.
    - You call SetProcessDpiAwareness before and after using GetDeviceCaps. Problem: This function requires at least Windows 8.1

    The real working solution

    It seems that the GetDeviceCaps function is not fully documented at MSDN. At least I discovered that pinvoke.net mentions a few further options that can be obtained by the function. At the end I came out with the following solution:

    public static int GetSystemDpi()
    {
        using (Graphics screen = Graphics.FromHwnd(IntPtr.Zero))
        {
            IntPtr hdc = screen.GetHdc();
    
            int virtualWidth = GetDeviceCaps(hdc, DeviceCaps.HORZRES);
            int physicalWidth = GetDeviceCaps(hdc, DeviceCaps.DESKTOPHORZRES);
            screen.ReleaseHdc(hdc);
    
            return (int)(96f * physicalWidth / virtualWidth);
        }
    }
    

    And the required additional code:

    private enum DeviceCaps
    {
        /// <summary>
        /// Logical pixels inch in X
        /// </summary>
        LOGPIXELSX = 88,
    
        /// <summary>
        /// Horizontal width in pixels
        /// </summary>
        HORZRES = 8,
    
        /// <summary>
        /// Horizontal width of entire desktop in pixels
        /// </summary>
        DESKTOPHORZRES = 118
    }
    
    /// <summary>
    /// Retrieves device-specific information for the specified device.
    /// </summary>
    /// <param name="hdc">A handle to the DC.</param>
    /// <param name="nIndex">The item to be returned.</param>
    [DllImport("gdi32.dll")]
    private static extern int GetDeviceCaps(IntPtr hdc, DeviceCaps nIndex);
    
    0 讨论(0)
  • 2020-12-30 10:13

    On Windows Vista and Windows 7, with DPIs above 120 (I think) and applications that it considers to be non-DPI aware, they switch into DPI Virtualization Mode.

    This does exactly what you're seeing - the application thinks it's running in 96dpi while Windows blows it up and renders everything bigger (and blurrier).

    For more details: https://docs.microsoft.com/en-gb/windows/win32/hidpi

    (original link (now redirects to above): http://msdn.microsoft.com/en-us/library/dd464660(VS.85).aspx#dpi_virtualization)

    The article explains how to disable it on a per-application basis.

    0 讨论(0)
提交回复
热议问题