1

Changed an MFC app to per-monitor DPI aware. On the WM_DPICHANGED message I wanted to changed the fonts of the CMFCMenuBar to be scaled correctly. So I added:

  LOGFONT logfont;
  GetGlobalData()->fontRegular.GetLogFont(&logfont);
  logfont.lfHeight=g_DPIHelper.ScaleNonClientMetricsFont(logfont.lfHeight);
  if (!m_wndMenuBar.SetMenuFont(&logfont)) {
    TRACE0("Unable to set menu font\n");
  }

I confirmed that logfont.lfHeight went from -11 to -17 in the test case. I confirmed the SetMenuFont() call returned success. Yet the CMFCMenuBar font shown on the menu bar is the same size as it was before. What am I missing?

TIA!!

df234987
  • 513
  • 2
  • 13
  • Hi, if you have solve the issue by yourself, you could [Accept Your Own Answers](https://stackoverflow.blog/2009/01/06/accept-your-own-answers/) – Drake Wu Jul 02 '20 at 07:16

1 Answers1

0

The problem is that after WM_DPICHANGED a WM_SETTINGCHANGED is sent and MFC then calls AFX_GLOBAL_DATA::OnSettingsChange() which calls UpdateFonts() which uses GetNonClientMetrics() which resets it back to the wrong size because the size is based on when the application started.

On WM_DPICHANGED calculate your scaling factor. Then do the actual font change in WM_SETTINGCHANGED which allows the font change size to take affect when you change the DPI of the screen (not sure if WM_SETTINGCHANGED called if moved to another window, if not the change can be done in WM_DPICHANGED. Here's one method:

void CMainFrame::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
{
  CFrameWndEx::OnSettingChange(uFlags, lpszSection);

  LOGFONT logfont;
  GetGlobalData()->fontRegular.GetLogFont(&logfont);
  logfont.lfHeight=g_DPIHelper.Scale(-11);
  if (!m_wndMenuBar.SetMenuFont(&logfont)) {
    TRACE0("Unable to set menu fonts\n");
  }
}
df234987
  • 513
  • 2
  • 13
  • A DC can span multiple monitors, so it doesn't make sense to talk of the DPI of a DC unless there's a rule that says it will be consistent. – Mark Ransom Jun 23 '20 at 22:01