Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【QT】获取主屏幕DPI

【QT】获取主屏幕DPI

原创
作者头像
lealc
发布于 2024-09-05 12:01:38
发布于 2024-09-05 12:01:38
4200
举报

背景

在DpiAware = SystemAware的情况下需要获取主屏的DPI值,

DPI感知

DPI(Dots Per Inch)是指每英寸的点数,通常用于描述屏幕分辨率。在Windows操作系统中,DPI感知(DPI Awareness)是指应用程序能够感知到屏幕的DPI设置,并根据DPI值调整其界面元素的大小和布局,以提供更好的用户体验。

DPI感知有两种模式:系统DPI感知和每个监视器DPI感知。

系统DPI感知(System aware)

系统DPI感知是指应用程序根据整个系统的DPI设置来调整其界面元素的大小和布局。这种模式下,当用户更改系统DPI设置时,所有应用程序的界面都会相应地调整。

每个监视器DPI感知(Per Monitor)

每个监视器DPI感知是指应用程序能够检测到每个显示器的DPI设置,并根据每个显示器的DPI值分别调整其界面元素的大小和布局。这种模式下,当用户在不同DPI设置的显示器之间移动应用程序窗口时,应用程序的界面会自动适应每个显示器的DPI设置。

注意事项

在实现DPI感知时,需要确保应用程序的界面元素能够正确地缩放,以避免在高DPI设置下出现模糊或过小的情况。

在使用每个监视器DPI感知时,需要注意处理不同显示器之间的DPI变化,以确保应用程序的界面在不同显示器之间保持一致。

在编写DPI感知应用程序时,建议使用支持高DPI的UI框架,如Windows Presentation Foundation (WPF)或Qt等。

QT应用

qt应用程序为了默认支持高清屏,设置的DPI感知类型为Per Monitor,以下为5.15.2源码

时机为程序创建第一个窗口之前,所以需要修改DPI感知类型需要在这个时机之前,否则会有warning提示设置失败。

代码语言:C
AI代码解释
复制
// Src\qtbase\src\plugins\platforms\windows\qwindowsintegration.cpp
QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList &paramList)
{
    initOpenGlBlacklistResources();

    static bool dpiAwarenessSet = false;
    int tabletAbsoluteRange = -1;
    // Default to per-monitor awareness to avoid being scaled when monitors with different DPI
    // are connected to Windows 8.1
    QtWindows::ProcessDpiAwareness dpiAwareness = QtWindows::ProcessPerMonitorDpiAware;
    m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness);
    QWindowsFontDatabase::setFontOptions(m_options);

    if (m_context.initPointer(m_options)) {
        QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
    } else {
        m_context.initTablet(m_options);
        if (tabletAbsoluteRange >= 0)
            m_context.setTabletAbsoluteRange(tabletAbsoluteRange);
    }

    if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication.
        if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
            m_context.setProcessDpiAwareness(dpiAwareness);
            qCDebug(lcQpaWindows)
                << __FUNCTION__ << "DpiAwareness=" << dpiAwareness
                << "effective process DPI awareness=" << QWindowsContext::processDpiAwareness();
        }
        dpiAwarenessSet = true;
    }

    m_context.initTouch(m_options);
    QPlatformCursor::setCapability(QPlatformCursor::OverrideCursor);

    m_context.initPowerNotificationHandler();
}

Windows上主动设置qt应用的DPI感知,需要判断系统不低于windows8.1

代码语言:C
AI代码解释
复制
if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) {
    return;
}

HMODULE shcoreModule = LoadLibraryW(L"SHCore.dll");
if (!shcoreModule) {
    qInfo() << "LoadLibraryW SHCore.dll error:" << GetLastError();
    return;
}

typedef HRESULT(WINAPI * SetProcessDpiAwareness)(int);
SetProcessDpiAwareness setProcessDpiAwareness =
    (SetProcessDpiAwareness)GetProcAddress(shcoreModule, "SetProcessDpiAwareness");

if (setProcessDpiAwareness) {
    HRESULT res = setProcessDpiAwareness(PROCESS_SYSTEM_DPI_AWARE);
    if (res != S_OK) {
        qInfo() << "SetProcessDpiAwareness error:" << res;
    } else {
        qInfo() << "SetProcessDpiAwareness success";
    }
}

if (shcoreModule) {
    FreeLibrary(shcoreModule);
}

获取主屏DPI

在默认qt程序下,获取主屏DPI需要先调整DPI感知类型然后再获取,否则会拿到错误的DPI值,主要利用SHCore.dll和User32.dll两个系统模块,系统不低于windows 8.1

话不多说,直接上代码,仅供参考学习

