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

Caspar Lee
  • 103
  • 8
  • 1
    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](https://msdn.microsoft.com/en-us/library/windows/desktop/bb776913%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396), 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 - on strike Feb 17 '16 at 12:27
  • 1
    BTW from VS2012 (or VS2010 not quite sure) on, CFileDialog automatically uses the Common Item Dialog without any additional work. – Jabberwocky Feb 18 '16 at 08:02
  • @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(m_pIFileDialog))->Show(m_ofn.hwndOwner); nResult = (hr == S_OK) ? IDOK : IDCANCEL; }` – Caspar Lee Feb 18 '16 at 12:32
  • @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]https://msdn.microsoft.com/en-us/library/wh5hz49d.aspx – Caspar Lee Feb 18 '16 at 12:46
  • 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 - on strike Feb 19 '16 at 08:34
  • 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. – James Johnston Apr 04 '16 at 20:42
  • 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. – Sahil Singh Dec 23 '16 at 13:50

2 Answers2

1

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.

peterfelts
  • 542
  • 5
  • 11
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.

Community
  • 1
  • 1
Simon Rozman
  • 308
  • 3
  • 8