Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Per monitor DPI aware Windows system image list

How do I retrieve system image list for given DPI?

When an application is system DPI-aware, the SHGetFileInfo and similar functions return a handle to a correctly scaled system image list. C++ example:

handle =
  SHGetFileInfo(L"", 0, &fileInfo, sizeof(fileInfo),
                SHGFI_SYSICONINDEX | (large ? SHGFI_LARGEICON : SHGFI_SMALLICON));

But with per-monitor DPI awareness, that's not enough, as the application can run on a monitor that does not use system DPI (or the application can have multiple windows, each on different monitor, with different DPI).

For example, on 168 DPI (175% zoom) monitor, with standard 96 system DPI, you get small unscaled 16x16 icons:

unscaled system icons

So I'm hoping, that there's a DPI-aware variant to the SHGetFileInfo (or similar), the way there are DPI aware variants of other functions like:

  • GetSystemMetricsForDpi for GetSystemMetrics;
  • SystemParametersInfoForDpi for SystemParametersInfo;
  • OpenThemeDataForDpi for OpenThemeData.
like image 247
Martin Prikryl Avatar asked Apr 05 '17 12:04

Martin Prikryl


People also ask

How do you override high DPI scaling behavior?

Right-click the application, select Properties, select the Compatibility tab, and then select the Disable display scaling on high DPI settings check box.

How do I make my application DPI aware?

To make your application dpi-aware, you must cancel automatic dpi scaling, and then adjust user interface elements to scale appropriately to the system dpi.

What is GDI DPI scaling?

GDI DPI Scaling enables applications that are not DPI aware to become per monitor DPI aware. This policy setting lets you specify legacy applications that have GDI DPI Scaling turned on. If you enable this policy setting, GDI DPI Scaling is turned on for all legacy applications in the list.


1 Answers

As a quick solution, I ended up using SHGetImageList, as suggested by @MickyD.

As mentioned in the function documentation (and as suggested by @JonathanPotter):

The IImageList pointer type, such as that returned in the ppv parameter, can be cast as an HIMAGELIST as needed; for example, for use in a list view.

Hence I use the SHGetImageList to collect all available system image lists sizes by calling it for 0..SHIL_LAST.

For each returned image list, I query its icon size using ImageList_GetIconSize and cache them all.

Then, when an image list is needed for a particular DPI, I pick the closest size available.

An obvious drawback is that on multi monitor systems with high system DPI, but with one low DPI monitor, one cannot retrieve reasonable size of small icons for the low DPI monitor.

like image 138
Martin Prikryl Avatar answered Sep 20 '22 16:09

Martin Prikryl