How to get Windows Display settings?

There is setting for Display in Windows 7 (Control Panel -> Display). It allows to change the size of the text and other items on the screen. I need to get this setting to be able to switch on/switch off some functionality in my C# application based on the setting value. Is that possible?


Both graphics.DpiX and DeviceCap.LOGPIXELSX return 96 on Surface Pro in all scaling levels.

Instead, I managed to calculate the scaling factor this way:

[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%
}

This setting is the screen DPI, or dots per inch.

Read it like so:

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

I don't think it's possible at the moment for the X and Y values to be different. A value of 96 corresponds to 100% font scaling (smaller), 120 corresponds to 125% scaling (medium) and 144 corresponds to 150% scaling (larger). However, users are able to set values other than these standard ones.

Do be aware that unless your application is declared to be DPI aware, then the values you observe may be subject to DPI virtualization.


The most easier way in my opinion is to use GetDeviceCaps function. From 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
}      

And usage:

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

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

In this approach you have no need to mark your app as dpi aware.


This is how you can do it in WPF. The return value is in WPF's logical units, which are equal to 1/96th of an inch. So if your screen DPI is set to 96, you will get a value of 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

(source)