2015-08-21 3 views
6

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

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

this Согласно учебнику,

Call SetProcessDpiAwareness before you create the application window.

И this учебника,

you must call SetProcessDpiAwareness prior to any Win32API call

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

[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 окна сообщений показать это содержание:

Dpi set: True
Process_System_DPI_Aware
Set DPI error: System.ComponentModel.Win32Exception (0x80004005): Access is denied
System.ComponentModel.Win32Exception (0x80004005): The operation completed successfully

Почему приложение по-прежнему установлен в 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:
Теперь захватывая Marshal.GetLastWin32Error() непосредственно после того, как методы PInvoke, это теперь фактически возвращает ошибку.

ответ

5

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

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

Смотрите этот блог для полного объяснения: http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

EDIT

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

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

[assembly: DisableDpiAwareness] 

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

+0

Ah! Конечно! См. Мой отредактированный код, возвращает «Установить ошибку DPI: System.ComponentModel.Win32Exception (0x80004005): Доступ запрещен« –

+2

См. Мое редактирование для другого подхода. – Aybe

+1

Это работало безупречно! Благодаря! –

Смежные вопросы