Make Windows Common Dialogs "Per Monitor DPI-Aware"
Asked Answered
O

2

8

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:

  1. 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.
  2. 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

Outfit answered 17/2, 2016 at 10:57 Comment(7)
Well, you normally wouldn't. Those dialogs that you're using are obsolete. For Open/Save/Browse for Folder, you would now use the Common Item Dialog, specifically IFileOpenDialog. These are available on Windows Vista and later and should already be DPI aware. Fall back to the older dialogs on downlevel operating systems.Spirituous
BTW from VS2012 (or VS2010 not quite sure) on, CFileDialog automatically uses the Common Item Dialog without any additional work.Obduliaobdurate
@Cody Gray I checked the code in "mfc\dlgfile.cpp", and found CFileDialog calss did use IFileDialog to show the dialog. if (m_bVistaStyle == TRUE) { ApplyOFNToShellDialog(); HRESULT hr = (static_cast<IFileDialog*>(m_pIFileDialog))->Show(m_ofn.hwndOwner); nResult = (hr == S_OK) ? IDOK : IDCANCEL; }Outfit
@Michael Walz Actually in VS2008, CFileDialog also uses IFileDialog if you are running in Windows Vista or later and set bVistaStyle to TRUE. (bVistaStyle is set to TRUE by default) [link]msdn.microsoft.com/en-us/library/wh5hz49d.aspxOutfit
Hmm, okay. I'm surprised they've kept MFC updated. Good stuff. I don't know, then. You aren't supposed to have to do anything in your own code to make the built-in common dialogs work. It may simply be that DPI support is broken there, as it is in many places in Windows. Unfortunately, I don't have a system with monitors running different DPIs, so I can't check it out for you.Spirituous
I'm pretty sure the things you've found are limitations of Windows and there's no (supported) way of fixing it. Even IFileDialog doesn't work. Note that Notepad is NOT per-monitor DPI aware, so DPI virtualization kicks in and "makes it work". You can notice the same problems in Internet Explorer, which IS per-monitor DPI aware.Testator
How did you handle WM_DPICHANGED in MFC? I am not able to find the name of handler function, and the respective macros, using which I can declare message map.Purpurin
R
2

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.

Realist answered 6/9, 2016 at 21:50 Comment(0)
H
0

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.

Hothouse answered 18/4, 2016 at 10:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.