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.henum 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,但是实际是100static DpiHelper::DPIScalingInfo GetDPIScalingInfo(LUID adapterID, UINT32 sourceID);static bool SetDPIScaling(LUID adapterID, UINT32 sourceID, UINT32 dpiPercentToSet);//当锁定的时候获取的值可能不对,例如dpi锁定200% 但是实际是100,则获取实际值100static 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 outdatedrequestPacket.header.adapterId = adapterID;requestPacket.header.id = sourceID;auto res = ::DisplayConfigGetDeviceInfo(&requestPacket.header);if (ERROR_SUCCESS == res){//successif (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 okdpiInfo.current = DpiVals[minAbs + requestPacket.curScaleRel];dpiInfo.recommended = DpiVals[minAbs];dpiInfo.maximum = DpiVals[minAbs + requestPacket.maxScaleRel];dpiInfo.bInitDone = true;}else{//Error! Probably DpiVals array is outdatedreturn dpiInfo;}}else{//DisplayConfigGetDeviceInfo() failedreturn 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 valuereturn 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 outdatedsetPacket.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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器数据恢复-ESXi虚拟化误删除的数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器安装的ESXi虚拟化系统&#xff0c;该虚拟化系统连接了多个LUN&#xff0c;其中一个LUN上运行了数台虚拟机&#xff0c;虚拟机安装Windows Server操作系统。 服务器故障&分析&#xff1a; 管理员因误操作删除了一台虚拟机&#x…

报错处理:Permission denied错误

报错处理 Permission denied错误 报错环境 在Linux上运行任何需要访问系统资源、文件或目录的命令时均有可能出现。 排错思路 该错误表示当前用户没有足够的权限执行指定的操作。排查时可以先查看具体的报错信息&#xff0c;例如文件或目录的路径以及相应的权限设置&#xff0c…

字符设备驱动(内核态用户态内存交互)

前言 内核驱动&#xff1a;运行在内核态的动态模块&#xff0c;遵循内核模块框架接口&#xff0c;更倾向于插件。 应用程序&#xff1a;运行在用户态的进程。 应用程序与内核驱动交互通过既定接口&#xff0c;内核态和用户态访问依然遵循内核既定接口。 环境搭建 系统&#…

HHDESK一键改密功能

HHDESK新增实用功能——使用SSH连接&#xff0c;对服务器/端口进行密码修改。 1 测试 首页点击资源管理——客户端&#xff0c;选择需要修改的连接&#xff1b; 可以先对服务器及端口进行测试&#xff0c;看是否畅通&#xff1b; 右键——测试——ping&#xff1b; 以及右…

【Python数据分析】Matplotlib小技巧!

1. 添加标题-title matplotlib.pyplot 对象中有个 title() 可以设置表格的标题。 **import** numpy **as** np **import** matplotlib.pyplot **as** plt \# 显示中文 plt.rcParams\[font.sans-serif\] \[uSimHei\] plt.rcParams\[axes.unicode\_minus\] **False** …

Spark整合hive的时候出错

Spark整合hive的时候 连接Hdfs不从我hive所在的机器上找&#xff0c;而是去连接我的集群里的另外两台机器 但是我的集群没有开 所以下面就一直在retry 猜测&#xff1a; 出现这个错误的原因可能与core-site.xml和hdfs-site.xml有关&#xff0c;因为这里面配置了集群的nameno…

三---开关稳压器

通过控制系统反馈&#xff0c;当电压上升时通过反馈降低&#xff0c;当电压下降时通过反馈升高&#xff1b;形成一个控制环路&#xff1b;控制电路&#xff1a;PWM&#xff08;脉宽调制&#xff09;&#xff0c;PFM&#xff08;频率控制方式&#xff09;&#xff0c;移相控制方…

Java并发编程第6讲——线程池(万字详解)

Java中的线程池是运用场景最多的并发框架&#xff0c;几乎所有需要异步或并发执行任务的程序都可以使用线程池&#xff0c;本篇文章就详细介绍一下。 一、什么是线程池 定义&#xff1a;线程池是一种用于管理和重用线程的技术&#xff08;池化技术&#xff09;&#xff0c;它主…

AcWing 898. 数字三角形 (每日一题)

