您的位置:
首页
>>
CLQ工作室开源代码
>> 主题: [windows api]处理高清屏幕下的缩放因子问题 SetProcessDpiAwareness WM_DPICHANGED
[最新]
[回主站]
标题
[windows api]处理高清屏幕下的缩放因子问题 SetProcessDpiAwareness WM_DPICHANGED
clq
浏览(452) +
2021-11-06 18:56:01 发表
编辑
关键字:
[2023-03-04 14:26:02 最后更新]
[windows api]处理高清屏幕下的缩放因子问题
特别是 4k 屏幕下,处理好后是非常漂亮的。基本上也能和 macos 一战(达到 200% 及以上的话)。
有好几个知识点:
首先是控件程序是否进行缩放,有不缩放,缩放一次,动态缩放多次三种。
可以取当前缩放的比例参数,不过这是一个枚举值,要再转换。也可以用另外一个 api 取显示器的物理分辨率和逻辑分辨率来自己计算。
这几个函数都在新的 dll 里,基本上都是要 windows 8.1 及之后的才支持。对于 c/c++ 要不升级头文件,要不直接动态取函数指针。
另外,SetProcessDpiAwareness 函数要在所有其他 windows api 函数调用之前使用(应该批的是创建第一个窗口之前吧)。
----------------------------------------------------------------
// [DllImport("SHCore.dll", SetLastError = true)]
// private static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness);
// private enum PROCESS_DPI_AWARENESS
// {
// Process_DPI_Unaware = 0, //不进行缩放
// Process_System_DPI_Aware = 1, //根据当前系统取一次参数进行缩放,后面显示器有变化也不缩放了
// Process_Per_Monitor_DPI_Aware = 2 //根据所处显示器动态变化
// }
2023 更新:
有些概念记错了,再更新一下。SetProcessDpiAwareness 加 Process_Per_Monitor_DPI_Aware 只是告诉系统说,我自己处理高清问题而已。它是不能像 linux 那样自己的高清放大界面和字体的。
程序中需要自己去放大界面还有手工调整字段大小。Process_Per_Monitor_DPI_Aware 时当切换不同分辨率的显示器时会发送 WM_DPICHANGED 消息,程序自己再动态调整。
参考 https://learn.microsoft.com/zh-cn/windows/win32/api/shellscalingapi/ne-shellscalingapi-process_dpi_awareness
https://learn.microsoft.com/zh-cn/windows/win32/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness
“
与其他感知值不同, PROCESS_PER_MONITOR_DPI_AWARE 应适应其打开的显示。 这意味着它始终以本机方式呈现,并且永远不会由系统缩放。 应用负责在接收 WM_DPICHANGED 消息时调整比例系数。 此消息的一部分包括窗口建议的修正。 此建议是从旧 DPI 值缩放到新 DPI 值的当前窗口。 例如,显示 A 上的窗口为 500 到 500,移动到显示 B 时,将收到建议的窗口矩形,即 1000 到 1000。 如果将同一窗口移动到显示 C,则附加到 WM_DPICHANGED 的建议窗口将 1500 到 1500。 此外,当此应用查询窗口大小时,它将始终获取实际的本机值。 同样,如果它要求三个监视器中的任何一个的 DPI,它将分别接收 96、192 和 288。
”
另外,这个效果也可以用 .manifest 文件来控制,所以不方便访问原始 windows api 的程序也可以处理的。
clq
2021-11-06 18:56:41 发表
编辑
//----------------------------------------------------------------
//windows 高分辩自适应
//参考 https://www.it1352.com/1749063.html 和 https://www.cnblogs.com/Philip-Tell-Truth/p/7290545.html
//可知,这是 windows 8.1 后才有的函数
//[DllImport("SHCore.dll", SetLastError = true)]
// private static extern bool SetProcessDpiAwareness(PROCESS_DPI_AWARENESS awareness);
// [DllImport("SHCore.dll", SetLastError = true)]
// private static extern void GetProcessDpiAwareness(IntPtr hprocess, out PROCESS_DPI_AWARENESS awareness);
// private enum PROCESS_DPI_AWARENESS
// {
// Process_DPI_Unaware = 0, //不进行缩放
// Process_System_DPI_Aware = 1, //根据当前系统取一次参数进行缩放,后面显示器有变化也不缩放了
// Process_Per_Monitor_DPI_Aware = 2 //根据所处显示器动态变化
// }
//https://docs.microsoft.com/en-us/windows/win32/api/shellscalingapi/nf-shellscalingapi-setprocessdpiawareness
//高版本 ide 也可以直接使用 shellscalingapi.h
int PROCESS_PER_MONITOR_DPI_AWARE = 2; //根据所处显示器动态变化,所以最好还要处理 wm_ 这个显示器的变化消息
HINSTANCE hdll = LoadLibrary("SHCore.dll");
if (hdll)
{
//SetProcessDpiAwareness = GetProcAddress(hdll, "SetProcessDpiAwareness");
//c++ 下要这样写
SetProcessDpiAwareness = (HRESULT (*)(int))GetProcAddress(hdll, "SetProcessDpiAwareness");
}
if (SetProcessDpiAwareness) //win10 下确实有用
{
SetProcessDpiAwareness(Process_Per_Monitor_DPI_Aware);
//还要取放大比例,所说目前是和 96 的默认 dpi 值进行对比
//MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
//MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST);
MonitorFromWindow(GetDesktopWindow(), MONITOR_DEFAULTTONEAREST); //应该是得到当前显示器
GetDpiForMonitor();
GetScaleFactorForMonitor();
}
// GetDpiForMonitor : 获取某个Monitor的DPI
// WM_DPICHANGED :当某个程序窗口被拖到另外一个DPI的Monitor时收到
//----------------------------------------------------------------
clq
2021-11-06 18:57:54 发表
编辑
https://www.it1352.com/1768163.html
//获取窗口当前显示在
上的监视器//(其中hWnd是感兴趣的窗口)。
HMONITOR hMonitor = MonitorFromWindow(hWnd,MONITOR_DEFAULTTONEAREST);
//获取监视器的逻辑宽度和高度。
MONITORINFOEX miex;
miex.cbSize = sizeof(miex);
GetMonitorInfo(hMonitor,& miex);
int cxLogical =(miex.rcMonitor.right-miex.rcMonitor.left);
int cyLogical =(miex.rcMonitor.bottom-miex.rcMonitor.top);
//获取监视器的物理宽度和高度。
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
EnumDisplaySettings(miex.szDevice,ENUM_CURRENT_SETTINGS,& dm);
int cxPhysical = dm.dmPelsWidth;
int cyPhysical = dm.dmPelsHeight;
//计算比例因子。
double horzScale =((double)cxPhysical /(double)cxLogical);
double vertScale =((double)cyPhysical /(double)cyLogical);
ASSERT(horzScale == vertScale);
NEWBT官方QQ群1: 276678893
可求档连环画,漫画;询问文本处理大师等软件使用技巧;求档softhub软件下载及使用技巧.
但不可"开车",严禁国家敏感话题,不可求档涉及版权的文档软件.
验证问题说明申请入群原因即可.