Wie erhalte ich Windows-Anzeigeeinstellungen?


74

In Windows 7 gibt es Einstellungen für die Anzeige (Systemsteuerung -> Anzeige). Hiermit können Sie die Größe des Texts und anderer Elemente auf dem Bildschirm ändern. Ich benötige diese Einstellung, um einige Funktionen in meiner C # -Anwendung basierend auf dem Einstellungswert ein- und ausschalten zu können. Ist das möglich?


1
Für welche Einstellung interessieren Sie sich? Es gibt viele.
— David Heffernan

Wenn Sie diese Seite mit einer Einstellung öffnen - Systemsteuerung -> Anzeige. Es gibt nur eine Einstellung, mit der Sie die Größe des Texts und anderer Elemente auf dem Bildschirm ändern können. Die Optionen sind "Kleiner", "Mittel" und "Größer"
— Newmember

Antworten:


52

Diese Einstellung ist die Bildschirm-DPI oder Punkte pro Zoll.

Lesen Sie es so:

float dpiX, dpiY;
Graphics graphics = this.CreateGraphics();
dpiX = graphics.DpiX;
dpiY = graphics.DpiY;

Ich denke nicht, dass es im Moment möglich ist, dass die X- und Y-Werte unterschiedlich sind. Ein Wert von 96 entspricht einer Skalierung von 100% (kleiner), 120 einer Skalierung von 125% (mittel) und 144 einer Skalierung von 150% (größer). Benutzer können jedoch andere Werte als diese Standardwerte festlegen.

Beachten Sie, dass die von Ihnen beobachteten Werte möglicherweise einer DPI-Virtualisierung unterliegen, sofern Ihre Anwendung nicht als DPI-fähig deklariert wird.


7
Ich habe versucht, diesen Code mit den verschiedenen Einstellungen und dem Wert der Grafik
— auszuführen. DpiX

1
DpiX ist 90?! Ich habe mich ab und zu angemeldet und es hat sich von 96 auf 120 geändert. Ich habe eine neue WinForms-App verwendet. Ich frage mich, ob Sie in Ihrer App etwas Besonderes tun. Haben Sie es in einem brandneuen WinForms-Projekt versucht?
— David Heffernan

1
Ich habe versucht, die mittlere Einstellung einzustellen und - es funktioniert! DpiX ist 120, aber für die größere Einstellung ist es 96 ...
— Newmember

9
Richtig, ich glaube ich verstehe es jetzt. Das Problem ist, dass Ihre App nicht als DPI-fähig markiert ist und daher wahrscheinlich alles unscharf erscheint. Sie sollten Ihre App im Manifest als DPI-fähig markieren.
— David Heffernan

3
@ColonelPanic thisist einfach ein beliebiges Steuerelement. msdn.microsoft.com/en-us/library/…
— David Heffernan

81

Sowohl Graphics.DpiX als auch DeviceCap.LOGPIXELSX geben in Surface Pro in allen Skalierungsstufen 96 zurück.

Stattdessen konnte ich den Skalierungsfaktor folgendermaßen berechnen:

[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
public enum DeviceCap
{
    VERTRES = 10,
    DESKTOPVERTRES = 117,

    // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html
}  


private float getScalingFactor()
{
    Graphics g = Graphics.FromHwnd(IntPtr.Zero);
    IntPtr desktop = g.GetHdc();
    int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
    int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES); 

    float ScreenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;

    return ScreenScalingFactor; // 1.25 = 125%
}

9
Wow, ich habe lange gesucht, wie man den wahren Skalierungsfaktor erhält, und das hat endlich meine Probleme gelöst!
— Andreas

10
In dem Moment, in dem du gerade weinen und aufgeben willst und dann auf so etwas stößt.
— Der Muffin-Mann

5
Bitte beachten Sie, dass Sie wahrscheinlich sowohl diese Lösung als auch die als akzeptiert gekennzeichnete Lösung verwenden möchten . Auf meinem System gibt das Lesen von g.DpiX 120 zurück, aber der Skalierungsfaktor beträgt immer noch 1,0.
— Todd Myhre

6
Zu Ihrer Information: Auf einem Dell Precision 5510-Laptop mit Win 10 64-Bit, Auflösung 3840 x 2160, Anzeigeskala auf 200% eingestellt (vom rechten Klick auf Desktop >> Anzeigeeinstellungen) geben sowohl LogicalScreenHeight als auch PhysicalScreenHeight im obigen Code dasselbe zurück. 2160. Dieser Code funktioniert also nicht, um in diesem Szenario die gewünschte 200% -Anzeigeskala zu erhalten.
— Nerdtron

