简述
在 Windows 中,文件查看有很多模式,比如:
- 缩略图 16*16
- 平铺 48*48
- 图标 32*32
- 列表 16*16
分别对应了多个不同大小的图标。
如果我们要从指定的可执行文件(exe)、动态链接库(dll)、或者图标文件中提取图标,可以使用 ExtractIconEx、ExtractIcon。
说明
函数 | 描述 |
---|---|
ExtractIcon() | 从一个文件中提取指定索引位置的图标,索引从 0 开始。这个函数总是返回大图标(32 x 32)。 |
ExtractIconEx() | 与 ExtractIcon() 相同,但可以提取大图标(32 x 32)和小图标(16 x 16)。 |
ExtractIconEx() 函数原型:
UINT EXtractlcohEX (
LPCTSTR IpSZFile, // 可执行文件、DLL、或图标文件
int nlconlndex, // 抽取第一个图标基于零的变址
HICON FAR*PhiCORLarge, // 大图标
HICON FAR'*phiconSmall, // 小图标
UINT nlcons // 从文件中抽取图标的数目
);
效果
依赖
在 pro中,添加:
QT += winextras
LIBS += -lshell32
这样,就可以使用 QtWin 将 HICON 转换为 QPixmap 了。
源码
头文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QtWin>
class QLineEdit;
class QPushButton;
class QListWidget;
class QTextEdit;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private slots:
void onSourceSelected();
void onSaveSelected();
void onExtract();
private:
QLineEdit *m_pSourceLineEdit;
QLineEdit *m_pSaveLineEdit;
QListWidget *m_pListWidget;
QTextEdit *m_pTextEdit;
QPushButton *m_pSourceButton;
QPushButton *m_pSaveButton;
QPushButton *m_pExtractButton;
};
#endif // WIDGET_H
源文件:
#include "widget.h"
#include <QLineEdit>
#include <QListWidget>
#include <QPushButton>
#include <QTextEdit>
#include <QFileDialog>
#include <QScopedArrayPointer>
#include <QPixmap>
#include <QFileInfo>
#include <QDir>
#include <QLayout>
#include <qDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
setWindowTitle(QStringLiteral("Qt之提取exe/dll/icon文件图标"));
resize(400, 400);
m_pSourceLineEdit = new QLineEdit(this);
m_pSaveLineEdit = new QLineEdit(this);
m_pListWidget = new QListWidget(this);
m_pTextEdit = new QTextEdit(this);
m_pSourceButton = new QPushButton(this);
m_pSaveButton = new QPushButton(this);
m_pExtractButton = new QPushButton(this);
m_pSourceLineEdit->setReadOnly(true);
m_pSaveLineEdit->setReadOnly(true);
m_pTextEdit->setReadOnly(true);
m_pSourceButton->setText(QStringLiteral("源文件"));
m_pSaveButton->setText(QStringLiteral("保存路径"));
m_pExtractButton->setText(QStringLiteral("提取"));
QGridLayout *pLayout = new QGridLayout(this);
pLayout->addWidget(m_pSourceLineEdit, 0, 0);
pLayout->addWidget(m_pSourceButton, 0, 1);
pLayout->addWidget(m_pSaveLineEdit, 1, 0);
pLayout->addWidget(m_pSaveButton, 1, 1);
pLayout->addWidget(m_pListWidget, 2, 0, 1, 2);
pLayout->addWidget(m_pTextEdit, 3, 0, 1, 2);
pLayout->addWidget(m_pExtractButton, 4, 1);
pLayout->setSpacing(10);
pLayout->setMargin(10);
m_pListWidget->setViewMode(QListWidget::IconMode );
m_pListWidget->setResizeMode(QListWidget::Adjust);
m_pListWidget->setMovement(QListWidget::Static);
connect(m_pSourceButton, &QPushButton::clicked, this, &Widget::onSourceSelected);
connect(m_pSaveButton, &QPushButton::clicked, this, &Widget::onSaveSelected);
connect(m_pExtractButton, &QPushButton::clicked, this, &Widget::onExtract);
}
Widget::~Widget()
{
}
// 设置源文件路径
void Widget::onSourceSelected()
{
QString fileName = QFileDialog::getOpenFileName(this, QString("Open File"),
"/home",
QString("All files (*.*);;DLL files (*.exe *.dll);;Images (*.png *.xpm *.jpg)"));
if (!fileName.isEmpty())
m_pSourceLineEdit->setText(fileName);
}
// 设置保存路径
void Widget::onSaveSelected()
{
QString dir = QFileDialog::getExistingDirectory(this, QString("Open Directory"),
"/home",
QFileDialog::ShowDirsOnly
| QFileDialog::DontResolveSymlinks);
if (!dir.isEmpty())
m_pSaveLineEdit->setText(dir);
}
// 提取
void Widget::onExtract()
{
// 删除之前的 item
int count = m_pListWidget->count();
for(int i = 0 ; i < count; ++i) {
QListWidgetItem *item = m_pListWidget->takeItem(0);
delete item;
}
m_pTextEdit->clear();
const QString sourceFile = m_pSourceLineEdit->text();
const QString fileRoot = m_pSaveLineEdit->text();
QString imageFileRoot = fileRoot.isEmpty() ? QDir::currentPath() : fileRoot;
const QFileInfo imageFileRootInfo(imageFileRoot);
// ExtractIconEx 从限定的可执行文件、动态链接库(DLL)、或者图标文件中生成图标句柄数组
const UINT iconCount = ExtractIconEx((wchar_t *)sourceFile.utf16(), -1, 0, 0, 0);
if (!iconCount) {
qDebug() << QString("%1 does not appear to contain icons.").arg(sourceFile);
return;
}
QScopedArrayPointer<HICON> icons(new HICON[iconCount]);
bool large = true;
const UINT extractedIconCount = large ?
ExtractIconEx((wchar_t *)sourceFile.utf16(), 0, icons.data(), 0, iconCount) :
ExtractIconEx((wchar_t *)sourceFile.utf16(), 0, 0, icons.data(), iconCount);
if (!extractedIconCount) {
m_pTextEdit->append(QStringLiteral("从 %1 提取图标失败").arg(sourceFile));
return;
}
m_pTextEdit->append(QString("%1 包含 %2 个图标").arg(sourceFile).arg(extractedIconCount));
imageFileRoot = imageFileRootInfo.absoluteFilePath() + QLatin1Char('/') + QFileInfo(sourceFile).baseName();
for (UINT i = 0; i < extractedIconCount; ++i) {
const QPixmap pixmap = QtWin::fromHICON(icons[i]);
if (pixmap.isNull()) {
m_pTextEdit->append(QStringLiteral("图标转换错误"));
continue;
}
// 添加新 item
QListWidgetItem *pItem = new QListWidgetItem(m_pListWidget);
pItem->setText(QString("%1 * %2").arg(pixmap.height()).arg(pixmap.width()));
pItem->setIcon(QIcon(pixmap));
m_pListWidget->addItem(pItem);
// 保存图片
const QString fileName = QString::fromLatin1("%1%2.png").arg(imageFileRoot)
.arg(i, 3, 10, QLatin1Char('0'));
if (!pixmap.save(fileName)) {
m_pTextEdit->append(QStringLiteral("写入图像文件 %1 错误").arg(fileName));
continue;
}
m_pTextEdit->append(QStringLiteral("保存图片文件 %1.").arg(QDir::toNativeSeparators(fileName)));
}
}
注意: large 表示大图标(32 * 32)如果要提取小图标(16 * 16),将 large 设置为 false 即可。