2015-08-21 25 views
6

Próbowałem wyłączyć sygnalizację DPI w aplikacji ClickOnce.
Szybko się dowiedziałem, nie można tego określić w manifeście, ponieważ ClickOnce nie obsługuje pliku asm.v3 w pliku manifestu.SetProcessDpiAwareness nie ma efektu

Następną opcją, którą znalazłem było wywołanie nowej funkcji Windows SetProcessDpiAwareness.

Według this samouczku

Call SetProcessDpiAwareness before you create the application window.

I this poradnik,

you must call SetProcessDpiAwareness prior to any Win32API call

Trzeba wywołać funkcję dość wcześnie. Tak więc, aby sprawdzić, jakie stworzył zupełnie pusty aplikacji WPF i uczynił to całą moją klasę aplikacji:

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

The 3 skrzynkach pokazać zawartość:

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

Dlaczego aplikacja nadal ustawiony do DPI_Aware? Czy to wezwanie nie jest wystarczająco wczesne?
Aplikacja rzeczywiście wykonuje skalowanie DPI.

Kiedy używam oczywistego definicję:

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

To nie powrócić Process_DPI_Unaware.

EDIT 1:
Teraz chwytając Marshal.GetLastWin32Error() bezpośrednio po metodach pinvoke, to teraz faktycznie zwraca błąd.

Odpowiedz

5

Pamiętaj, że z SetLastError i GetLastWin32Error każde połączenie pomiędzy takimi jak MessageBox.Show wpłynie na jego wynik. Upewnij się, że zawsze otrzymujesz ostatni błąd zaraz po wywołaniu natywnej metody.

Może to być bardzo dobrze, że otrzymujesz oczekiwane zachowanie, ale został wprowadzony w błąd przez kod błędu.

Zobacz ten post na blogu dla pełnego wyjaśnienia: http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

EDIT

Nie całkiem pewni, co powoduje odmowa dostępu ... ale jest to prosty i skuteczny trik, który wyłącza świadomość DPI:

zmieniać swoich AssemblyInfo.cs i dodaj następujący:

[assembly: DisableDpiAwareness] 

Źródło: https://code.msdn.microsoft.com/windowsdesktop/Per-Monitor-Aware-WPF-e43cde33 (komentarze w PerMonitorAwareWPFWindow.xaml.cs)

+0

Ah! Oczywiście! Proszę zobaczyć mój edytowany kod, zwraca "Ustaw błąd DPI: System.ComponentModel.Win32Exception (0x80004005): Odmowa dostępu" –

+2

Zobacz moją edycję innego podejścia. – Aybe

+1

To działało bez zarzutu! Dzięki! –

Powiązane problemy