代码语言:C
AI代码解释
复制
bool GetPrimaryMonitorDpi(float &dpi) {
    bool bRes = false;

    HMODULE shcoreModule = nullptr;

    do 
    {
        if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8_1) {
            break;
        }

        class ScopedPerMonitorAware {
           typedef DPI_AWARENESS_CONTEXT(WINAPI* SetThreadDpiAwarenessContext)(DPI_AWARENESS_CONTEXT);

           public:
            ScopedPerMonitorAware() {
                user32Module_ = LoadLibraryW(L"User32.dll");
                if (!user32Module_) {
                    return;
                }

                setThreadDpiAwarenessContext_ =
                    (SetThreadDpiAwarenessContext)GetProcAddress(user32Module_, "SetThreadDpiAwarenessContext");
                if (!setThreadDpiAwarenessContext_) {
                    return;
                }

                bak_ = setThreadDpiAwarenessContext_(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE);
                if (bak_ == NULL)
                    qInfo() << __FUNCTION__ << " SetThreadDpiAwarenessContext failed " << ::GetLastError();
            }
            ~ScopedPerMonitorAware() {
                if (bak_ != NULL && setThreadDpiAwarenessContext_) {
                    setThreadDpiAwarenessContext_(bak_);
                }
                
                if (user32Module_) {
                    FreeLibrary(user32Module_);
                }
            }

           private:
            DPI_AWARENESS_CONTEXT bak_;
            HMODULE user32Module_ = nullptr;
            SetThreadDpiAwarenessContext setThreadDpiAwarenessContext_ = nullptr;
        } scoped_per_monitor_aware;

        HMODULE shcoreModule = LoadLibraryW(L"SHCore.dll");
        if (!shcoreModule) {
            break;
        }

        typedef HRESULT(WINAPI * GetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);
        GetDpiForMonitor getDpiForMonitor =
            (GetDpiForMonitor)GetProcAddress(shcoreModule, "GetDpiForMonitor");

        if (!getDpiForMonitor) {
            break;
        }

        HMONITOR monitor = ::MonitorFromPoint({0, 0}, MONITOR_DEFAULTTOPRIMARY);
        UINT result = 0, dpiY = 0;
        const auto ret = getDpiForMonitor(monitor, MDT_EFFECTIVE_DPI, &result, &dpiY);
        if (ret != S_OK) {
            break;
        }

        dpi = dpiY / 96.0f;
        bRes = true;
    } while (0);

    if (shcoreModule) {
        FreeLibrary(shcoreModule);
    }

    return bRes;
}

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
qt多屏不同DPI下的拖拽问题
在主屏设置DPI=1.5,副屏设置DPI=1.0时,将qt窗口移动到副屏,拖拽qt treeview或者listview中的元素时,会发生异常显示,位置错误等问题
lealc
2024/07/22
5652
qt多屏不同DPI下的拖拽问题
Windows 下的高 DPI 应用开发(UWP / WPF / Windows Forms / Win32)
本文将介绍 Windows 系统中高 DPI 开发的基础知识。由于涉及到坐标转换,这种转换经常发生在计算的不知不觉中;所以无论你使用哪种 Windows 下的 UI 框架进行开发,你都需要了解这些内容,以免不断踩坑。
walterlv
2023/10/22
1.1K0
Windows 下的高 DPI 应用开发(UWP / WPF / Windows Forms / Win32)
Windows下的代码注入
木马和病毒的好坏很大程度上取决于它的隐蔽性,木马和病毒本质上也是在执行程序代码,如果采用独立进程的方式需要考虑隐藏进程否则很容易被发现,在编写这类程序的时候可以考虑将代码注入到其他进程中,借用其他进程的环境和资源来执行代码。远程注入技术不仅被木马和病毒广泛使用,防病毒软件和软件调试中也有很大的用途,最近也简单的研究过这些东西,在这里将它发布出来。 想要将代码注入到其他进程并能成功执行需要解决两个问题:
Masimaro
2018/10/10
1.4K0
C/C++ 实现常用的线程注入
各种API远程线程注入的方法,分别是 远程线程注入,普通消息钩子注入,全局消息钩子注入,APC应用层异步注入,ZwCreateThreadEx强力注入,纯汇编实现的线程注入等。
王瑞MVP
2022/12/28
7430
支持 Windows 10 最新 PerMonitorV2 特性的 WPF 多屏高 DPI 应用开发
发布于 2018-10-22 18:04 更新于 2018-12-14 01:54
walterlv
2020/02/10
1.8K0
进程注入1:通过LoadLibrary注入DLL
进程注入是将任意代码写入已经运行的进程中并执行,可以用来逃避检测对目标目标进程中的敏感信息进行读/写/执行访问,还可以更改该进程的行为。
黑白天安全
2021/04/07
2.6K0
进程注入1:通过LoadLibrary注入DLL
从零开始编写网络游戏--基础篇(1)
       最近2周比较忙,没有抽出时间来写Blog,不过在这段时间里面把整个思路理了一遍,梳理了一下大纲,以后会多抽时间来写Blog。
