tringi / win32-dpi

Example of properly DPI-scaling Win32 windows across XP to latest Windows 11

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Win32 DPI-aware window example

Trivial example on how to write Win32 DPI-aware GUI application that scales properly on everything starting Windows XP and ending with latest Windows 11 (tested on insider build 10.0.22523.1).

In a nutshell

  • Primary monitor is usually at System DPI (unless changed without restart)
  • Other monitors can be at higher or lower DPI than System
  • All metrics normally (pre-v2) reported to the application are in System DPI
  • Some APIs (GetThemeFont) scale the reported values when in PerMonitorV2 awareness mode
  • It's error-prone to call GetSystemMetrics wherever needed and scale manually, precompute these
  • Mostly everything derives metrics from font size
    • recreate fonts on DPI change, remember height, rescale accordingly
  • Window and Taskbar icons sizes change too
    • the OS may ask for different DPI icon (e.g. for Taskbar on monitor with different DPI)
  • Since Windows 10 there is mismatch between reality and documented Taskbar icon size
    • Taskbar used to use ICON_BIG/SM_CXICON-sized icon (32×32) but starting with Windows 10, it's resized down to 24×24 (so called Start size on XP)
    • there is no API to query, so testing OS version, and updating code as Microsoft makes changes, remains
    • Alt+Tab in Windows 11 now does the same, takes BIG icon, and scales it down to size of a SMALL one (16×16)

Additional

  • The example also shows how to track "TextScaleFactor" for UWP apps, see Settings > Accessibility > Text size, and apply it to Win32 window content scaling.
  • Multiple WM_SETTINGCHANGE and other GUI change notifications can come in quick succession, so it is possible to alleviate excess refresh and flickering by coalescing those, to improve user experience.

Manifest

For the application to support DPI scaling to the full extent of what the underlying Operating System supports, the process DPI awareness must be set. That's accomplished either through manifest, or calling API(s). The API way is complicated. We will use my rsrcgen.exe tool to generate manifest that will request everything known so far, and then deal with what we get at runtime.

API alternative:

Additional reading

ISC License

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

About

Example of properly DPI-scaling Win32 windows across XP to latest Windows 11

License:ISC License


Languages

Language:C++ 100.0%