I know this has been asked before, but I've tried all the answers I've found and none of them seem to work for me. Answers seem to work on a single monitor, or require a window handle, or to be in a WPF application. I've a C# class library with no UI that is called from a different language all together.
I've been asked to determine the scaling factor, e.g. 1, 1.25, 1.5, etc. for each monitor attached to the current PC in a C# class library.
I also need to provide the resolution and colour depth for each monitor. The registry does hold the DpiValue
, whatever that is, in Windows 10 under
Computer\HKEY_CURRENT_USER\Control Panel\Desktop\PerMonitorSettings
However I have no idea how to map those to a Screen
in order to get the matching resolution returned in
System.Windows.Forms.Screen.AllScreens
So does anyone have a way of getting this information?
I believe I have finally (after a long time of searching) found an answer that works, it even works on my high DPI Surface Book 2 screen. I have tested it as much as I can, and so far it's always returned the correct value.
Here's how I did it, thanks to whoever posted the code fragments in the past where I gathered this from.
First you need a structure to call EnumDisplaySettings in user32.dll
[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
private const int CCHDEVICENAME = 0x20;
private const int CCHFORMNAME = 0x20;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmDeviceName;
public short dmSpecVersion;
public short dmDriverVersion;
public short dmSize;
public short dmDriverExtra;
public int dmFields;
public int dmPositionX;
public int dmPositionY;
public ScreenOrientation dmDisplayOrientation;
public int dmDisplayFixedOutput;
public short dmColor;
public short dmDuplex;
public short dmYResolution;
public short dmTTOption;
public short dmCollate;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
public string dmFormName;
public short dmLogPixels;
public int dmBitsPerPel;
public int dmPelsWidth;
public int dmPelsHeight;
public int dmDisplayFlags;
public int dmDisplayFrequency;
public int dmICMMethod;
public int dmICMIntent;
public int dmMediaType;
public int dmDitherType;
public int dmReserved1;
public int dmReserved2;
public int dmPanningWidth;
public int dmPanningHeight;
}
Then you need to declare the external function call
[DllImport("user32.dll")]
public static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);
Then you need to use it to calculate the screen scaling
Screen[] screenList = Screen.AllScreens;
foreach (Screen screen in screenList)
{
DEVMODE dm = new DEVMODE();
dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
EnumDisplaySettings(screen.DeviceName, -1, ref dm);
var scalingFactor = Math.Round(Decimal.Divide(dm.dmPelsWidth, screen.Bounds.Width), 2);
}
Hope others find this useful.