对于Windows中高DPI支持的总结
acmilan2016/04/08软件综合 IP:四川
一、缩放比例和DPI的关系

DPI本意指的是“每英寸点数”,但是由于各大显示器厂商并不理会系统设置,因此它的值现在并不具有任何实际意义,仅仅是一个缩放因子而已。在Windows中,默认的DPI值为96,定义为100%缩放(即不缩放)。一般来说,缩放比例的步进值是25%,对应DPI的步进值为24,当然用户也可以定义任意缩放值。

缩放比例和DPI的关系:
100% - 96 DPI
125% - 120 DPI
150% - 144 DPI
175% - 168 DPI
200% - 192 DPI
依次类推
500% - 480 DPI

二、支持的缩放比例

Windows NT 3.x / 4.0 —— 支持100%和125%两个缩放比例
Windows 95 / 98 / Me / 2000 —— 支持最高到500%
Windows XP / 2003 / Vista —— 最高可调到500%,但支持最高到155%(超过这个比例鼠标指针会糊掉)
Windows 7 / 8 —— 最高可调到500%,但支持最高到199%(超过这个比例鼠标指针会糊掉)
Windows 8.1 / 10 —— 支持最高到500%

三、如何调整DPI

Windows NT 3.x —— 主群组,控制面板,显示
Windows 95 / NT 4.0 —— 右键桌面,属性,设置
Windows 98 / Me / 2000 / XP / 2003 —— 右键桌面,属性,设置,高级
Windows Vista —— 右键桌面,个性化,调整字体大小(DPI)
以上系统应用新DPI需重新启动

Windows 7 / 8 / 8.1 —— 右键桌面,屏幕分辨率,放大或缩小文本和其它项目
以上系统应用新DPI需重新登录

Windows 10 —— 右键桌面,显示设置
以上系统应用新DPI不需重新登录,但部分程序需重新登录才能响应新DPI设置

四、DPI如何获取

Windows 8及之前版本仅支持系统级DPI——
在C#程序中,可使用XXXXXXXXXXXomHwnd(IntPtr.Zero).DpiX和DpiY获取。
在C/C++程序中,可以先GetDC(NULL)获取桌面hDC,然后GetDeviceCaps(hDC, LOGPIXELSX和LOGPIXELSY)获取,最后别忘了ReleaseDC(hDC)。

Windows 8.1及之后版本支持逐显示器级DPI——
在C/C++程序中,可以使用MonitorFromPoint和GetDpiForMonitor获取指定显示器的DPI,也可以从WM_DPICHANGED消息的lParam参数中获取。

五、关于Windows Vista+的系统级DPI虚拟化

由于长期以来屏幕的分辨率都没有上去,导致大多数第三方的老旧Windows软件并不理会高DPI,这导致了很多软件在高DPI下,出现排版错乱、界面元素过小等问题。为了解决这个问题,Windows Vista引入了DPI虚拟化机制,通过DWM对界面进行强制缩放来解决界面错乱问题。

在超过125%比例时,Windows Vista会开启DPI虚拟化。Windows 10使用滑杆调整DPI的话,在125%也会进行DPI虚拟化。但使用自定义缩放比例对话框设置的话,目前与之前版本表现一样。

这种机制不是万能的,它仅仅解决了界面错乱的问题。它仅对客户区进行缩放,也就是说,如果程序对非客户区进行操作(如截屏),DPI虚拟化是无能为力的。DPI虚拟化还会引起界面的模糊(整数倍缩放例外,如200%)。

如果用户认为这种缩放引起了兼容性问题,可以在自定义对话框中勾选“使用Windows XP风格DPI缩放比例”关闭DPI虚拟化。Windows 8.1把它放到了exe属性中,兼容性选项卡勾选“高DPI时禁用显示缩放”,可对程序单独关闭DPI虚拟化。

如果程序已经支持高DPI,Windows Vista允许程序关闭DPI虚拟化,方法是调用user32.dll中的SetProcessDPIAware()函数,声明程序支持DPI缩放。这个函数对整个进程起作用,也就是说DLL是不应该调用这个函数的。

在调用这个函数之前,通过GetDeviceCaps获得的DPI是96;调用这个函数之后,可通过GetDeviceCaps获得真实的DPI值。

获取程序的DPI支持状态,可使用user32.dll中的IsProcessDPIAware()函数。

