Я только что справился с той же проблемой, и хотя в StackOverflow есть много вопросов, связанных с DPI, я не нашел все ответы в одном месте.
Ответ на вопроса) проще: начиная с Windows Vista, Windows поддерживает два вида изменения размеров, связанных с DPI.Если вы нажмете «Установить пользовательский размер текста (DPI)» в настройках дисплея, вы увидите, что по умолчанию 125% использует изменение размера, совместимое с Windows XP, а 150% - нет.
Вопрос б) сложнее.Если вы ищете 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);