aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2016-08-01 11:14:37 +0200
committerLiang Qi <liang.qi@qt.io>2016-08-01 11:14:41 +0200
commit93a998f5ef31f7d9f8dd72909c4342db84cc1b59 (patch)
treebd3cf0cd679166978eaf7c7b5e9e99740cd8bda9
parentdf31e3295eb114452bf4176ebdc1aa303fbe2b42 (diff)
parent4d09bf3dd58b1ccf67a8f6e9623964684b6f231a (diff)
Merge remote-tracking branch 'origin/5.6' into 5.7
-rw-r--r--LICENSE.GPLv22
-rw-r--r--LICENSE.GPLv32
-rw-r--r--LICENSE.LGPLv212
-rw-r--r--LICENSE.LGPLv32
-rw-r--r--examples/winextras/iconextractor/iconextractor.pro2
-rw-r--r--examples/winextras/iconextractor/main.cpp277
6 files changed, 237 insertions, 50 deletions
diff --git a/LICENSE.GPLv2 b/LICENSE.GPLv2
index 6dbb032..a424477 100644
--- a/LICENSE.GPLv2
+++ b/LICENSE.GPLv2
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU General Public License version 2, which is displayed below.
-------------------------------------------------------------------------
diff --git a/LICENSE.GPLv3 b/LICENSE.GPLv3
index 4e49b12..71c4ad4 100644
--- a/LICENSE.GPLv3
+++ b/LICENSE.GPLv3
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 3. That license references
the General Public License version 3, that is displayed below. Other
portions of the Qt Toolkit may be licensed directly under this license.
diff --git a/LICENSE.LGPLv21 b/LICENSE.LGPLv21
index 6e18461..dfcab5e 100644
--- a/LICENSE.LGPLv21
+++ b/LICENSE.LGPLv21
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 2.1, which is displayed below.
-------------------------------------------------------------------------
diff --git a/LICENSE.LGPLv3 b/LICENSE.LGPLv3
index 4d67bac..6bf924c 100644
--- a/LICENSE.LGPLv3
+++ b/LICENSE.LGPLv3
@@ -3,7 +3,7 @@
The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
Contact: http://www.qt.io/licensing/
- You may use, distribute and copy the Qt GUI Toolkit under the terms of
+ You may use, distribute and copy the Qt Toolkit under the terms of
GNU Lesser General Public License version 3, which is displayed below.
This license makes reference to the version 3 of the GNU General
Public License, which you can find in the LICENSE.GPLv3 file.
diff --git a/examples/winextras/iconextractor/iconextractor.pro b/examples/winextras/iconextractor/iconextractor.pro
index a8a967c..66c6dad 100644
--- a/examples/winextras/iconextractor/iconextractor.pro
+++ b/examples/winextras/iconextractor/iconextractor.pro
@@ -2,7 +2,7 @@ TEMPLATE = app
TARGET = iconextractor
CONFIG += console
QT = core gui winextras
-LIBS += -lshell32
+LIBS += -lshell32 -luser32
SOURCES += main.cpp
target.path = $$[QT_INSTALL_EXAMPLES]/winextras/iconextractor
diff --git a/examples/winextras/iconextractor/main.cpp b/examples/winextras/iconextractor/main.cpp
index 69fec10..eb39f9f 100644
--- a/examples/winextras/iconextractor/main.cpp
+++ b/examples/winextras/iconextractor/main.cpp
@@ -50,75 +50,262 @@
#include <QtWin>
+#include <QCommandLineParser>
+#include <QCommandLineOption>
+#include <QDir>
+#include <QFileInfo>
#include <QGuiApplication>
+#include <QImage>
+#include <QPixmap>
#include <QScopedArrayPointer>
#include <QStringList>
-#include <QPixmap>
-#include <QImage>
-#include <QFileInfo>
-#include <QDir>
+#include <QSysInfo>
+
#include <iostream>
+#include <shellapi.h>
+#include <comdef.h>
+#include <commctrl.h>
+#include <objbase.h>
+#include <commoncontrols.h>
+
/* This example demonstrates the Windows-specific image conversion
* functions. */
-int main(int argc, char *argv[])
+struct PixmapEntry {
+ QString name;
+ QPixmap pixmap;
+};
+
+typedef QList<PixmapEntry> PixmapEntryList;
+
+static std::wostream &operator<<(std::wostream &str, const QString &s)
{
- QGuiApplication a(argc, argv);
-
- QStringList arguments = QCoreApplication::arguments();
- arguments.pop_front();
- const bool large = !arguments.isEmpty() && arguments.front() == "-l";
- if (large)
- arguments.pop_front();
- if (arguments.size() < 1) {
- std::cout << "Usage: iconextractor [OPTIONS] FILE [IMAGE_FILE_FOLDER]\n\n"
- "Extracts Windows icons from executables, DLL or icon files\n"
- "and writes them out as numbered .png-files.\n\n"
- "Options: -l Extract large icons.\n\n"
- "Based on Qt " << QT_VERSION_STR << "\n";
- return 1;
- }
- const QString sourceFile = arguments.at(0);
- QString imageFileRoot = arguments.size() > 1 ? arguments.at(1) : QDir::currentPath();
- const QFileInfo imageFileRootInfo(imageFileRoot);
- if (!imageFileRootInfo.isDir()) {
- std::cerr << imageFileRoot.toStdString() << " is not a directory.\n";
- return 1;
- }
+#ifdef Q_OS_WIN
+ str << reinterpret_cast<const wchar_t *>(s.utf16());
+#else
+ str << s.toStdWString();
+#endif
+ return str;
+}
- const UINT iconCount = ExtractIconEx((wchar_t *)sourceFile.utf16(), -1, 0, 0, 0);
+static QString formatSize(const QSize &size)
+{
+ return QString::number(size.width()) + QLatin1Char('x') + QString::number(size.height());
+}
+
+// Extract icons contained in executable or DLL using the Win32 API ExtractIconEx()
+static PixmapEntryList extractIcons(const QString &sourceFile, bool large)
+{
+ const QString nativeName = QDir::toNativeSeparators(sourceFile);
+ const wchar_t *sourceFileC = reinterpret_cast<const wchar_t *>(nativeName.utf16());
+ const UINT iconCount = ExtractIconEx(sourceFileC, -1, 0, 0, 0);
if (!iconCount) {
- std::cerr << sourceFile.toStdString() << " does not appear to contain icons.\n";
- return 1;
+ std::wcerr << sourceFile << " does not appear to contain icons.\n";
+ return PixmapEntryList();
}
QScopedArrayPointer<HICON> icons(new HICON[iconCount]);
const UINT extractedIconCount = large ?
- ExtractIconEx((wchar_t *)sourceFile.utf16(), 0, icons.data(), 0, iconCount) :
- ExtractIconEx((wchar_t *)sourceFile.utf16(), 0, 0, icons.data(), iconCount);
+ ExtractIconEx(sourceFileC, 0, icons.data(), 0, iconCount) :
+ ExtractIconEx(sourceFileC, 0, 0, icons.data(), iconCount);
if (!extractedIconCount) {
qErrnoWarning("Failed to extract icons from %s", qPrintable(sourceFile));
- return 1;
+ return PixmapEntryList();
}
- std::cout << sourceFile.toStdString() << " contains " << extractedIconCount << " icon(s).\n";
+ PixmapEntryList result;
+ result.reserve(int(extractedIconCount));
+
+ std::wcout << sourceFile << " contains " << extractedIconCount << " icon(s).\n";
- imageFileRoot = imageFileRootInfo.absoluteFilePath() + QLatin1Char('/') + QFileInfo(sourceFile).baseName();
for (UINT i = 0; i < extractedIconCount; ++i) {
- const QPixmap pixmap = QtWin::fromHICON(icons[i]);
- if (pixmap.isNull()) {
- std::cerr << "Error converting icons.\n";
- return 1;
+ PixmapEntry entry;
+ entry.pixmap = QtWin::fromHICON(icons[i]);
+ if (entry.pixmap.isNull()) {
+ std::wcerr << "Error converting icons.\n";
+ return PixmapEntryList();
+ }
+ entry.name = QString::fromLatin1("%1_%2x%3").arg(i, 3, 10, QLatin1Char('0'))
+ .arg(entry.pixmap.width()).arg(entry.pixmap.height());
+ result.append(entry);
+ }
+ return result;
+}
+
+// Helper for extracting large/jumbo icons available from Windows Vista onwards
+// via SHGetImageList().
+static QPixmap pixmapFromShellImageList(int iImageList, const SHFILEINFO &info)
+{
+ QPixmap result;
+ // For MinGW:
+ static const IID iID_IImageList = {0x46eb5926, 0x582e, 0x4017, {0x9f, 0xdf, 0xe8, 0x99, 0x8d, 0xaa, 0x9, 0x50}};
+
+ IImageList *imageList = Q_NULLPTR;
+ if (FAILED(SHGetImageList(iImageList, iID_IImageList, reinterpret_cast<void **>(&imageList))))
+ return result;
+
+ HICON hIcon = 0;
+ if (SUCCEEDED(imageList->GetIcon(info.iIcon, ILD_TRANSPARENT, &hIcon))) {
+ result = QtWin::fromHICON(hIcon);
+ DestroyIcon(hIcon);
+ }
+ return result;
+}
+
+// Extract icons that would be displayed by the Explorer (shell)
+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 {
+ const char *name;
+ unsigned flags;
+ };
+
+ const FlagEntry modeEntries[] =
+ {
+ {"", 0},
+ {"open", SHGFI_OPENICON},
+ {"sel", SHGFI_SELECTED},
+ };
+ const FlagEntry standardSizeEntries[] =
+ {
+ {"s", SHGFI_SMALLICON},
+ {"l", SHGFI_LARGEICON},
+ {"sh", SHGFI_SHELLICONSIZE},
+ };
+
+ const QString nativeName = QDir::toNativeSeparators(sourceFile);
+ const wchar_t *sourceFileC = reinterpret_cast<const wchar_t *>(nativeName.utf16());
+
+ SHFILEINFO info;
+ unsigned int baseFlags = SHGFI_ICON | SHGFI_SYSICONINDEX | SHGFI_ICONLOCATION;
+ if (addOverlays)
+ baseFlags |= SHGFI_ADDOVERLAYS | SHGFI_OVERLAYINDEX;
+ if (!QFileInfo(sourceFile).isDir())
+ baseFlags |= SHGFI_USEFILEATTRIBUTES;
+
+ const size_t modeEntryCount = sizeof(modeEntries) / sizeof(modeEntries[0]);
+ const size_t standardSizeEntryCount = sizeof(standardSizeEntries) / sizeof(standardSizeEntries[0]);
+ PixmapEntryList result;
+ for (size_t m = 0; m < modeEntryCount; ++m) {
+ const unsigned modeFlags = baseFlags | modeEntries[m].flags;
+ QString modePrefix = QLatin1String("_shell_");
+ if (modeEntries[m].name[0])
+ modePrefix += QLatin1String(modeEntries[m].name) + QLatin1Char('_');
+ for (size_t s = 0; s < standardSizeEntryCount; ++s) {
+ const unsigned flags = modeFlags | standardSizeEntries[s].flags;
+ const QString prefix = modePrefix + QLatin1String(standardSizeEntries[s].name)
+ + QLatin1Char('_');
+ ZeroMemory(&info, sizeof(SHFILEINFO));
+ const HRESULT hr = SHGetFileInfo(sourceFileC, 0, &info, sizeof(SHFILEINFO), flags);
+ if (FAILED(hr)) {
+ _com_error error(hr);
+ std::wcerr << "SHGetFileInfo() failed for \"" << nativeName << "\", "
+ << std::hex << std::showbase << flags << std::dec << std::noshowbase
+ << " (" << prefix << "): " << error.ErrorMessage() << '\n';
+ continue;
+ }
+
+ if (info.hIcon) {
+ PixmapEntry entry;
+ entry.pixmap = QtWin::fromHICON(info.hIcon);
+ DestroyIcon(info.hIcon);
+ if (entry.pixmap.isNull()) {
+ std::wcerr << "Error converting icons.\n";
+ return PixmapEntryList();
+ }
+ entry.name = prefix + formatSize(entry.pixmap.size());
+
+ const int iconIndex = info.iIcon & 0xFFFFFF;
+ const int overlayIconIndex = info.iIcon >> 24;
+
+ std::wcout << "Obtained icon #" << iconIndex;
+ if (addOverlays)
+ std::wcout << " (overlay #" << overlayIconIndex << ')';
+ if (info.szDisplayName[0])
+ std::wcout << " from " << QString::fromWCharArray(info.szDisplayName);
+ std::wcout << " (" << entry.pixmap.width() << 'x'
+ << entry.pixmap.height() << ") for " << std::hex << std::showbase << flags
+ << std::dec << std::noshowbase << '\n';
+
+ result.append(entry);
+ }
+ } // for standardSizeEntryCount
+ // Windows Vista onwards: extract large/jumbo icons
+ if (QSysInfo::windowsVersion() >= QSysInfo::WV_VISTA && info.hIcon) {
+ const QPixmap extraLarge = pixmapFromShellImageList(sHIL_EXTRALARGE, info);
+ if (!extraLarge.isNull()) {
+ PixmapEntry entry;
+ entry.pixmap = extraLarge;
+ entry.name = modePrefix + QLatin1String("xl_") + formatSize(extraLarge.size());
+ result.append(entry);
+ }
+ const QPixmap jumbo = pixmapFromShellImageList(sHIL_JUMBO, info);
+ if (!jumbo.isNull()) {
+ PixmapEntry entry;
+ entry.pixmap = jumbo;
+ entry.name = modePrefix + QLatin1String("jumbo_") + formatSize(extraLarge.size());
+ result.append(entry);
+ }
}
- const QString fileName = QString::fromLatin1("%1%2.png").arg(imageFileRoot)
- .arg(i, 3, 10, QLatin1Char('0'));
- if (!pixmap.save(fileName)) {
- std::cerr << "Error writing image file " << fileName.toStdString() << ".\n";
+ } // for modes
+ return result;
+}
+
+static const char description[] =
+ "\nExtracts Windows icons from executables, DLL or icon files and writes them\n"
+ "out as numbered .png-files.\n"
+ "When passing the --shell option, the icons displayed by Explorer are extracted.\n";
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+ QCoreApplication::setApplicationName("Icon Extractor");
+ QCoreApplication::setOrganizationName("QtProject");
+ QCoreApplication::setApplicationVersion(QT_VERSION_STR);
+ QCommandLineParser parser;
+ parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsCompactedShortOptions);
+ parser.setApplicationDescription(QLatin1String(description));
+ parser.addHelpOption();
+ parser.addVersionOption();
+ const QCommandLineOption largeIconOption("large", "Extract large icons");
+ parser.addOption(largeIconOption);
+ const QCommandLineOption shellIconOption("shell", "Extract shell icons using SHGetFileInfo()");
+ parser.addOption(shellIconOption);
+ const QCommandLineOption shellOverlayOption("overlay", "Extract shell overlay icons");
+ parser.addOption(shellOverlayOption);
+ parser.addPositionalArgument("file", "The file to open.");
+ parser.addPositionalArgument("image file folder", "The folder to store the images.");
+ parser.process(app);
+ const QStringList &positionalArguments = parser.positionalArguments();
+ if (positionalArguments.isEmpty())
+ parser.showHelp(0);
+
+ QString imageFileRoot = positionalArguments.size() > 1 ? positionalArguments.at(1) : QDir::currentPath();
+ const QFileInfo imageFileRootInfo(imageFileRoot);
+ if (!imageFileRootInfo.isDir()) {
+ std::wcerr << imageFileRoot << " is not a directory.\n";
+ return 1;
+ }
+ const QString &sourceFile = positionalArguments.constFirst();
+ imageFileRoot = imageFileRootInfo.absoluteFilePath() + QLatin1Char('/') + QFileInfo(sourceFile).baseName();
+
+ const PixmapEntryList pixmaps = parser.isSet(shellIconOption)
+ ? extractShellIcons(sourceFile, parser.isSet(shellOverlayOption))
+ : extractIcons(sourceFile, parser.isSet(largeIconOption));
+
+ for (int i = 0, count = pixmaps.size(); i < count; ++i) {
+ const QString fileName = imageFileRoot + pixmaps.at(i).name + QLatin1String(".png");
+ if (!pixmaps.at(i).pixmap.save(fileName)) {
+ std::wcerr << "Error writing image file " << fileName << ".\n";
return 1;
}
- std::cout << "Wrote image file "
- << QDir::toNativeSeparators(fileName).toStdString() << ".\n";
+ std::wcout << "Wrote " << QDir::toNativeSeparators(fileName) << ".\n";
}
return 0;
}