I need to get large "jumbo" file icons (256x256 px) with overlay (for example link icon for shortcuts), basically the same as can be seen in Windows File Explorer when you set to view items in extra large icons.
For example I have a shortcut "a.txt.lnk" to a text file, which has this icon in File Explorer. This is what I want to get (yes, the arrow in the bottom left corner is what I mean by overlay):
I googled really hard to find out how to do this.
To experiment with the code I used iconextractor example in QtWinExtras library (in sources of Qt framework). Unfortunately it has some issues and does not work well. All I managed to do was to obtain either small icons (32x32 px) with shortcut overlay or "jumbo" icons without overlay. This:
or this:
I simplified the code from the Qt example to this main.cpp:
#include <QtWin>
#include <QDebug>
#include <QDir>
#include <QFileInfo>
#include <QGuiApplication>
#include <QImage>
#include <QPixmap>
#include <comdef.h>
#include <CommCtrl.h>
#include <commoncontrols.h>
struct PixmapEntry {
QString name;
QPixmap pixmap;
};
using PixmapEntryList = QVector<PixmapEntry>;
static QString formatSize(const QSize &size)
{
return QString::number(size.width()) + u'x' + QString::number(size.height());
}
static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
{
QPixmap result;
static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
IImageList *imageList = nullptr;
if (FAILED(SHGetImageList(iImageList, iID_IImageList, reinterpret_cast<void **>(&imageList))))
return result;
HICON hIcon = nullptr;
// NOTE: the following was missing in original Qt code
// and therefore returned no jumbo icons at all when
// overlays were requested.
// Highest 8 bits are reverved for overlay index.
int iconIndex = info.iIcon & 0xFFFFFF;
if (SUCCEEDED(imageList->GetIcon(iconIndex, ILD_TRANSPARENT, &hIcon))) {
result = QtWin::fromHICON(hIcon);
DestroyIcon(hIcon);
}
return result;
}
static PixmapEntryList extractShellIcons(const QString &sourceFile, bool addOverlays)
{
enum { // Shell image list ids
sHIL_EXTRALARGE = 0x2, // 48x48 or user-defined
sHIL_JUMBO = 0x4 // 256x256 (Vista or later)
};
struct FlagEntry {
QString name;
unsigned flags;
};
const QString nativeName = QDir::toNativeSeparators(sourceFile);
const auto *sourceFileC = reinterpret_cast<const wchar_t *>(nativeName.utf16());
SHFILEINFO info;
unsigned int flags = SHGFI_ICON | SHGFI_SYSICONINDEX | SHGFI_SHELLICONSIZE;
if (addOverlays)
flags |= SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX; // What do these flags do? How to utilize the overlay index?
PixmapEntryList result;
const QString prefix = "sh_";
ZeroMemory(&info, sizeof(SHFILEINFO));
SHGetFileInfo(sourceFileC, 0, &info, sizeof(SHFILEINFO), flags);
// extract standard icon
PixmapEntry entry;
entry.pixmap = QtWin::fromHICON(info.hIcon);
DestroyIcon(info.hIcon);
if (entry.pixmap.isNull()) {
qWarning() << "Error converting icons.";
return PixmapEntryList();
}
entry.name = prefix + formatSize(entry.pixmap.size());
const int iconIndex = info.iIcon & 0xFFFFFF;
const int overlayIconIndex = info.iIcon >> 24; // Note: some resources suggest there should be -1 to adjust for 0-based index. Really?
qDebug() << "Obtained icon #" << iconIndex << "overlay #" << overlayIconIndex;
result.append(entry);
// extract jumbo icon
const QPixmap jumbo = pixmapFromShellImageList(sHIL_JUMBO, info);
if (!jumbo.isNull()) {
PixmapEntry entry;
entry.pixmap = jumbo;
entry.name = QLatin1String("jumbo_") + formatSize(jumbo.size());
result.append(entry);
}
return result;
}
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
const QString &sourceFile = "C:/my/path/to/some/link/a.txt.lnk";
QString imageFileRoot = QDir::currentPath() + u'/';
// Note: Settings true or false in the following line has no effect of overlays.
// Small icons have always overlays, jumbo icons have never overlays.
const PixmapEntryList pixmaps = extractShellIcons(sourceFile, true);
for (const auto &entry : pixmaps) {
const QString fileName = imageFileRoot + entry.name + QLatin1String(".png");
entry.pixmap.save(fileName);
qDebug() << "Wrote " << QDir::toNativeSeparators(fileName);
}
return 0;
}
and iconextractor.pro:
TEMPLATE = app
TARGET = iconextractor
CONFIG += console
QT = core gui winextras
LIBS += -lshell32 -luser32
SOURCES += main.cpp
My problem is that I do not understand what is this line flags |= SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX; good for. It has no effect on standard icons (they contain overlay even without this line) and has no effect on jumbo icons (they do not contain overlay anyway). ObviouslyI can get icon overlay index but I have no idea what I should do with it. How to get the jumbo sized icon with overlay?



