2015-08-21 16 views
6

Ho cercato di disabilitare la consapevolezza DPI su un'applicazione ClickOnce.
Ho scoperto rapidamente, non è possibile specificarlo nel manifest, perché ClickOnce non supporta asm.v3 nel file manifest.SetProcessDpiAreazione non ha effetto

L'opzione successiva che ho trovato era chiamare la nuova funzione di Windows SetProcessDpiAwareness.

Secondo this tutorial,

Call SetProcessDpiAwareness before you create the application window.

E this tutorial,

you must call SetProcessDpiAwareness prior to any Win32API call

Bisogna chiamare la funzione molto presto. Così, per testare, ho creato un'applicazione del tutto vuoto WPF, e fatto di questo la mia intera classe 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()); 
} 

Le 3 finestre di messaggio mostrano questo contenuto:

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

Perché è l'applicazione ancora impostato a DPI_Aware? Questa chiamata non è abbastanza presto?
L'applicazione presenta effettivamente il ridimensionamento DPI.

Quando uso la definizione manifesta:

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

Si fa ritorno Process_DPI_Unaware.

EDIT 1:
Ora afferrando Marshal.GetLastWin32Error() subito dopo metodi PInvoke, questo ora effettivamente restituisce un errore.

risposta

5

Attenzione con SetLastError e GetLastWin32Error, qualsiasi chiamata intermedia tra MessageBox.Show influirà sul risultato. Assicurati di ottenere sempre l'ultimo errore subito dopo aver chiamato il tuo metodo nativo.

Quindi potrebbe essere molto bene che si sta ottenendo il comportamento previsto, ma essere fuorviato dal codice di errore.

Vedi questo post del blog per una spiegazione completa: http://blogs.msdn.com/b/oldnewthing/archive/2015/08/19/10636096.aspx

EDIT

Non del tutto sicuro di cosa sta causando accesso negato ... ma c'è un trucco semplice ed efficace che disabilita la consapevolezza DPI:

Mostra le AssemblyInfo.cs e aggiungere quanto segue:

[assembly: DisableDpiAwareness] 

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

+0

Ah! Ovviamente! Si prega di consultare il mio codice modificato, restituisce "Imposta errore DPI: System.ComponentModel.Win32Exception (0x80004005): accesso negato" –

+2

Vedere la mia modifica per un altro approccio. – Aybe

+1

Che ha funzionato perfettamente! Grazie! –

Problemi correlati