Per monitor DPI aware Windows system image list
Asked Answered
A

1

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:

Anxiety answered 5/4, 2017 at 12:15 Comment(12)
Why don't you just load the largest DPI images and let the WinForms control worry about scaling?Macruran
@MickyD Thanks for your comment. Though e.g. with 96 system DPI, I can get 32x32 icons at most (SHGFI_LARGEICON). As I need even the "large" icons in my application, I need even larger than 32x32 on high DPI monitor.Anxiety
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 hereMacruran
@MickyD Thanks. Yes, I've seen that SHGetImageList supports larger icon sizes. While that's possibly an acceptable workaround, it would be a huge change to my code. I'm looking for a handle to the system image list. While the SHGetImageList gets you IImageList.Anxiety
No problem good buddyMacruran
@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.Shwalb
HIMAGELIST hImageList = reinterpret_cast<HIMAGELIST>(IImageList); fwiw.Coleoptile
@JonathanPotter Thanks for your comment. Is it documented anywhere, that the handle to the image list is actually a pointer to the IImageList interface?Anxiety
msdn.microsoft.com/en-us/library/windows/desktop/…Coleoptile
@JonathanPotter Thanks. That's closer to an acceptable workaround. But still the SHGetImageList provides 4 icons sizes only. What is better than the two I have atm, but still not enough for all DPI's.Anxiety
There are only 4 sizes, you just have to pick the closest one based on DPI and scale as appropriate.Coleoptile
@JonathanPotter OK, that's actually probably right! Will look into it.Anxiety
A
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.

Anxiety answered 28/4, 2017 at 19:4 Comment(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.Quantum

© 2022 - 2024 — McMap. All rights reserved.