DPI 设置和获取

DPI设置与获取之前请保证程序已经打开DPI感知或者在清单文件嵌入DPI感知,否则API可能获取的值不准确
在这里插入图片描述

方法一:GetScaleFactorForMonitor

通过枚举显示器获取不同设备的DPI,获取的是实际DPI

static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,LPARAM dwData)
{
    std::vector<int> *pvec_ret = (std::vector<int> *)(dwData);
    DEVICE_SCALE_FACTOR val = DEVICE_SCALE_FACTOR_INVALID;
    GetScaleFactorForMonitor(hMonitor, &val);
    if (val != DEVICE_SCALE_FACTOR_INVALID)
        pvec_ret->push_back(val);
    return TRUE;
}

std::vector<int> DpiHelper::GetDpiFromMonitors()
{
    std::vector<int> vec_ret;
    do
    {
        HDC hdc = GetDC(NULL);
        if (hdc == nullptr)
        {
            OutputDebugStringA("DpiHelper::GetDpiFromMonitors GetDC failed");
            break;
        }

        EnumDisplayMonitors(hdc, NULL, MonitorEnumProc, (LPARAM)&vec_ret);
        ReleaseDC(NULL,hdc);
    } while (false);
   
    if (vec_ret.empty())
        vec_ret.push_back(100);

    return vec_ret;
}

方法二:DisplayConfigGetDeviceInfo

实测过程中发现有时候该值返回的与实际值不一致。例如当系统锁定缩放200%,通过显示设置查看的值200%,但当打开自定义缩放的时候发现实际值是100%。此时该接口返回的是200%

具体代码如下:
DpiHelper.h

#pragma once
#include <Windows.h>
#include <vector>


/*
* OS reports DPI scaling values in relative terms, and not absolute terms.
* eg. if current DPI value is 250%, and recommended value is 200%, then
* OS will give us integer 2 for DPI scaling value (starting from recommended
* DPI scaling move 2 steps to the right in this list).
* values observed (and extrapolated) from system settings app (immersive control panel).
*/
static const UINT32 DpiVals[] = { 100,125,150,175,200,225,250,300,350, 400, 450, 500 };

class DpiHelper
{
public:
    template<class T, size_t sz>
    static size_t CountOf(const T (&arr)[sz])
    {
        UNREFERENCED_PARAMETER(arr);
        return sz;
    }

    /*
    * @brief : Use QueryDisplayConfig() to get paths, and modes.
    * @param[out] pathsV : reference to a vector which will contain paths
    * @param[out] modesV : reference to a vector which will contain modes
    * @param[in] flags : determines the kind of paths to retrieve (only active paths by default)
    * return : false in case of failure, else true
    */
    static bool GetPathsAndModes(std::vector<DISPLAYCONFIG_PATH_INFO>& pathsV, std::vector<DISPLAYCONFIG_MODE_INFO>& modesV, int flags = QDC_ONLY_ACTIVE_PATHS);

    //out own enum, similar to DISPLAYCONFIG_DEVICE_INFO_TYPE enum in wingdi.h
    enum class DISPLAYCONFIG_DEVICE_INFO_TYPE_CUSTOM : int
    {
        DISPLAYCONFIG_DEVICE_INFO_GET_DPI_SCALE = -3, //returns min, max, suggested, and currently applied DPI scaling values.
        DISPLAYCONFIG_DEVICE_INFO_SET_DPI_SCALE = -4, //set current dpi scaling value for a display
    };

    /*
    * struct DISPLAYCONFIG_SOURCE_DPI_SCALE_GET
    * @brief used to fetch min, max, suggested, and currently applied DPI scaling values.
    * All values are relative to the recommended DPI scaling value
    * Note that DPI scaling is a property of the source, and not of target.
    */
    struct DISPLAYCONFIG_SOURCE_DPI_SCALE_GET
    {
        DISPLAYCONFIG_DEVICE_INFO_HEADER            header;
        /*
        * @brief min value of DPI scaling is always 100, minScaleRel gives no. of steps down from recommended scaling
        * eg. if minScaleRel is -3 => 100 is 3 steps down from recommended scaling => recommended scaling is 175%
        */
        std::int32_t minScaleRel;