大家好 我是寸铁 希望这篇题解对你有用&#xff0c;麻烦动动手指点个赞或关注&#xff0c;感谢您的关注 注意 像数组下标出现i-1的&#xff0c;在循环的时候从i1开始。 关于0x3f3f3f3f和Integer.MAX_VALUE 0x3f3f3f3f:1061109567 Integer.MAX_VALUE:2147483647 在选用Integ…

【缓存设计】记一种不错的缓存设计思路

文章目录 前言场景设计思路小结 前言 之前与同事讨论接口性能问题时听他介绍了一种缓存设计思路&#xff0c;觉得不错&#xff0c;做个记录供以后参考。 场景 假设有个以下格式的接口&#xff1a; GET /api?keys{key1,key2,key3,...}&types{1,2,3,...}其中 keys 是业务…

C语言“牵手”天猫商品详情数据方法,天猫商品详情API接口申请指南

天猫商城平台是阿里巴巴集团旗下的一个综合性购物网站。 天猫商城的前身是淘宝商城&#xff0c;于2012年1月11日上午更名。天猫是一个整合数千家品牌商、生产商&#xff0c;为商家和消费者之间提供一站式解决方案的B2C&#xff08;Business-to-Consumer&#xff0c;商业零售&a…

【业务功能篇78】微服务-前端后端校验- 统一异常处理-JSR-303-validation注解

5. 前端校验 我们在前端提交的表单数据&#xff0c;我们也是需要对提交的数据做相关的校验的 Form 组件提供了表单验证的功能&#xff0c;只需要通过 rules 属性传入约定的验证规则&#xff0c;并将 Form-Item 的 prop 属性设置为需校验的字段名即可 校验的页面效果 前端数据…

超越界限:大模型应用领域扩展,探索文本分类、文本匹配、信息抽取和性格测试等多领域应用

超越界限&#xff1a;大模型应用领域扩展&#xff0c;探索文本分类、文本匹配、信息抽取和性格测试等多领域应用 随着 ChatGPT 和 GPT-4 等强大生成模型出现&#xff0c;自然语言处理任务方式正在逐步发生改变。鉴于大模型强大的任务处理能力&#xff0c;未来我们或将不再为每…

每天一道leetcode:542. 01 矩阵(图论中等广度优先遍历)

今日份题目&#xff1a; 给定一个由 0 和 1 组成的矩阵 mat &#xff0c;请输出一个大小相同的矩阵&#xff0c;其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。 两个相邻元素间的距离为 1 。 示例1 输入&#xff1a;mat [[0,0,0],[0,1,0],[0,0,0]] 输出&#xff…

Hadoop HA模式切换

Hadoop HA模式下 主从的切换&#xff08;操作命令&#xff09; YARN HA 获取所有RM节点的状态 yarn rmadmin -getAllServiceState获取 rm1 节点的状态 yarn rmadmin -getServiceState rm1手动将 rm1 的状态切换到STANDBY yarn rmadmin -transitionToStandby rm1 ##或者 y…

网络防御和入侵检测

网络防御和入侵检测是维护网络安全的关键任务&#xff0c;可以帮助识别和阻止未经授权的访问和恶意行为。以下是一些基本的步骤和方法&#xff0c;用于进行网络防御和入侵检测。 网络防御&#xff1a; 防火墙设置&#xff1a; 部署防火墙来监控和控制网络流量&#xff0c;阻止…

c# modbus CRC计算器(查表法)

一、简介&#xff1a; 本案例为crc计算器&#xff0c;通过查表法计算出结果 1.窗体后台源代码 using Crc; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text…

修改Jupyter Notebook默认打开路径

这里我是重新下载的anaconda&#xff0c;打开Jupyter之后是默认在C盘的一个路径的&#xff0c;现在我们就来修改一下它的一个默认打开路径&#xff0c;这样在我们后续学习过程中&#xff0c;可以将ipynb后缀的文件放在这个目录下就能查看了。 1、先打开Anaconda Prompt&#x…

数据库第十七课-------ETL任务调度系统的安装和使用

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; ​&#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382; &#x1f389;&#x1f389;&#x1f389…

商城-学习整理-集群-K8S-集群环境部署(二十四)

目录 一、MySQL集群1、mysql集群原理2、Docker安装模拟MySQL主从复制集群1、下载mysql镜像2、创建Master实例并启动3、创建 Slave 实例并启动4、为 master 授权用户来同步数据1、进入 master 容器2、进入 mysql 内部 &#xff08;mysql –uroot -p&#xff09;3、查看 master 状…