8
votes

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

2
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.Cody Gray♦
BTW from VS2012 (or VS2010 not quite sure) on, CFileDialog automatically uses the Common Item Dialog without any additional work.Jabberwocky
@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; }Caspar Lee
@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.aspxCaspar Lee
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.Cody Gray♦

2 Answers

1
votes

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.

0
votes

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.