5
votes

For one of my application (write in WPF), I need to get some informations about monitors : Current resolution, scaling factor and real resolution.

I know this question has been asked many times but I'm not able to find a good answer in all SO questions that talked about that...

In my case for example, I have 3 monitors placed in this order :

  • Monitor 1 (integrated laptop screen) : 1920x1080, scaled at 125%
  • Monitor 2 (LG 22") : 1920x1080, scaled at 100% (PRIMARY MONITOR)
  • Monitor 3 (LG 22") : 1920x1080, scaled at 100%

When using System.Windows.Forms.Screen.AllScreens, I obtain a resolution of 1536x864 for my first monitor. It's OK because 1536*1.25 = 1920. But i'm not able to find either the 1.25 or the 1920 ^^ (for the other monitors it's OK because they're scaled at 100%).

But if I set monitor 1 to be primary I can obtain it's real resolution but for monitor 2 and 3 I obtain 2400*1350... It's 1920x1080 multiply by the primary monitor's scaling factor : 1.25

It's been 2 days since I try many ways. I've tried AllScreens in Windows.Forms. In WinAPI I've tried EnumDisplayMonitors, GetDeviceCaps, GetScaleFactorForMonitor, GetDpiForMonitor... Everything always give me a 100% scaling factor or a DPI of 96 for my first monitor which is an error...

Do you know a secure way to obtain these informations ? In WMI, in registry, etc...

Thanks for your help !

(PS : if needed I can provide code sample of what I tried but I don't want to flood this first post)

EDIT : I forgot to mention that I need to obtain these informations without any visual app (my DLL is called from a VB application)

1
How does your program declare its DPI awareness?David Heffernan
I haven't set anything in my program, just "add new project WPF" in Visual Studio :)David CASBONNE
Well, it's time to find out, isn't it. You know what DPI awareness is right?David Heffernan
Not really... I've read some threads about that but it's not very clear in my head... Do you think that declaring DPI awareness in my program would help me finding these informations ?David CASBONNE
I think you are not going to make any progress until you understand the concept of DPI awareness comprehensively.David Heffernan

1 Answers

4
votes

I have almost exactly the same setup. I was able to get the real resolution by calling EnumDisplaySettings using p/invoke.

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace RealScreenResolution
{
    class Program
    {
        const int ENUM_CURRENT_SETTINGS = -1;

        static void Main(string[] args)
        {
            foreach (Screen screen in Screen.AllScreens)
            {
                DEVMODE dm = new DEVMODE();
                dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
                EnumDisplaySettings(screen.DeviceName, ENUM_CURRENT_SETTINGS, ref dm);

                Console.WriteLine($"Device: {screen.DeviceName}");
                Console.WriteLine($"Real Resolution: {dm.dmPelsWidth}x{dm.dmPelsHeight}");
                Console.WriteLine($"Virtual Resolution: {screen.Bounds.Width}x{screen.Bounds.Height}");
                Console.WriteLine();
            }
        }

        [DllImport("user32.dll")]
        public static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

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

And the output:

Device: \\.\DISPLAY1
Real Resolution: 1920x1080
Virtual Resolution: 1536x864

Device: \\.\DISPLAY2
Real Resolution: 1920x1080
Virtual Resolution: 1920x1080

Device: \\.\DISPLAY3
Real Resolution: 1920x1080
Virtual Resolution: 1920x1080

https://stackoverflow.com/a/36864741/987968 http://pinvoke.net/default.aspx/user32/EnumDisplaySettings.html?diff=y