SetProcessDpiAwareness не имеет эффекта

Я пытался отключить осведомленность DPI в приложении ClickOnce.
Я быстро выяснил, что его невозможно указать в манифесте, потому что ClickOnce не поддерживает asm.v3 в файле манифеста.

следующий вариант, который я нашел, вызывал новую функцию Windows SetProcessDpiAwareness.

по данным этой учебник

вызовите SetProcessDpiAwareness перед созданием окно приложения.

и этой учебник

вы должны вызвать SetProcessDpiAwareness до любого вызова Win32API

вы должны вызвать функцию довольно рано. Итак, чтобы проверить, я создал полностью пустое приложение WPF и сделал это весь мой класс приложения:

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

3 окна сообщений показывают это содержание:

набор точек на дюйм: True
Process_System_DPI_Aware
Установить ошибку DPI: система.ComponentModel.Win32Exception (0x80004005): Доступ запрещен
Система.ComponentModel.Win32Exception (0x80004005): операция завершена успешно

почему приложение все еще установлено в DPI_Aware? Этот звонок недостаточно ранний?
Приложение действительно испытывает масштабирование DPI.

когда я использую определение манифеста:

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

возвращает Process_DPI_Unaware.

EDIT 1:
Теперь хватаем Маршала.GetLastWin32Error () непосредственно после методов pInvoke теперь фактически возвращает ошибку.

1 ответов


будьте осторожны с SetLastError и GetLastWin32Error, любой вызов между такими как MessageBox.Show повлияет на его результат. Убедитесь, что всегда получаете последнюю ошибку сразу после вызова собственного метода.

так что это может быть очень хорошо, что вы получаете ожидаемое поведение, но вводитесь в заблуждение кодом ошибки.

посмотреть в блоге полное описание : http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

редактировать

не совсем уверен, что вызывает отказ в доступе ...но есть простой и эффективный трюк, который отключает осведомленность DPI:

редактировать AssemblyInfo.cs и добавить следующее:

[assembly: DisableDpiAwareness]

источник:https://code.msdn.microsoft.com/windowsdesktop/Per-Monitor-Aware-WPF-e43cde33 (комментарии в PerMonitorAwareWPFWindow.код XAML.cs)