6

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:

12
  • 2
    Ah, I have code that instructs SHGetImageList to return the jumbo 256x256 icons if that's what you need. Upon looking at it again I suspect I originally got it from here
    – user585968
    Commented Apr 5, 2017 at 13:52
  • 1
    @MickyD Because that's not the "right" solution. Icon designers will put more detail in jumbo icons and for small icons, e.g. 16px they omit that detail and create bespoke variants. Commented Apr 5, 2017 at 14:51
  • 2
    HIMAGELIST hImageList = reinterpret_cast<HIMAGELIST>(IImageList); fwiw. Commented Apr 5, 2017 at 20:49
  • 1
  • 1
    There are only 4 sizes, you just have to pick the closest one based on DPI and scale as appropriate. Commented Apr 6, 2017 at 7:57

1 Answer 1

3

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.

1
  • I think what you have is close to the optimal solution (assuming icon quality is your goal). It might even be what the system does internally when you start an app with a nonstandard DPI. Because without some sort of SHGetImageListForDPI, there's no way to achieve what you want dynamically. The only way I can see to get a better icon quality is to just skip the disk cache and query the icon (& overlays) directly - in theory, icons could come in arbitrary sizes, so you might get a better icon than one that's a rescaled version of a standard-sized one.
    – user541686
    Commented Apr 21, 2023 at 7:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.