C++ DPI

定义

英文全称为Dots per inch,每英寸点数,监视器没有点,但有像素,在显示器上就是每英寸的像素个数。

Window上一般默认是96 dpi 作为100% 的缩放比率, 但是要注意的是该值未必是真正的显示器物理值, 只是Windows里我们的一个参考标准。

一般来说,缩放比例的步进值是25%,对应DPI的步进值为24,当然用户也可以定义任意缩放值。

缩放比例和DPI的关系:

100% - 96 DPI

125% - 120 DPI

150% - 144 DPI

175% - 168 DPI

200% - 192 DPI

依次类推

500% - 480 DPI

检测DPI的函数

Windows 8及之前版本仅支持系统级DPI——

可以先GetDC(NULL)获取桌面hDC,然后GetDeviceCaps(hDC, LOGPIXELSX和LOGPIXELSY)获取,最后别忘了ReleaseDC(hDC)。

Windows 8.1及之后版本支持逐显示器级DPI——

在C/C++程序中,可以使用MonitorFromPoint和GetDpiForMonitor获取指定显示器的DPI,也可以从WM_DPICHANGED消息的lParam参数中获取。

关于高DPI的支持

原因:

系统字体是是以固定大小(宋体10号字,物理尺寸为(10/72)英寸)设计的,在移动设备时代和大显示器的高分辨率时代,这样的字体太小了,要想在屏幕分辨率不变的前提下,让字体更大,就需要让字体占有更多的像素,通过提高DPI可以实现,

实现方式:

Vista/Win7/Win8

DWM(Desktop Window Manager) 虚拟化支持:通过DWM的缩放实现的, 具体过程是这样的, 比如我们当前系统的DPI是200%, 我们程序运行时,系统会告诉你当前DPI仍然是96(100%), 所以我们程序会仍然按照100%的方式进行绘画, 但是系统给我们的坐标是根据DPI缩小过后的(也就是我们对窗口调用GetWindowRect或是通过GetSystemMetrics(SM_CXSCREEN)得到的大小会比实际大小减半) , 当我们画完之后, DWM再对整个窗口进行200% 放大后画到屏幕上, 这样看起来我们的程序就自动支持高DPI了。

DWM缺点

经过缩放后的内容看起来会变模糊, 比如文字会有明显的锯齿

如果程序已经支持高DPI,系统允许程序关闭DPI虚拟化,方法是调用user32.dll中的SetProcessDPIAware()函数,声明程序支持DPI缩放。

这个函数对整个进程起作用,也就是说DLL是不应该调用这个函数的。

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

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

系统还允许在程序的manifest(清单)资源(一个嵌入exe的xml配置文件)中声明程序支持DPI缩放,声明true相当于在程序启动时运行SetProcessDPIAware()函数。

Win8.1及以后

 WIn8.1对高DPi以3种方式支持 Process_DPI_Awareness :  

typedef enum _Process_DPI_Awareness { 
  Process_DPI_Unaware            = 0,//不支持DPI缩放
  Process_System_DPI_Aware       = 1,//支持系统级DPI
  Process_Per_Monitor_DPI_Aware  = 2//支持逐显示器DPI
} Process_DPI_Awareness;

第一种Unaware, 该种方式是告诉系统, 我的程序不支持DPI aware, 请通过DWM虚拟化帮我们实现。 该方式和上面Win7/Win8对高DPI的支持的实现基本一样,主要区别是它通过GetWindowRect取到的坐标都是经过DWM缩放后的, 无论对方窗口是不是支持DWM虚拟化。 

第二种方式是System DPI aware, 该方式下告诉系统, 我的程序会在启动的显示器上自己支持DPI aware, 所以不需要对我进行DWM 虚拟化。 但是当我的程序被拖动到其他DPI不一样的显示器时, 请对我们先进行system DWM虚拟化缩放。 

第三种方式是Per Monitor DPI aware, 该方式是告诉系统, 请永远不要对我进行DWM虚拟化,我会自己针对不同的Monitor的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资源中的声明的等效函数调用也不同:

false —— SetProcessDpiAwareness(0) —— 什么也不做

true —— SetProcessDpiAwareness(1) —— SetProcessDPIAware()

true/pm —— SetProcessDpiAwareness(2) —— SetProcessDPIAware()

per monitor —— SetProcessDpiAwareness(2) —— 什么也不做

相关API:

SetProcessDpiAwareness :设置当前进程对高DPi的支持方式

GetProcessDpiAwareness :查询某个进程对高DPI的支持方式

GetDpiForMonitor : 获取某个Monitor的DPI

WM_DPICHANGED :当某个程序窗口被拖到另外一个DPI的Monitor时收到

VS设置方式

View->Property Pages->Configuration->Manifest Tool->Input and Output->DPI Awareness, 默认设置High Dpi Aware

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SystemVerilog的DPI(Direct Programming Interface)是一种与其他编程语言进行交互的接口。它由SystemVerilog层和其他语言层组成,这两层是相互独立的,并且它们的编译也是相互独立的。DPI的设计目的是为了满足在SystemVerilog中使用其他语言开发的模块的需求,特别是C和C++。在DPI的分层结构中,组件的规范和实现被明确分开,实际实现对于使用DPI语言来说是透明的。例如,使用DPI调用的C函数对于SystemVerilog来说是一个黑盒子,而SystemVerilog无需更改即可对其进行调用。 具体使用DPI-C的过程如下: 1. 在C代码中,使用#include <svdpi.h>导入SystemVerilog的DPI头文件,并使用extern关键字声明SystemVerilog中的函数。 2. 在C代码中,编写调用SystemVerilog函数的代码。例如,调用名为apb_write的SystemVerilog任务,可以使用apb_write(0x3500000, 0x1)。 3. 在SystemVerilog代码中,使用import "DPI"语句导入DPI定义的上下文,并定义一个调用C函数的任务。例如,定义名为c_test的任务,输入参数为addr。 4. 在SystemVerilog代码中,使用initial块调用C函数。例如,使用c_test('h1000)和c_test('h2000)调用c_test任务。 5. 在SystemVerilog代码中,使用export "DPI"语句导出SystemVerilog任务。例如,导出名为apb_write的任务。 6. 使用VCS命令编译SystemVerilog和C代码。例如,使用vcs -sverilog hdl_top.sv c_test.c进行编译。 以上是使用DPI-C的简要示例说明,通过这种方式,可以在SystemVerilog和C之间实现函数和任务的互相调用。 #### 引用[.reference_title] - *1* *2* [【原创】SystemVerilog中传说的DPI](https://blog.csdn.net/m0_46345246/article/details/121199713)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [[SV]SystemVerilog DPI应用实例](https://blog.csdn.net/gsjthxy/article/details/125785799)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值