【问题标题】:VERTRES and HORZRES depends on scaling setting when system booted upVERTRES 和 HORZRES 取决于系统启动时的缩放设置
【发布时间】:2019-06-16 09:48:32
【问题描述】:

我最近一直在使用 WINAPI 来检索缩放设置和屏幕分辨率,我遇到了这种奇怪的行为。

我有一个小的 C++ 程序(下面提供了列表),它可以检索 VERTRES、HORZRES、DESKTOPVERTRES 和 DESKTOPHORZRES 的值。我的程序还将 DPI 感知模式设置为 1(系统级感知)。我注意到 VERTRES、HORZRES 报告的值取决于系统启动时使用的系统比例因子。

所以在我的笔记本电脑上,我将系统缩放系数配置为 150%,分辨率为 1920x1080。那是启动时的配置。当我检索 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;
}

【问题讨论】:

  • 除非您在更改 DPI 后重新启动(或至少注销),否则很多事情都会变得很奇怪。就是这样。
  • 我使用 SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_SYSTEM_AWARE); 设置 DPI 感知,两者都无法重现您的问题。当比例因子增加时,HORZRES 值总是减小。 (100%-1920; 125%-1536; 150%-1280; 175%-1097) 我没有重启。
  • 我在 Windows 10 Enterprise Desktop 上测试。
  • @RitaHan-MSFT,感谢您的意见。是的,如果我将缩放因子从默认的 100% 增加到例如,我可以看到相同的行为。 150%。在这种情况下,我看到 HORZRES 越来越小(如我所料)。当我将比例因子保持在 150% 并重新启动计算机时,我的问题就出现了。

标签: winapi windows-10 dpi-aware


【解决方案1】:

@AlexanderZinovyev 感谢您的进一步解释,我可以通过将比例因子保持为 150% 并重新启动计算机来重现您的问题。

查看GetDeviceCaps API 文档后发现如下注释:

注意 GetDeviceCaps 报告显示驱动程序提供的信息。 如果 显示驱动程序拒绝报告任何信息,GetDeviceCaps 根据固定计算计算信息。 如果显示驱动程序 报告无效信息,GetDeviceCaps 返回无效信息。 另外,如果 显示驱动程序拒绝报告信息,GetDeviceCaps 可能 计算不正确的信息,因为它假定固定 DPI (96 DPI) 或固定大小(取决于显示驱动程序所做的信息和 没有提供)。 不幸的是,实现的显示驱动程序 到 Windows 显示驱动程序模型 (WDDM)(在 Windows 中引入 Vista) 导致 GDI 无法获取信息,因此 GetDeviceCaps 必须始终 计算信息。

看来GetDeviceCaps API的返回值可能无法反映设备的真实价值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-09
    • 2016-11-29
    • 2015-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多