I'm in the process of making an application DPI Aware but I have a need to do a GetWindowRect
on HWNDs from other applications. My problem is this works fine on applications that are also DPI Aware but how do I detect if the HWND
handle is DPI virtualized e.g. scaled so I can scale it myself? Or are there other APIs I've missed which will give me the size of the window in a DPI aware way from a HWND from another process?
I've tried the LogicalToPhysicalPoint
but that always seem to fail, possibly because the HWND doesn't belong to my application.
To make your application dpi-aware, you must cancel automatic dpi scaling, and then adjust user interface elements to scale appropriately to the system dpi.
The DPI Awareness Mode specifies the way an application is displayed when shown on a high resolution screen. Unaware. This mode works on all Windows versions prior to Windows Vista. In this mode, applications assume that all displays have the default 96 DPI (100%) scaling.
Select Display > Change the size of text, apps, and other items, and then adjust the slider for each monitor. Right-click the application, select Properties, select the Compatibility tab, and then select the Disable display scaling on high DPI settings check box.
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
andLogicalToPhysicalPoint
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With