6
Ich habe das gleiche Problem wie bei @Nerdtron mit ähnlicher Hardware beobachtet. Dieser Code funktioniert leider nicht zuverlässig auf allen Monitoren.
— OfficeAddinDev

17

Der meiner Meinung nach einfachste Weg ist die Verwendung der GetDeviceCapsFunktion. Von pinvoke.net :

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int GetDeviceCaps(IntPtr hDC, int nIndex);

public enum DeviceCap
{
  /// <summary>
  /// Logical pixels inch in X
  /// </summary>
  LOGPIXELSX = 88,
  /// <summary>
  /// Logical pixels inch in Y
  /// </summary>
  LOGPIXELSY = 90

  // Other constants may be founded on pinvoke.net
}      

Und Verwendung:

Graphics g = Graphics.FromHwnd(IntPtr.Zero);            
IntPtr desktop = g.GetHdc();

int Xdpi = GetDeviceCaps(desktop, (int)DeviceCap.LOGPIXELSX);
int Ydpi = GetDeviceCaps(desktop, (int)DeviceCap.LOGPIXELSY);    

Bei diesem Ansatz müssen Sie Ihre App nicht als dpi-fähig markieren.


12
Vergessen Sie nicht, ReleaseHdc
— BitsEvolved am

@ BitsEvolved absolut. Dies löst "meinen" Speicherverlust (in einem völlig anderen Kontext)! Danke vielmals.
— Wolf

1
In den Kommentaren zur GetDeviceCaps-Funktion steht unter dem von Ihnen angegebenen Link für LOGPIXELSX und LOGPIXELSY Folgendes: "In einem System mit mehreren Anzeigemonitoren ist dieser Wert für alle Monitore gleich." Etwas zu beachten ...
— RenniePet

16

So können Sie es in WPF machen. Der Rückgabewert ist in den logischen Einheiten von WPF angegeben, die 1/96 Zoll entsprechen. Wenn Ihre Bildschirm-DPI auf 96 eingestellt ist, erhalten Sie den Wert 1.

Matrix m =
PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformToDevice;
double dx = m.M11; // notice it's divided by 96 already
double dy = m.M22; // notice it's divided by 96 already

( Quelle )


1
Danke, ich denke das ist der einfachste Weg für wpf.
— Mitra M

10

Hier ist eine Lösung, die unter Windows 10 gut funktioniert. DPI-Erkennung oder ähnliches ist nicht erforderlich.

public static int GetWindowsScaling()
{
    return (int)(100 * Screen.PrimaryScreen.Bounds.Width / SystemParameters.PrimaryScreenWidth);
}

Interessant ist, dass Screen.PrimaryScreen.Bounds.Width manchmal nicht die tatsächliche Bildschirmbreite zurückgibt und dieselbe wie SystemParameters.PrimaryScreenWidth zurückgibt. Ich habe dieses Problem beim Arbeiten mit der UI-Automatisierung. Und ich musste stattdessen Screen.PrimaryScreen.WorkingArea.Width verwenden.
— Sarh

8

Ich verwende diese Methode in meiner Konsolenanwendung:

float dpiX, dpiY;
using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
{
    dpiX = graphics.DpiX;
    dpiY = graphics.DpiY;
}

8

Die Verwendung der Antwort von Farshid T als Basis funktioniert in jedem Skalierungsfaktor mit Ausnahme von 125%. Ich habe ungefähr 20 verschiedene Skalierungsfaktoren getestet, und der DPI gibt immer 96 zurück, außer wenn er auf 125% eingestellt ist, was einen DPI von 120 ergibt. 120/96 = 1,25. Ich bin mir nicht sicher, warum dies der Fall ist, aber dieser Code scheint für jede Skalierungseinstellung zu funktionieren.

    [DllImport("gdi32.dll")]
    static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
    public enum DeviceCap
    {
        VERTRES = 10,
        DESKTOPVERTRES = 117,
        LOGPIXELSY = 90,

        // http://pinvoke.net/default.aspx/gdi32/GetDeviceCaps.html

und Verwendung:

        Graphics g = Graphics.FromHwnd(IntPtr.Zero);
        IntPtr desktop = g.GetHdc();
        int LogicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.VERTRES);
        int PhysicalScreenHeight = GetDeviceCaps(desktop, (int)DeviceCap.DESKTOPVERTRES);
        int logpixelsy = GetDeviceCaps(desktop, (int)DeviceCap.LOGPIXELSY);
        float screenScalingFactor = (float)PhysicalScreenHeight / (float)LogicalScreenHeight;
        float dpiScalingFactor = (float)logpixelsy / (float)96;

        if (screenScalingFactor > 1 ||
            dpiScalingFactor > 1)
        {
            // do something nice for people who can't see very well...
        }

