Настройка дисплея Windows на 150% по-прежнему показывает 96 DPI - PullRequest
9 голосов
/ 10 августа 2011

На моем ноутбуке с Win7, когда я установил настройку дисплея на 125%, DPI будет отображаться как 120 (с использованием graphics.DpiX и GetDeviceCaps), как ожидалось.Тем не менее, при отображении на 150%, DPI составляет 96 (?!), Точно так же, как и на 100%.Кто-нибудь знает, а) почему это так, и б) есть ли другой способ, кроме проверки DPI, чтобы определить, установлен ли дисплей на что-либо, кроме 100%?Я пишу приложение, в котором хочу отображать сообщение, когда для дисплея установлено значение> = 150%.

Спасибо.

Ответы [ 2 ]

11 голосов
/ 10 августа 2011

В Windows Vista и Windows 7 с DPI выше 120 (я думаю) и приложениями, которые, по его мнению, не поддерживают DPI, они переключаются в режим виртуализации DPI.

Это делает именно то, что вывидя - приложение думает, что оно работает в 96dpi, в то время как Windows взрывает его и рендерит все больше (и размытие).

Для более подробной информации: http://msdn.microsoft.com/en-us/library/dd464660(VS.85).aspx#dpi_virtualization

В статье объясняется, как отключить егодля каждого приложения.

8 голосов
/ 21 июля 2015

Я только что справился с той же проблемой, и хотя в StackOverflow есть много вопросов, связанных с DPI, я не нашел все ответы в одном месте.

Ответ на вопроса) проще: начиная с Windows Vista, Windows поддерживает два вида изменения размеров, связанных с DPI.Если вы нажмете «Установить пользовательский размер текста (DPI)» в настройках дисплея, вы увидите, что по умолчанию 125% использует изменение размера, совместимое с Windows XP, а 150% - нет.

Custom DPI Settings

Вопрос б) сложнее.Если вы ищете StackOverflow, обычно вы можете найти следующий ответ:

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

Однако он всегда будет возвращать 96, независимо от фактических настроек DPI, если только ...
- вы используете Windows XP илиРежим совместимости отмечен в настройках DPI. Проблема : вы не можете применить его к пользователям.
- DWM отключен (вы используете базовые или классические темы). Проблема : то же, что и выше.
- Вы вызываете функцию SetProcessDPIAware перед использованием GetDeviceCaps. Проблема : эта функция должна вызываться один раз, перед всем другим рендерингом.Если у вас есть существующее приложение, не поддерживающее DPI, изменение осведомленности разрушит весь внешний вид.Его нельзя отключить после вызова функции.
- Вы вызываете SetProcessDpiAwareness до и после использования GetDeviceCaps. Проблема : для этой функции требуется как минимум Windows 8.1

Реальное рабочее решение

Кажется, что функция GetDeviceCaps не полностью документирована в MSDN.По крайней мере, я обнаружил, что pinvoke.net упоминает еще несколько параметров, которые могут быть получены функцией.В конце я получил следующее решение:

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);
    }
}

И требуемый дополнительный код:

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);
...