VERTRES и HORZRES зависят от настроек масштабирования при загрузке системы - PullRequest
0 голосов
/ 23 января 2019

Я недавно играл с WINAPI, чтобы получить настройки масштабирования и разрешение экрана, и я столкнулся с этим странным поведением.

У меня есть небольшая программа на C ++ (список доступен ниже), которая получает значения VERTRES, HORZRES, DESKTOPVERTRES и DESKTOPHORZRES. Моя программа также устанавливает режим осведомленности DPI на 1 (осведомленность на уровне системы). Я заметил, что значения, сообщаемые VERTRES, HORZRES, зависят от коэффициента масштабирования системы, используемого при запуске системы.

Итак, на моем ноутбуке я настроил коэффициент масштабирования системы до 150% и разрешение 1920х1080. Это конфигурация при запуске. Когда я получаю HORZRES и DESKTOPHORZRES, оба значения отображаются как 1920.

Если я изменяю настройку масштабирования на 100% и не перезагружаю компьютер, в следующий раз, когда я получу эти значения, они будут указаны как 2880 (для HORZRES) и 1920 (для DESKTOPHORZRES).

После перезагрузки компьютера с настройками масштабирования, установленными на 100%, оба значения снова отображаются в 1920 году.

Если я снова изменю масштабирование на 150%, значения будут отображаться как 1280 (HORZRES) и 1920 (DESKTOPHORZRES).

Описанное поведение наблюдается только тогда, когда я устанавливаю DPI-осведомленность на 1, если для него установлено значение 0 («не в курсе») или 2 («на экран-осведомленность»), значения всегда отображаются как 1280 (HORZRES) и 1920 (DESKTOPHORZRES) независимо от того, как было настроено масштабирование при запуске.

Мне было интересно, почему значение, сообщаемое HORZRES (или VERTRES), зависит от коэффициента масштабирования, используемого при запуске системы? Это ожидаемое поведение?

Если выше уже было где-то описано, буду признателен за любые ссылки.

#include "stdafx.h"
#include <iostream>
#include <vector>
#include <cerrno>
#include <string>
#include <sstream>
#include <math.h>
#include <Windows.h>
#include <shellscalingapi.h>
#include <winuser.h>

class Rectangular
{
public:
    Rectangular(int height, int width) : height(height), width(width) {};
    const int height;
    const int width;
};

class MonitorInfo
{
public:
    MonitorInfo(std::string device_name, Rectangular logical_resolution, Rectangular physical_resolution, Rectangular physical_size_mm) :
        device_name(device_name), logical_resolution(logical_resolution), physical_resolution(physical_resolution),
        physical_size_mm(physical_size_mm), scaling(static_cast<int>(std::round(100.0*(float)physical_resolution.height / (float)logical_resolution.height))) {};

    void print_to_stdout() const;
    const std::string device_name;
    const Rectangular logical_resolution;
    const Rectangular physical_resolution;
    const Rectangular physical_size_mm;
    const int scaling;
};


class MonitorsInformation
{
public:
    MonitorsInformation();
    const std::vector<MonitorInfo>& get_monitors_info() const { return monitors; }
    std::string get_last_error_string() const { return last_error; }
    Rectangular get_monitors_rectangular() const;
private:
    RECT rectangular_combined;
    std::vector<MonitorInfo> monitors;
    std::string  last_error;
    static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData);
};

void MonitorInfo::print_to_stdout() const
{
    std::cout << "\nDevice: " << device_name << "\nLogical Screen resolution: " << logical_resolution.width << "x" << logical_resolution.height;
    std::cout << "\nPhysical Screen resolution: " << physical_resolution.width << "x" << physical_resolution.height;
    std::cout << "\nDPI ratio: " << scaling;
    std::cout << "\nPhysical Size(mm): " << physical_size_mm.width << "x" << physical_size_mm.height << "\n";
}


