吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

搜索
查看: 9253|回复: 8
收起左侧

[VC] 【原创】实现每显示器高DPI识别(Per-Monitor DPI Aware)的注意事项

[复制链接]
Mouri_Naruto 发表于 2016-7-6 11:06
本帖最后由 Mouri_Naruto 于 2016-7-6 11:09 编辑

为了在Win10下随时随地程序窗口都不模糊都能正常缩放,你必须在你的程序中加入Per-Monitor DPI Aware支持
因为Win10开始,用户在设置应用中调整DPI是不需要注销的!于是一些System Aware和Unaware的应用会被DWM虚拟化技术进行粗暴缩放,于是就模糊了
如果你定义你的程序支持Per-Monitor DPI Aware,但又没实现Per-Monitor DPI Aware支持的话,就会无法动态缩放(体验比模糊更加糟糕)

实现Per-Monitor DPI Aware支持,首先在程序清单中加入<dpiAware>True/PM</dpiAware>;或者你也可以在VS的项目属性里面设置即可
有人绝对会问,为何不调用API设置,因为对应API要求Windows 8.1以上;所以为了方便起见,我建议还是在清单文件添加


接着,获取DPI的部分需要重写
因为我们惯用的GetDeviceCaps只能获取系统DPI(MSDN指明是与显卡驱动的实现有关)
要获取真实DPI,你需要使用GetDpiForMonitor;但这个API至少要8.1起步
我在下面提供一些参考

重写的GetDpiForMonitor
[C++] 纯文本查看 复制代码
#include <ShellScalingApi.h>

static HRESULT WINAPI GetDpiForMonitor(
        _In_ HMONITOR hmonitor,
        _In_ MONITOR_DPI_TYPE dpiType,
        _Out_ UINT *dpiX,
        _Out_ UINT *dpiY)
{
        HINSTANCE hInstWinSta = LoadLibraryW(L"SHCore.dll");
        if (hInstWinSta == nullptr) return E_NOINTERFACE;

        typedef HRESULT(WINAPI * PFN_GDFM)(
                HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);

        PFN_GDFM pGetDpiForMonitor =
                (PFN_GDFM)GetProcAddress(hInstWinSta, "GetDpiForMonitor");
        if (pGetDpiForMonitor == nullptr) return E_NOINTERFACE;

        return pGetDpiForMonitor(hmonitor, dpiType, dpiX, dpiY);
}


获取DPI比例的代码逻辑片段
[C++] 纯文本查看 复制代码
// 获取DPI比例

        HRESULT hr = E_FAIL;

        hr = GetDpiForMonitor(
                MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST),
                MDT_EFFECTIVE_DPI, (UINT*)&g_xDPI, (UINT*)&g_yDPI);
        if (hr != S_OK)
        {
                g_xDPI = GetDeviceCaps(GetDC(hWnd), LOGPIXELSX);
                g_yDPI = GetDeviceCaps(GetDC(hWnd), LOGPIXELSY);
        }


然后实现窗口的WM_DPICHANGED消息,该消息有用的参数
[C++] 纯文本查看 复制代码
// LOWORD(wParam); // x轴DPI
// HIWORD(wParam); // y轴DPI
// (RECT*)lParam /// 系统建议的新窗口位置

你应该在该消息实现对界面的调整或者通知你的UI框架


到这里,MSDN文档的Sample基本就结束了


但是你要真的碰到不同DPI缩放的显示器或者调整DPI后没有注销,然后你就傻了
因为标题栏和菜单不支持缩放


要实现这个问题,貌似只有一种方式,那就是隐藏非客户区,自己绘制一个标题栏并且自己绘制菜单


但是如果你不要自绘标题栏和菜单(太麻烦了,而且浪费时间)


你可以学习Windows 10的命令提示符窗口,调用(未公开)API让系统自动帮你缩放标题栏和菜单


[C++] 纯文本查看 复制代码
// 开启对话框Per-Monitor DPI Aware支持(至少Win10)
inline BOOL EnablePerMonitorDialogScaling()
{
        typedef BOOL(WINAPI *PFN_EnablePerMonitorDialogScaling)();

        PFN_EnablePerMonitorDialogScaling pEnablePerMonitorDialogScaling =
                (PFN_EnablePerMonitorDialogScaling)GetProcAddress(
                        GetModuleHandleW(L"user32.dll"), (LPCSTR)2577);

        if (pEnablePerMonitorDialogScaling) return pEnablePerMonitorDialogScaling();
        return -1;
}

// 开启子窗体DPI消息(至少Win10)
inline BOOL EnableChildWindowDpiMessage(
        _In_ HWND hWnd,
        _In_ BOOL bEnable)
{
        typedef BOOL(WINAPI *PFN_EnableChildWindowDpiMessage)(HWND, BOOL);

        PFN_EnableChildWindowDpiMessage pEnableChildWindowDpiMessage =
                (PFN_EnableChildWindowDpiMessage)GetProcAddress(
                        GetModuleHandleW(L"user32.dll"), "EnableChildWindowDpiMessage");

        if (pEnableChildWindowDpiMessage)
                return pEnableChildWindowDpiMessage(hWnd, bEnable);
        return -1;
}


以上API定义通过IDA查看Win10的ConhostV2.dll得到
可用于Windows 10 Threshold 1及以后(如果微软不去掉的话)

在显示对话框前调用下EnablePerMonitorDialogScaling();不用实现WM_DPICHANGED消息,系统会自动帮你缩放对话框
窗体应用,需要用CreateWindowEx创建窗体后;调用EnableChildWindowDpiMessage(窗口hWnd,TRUE);
然后适当在WM_DPICHANGED添加调整代码即可完美Per-Monitor DPI Aware


效果图,仅供参考(调整DPI后没有注销,对话框应用)
NSudoV4.png

希望我的资料能够对开发应用的人有帮助

毛利, 2016/7/6











免费评分

参与人数 2热心值 +2 收起 理由
不懂破解 + 1 从远景过来支持下楼主的 NSudo 4.0
a43006 + 1 毛利 鸣人~ 厉害了~

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

ZMZwise 发表于 2016-7-6 11:21
楼主厉害啊,看看,
王美君 发表于 2016-7-6 11:49
云在青霄水在瓶 发表于 2016-7-6 21:48
*﹏暎雪ヤ 发表于 2016-7-24 19:40
好深奥呀,楼主能细讲下吗
 楼主| Mouri_Naruto 发表于 2016-7-24 19:56
*﹏暎雪ヤ 发表于 2016-7-24 19:40
好深奥呀,楼主能细讲下吗

我想知道你哪些地方不明白,这样我可以更好的帮助你,谢谢
不懂破解 发表于 2016-7-27 11:41
从远景过来支持下楼主的 NSudo 4.0,同时也支持下 Per-Monitor DPI Aware 的实现代码
王山而 发表于 2017-8-8 08:08
多谢楼主分享,刚好遇到HIGH DPI问题。
模天 发表于 2017-9-6 19:07 来自手机
留名备用。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2021-6-22 12:29

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表