Windows Vista还允许在程序的manifest(清单)资源(一个嵌入exe的xml配置文件)中声明程序支持DPI缩放,声明<dpiAware>true</dpiAware>相当于在程序启动时运行SetProcessDPIAware()函数。
<code class="lang-xml"><?xml version="1.0" encoding="UTF-8" standalone="yes"?>
                       
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestversion="1.0">
    <description>A free .NET IDE</description>
    <dependency>
        <dependentassembly>
            <assemblyidentity                 type="win32"                 name="Microsoft.Windows.Common-Controls"                 version="6.0.0.0"                 processorarchitecture="*"                 publickeytoken="6595b64144ccf1df"                 language="*"             >
        </assemblyidentity></dependentassembly>
    </dependency>
                           
    <trustinfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedprivileges>
                
                
                <requestedexecutionlevel level="asInvoker" uiaccess="false">
                
            </requestedexecutionlevel></requestedprivileges>
        </security>
    </trustinfo>
                           
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowssettings xmlns:ws="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
            <ws:dpiaware>true</ws:dpiaware> 
        </windowssettings>
    </application>
</assembly></code>

六、关于Windows 8.1+的逐显示器DPI虚拟化

在Windows 8.1中,引入了另一个DPI缩放级别:逐显示器DPI。程序窗口在拖动到其它DPI不同的显示器时(或Windows 10中DPI设置实时变化时),会收到WM_DPICHANGED消息,程序需要响应这个消息以对DPI改变做出响应,重新进行界面布局缩放。

由于以前的程序只支持在启动时进行布局缩放,并不响应WM_DPICHANGED消息,所以在拖动到其它DPI不同的显示器时(或Windows 10中DPI设置实时变化时),系统会对它们进行DPI虚拟化。

Windows 8.1引入了一个新的函数进行DPI缩放级别声明。调用shcore.dll中的SetProcessDpiAwareness(int level)可以声明DPI缩放级别:0表示不支持DPI缩放,1表示支持系统级DPI,2表示支持逐显示器DPI。

这个函数调用一次之后,进程的DPI缩放级别即被锁定无法更改,即使使用老的SetProcessDPIAware函数也不行。老版本的SetProcessDPIAware()调用等价于SetProcessDpiAwareness(1),它也会锁定DPI缩放级别。所以SetProcessDpiAwareness必须在任何指定DPI缩放级别的操作之前调用,否则无效。

在级别0,无论是GetDeviceCaps还是GetDpiForMonitor都会返回96;在级别1,两个函数都会返回系统级DPI的值;在级别2,GetDeviceCaps返回系统级DPI,而GetDpiForMonitor返回指定显示器的DPI,同时窗口还会收到WM_DPICHANGED消息。

获得某个进程的DPI缩放级别,可以使用shcore.dll中的GetProcessDpiAwareness函数。

Windows 8.1和之前的操作系统中,manifest资源中的<dpiAware>声明的等效函数调用也不同:
false —— SetProcessDpiAwareness(0) —— 什么也不做
true —— SetProcessDpiAwareness(1) —— SetProcessDPIAware()
true/pm —— SetProcessDpiAwareness(2) —— SetProcessDPIAware()
per monitor —— SetProcessDpiAwareness(2) —— 什么也不做

[修改于 8年8个月前 - 2016/04/09 10:29:53]

来自:计算机科学 / 软件综合
1
已屏蔽 原因:{{ notice.reason }}已屏蔽
{{notice.noticeContent}}
~~空空如也
acmilan 作者
8年8个月前 IP:四川
815553
解决200%缩放下Windows 7虚拟机鼠标指针问题

【鼠标有锯齿】

将C:\Windows\Cursors中的指针文件替换为Win8.1或Win10的

Win8.1鼠标指针打包:
attachment icon Cursors_Win81.zip 233.30KB ZIP 29次下载
Win10鼠标指针打包:
attachment icon Cursors_Win10.zip 450.22KB ZIP 27次下载

【鼠标飘忽,不能切换】

关闭指针阴影(如图所示)

Windows 7 199%-2016-04-09-13-13-08.png
引用
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
所属分类
上级专业
同级专业
acmilan
进士 学者 笔友
文章
461
回复
2934
学术分
4
2009/05/30注册,5年10个月前活动
暂无简介
主体类型:个人
所属领域:无
认证方式:邮箱
IP归属地:未同步
文件下载
加载中...
{{errorInfo}}
{{downloadWarning}}
你在 {{downloadTime}} 下载过当前文件。
文件名称:{{resource.defaultFile.name}}
下载次数:{{resource.hits}}
上传用户:{{uploader.username}}
所需积分:{{costScores}},{{holdScores}}下载当前附件免费{{description}}
积分不足,去充值
文件已丢失

当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}
视频暂不能访问,请登录试试
仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。
音频暂不能访问,请登录试试
支持的图片格式:jpg, jpeg, png
插入公式
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
收藏
取消收藏
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
管理提醒
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}