MonitorsInformation::MonitorsInformation() : rectangular_combined(RECT()), last_error(std::string()), monitors(std::vector<MonitorInfo>())
{
    EnumDisplayMonitors(0, 0, MonitorEnum, (LPARAM)this);
}

BOOL CALLBACK MonitorsInformation::MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
{
    MonitorsInformation* pThis = reinterpret_cast<MonitorsInformation*>(pData);

    MONITORINFOEXA monitor_info;
    monitor_info.cbSize = sizeof(MONITORINFOEXA);

    if (!GetMonitorInfoA(hMon, &monitor_info))
    {
        pThis->last_error = "GetMonitorInfoA failed with error: " + errno;
        return FALSE;
    }

    UnionRect(&pThis->rectangular_combined, &pThis->rectangular_combined, lprcMonitor);

    HDC device_context = CreateDCA(NULL, monitor_info.szDevice, NULL, NULL);

    int LogicalScreenHeight = GetDeviceCaps(device_context, VERTRES);
    int LogicalScreenWidth = GetDeviceCaps(device_context, HORZRES);
    int PhysicalScreenHeight = GetDeviceCaps(device_context, DESKTOPVERTRES);
    int PhysicalScreenWidth = GetDeviceCaps(device_context, DESKTOPHORZRES);

    pThis->monitors.push_back(
        MonitorInfo(
            std::string(monitor_info.szDevice),
            Rectangular(
                LogicalScreenHeight,
                LogicalScreenWidth),
            Rectangular(
                PhysicalScreenHeight,
                PhysicalScreenWidth),
            Rectangular(
                GetDeviceCaps(device_context, VERTSIZE),
                GetDeviceCaps(device_context, HORZSIZE))));

    return TRUE;
}

Rectangular MonitorsInformation::get_monitors_rectangular() const
{
    return Rectangular(
        std::abs(rectangular_combined.top) + std::abs(rectangular_combined.bottom),
        std::abs(rectangular_combined.left) + std::abs(rectangular_combined.right));
}


int main()
{
    SetProcessDPIAware();

    for (;;)
    {
        MonitorsInformation MonitorsInfo;
        char exit_char = 'N';
        std::cout << "You have " << MonitorsInfo.get_monitors_info().size() << " monitors connected.\n";
        printf("Screen rectangular. %d x %d\n",
            MonitorsInfo.get_monitors_rectangular().width, MonitorsInfo.get_monitors_rectangular().height);

        for (auto &monitor : MonitorsInfo.get_monitors_info())
        {
            monitor.print_to_stdout();
        }
        std::cout << "Would you like to repeat? [Y]/[N]\n";
        std::cin >> exit_char;
        if (exit_char == 'N' || exit_char == 'n')
        {
            break;
        }
    }

    return 0;
}

1 Ответ

0 голосов
/ 25 января 2019

@ AlexanderZinovyev Спасибо за дальнейшие разъяснения, и я могу воспроизвести вашу проблему с сохранением коэффициента масштабирования до 150% и перезагрузкой компьютера.

После проверки документа API GetDeviceCaps я обнаружил следующее примечание:

Примечание. GetDeviceCaps сообщает информацию, предоставляемую драйвером дисплея. Если драйвер дисплея отказывается сообщать какую-либо информацию, GetDeviceCaps вычисляет информацию на основе фиксированных вычислений. Если драйвер дисплея сообщает о неверной информации, GetDeviceCaps возвращает неверную информацию. Кроме того, если драйвер дисплея отказывается сообщать информацию, GetDeviceCaps может вычислять неверную информацию , поскольку он принимает либо фиксированный DPI (96 DPI), либо фиксированный размер (в зависимости от информации, которую драйвер дисплея сделал и не сделалпредоставлять). К сожалению, драйвер дисплея, который реализован в модели драйвера дисплея Windows (WDDM) (представлен в Windows Vista), заставляет GDI не получать информацию, поэтому GetDeviceCaps всегда должен вычислять информацию.

Похоже, что возвращаемое значение API GetDeviceCaps может не отражать реальную стоимость устройства.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...