        /*
        * @brief currently applied DPI scaling value wrt the recommended value. eg. if recommended value is 175%,
        * => if curScaleRel == 0 the current scaling is 175%, if curScaleRel == -1, then current scale is 150%
        */
        std::int32_t curScaleRel;

        /*
        * @brief maximum supported DPI scaling wrt recommended value
        */
        std::int32_t maxScaleRel;
    };

    /*
    * struct DISPLAYCONFIG_SOURCE_DPI_SCALE_SET
    * @brief set DPI scaling value of a source
    * Note that DPI scaling is a property of the source, and not of target.
    */
    struct DISPLAYCONFIG_SOURCE_DPI_SCALE_SET
    {
        DISPLAYCONFIG_DEVICE_INFO_HEADER            header;
        /*
        * @brief The value we want to set. The value should be relative to the recommended DPI scaling value of source.
        * eg. if scaleRel == 1, and recommended value is 175% => we are trying to set 200% scaling for the source
        */
        int32_t scaleRel;
    };

    /*
    * struct DPIScalingInfo
    * @brief DPI info about a source
    * mininum :     minumum DPI scaling in terms of percentage supported by source. Will always be 100%.
    * maximum :     maximum DPI scaling in terms of percentage supported by source. eg. 100%, 150%, etc.
    * current :     currently applied DPI scaling value
    * recommended : DPI scaling value reommended by OS. OS takes resolution, physical size, and expected viewing distance
    *               into account while calculating this, however exact formula is not known, hence must be retrieved from OS
    *               For a system in which user has not explicitly changed DPI, current should eqaul recommended.
    * bInitDone :   If true, it means that the members of the struct contain values, as fetched from OS, and not the default
    *               ones given while object creation.
    */
    struct DPIScalingInfo
    {
        UINT32 mininum = 100;
        UINT32 maximum = 100;
        UINT32 current = 100;
        UINT32 recommended = 100;
        bool bInitDone = false;
    };

    DpiHelper();
    ~DpiHelper();
    //当锁定的时候获取的值可能不对,例如dpi锁定200%,该函数获取的是200,但是实际是100
    static DpiHelper::DPIScalingInfo GetDPIScalingInfo(LUID adapterID, UINT32 sourceID);
    static bool SetDPIScaling(LUID adapterID, UINT32 sourceID, UINT32 dpiPercentToSet);

    //当锁定的时候获取的值可能不对,例如dpi锁定200% 但是实际是100,则获取实际值100
    static std::vector<int> GetDpiFromMonitors();
};


DpiHelper.cpp

#include "DpiHelper.h"
#include <memory>
#include <cassert>
#include<Windows.h>
#include<shtypes.h>
#include<shellscalingapi.h>

bool DpiHelper::GetPathsAndModes(std::vector<DISPLAYCONFIG_PATH_INFO>& pathsV, std::vector<DISPLAYCONFIG_MODE_INFO>& modesV, int flags)
{
    UINT32 numPaths = 0, numModes = 0;
    auto status = GetDisplayConfigBufferSizes(flags, &numPaths, &numModes);
    if (ERROR_SUCCESS != status)
    {
        return false;
    }

    std::unique_ptr<DISPLAYCONFIG_PATH_INFO[]> paths(new DISPLAYCONFIG_PATH_INFO[numPaths]);
    std::unique_ptr<DISPLAYCONFIG_MODE_INFO[]> modes(new DISPLAYCONFIG_MODE_INFO[numModes]);
    status = QueryDisplayConfig(flags, &numPaths, paths.get(), &numModes, modes.get(), nullptr);
    if (ERROR_SUCCESS != status)
    {
        return false;
    }

    for (unsigned int i = 0; i < numPaths; i++)
    {
        pathsV.push_back(paths[i]);
    }

    for (unsigned int i = 0; i < numModes; i++)
    {
        modesV.push_back(modes[i]);
    }

    return true;
}


DpiHelper::DpiHelper()
{
}


DpiHelper::~DpiHelper()
{
}


