7

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)

David CASBONNE
  • 139
  • 2
  • 9
  • How does your program declare its DPI awareness? – David Heffernan Apr 03 '17 at 14:49
  • I haven't set anything in my program, just "add new project WPF" in Visual Studio :) – David CASBONNE Apr 03 '17 at 14:51
  • Well, it's time to find out, isn't it. You know what DPI awareness is right? – David Heffernan Apr 03 '17 at 14:58
  • 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 Apr 03 '17 at 15:01
  • I think you are not going to make any progress until you understand the concept of DPI awareness comprehensively. – David Heffernan Apr 03 '17 at 15:03
  • WPF applications are *system* DPI aware by default. In .NET Framework 4.6.2 you can easily enable per monitor DPI awareness: https://github.com/Microsoft/WPF-Samples/tree/master/PerMonitorDPI. – mm8 Apr 03 '17 at 15:04
  • @david : OK I understand principe of scaling, I understand DPI in WPF context but I don't understand the relation between obtaining resolution and the fact that the app is DPI aware or not. Why these informations are not accessible via simple API ?? – David CASBONNE Apr 03 '17 at 15:12
  • Yawn. Trying to work this out with an incomplete understanding is tedious. Don't waste your own time on this. Don't flail around in the dark. Back your own ability to be able to understand this. – David Heffernan Apr 03 '17 at 15:14
  • @mm8 : thanks for the link, I'll read carefuly but what I forgot to mention is my app should run in .Net 4. – David CASBONNE Apr 03 '17 at 15:14
  • Did you read this?: https://msdn.microsoft.com/en-us/library/windows/desktop/ee308410(v=vs.85).aspx – mm8 Apr 03 '17 at 15:15
  • @DavidHeffernan : it's not a question about wasting my time, I HAVE to do that, I'd prefer not but that's not the case. Could you try to help me or not ? Why a blank new WPF app always return 100% scaling ? Or a DPI of 96 ? – David CASBONNE Apr 03 '17 at 15:16
  • @mm8 : thanks for the link, I will read that. – David CASBONNE Apr 03 '17 at 15:17
  • I can't help you until you understand DPI awareness. Sorry. – David Heffernan Apr 03 '17 at 15:25
  • Oh yes, I wasn't asking you for learning me DPI awareness :) Thanks to mm8 links, I was able to find a demo app from Microsoft that can obtain good DPI for my screens. I now have to understand why my app wouldn't do that since they used GetDpiForMonitor as I was doing... (but maybe, as you said, understanding DPI awareness will help me for that point). – David CASBONNE Apr 03 '17 at 15:59
  • Main post edited : I forgot to mention that I need to obtain these informations without any visual app (my DLL is called from a VB application) – David CASBONNE Apr 03 '17 at 17:35

1 Answers1

7

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;

const int ENUM_CURRENT_SETTINGS = -1;

foreach (Screen screen in Screen.AllScreens)
{
    var 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")]
static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

[StructLayout(LayoutKind.Sequential)]
public struct DEVMODE
{
    [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

colton7909
  • 824
  • 12
  • 16