2
Sollten Sie aus Sicherheitsgründen nicht auch Folgendes hinzufügen: g.ReleaseHdc (Desktop);
— Don

6

Verwenden Sie im Fall von WPF das folgende Snippet:

PresentationSource source = PresentationSource.FromVisual(this);

        double dpiX, dpiY;
        if (source != null)
        {
            dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
            dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
        }

5

Dies ist eine sehr alte Frage, aber seit Windows 8.1 kann man verschiedene andere Funktionen verwenden, wie z GetDpiForWindow

In C #:

[DllImport("user32.dll")]
static extern int GetDpiForWindow(IntPtr hWnd);

public float GetDisplayScaleFactor(IntPtr windowHandle)
{
    try
    {
        return GetDpiForWindow(windowHandle) / 96f;
    }
    catch
    {
        // Or fallback to GDI solutions above
        return 1;
    }
}

Damit dies unter Windows 10 ordnungsgemäß funktioniert, müssen Sie app.manifestIhrem C # -Projekt Folgendes hinzufügen :

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
          manifestVersion="1.0">
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <!-- The combination of below two tags have the following effect : 
      1) Per-Monitor for >= Windows 10 Anniversary Update
      2) System < Windows 10 Anniversary Update -->
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
    </windowsSettings>
  </application>

</assembly>

Sie sagen, dies sollte für Windows 8.1 und höher funktionieren, aber in dem Microsoft-Dokument, auf das Sie verweisen, steht "Anforderungen: Windows 10, Version 1607".
— RenniePet

Oh ja, guter Fang. Ich glaube, ich habe dies mit dem GetDpiForMonitor-API-Aufruf verwechselt. docs.microsoft.com/en-us/windows/win32/api/shellscalingapi/…
— Ziriax

1

Ich denke, dies sollte Ihnen die Informationen liefern, nach denen Sie suchen:

http://www.pinvoke.net/default.aspx/user32.getsystemmetrics

http://pinvoke.net/default.aspx/Enums.SystemMetric

Bearbeiten - Oh, tut mir leid, es gibt einen einfacheren Weg, diese Informationen jetzt ohne Pinvoke zu erhalten.

http://msdn.microsoft.com/en-us/library/system.windows.forms.systeminformation.aspx


Leider spiegeln die Systeminformationen nicht die dpi-Skala wider. Es scheint auch, dass die dpiX / dpiY-Eigenschaft des Grafikkontexts 96 für 150% zurückgibt (zumindest auf einem Surface Pro 2). Sie können also nicht zwischen 100% und 150% Zoom unterscheiden. Kennt jemand eine richtige Methode?
— Zuppa

1

Eine vollständigere Version von Ric Gaudets Antwort:

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern int GetDeviceCaps(IntPtr hDC, int nIndex);

public enum DeviceCap
{
    VERTRES = 10,
    DESKTOPVERTRES = 117
}

static double GetWindowsScreenScalingFactor(bool percentage = true)
{
    //Create Graphics object from the current windows handle
    Graphics GraphicsObject = Graphics.FromHwnd(IntPtr.Zero);
    //Get Handle to the device context associated with this Graphics object
    IntPtr DeviceContextHandle = GraphicsObject.GetHdc();
    //Call GetDeviceCaps with the Handle to retrieve the Screen Height
    int LogicalScreenHeight = GetDeviceCaps(DeviceContextHandle, (int)DeviceCap.VERTRES);
    int PhysicalScreenHeight = GetDeviceCaps(DeviceContextHandle, (int)DeviceCap.DESKTOPVERTRES);
    //Divide the Screen Heights to get the scaling factor and round it to two decimals
    double ScreenScalingFactor = Math.Round((double)PhysicalScreenHeight / (double)LogicalScreenHeight, 2);
    //If requested as percentage - convert it
    if (percentage)
    {
        ScreenScalingFactor *= 100.0;
    }
    //Release the Handle and Dispose of the GraphicsObject object
    GraphicsObject.ReleaseHdc(DeviceContextHandle);
    GraphicsObject.Dispose();
    //Return the Scaling Factor
    return ScreenScalingFactor;
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.