Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.1k views
in Technique[技术] by (71.8m points)

wpf - C# - How to get real screen resolution in multiple monitors context?

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)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

56.6k users

...