In the Windows 10 file properties of an executable in the compatibility tab, there is an option to override the default DPI scaling behaviour. The default is "Application", which lets the program handle DPI scaling itself. I'd like to change this option on an executable (not developed by me), which I want to be scaled by Windows (option "System"). How can I change this property programmatically (WinAPI?)?
Related
There are over 200 older programs that aren't displayed correctly and setting each .exe DPI awareness is a chore, I'm looking for a way to automate it from a batch process or a context menu that would possibly make it easier and quicker.
Is there a way DPI Aware settings on Windows 10 context menu, or somehow change the DPI settings to all the .exe/.lnk files in a single menu?
I have a program which was created in VS2008 with MFC.
Now I've modified it to make it "Per Monitor DPI-Aware", and it's almost done. I've modified the manifest and handled the WM_DPICHANGE message. But there's still one problem:
I used CFileDialog class to show Open/Save dialogs, and used SHBrowseForFolder function to show folder selection dialog. But all these dialogs are NOT "Per Monitor DPI-Aware", they won't adjust their UI when you move them between monitors with different DPI settings.
I use spy++ to monitor messages of these dialogs, I find they can receive WM_DPICHANGED message but they just don't handle it.
And I've tested the open file dialog in notepad.exe on Windows 10, it worked perfectly.
Does anyone know how can I make these dialogs "Per Monitor DPI-Aware"?
--------EDIT--------
There're two more problems:
When I move a window to a monitor with different DPI, the window resize itself, but the height of it's title bar and title font-size are not changed.
The checkbox controls' box size is not changed either.
I feel these problems may have some kind of connections, but I can't figure it out.
--------SAD NEWS--------
I compiled microsoft's "DPI Tutorial Sample" with VS2013, and it has the same problem.
https://code.msdn.microsoft.com/DPI-Tutorial-sample-64134744
The titlebar (caption bar) can be scaled by calling EnableNonClientDpiScaling which is available on versions of Windows >= the Windows 10 Anniversary Update (1607).
If you want to DPI scale an older dialog that doesn't support per-monitor DPI scaling you can use SetThreadDpiAwarenessContext (with DPI_AWARENESS_CONTEXT_SYSTEM_AWARE or DPI_AWARENESS_CONTEXT_UNAWARE) to have the top-level windows of the dialog scaled by Windows. The dialog might be blurry but it will at least be sized correctly (also only available on >= 1607 builds of Windows 10). The usage pattern is to call this API before opening the dialog and then restore the previous DPI context immediately after calling the API.
According to MSDN the window that processes WM_DPICHANGED message should return 0. However, any MFC window or control you send WM_DPICHANGED will return 0, since thay call the default window procedure for the unknown messages.
Therefore, judging if some window does process WM_DPICHANGED message by testing its LRESULT return value against zero is not accurate.
The window's title bar of a per-monitor DPI aware application doesn't scale when moving across different DPI monitors as documented on MSDN. Unfortunately, non-client area of the window never adjust the DPI.
Calculator and other per-monitor DPI aware Windows native apps have custom title bar drawing, as described here.
I don't like the Windows auto scaling on high DPI settings. So I normally turn the scaling off by check the settings on Compatability of the exe properties.
I used Matlab compiler to generate an exe, but its Disable display scaling on high DPI settings is greyed. When I run this exe, its window would be too big than normal. How to disable the scaling so it's normal?
Try Control Panel: Display : Custome DPI Setting: Use Windows XP Style DPI scaling
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.
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.
DPI aware flag is set over application level and not the window level So if you are able to get the process of that particular window handle of other application then you can use GetProcessDpiAwareness() function to get the dpi aware flag of that particular process please see this microsoft documentation https://msdn.microsoft.com/en-us/library/windows/desktop/dn302113(v=vs.85).aspx
We noticed that on W7 with DPI set to > 125% or to > 100% with ("Use windows xp style dpi scaling") turned off, our fullscreen mode (which sets the client rect of our window = desktop rect of the main monitor) no longer hides the task bar like it does for other settings.
(The setting can be found in the Control Panel\Appearance and Personalization\Display section after clicking on the "Set custom text size (DPI)" link)
I found the following interesting article:
http://www.mathies.com/weblog/?p=908
So I set out to try to work around the bug in other means than manually hiding/restoring the taskbar visibility but so far I've failed and currently believe it's a bug in W7 (and possibly vista).
The following applications also fail to work properly in fullscreen mode (the taskbar is still visible):
* Microsoft Visual Studio 2008
* Microsoft Word 2007
* Adobe Reader 9.1.3
These apps work (probably by hiding the task bar through the WIN32 API):
* Powerpoint Slide Show
I also tried creating a brand new MFC-based app and use its "SetFullScreenMode()" functionality but it fails in the same way as all other apps on the list.
For now it seems the only temporary fix which has worked for me is to disable display scaling on high DPI settings for the program your using fullscreen with.
To do this goto properties (right-click the program's shortcut) >> compatability >> and check the option to disable display scaling on high DPI settings.
The only drawback is that you will not get the higher DPI for that program but the taskbar should hide when fullscreen is enabled.
This is a problem that I understand Windows 7 developers are aware of but have not come out with a solution.