DpiHelper::DPIScalingInfo DpiHelper::GetDPIScalingInfo(LUID adapterID, UINT32 sourceID)
{
    DPIScalingInfo dpiInfo = {};

    DpiHelper::DISPLAYCONFIG_SOURCE_DPI_SCALE_GET requestPacket = {};
    requestPacket.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)DpiHelper::DISPLAYCONFIG_DEVICE_INFO_TYPE_CUSTOM::DISPLAYCONFIG_DEVICE_INFO_GET_DPI_SCALE;
    requestPacket.header.size = sizeof(requestPacket);
    assert(0x20 == sizeof(requestPacket));//if this fails => OS has changed somthing, and our reverse enginnering knowledge about the API is outdated
    requestPacket.header.adapterId = adapterID;
    requestPacket.header.id = sourceID;

    auto res = ::DisplayConfigGetDeviceInfo(&requestPacket.header);
    if (ERROR_SUCCESS == res)
    {//success
        if (requestPacket.curScaleRel < requestPacket.minScaleRel)
        {
            requestPacket.curScaleRel = requestPacket.minScaleRel;
        }
        else if (requestPacket.curScaleRel > requestPacket.maxScaleRel)
        {
            requestPacket.curScaleRel = requestPacket.maxScaleRel;
        }

        std::int32_t minAbs = abs((int)requestPacket.minScaleRel);
        if (DpiHelper::CountOf(DpiVals) >= (size_t)(minAbs + requestPacket.maxScaleRel + 1))
        {//all ok
            dpiInfo.current = DpiVals[minAbs + requestPacket.curScaleRel];
            dpiInfo.recommended = DpiVals[minAbs];
            dpiInfo.maximum = DpiVals[minAbs + requestPacket.maxScaleRel];
            dpiInfo.bInitDone = true;
        }
        else
        {
            //Error! Probably DpiVals array is outdated
            return dpiInfo;
        }
    }
    else
    {
        //DisplayConfigGetDeviceInfo() failed
        return dpiInfo;
    }

    return dpiInfo;
}


bool DpiHelper::SetDPIScaling(LUID adapterID, UINT32 sourceID, UINT32 dpiPercentToSet)
{
    DPIScalingInfo dPIScalingInfo = GetDPIScalingInfo(adapterID, sourceID);

    if (dpiPercentToSet == dPIScalingInfo.current)
    {
        return true;
    }

    if (dpiPercentToSet < dPIScalingInfo.mininum)
    {
        dpiPercentToSet = dPIScalingInfo.mininum;
    }
    else if (dpiPercentToSet > dPIScalingInfo.maximum)
    {
        dpiPercentToSet = dPIScalingInfo.maximum;
    }

    int idx1 = -1, idx2 = -1;

    int i = 0;
    for (const auto& val : DpiVals)
    {
        if (val == dpiPercentToSet)
        {
            idx1 = i;
        }

        if (val == dPIScalingInfo.recommended)
        {
            idx2 = i;
        }
        i++;
    }

    if ((idx1 == -1) || (idx2 == -1))
    {
        //Error cannot find dpi value
        return false;
    }

    int dpiRelativeVal = idx1 - idx2;

    DpiHelper::DISPLAYCONFIG_SOURCE_DPI_SCALE_SET setPacket = {};
    setPacket.header.adapterId = adapterID;
    setPacket.header.id = sourceID;
    setPacket.header.size = sizeof(setPacket);
    assert(0x18 == sizeof(setPacket));//if this fails => OS has changed somthing, and our reverse enginnering knowledge about the API is outdated
    setPacket.header.type = (DISPLAYCONFIG_DEVICE_INFO_TYPE)DpiHelper::DISPLAYCONFIG_DEVICE_INFO_TYPE_CUSTOM::DISPLAYCONFIG_DEVICE_INFO_SET_DPI_SCALE;
    setPacket.scaleRel = (UINT32)dpiRelativeVal;

    auto res = ::DisplayConfigSetDeviceInfo(&setPacket.header);
    if (ERROR_SUCCESS == res)
    {
        return true;
    }
    else
    {
        return false;
    }
    return true;
}

static BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,LPARAM dwData)
{
    std::vector<int> *pvec_ret = (std::vector<int> *)(dwData);
    DEVICE_SCALE_FACTOR val = DEVICE_SCALE_FACTOR_INVALID;
    GetScaleFactorForMonitor(hMonitor, &val);
    if (val != DEVICE_SCALE_FACTOR_INVALID)
        pvec_ret->push_back(val);
    return TRUE;
}

std::vector<int> DpiHelper::GetDpiFromMonitors()
{
    std::vector<int> vec_ret;
    do
    {
        HDC hdc = GetDC(NULL);
        if (hdc == nullptr)
        {
            OutputDebugStringA("DpiHelper::GetDpiFromMonitors GetDC failed");
            break;
        }

        EnumDisplayMonitors(hdc, NULL, MonitorEnumProc, (LPARAM)&vec_ret);
        ReleaseDC(NULL,hdc);
    } while (false);
   
    if (vec_ret.empty())
        vec_ret.push_back(100);

    return vec_ret;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/94622.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

华为数通方向HCIP-DataCom H12-821题库(单选题:101-120)

第101题 可用于多种路由协议,由 ​​if-match​​​和 ​​apply​​子句组成的路由选择工具是 A、​​route-policy​​ B、​​IP-Prefix​​ C、​​commnityfilter​​ D、​​as-path-filter​​ 答案&#xff1a;A 解析&#xff1a; Route-policy&#xff08;路由策…

【进阶篇】MySQL 存储引擎详解

文章目录 0.前言1.基础介绍2.1. InnoDB存储引擎底层原理InnoDB记录存储结构和索引页结构InnoDB记录存储结构&#xff1a;InnoDB索引页结构&#xff1a; 3. MVCC 详解3.1. 版本号分配&#xff1a;3.2. 数据读取&#xff1a;3.3. 数据写入&#xff1a;3.4. 事务隔离级别&#xff…

Jenkins 详细安装流程及填坑记录「图文」

目录 一、前言 二、环境准备 三、安装步骤 1、安装jdk 2、安装jenkins 3、配置修改 4、jenkins启动 四、登录jenkins 一、前言 省流&#xff1a;本文仅记录Jenkins详细安装过程&#xff0c;以及安装过程中经常遇到的问题。 二、环境准备 Linux系统&#xff1a;CentOS…

基于Spring实现博客项目

访问地址:用户登录 代码获取:基于Spring实现博客项目: Spring项目写博客项目 一.项目开发 1.项目开发阶段 需求评审,需求分析项目设计(接口设计,DB设计等&#xff0c;比较大的需求,需要设计流程图&#xff0c;用例图,UML, model中的字段)开发&#xff0b;自测提测(提交测试…

网易新财报:游戏稳、有道进、云音乐正爬坡

今年以来&#xff0c;AI大模型的火热程度屡屡攀升&#xff0c;越来越多的企业都加入到了AI大模型的赛场中&#xff0c;纷纷下场布局。而在众多参与者中&#xff0c;互联网企业的身影更是频频浮现&#xff0c;比如&#xff0c;百度、阿里巴巴、腾讯等等。值得一提的是&#xff0…

同态比较算法

参考文献&#xff1a; [PS73] Paterson M S, Stockmeyer L J. On the number of nonscalar multiplications necessary to evaluate polynomials[J]. SIAM Journal on Computing, 1973, 2(1): 60-66.[IZ21] Iliashenko I, Zucca V. Faster homomorphic comparison operations …

《Flink学习笔记》——第八章 状态管理

8.1 Flink中的状态 8.1.1 概述 在Flink中&#xff0c;算子任务可以分为无状态和有状态两种情况。 **无状态的算子&#xff1a;**每个事件不依赖其它数据&#xff0c;自己处理完就输出&#xff0c;也不需要依赖中间结果。例如&#xff1a;打印操作&#xff0c;每个数据只需要…

(AS笔记)上传aar包到Maven中央仓库

目录 一、SonaType账户注册与登录 &#xff08;1&#xff09;注册 &#xff08;2&#xff09;登录 二、创建工单 &#xff08;1&#xff09;Github子域名验证 &#xff08;2&#xff09;自定义域名验证 三、登录Nexus Repository Manager 四、GPG签名生成和发布 五、Andr…

IEC 60068 环境测试介绍及其标准下载

IEC 60068 环境测试介绍及其标准下载 IEC 60068 标准由国际电工委员会 (IEC) 发布&#xff0c;是用于电工产品环境测试的国际标准。 IEC 60068 系列包含有关标准、环境测试程序和测试严重性的基本信息。 IEC 60068 环境测试 制定这一系列标准是为了在特定产品类型&#xff08…

C语言(第三十一天)

6. 调试举例1 求1!2!3!4!...10!的和&#xff0c;请看下面的代码&#xff1a; #include <stdio.h> //写一个代码求n的阶乘 int main() {int n 0;scanf("%d", &n);int i 1;int ret 1;for(i1; i<n; i){ret * i;}printf("%d\n", ret);return …

线性代数(五) 线性空间

前言 《线性代数(三) 线性方程组&向量空间》我通过解线性方程组的方式去理解线性空间。此章从另一个角度去理解 空间是什么 大家较熟悉的&#xff1a;平面直角坐标系是最常见的二维空间 空间由无穷多个坐标点组成 每个坐标点就是一个向量 反过来&#xff0c;也可说&…

【附安装包】CAD2024(建筑版)安装教程

软件下载 软件&#xff1a;CAD建筑版本&#xff1a;2023语言&#xff1a;简体中文大小&#xff1a;4.52G安装环境&#xff1a;Win11/Win10硬件要求&#xff1a;CPU2.5GHz 内存8G(或更高&#xff09;下载通道①百度网盘丨64位下载链接&#xff1a;https://pan.baidu.com/s/1cHe…

万级数据优化EasyExcel+mybatis流式查询导出封装

文章目录 前言.万级数据优化一. 直接上流式查询封装工具代码二. 传统分页导出查询三. 流式查询概念游标查询 前言.万级数据优化 我们不妨先给大家讲一个概念&#xff0c;利用此概念我们正好给大家介绍一个数据库优化的小技巧&#xff1a; 需求如下&#xff1a;将一个地市表的数…

CSS中如何实现文字阴影效果(text-shadow)?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 实现思路⭐ 示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前…

视频汇聚/视频云存储/视频监控管理平台EasyCVR安全检查的相关问题及解决方法

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

解读GIS软件:从ArcGIS到山海鲸可视化的全方位介绍

在现代社会&#xff0c;地理信息系统&#xff08;GIS&#xff09;的应用已经渗透到了各个领域&#xff0c;为我们提供了丰富的地理数据分析和可视化工具。下面介绍几款常见的GIS工具软件&#xff0c;一起来了解它们的特点和优势。 1. ArcGIS: ArcGIS由Esri公司开发&#xff0c;…

php环境搭建步骤(与资源配套使用版)

1.将phpEnv.zip下载到D盘下 2.解压到当前文件夹 3.找到Apache24下的bin目录&#xff0c;执行cmd操作&#xff0c;回车。 4.在cmd中执行代码 Httpd -k install -n “Apache24” 4.使用winR键打开运行&#xff0c;输入services.msc &#xff0c;回车&#xff0c;进入服务 …

ipad有必要用手写笔吗?开学季实惠的电容笔推荐

iPad平板的机型经过了一次又一次的升级&#xff0c;增加了更多的功能&#xff0c;如今已有了与笔记本电脑匹敌的能力。而到了如今&#xff0c;科技的发展&#xff0c;iPad也从一个娱乐工具&#xff0c;变成了一个集学习、画画、办公于一体的强大工具。为了提高生产效率&#xf…

PHP教学资源管理系统Dreamweaver开发mysql数据库web结构php编程计算机网页

一、源码特点 PHP 教学资源管理系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 源码 https://download.csdn.net/download/qq_41221322/88260480 论文 https://downl…

入海排污口水质自动监测系统,助力把好入河入海“闸门”

随着经济社会的不断发展&#xff0c;污水的排放强度不断加大&#xff0c;大量的污水排入河流、湖泊和海洋中&#xff0c;造成了水体污染&#xff0c;严重影响着我国的用水安全、公众健康、经济发展与社会稳定。入河入海排污口是污染物进入河流和海洋的最后关口&#xff0c;也是…