帘卷西风
2018/08/03
7610
1.8 运用C编写ShellCode代码
在笔者前几篇文章中,我们使用汇编语言并通过自定位的方法实现了一个简单的MessageBox弹窗功能,但由于汇编语言过于繁琐在编写效率上不仅要考验开发者的底层功底,还需要写出更多的指令集,这对于普通人来说是非常困难的,当然除了通过汇编来实现ShellCode的编写以外,使用C同样可以实现编写,在多数情况下读者可以直接使用C开发,只有某些环境下对ShellCode条件有极为苛刻的长度限制时才会考虑使用汇编。
王瑞MVP
2023/08/30
3650
1.8 运用C编写ShellCode代码
高级远程线程注入NtCreateThreadEx
在Windows下NtCreateThreadEx是CreateRemoteThread的底层函数。RtlCreateUserThread 也是对 NtCreateThreadEx的一层包装
IBinary
2022/05/10
1.6K0
C++基础语法梳理:Windows 的动态链接库
GUI(Graphical User Interface)应用,链接器选项:/SUBSYSTEM:WINDOWS
玖柒的小窝
2021/11/01
1.2K0
科普 | DLL劫持原理与实践
DLL劫持算是一个老的漏洞,而且乌云漏洞库中也有很多的案例,只不过案例更多的只是验证一下,并没有教如何利用。至于为什么专门抓起来再学一遍了,唉,内网渗透需要
HACK学习
2019/09/04
5.2K0
科普 | DLL劫持原理与实践
网络游戏开发基础篇
1、单例:单例模式是一种使用广泛而又比较简单的设计模式,他的定义我就不多介绍了,大家上网一查就知道了,基本都能理解。在游戏开发中,会有很多单件,所以封装一个单例类供后面的开发使用。
全栈程序员站长
2022/07/22
1.3K0
Windows微信DPI适配
一、背景 随着近些年屏幕设备的不断发展,各种显示设备的分辨率也越来越高,在尺寸保持基本不变的情况下,分辨率越高,设备的DPI也越高,清晰度也就越高。高DPI的设备给我们提供了更精细的画质,然而Windows上的大多数应用并没有适配高DPI的显示器,导致应用在这些设备显示模糊,体验非常差。 为了让应用在高DPI的设备上依然显示清晰,我们就需要对高DPI的设备进行适配。 二、基础概念 2.1 DPI是什么 DPI是Dots Per Inch的缩写,表示显示设备在每英寸上有多少个像素点。在开发过程中,
微信终端开发团队
2018/01/29
5.9K1
Windows微信DPI适配
干货 | 绕过AMSI实现免杀的研究和思路
Antimalware Scan Interface(AMSI)为反恶意软件扫描接口。
HACK学习
2021/11/12
9720
技术分享|amsi绕过总结
Antimalware Scan Interface(AMSI)为反恶意软件扫描接口。
亿人安全
2022/06/30
2K0
技术分享|amsi绕过总结
远程线程注入Dll,突破Session 0
其实今天写这个的主要原因就是看到倾旋大佬有篇文章提到:有些反病毒引擎限制从lsass中dump出缓存,可以通过注入lsass,就想试试注入lsass
HACK学习
2021/05/14
1.2K0
使用WFH搜索Windows可执行程序中的常见漏洞或功能
WFH,全名为Windows Feature Hunter,即Windows功能搜索工具,该工具基于Python开发,使用Frida实现其功能,可以帮助广大研究人员搜索和识别Windows可执行程序中的常见安全漏洞以及功能。当前版本的WFH能够自动识别动态链接库DLL中潜在的侧加载问题以及组件对象模型COM中劫持攻击的实现可能。
FB客服
2021/08/24
1K0
Windows 系统上使用任务管理器查看进程的各项属性(命令行、DPI、管理员权限等)
Windows 系统上的任务管理器进化到 Windows 10 的 1809 版本后,又新增了几项可以查看的进程属性。
walterlv
2023/10/22
5.1K0
Windows 系统上使用任务管理器查看进程的各项属性(命令行、DPI、管理员权限等)
无注册表的COM调用
对于COM,一般用CoCreateInstance来创建对象,这就要求COM的dll要用regsvr32注册,因为CoCreateInstance是要读注册表信息完成相应操作的。
井九
2024/10/12
1630
绝大部分测试和开发人员都不知道的DLL
1. Kernel32.dll 它包含那些用于管理内存、进程和线程的函数,例如CreateThread函数;
苦叶子
2021/09/15
8090
相关推荐
qt多屏不同DPI下的拖拽问题
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档