Как получить коэффициент масштабирования для каждого монитора, например, 1, 1,25, 1,5 - PullRequest
1 голос
/ 26 марта 2020

Я знаю, что об этом уже спрашивали, но я попробовал все ответы, которые нашел, и ни один из них, похоже, не работает для меня. Кажется, что ответы работают на одном мониторе, требуют дескриптора окна или находятся в приложении WPF. У меня есть C# библиотека классов без пользовательского интерфейса, которая все время вызывается из другого языка.

Меня попросили определить коэффициент масштабирования, например, 1, 1,25, 1,5 и т. Д. c , для каждого монитора, подключенного к текущему P C в библиотеке классов C#.

Мне также необходимо указать разрешение и глубину цвета для каждого монитора. Реестр содержит DpiValue, что бы это ни было, в Windows 10 в

Computer\HKEY_CURRENT_USER\Control Panel\Desktop\PerMonitorSettings

Однако я понятия не имею, как сопоставить их с Screen, чтобы получить возвращаемое разрешение в

System.Windows.Forms.Screen.AllScreens

Так есть ли у кого-нибудь способ получить эту информацию?

Ответы [ 2 ]

0 голосов
/ 02 апреля 2020

Я полагаю, что наконец-то (после долгого поиска) нашел ответ, который работает, он работает даже на моем экране Surface Book 2 с высоким DPI. Я проверил это столько, сколько смогу, и до сих пор оно всегда возвращало правильное значение.

Вот как я это сделал, благодаря тому, кто в прошлом размещал фрагменты кода, откуда я его собрал.

Сначала вам нужна структура для вызова EnumDisplaySettings в user32.dll

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

Затем вам нужно объявить внешний вызов функции

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

Затем вам нужно использовать ее для рассчитать масштабирование экрана

            Screen[] screenList = Screen.AllScreens;

            foreach (Screen screen in screenList)
            {
                DEVMODE dm = new DEVMODE();
                dm.dmSize = (short)Marshal.SizeOf(typeof(DEVMODE));
                EnumDisplaySettings(screen.DeviceName, -1, ref dm);

                var scalingFactor = Math.Round(Decimal.Divide(dm.dmPelsWidth, screen.Bounds.Width), 2);
            }

Надеюсь, другие найдут это полезным.

0 голосов
/ 26 марта 2020

Я думаю, вы можете получить коэффициент масштабирования для каждого монитора следующим образом.

public void GetScalingFactor()
{
    List<double> physicalWidths = new List<double>();

    //Get physical width for each monitor
    ManagementObjectSearcher searcher = new ManagementObjectSearcher("\\root\\wmi", "SELECT * FROM WmiMonitorBasicDisplayParams");

    foreach (ManagementObject monitor in searcher.Get())
    {
        //Get the physical width (inch)
        double width = (byte)monitor["MaxHorizontalImageSize"] / 2.54;
        physicalWidths.Add(width);
    }

    //Get screen info for each monitor
    Screen[] screenList = Screen.AllScreens;
    int i = 0;

    foreach (Screen screen in screenList)
    {
        //Get the physical width (pixel)
        double physicalWidth;
        if (i < physicalWidths.Count)
        {
            //Get the DPI
            uint x, y;
            GetDpi(screen, DpiType.Effective, out x, out y);

            //Convert inch to pixel
            physicalWidth = physicalWidths[i] * x;
        }
        else
        {
            physicalWidth = SystemParameters.PrimaryScreenWidth;
        }
        i++;

        //Calculate the scaling
        double scaling = 100 * (physicalWidth / screen.Bounds.Width);
        double scalingFactor = physicalWidth / screen.Bounds.Width;

        //Output the result
        Console.WriteLine(scalingFactor);
    }
}

И вам также нужно добавить эти коды, чтобы использовать их для получения DPI монитора (этот код от { ссылка } , спасибо @ Koopakiller ):

public void GetDpi(Screen screen, DpiType dpiType, out uint dpiX, out uint dpiY)
{
    var pnt = new System.Drawing.Point(screen.Bounds.Left + 1, screen.Bounds.Top + 1);
    var mon = MonitorFromPoint(pnt, 2/*MONITOR_DEFAULTTONEAREST*/);
    GetDpiForMonitor(mon, dpiType, out dpiX, out dpiY);
}

//https://msdn.microsoft.com/en-us/library/windows/desktop/dd145062(v=vs.85).aspx
[DllImport("User32.dll")]
private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);

//https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510(v=vs.85).aspx
[DllImport("Shcore.dll")]
private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);

//https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511(v=vs.85).aspx
public enum DpiType
{
    Effective = 0,
    Angular = 1,
    Raw = 2,
}
...