This is not an actual problem. If you mark your process as high-DPI aware, then the system will no longer do any sort of DPI virtualization and the APIs will no longer lie to you about the actual values.
In particular, if you call GetWindowRect
or GetClientRect
from a high-DPI aware application, you will get the actual values in screen coordinates. This will be true not only for windows belonging to your application's process, but also for windows belonging to other processes, regardless of that other process's DPI awareness setting.
As of Windows 8.1, the PhysicalToLogicalPoint
and LogicalToPhysicalPoint
functions are no longer necessary and don't actually do anything. The documentation for these two functions calls this out explicitly:
In Windows 8.1, the additional virtualization of the system and inter-process communications means that for the majority of applications, you do not need these APIs. As a result, in Windows 8.1, PhysicalToLogicalPoint
and LogicalToPhysicalPoint
no longer transform points. The system returns all points to an application in its own coordinate space.
The last sentence is just a different way of phrasing what I said above. The system returns values according to the DPI awareness of the caller. If your process is high-DPI aware, then you will get the real values. You do not need to scale the values yourself. If you are not high-DPI aware, then you are subject to being lied to about the actual values. But that makes sense, because it is assumed that you cannot handle the truth and will not react appropriately.
Just to be clear, I should point out that there are actually two levels of high-DPI awareness now, as of Windows 8.1 (and continued in Windows 10):
There is the first level, introduced way back with Windows Vista, of high-DPI awareness. This is indicated by a setting of true
in the application's manifest file, and it just means that you (the application) is able to deal with a system DPI that is set to something other than the classic default of 96 DPI.
Based on the above knowledge, then, we know that if a process with this DPI-awareness setting calls an API function that returns screen coordinates, it will receive the values in terms of the system DPI.
Then there is the new level, introduced with Windows 8.1, of per-monitor high-DPI awareness. This is indicated by a setting of True/PM
in the application's manifest, and it means that you (the application) is able to deal with different monitors having different DPI settings. In other words, while there is still a system default DPI (and it may be 96 DPI or it may be something else), there may be monitors attached to the system that use a different DPI setting (something other than the system DPI).
Again, based on the above understanding, we know that if a process that is per-monitor high-DPI aware calls an API function that returns screen coordinates, it will receive the actual coordinates relative to the DPI of the monitor that contains the window in question.
If your process is not DPI aware at all (no setting in the manifest, or false
), then when you call API functions that return screen coordinates, you will receive the coordinates scaled/virtualized based on a system-wide DPI of 96 DPI.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…