2015-08-21 19 views
6

Ich habe versucht, die DPI-Erkennung in einer ClickOnce-Anwendung zu deaktivieren.
Ich fand es schnell heraus, es ist nicht möglich, es im Manifest anzugeben, da ClickOnce asm.v3 in der Manifestdatei nicht unterstützt.SetProcessDpiAwareness hat keinen Effekt

Die nächste Option, die ich fand, war die neue Windows-Funktion SetProcessDpiAwareness aufrufen.

Nach this Tutorial

Call SetProcessDpiAwareness before you create the application window.

Und this Tutorial

you must call SetProcessDpiAwareness prior to any Win32API call

Sie haben die Funktion ziemlich früh zu nennen. Also, um zu testen, habe ich eine völlig leere WPF-Anwendung erstellt, und machte diese meine gesamte App-Klasse:

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

Die 3 Meldungsfelder zeigen diesen Inhalt:

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

Warum ist die Anwendung noch gesetzt zu DPI_Aware? Ist dieser Anruf nicht früh genug?
Die Anwendung erlebt tatsächlich DPI-Skalierung.

Wenn ich das Manifest Definition verwenden:

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

Es zurückkehrt Process_DPI_Unaware.

EDIT 1:
Jetzt Marshal.GetLastWin32Error() direkt nach PInvoke Methoden greifen, dies jetzt gibt tatsächlich einen Fehler.

Antwort

5

Vorsicht mit SetLastError und GetLastWin32Error, jeder Anruf dazwischen wie MessageBox.Show beeinflusst sein Ergebnis. Stellen Sie sicher, dass immer der letzte Fehler direkt nach dem Aufruf der nativen Methode angezeigt wird.

So könnte es sehr gut sein, dass Sie das erwartete Verhalten erhalten, aber durch den Fehlercode irregeführt werden.

Sehen Sie diese Blog-Post für eine vollständige Erklärung: http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

EDIT

Nicht ganz sicher, was verursacht Zugriff verweigert ... aber es gibt einen einfachen und effektiven Trick, die DPI Bewusstsein deaktiviert:

Bearbeiten Sie Ihre AssemblyInfo.cs und fügen Sie folgendes:

[assembly: DisableDpiAwareness] 

Quelle: https://code.msdn.microsoft.com/windowsdesktop/Per-Monitor-Aware-WPF-e43cde33 (Kommentare in PerMonitorAwareWPFWindow.xaml.cs)

+0

Ah! Na sicher! Bitte sehen Sie meinen bearbeiteten Code, gibt "Set DPI Fehler: System.ComponentModel.Win32Exception (0x80004005): Zugriff verweigert" –

+2

Siehe meine Bearbeitung für einen anderen Ansatz. – Aybe

+1

Das hat einwandfrei funktioniert! Vielen Dank! –