0

For an application which will be used to calibrate optical systems, I need to know the scaling a user has set in his/her settings... I have tried to get the DPI values for the physical screen and the virtual screen (with applied user scaling). By dividing I should get the scaling factor... but I haven't managed to get it to work.

So is there a way to get the scaling factor right away through a DLL or something else? Or was my way correct and I have to calculate it? If so: how can I get the two values for physical screen and the virtual screen (with applied user scaling)?

I have tried to Use the "user32.dll", the "Shcore.dll", Control.AutoScaleFactor and the System.Drawing... In any way I only get the values for the virtual screen (with applied user scaling) or a relationship of 1 which would mean the user has set its scaling to 100% which isn't true. I did not manage to get the physical screen DPI or a correct scaling factor

Here's what I have tried by using the GetDpiForMonitor function

{
 [DllImport("Shcore.dll")]
    private static extern int GetDpiForMonitor(IntPtr hmonitor, MonitorDpiType dpiType, out uint dpiX, out uint dpiY);

    private enum MonitorDpiType
    {
        EffectiveDpi = 0,
        AngularDpi = 1,
        RawDpi = 2,
    }

    private void ShowPPI_Click(object sender, EventArgs e)
    {
        IntPtr primaryMonitor = IntPtr.Zero; 
        uint dpiX, dpiY;
        int result = GetDpiForMonitor(primaryMonitor, MonitorDpiType.EffectiveDpi, out dpiX, out dpiY);


        MessageBox.Show(result.ToString());
    }
}
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
  • You can calculate it from the results of GetMonitorInfo and GetDpiForMonitor. – emoacht Jun 18 '23 at 13:45
  • sadly thats not very helpfull. I tried it in many ways and writting "GetMonitorInfo and GetDpiForMonitor " does not help. so how can i implement them and how do i get the pure monitor DPI?? i only get the user scaled one, with 135% thats 130 instead of 96 as a example – Simon Dengler Jun 21 '23 at 22:01
  • Show what you tried so far. Then other people can suggest a modification. – emoacht Jun 22 '23 at 11:40
  • of course! i guess i should have included that in the first place. – Simon Dengler Jun 26 '23 at 06:04
  • You are supposed to include the code itself in the question. Then, have you tried [GetDpiForMonitor](https://learn.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-getdpiformonitor)? If so, what is the issue with it? – emoacht Jun 26 '23 at 21:45
  • My issue is that i cant get sensful results, but to be honest i dont realy know how to use the funktion. when i use the variable result it displays a huge value like -21309 – Simon Dengler Jun 28 '23 at 09:38
  • Does this answer your question? [How to get scaling factor for each monitor, e.g. 1, 1.25, 1.5](https://stackoverflow.com/questions/60872044/how-to-get-scaling-factor-for-each-monitor-e-g-1-1-25-1-5) – Heretic Monkey Jun 28 '23 at 23:06
  • i havent got much tie for now... thats why i cant properly code and test, but it seems very promisin so i will look in to it when i have more free time! – Simon Dengler Jul 02 '23 at 11:57

1 Answers1

0

You can get the monitor handle of primary monitor by MonitorFromWindow or other fuctions.

So if you want to get the primary monitor's DPI Scale, the code will be like the following.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class DpiHelper
{
    [DllImport("User32.dll")]
    static extern IntPtr MonitorFromWindow(
        IntPtr hwnd,
        MONITOR_DEFAULTTO dwFlags);

    enum MONITOR_DEFAULTTO : uint
    {
        MONITOR_DEFAULTTONULL = 0x00000000,
        MONITOR_DEFAULTTOPRIMARY = 0x00000001,
        MONITOR_DEFAULTTONEAREST = 0x00000002,
    }

    [DllImport("Shcore.dll")]
    static extern int GetDpiForMonitor(
        IntPtr hmonitor,
        MONITOR_DPI_TYPE dpiType,
        out uint dpiX,
        out uint dpiY);

    enum MONITOR_DPI_TYPE
    {
        MDT_Effective_DPI = 0,
        MDT_Angular_DPI = 1,
        MDT_Raw_DPI = 2,
        MDT_Default = MDT_Effective_DPI
    }

    const double DefaultPixelsPerInch = 96D;

    public static void CheckPrimaryMonitorDpi()
    {
        var monitorHandle = MonitorFromWindow(
            IntPtr.Zero,
            MONITOR_DEFAULTTO.MONITOR_DEFAULTTOPRIMARY);

        var result = GetDpiForMonitor(
            monitorHandle,
            MONITOR_DPI_TYPE.MDT_Default,
            out uint dpiX,
            out uint dpiY);
        if (result is 0)
        {
            Debug.WriteLine($"DPI Scale X {dpiX / DefaultPixelsPerInch}");
            Debug.WriteLine($"DPI Scale Y {dpiY / DefaultPixelsPerInch}");
        }
    }
}

Don't forget to add a correct application manifest. Setting the default DPI awareness for a process

emoacht
  • 2,764
  • 1
  • 13
  • 24