0

Is it possible to get the DPI value of specific monitor?

I have tried all the methods that are online but they are always return the value of the primary monitor.

examples that i have used :

example1

using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
       dpiX = g.DpiX;
       dpiY = g.DpiY;
}

example2

PresentationSource source = PresentationSource.FromVisual(this);

double dpiX, dpiY;
if (source != null) {
    dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
    dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
}

example3

var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);

var dpiX = (int)dpiXProperty.GetValue(null, null);
var dpiY = (int)dpiYProperty.GetValue(null, null);

none of the above works for specific monitor

gmetax
  • 3,853
  • 2
  • 31
  • 45
  • I am not absolutely sure about this, that's why I am only putting it in a comment: I am afraid that the DPI values that you may get from Windows refer to a DPI setting configured within Windows, not the actual DPI capability of the hardware, so that would mean that it is global. It simply helps an application to know how many pixels to draw to make something appear as one inch long. Also, it may be very difficult, if not impossible, to obtain the actual DPI of the hardware. But let's see if anyone else knows better. – Mike Nakis May 03 '17 at 20:56
  • but you can specify different zoom for different monitors so you have different DPI. http://jmp.sh/CJLjx2s – gmetax May 03 '17 at 21:02
  • I do not have access to W10 so I cannot verify this. Either it does not set a different scale on different monitors, or this scale that it sets is not DPI, or, well, there is some extra setting somewhere that I am unaware of. – Mike Nakis May 03 '17 at 21:06
  • it sets different scale and the dpi changes if you do that change on the primary screen. but all the above methods gets the dpi value of primary screen – gmetax May 03 '17 at 21:07
  • The OS lies to you if you don't declare your app to be per-monitor DPI aware. You can [fix that](https://msdn.microsoft.com/en-us/library/windows/desktop/ee308410(v=vs.85).aspx), but then you are liable to have two problems, correctly handling the notification is not that easy. SetThreadDpiAwarenessContext() is a simple approach, but only works on Win10. Consider that you really only want to know how your app behaves, not how the OS behaves. The user can simply use Control Panel. – Hans Passant May 03 '17 at 22:43
  • but even if you set DPI aware your app you will have issues when you are trying to draw or to check if the point of the mouse is correctly over a specified element, if you have the dpi scale you can get the values and calculate the correct values – gmetax May 03 '17 at 22:48

2 Answers2

2

You can use:

GetDpiForMonitor

Now, it depends whether you have said if your application is DPI aware or not, on how you can get to those per monitor dpi values - if you aren't DPI aware, then you could be lied to on the actual DPI.

If you do:

SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE).

(or set it in your app.manfest).

Then what you can do next is enumerate the monitors, and call GetDpiForMonitor to get the actual DPI set by the user for each one.

You could use this code that uses System.Windows.Forms.Screen and MonitorFromPoint to get a handle to each screen.

If you look at:

there's a sample WPF application there, with some helper calls (in managed c++)...but you can equally do your own DLLImports of the WIN32 APIs, etc.

Community
  • 1
  • 1
Colin Smith
  • 12,375
  • 4
  • 39
  • 47
  • haven't make it work yet, cause the project NativeMethods needs to have vs2013 and i am looking for a workaround – gmetax May 05 '17 at 11:25
  • just load the .cs file...add it to your existing project....no need to open the project if you can't – Colin Smith May 05 '17 at 13:12
  • it is a c++ project not c# – gmetax May 05 '17 at 13:32
  • if you can't don't want to use the managed c++ code, then you can achieve the same by doing dllimport of the WIN32 calls...and handling the DPI changed broadcast message if you want. try this one: http://stackoverflow.com/questions/41531438/c-sharp-getting-dpi-scaling-for-each-monitor-in-windows – Colin Smith May 05 '17 at 14:59
0

You need .Net 4.7

See: https://msdn.microsoft.com/en-us/library/ms171868(v=vs.110).aspx

Sections:

  • High DPI support
  • Per-monitor DPI
Wouter
  • 2,540
  • 19
  • 31
  • thanks for the suggestion but that is DPI-Awareness, you cannot get the how everything is scaled or need to be scaled – gmetax May 03 '17 at 22:19