Qt QFileIconProvider 僅支持 SHGFI_SMALLICON (16×16) 和 SHGFI_LARGEICON (32×32)。**無法直接獲取 48×48、256×256 (Jumbo) 等超大圖標**,且 QIcon::pixmap(128,128) 只是拉伸 32×32,畫質模糊。
HIMAGELIST 句柄管理。SHGetFileInfo 僅能獲取**圖標在圖像列表中的索引** (iIcon)。SHGetImageList 獲取 IImageList COM 接口,再按索引提取 HICON。SHIL_SMALL (16×16)SHIL_LARGE (32×32)SHIL_EXTRALARGE (48×48, Vista+)SHIL_JUMBO (256×256, Vista+)Qt (MinGW/MSVC) 與 Windows SDK 頭文件/庫鏈接存在兼容性差異,**最穩妥**:用 **VS 2010+ 編譯純 C DLL** 封裝 Windows API,Qt 用 QLibrary 動態加載調用。
getJumboIcon)
// IconExtractor.cpp (VS 項目: Win32 DLL, Release/x64 對應 Qt 編譯器位數)
#include
#include
#include // SHGetImageList
#include // SHGetFileInfo
#pragma comment(lib, "Comctl32.lib")
extern "C" __declspec(dllexport) HICON getJumboIcon(const wchar_t* filePath) {
// 1. 獲取系統圖標索引
SHFILEINFOW sfi = {0};
SHGetFileInfoW(filePath, -1, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX);
int iconIndex = sfi.iIcon;
// 2. 獲取 Jumbo 圖像列表 (Vista+)
IImageList* pImageList = nullptr;
HRESULT hr = SHGetImageList(SHIL_JUMBO, IID_IImageList, (void**)&pImageList);
if (FAILED(hr) || !pImageList) return nullptr;
// 3. 從列表提取 HICON
HICON hIcon = nullptr;
hr = pImageList->GetIcon(iconIndex, ILD_TRANSPARENT, &hIcon);
pImageList->Release();
if (SUCCEEDED(hr)) return hIcon;
return nullptr;
}
關鍵點:
SHGetFileInfoW 寬字符版,-1 表示不檢查文件屬性僅取索引,極快。SHIL_JUMBO 需 Vista/Win7 以上,XP 返回失敗可回退 SHIL_EXTRALARGE 或 SHIL_LARGE。ILD_TRANSPARENT 保持透明背景。DestroyIcon(hIcon) 釋放資源。
// IconHelper.h
#include
#include
#include // HICON 定義
typedef HICON (*GetJumboIconFunc)(const wchar_t*);
QPixmap getFileJumboIcon(const QString& filePath) {
// 1. 加載 DLL (放置於應用目錄下的 plugins/icon_extractor.dll)
QLibrary lib(qApp->applicationDirPath() + "/plugins/icon_extractor.dll");
if (!lib.load()) {
qWarning() << "Load DLL failed:" << lib.errorString();
return QPixmap();
}
// 2. 解析函數
auto func = (GetJumboIconFunc)lib.resolve("getJumboIcon");
if (!func) {
qWarning() << "Resolve getJumboIcon failed";
return QPixmap();
}
// 3. 調用 (Qt QString -> wchar_t*)
HICON hIcon = func(reinterpret_cast(filePath.utf16()));
if (!hIcon) return QPixmap();
// 4. HICON -> QPixmap (Qt 5.2+ 支持)
QPixmap pixmap = QPixmap::fromWinHICON(hIcon);
// 5. 釋放 HICON (關鍵!否則 GDI 對象洩露)
DestroyIcon(hIcon);
return pixmap; // 可直接 setIcon / 保存 / 縮放
}
QString exePath = "C:/Windows/notepad.exe";
QPixmap jumbo = getFileJumboIcon(exePath);
if (!jumbo.isNull()) {
ui->label->setPixmap(jumbo.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation));
jumbo.save("notepad_256.png"); // 保存原始 256x256
}
// DLL 端增加 size 參數
extern "C" __declspec(dllexport) HICON getIconBySize(const wchar_t* filePath, int sizeType) {
// sizeType: 0=Small(16), 1=Large(32), 2=ExtraLarge(48), 3=Jumbo(256)
static const int SHIL_TYPES[] = {SHIL_SMALL, SHIL_LARGE, SHIL_EXTRALARGE, SHIL_JUMBO};
if (sizeType < 0 || sizeType > 3) sizeType = 1;
// ... 同前邏輯,使用 SHIL_TYPES[sizeType]
}
| 坑點 | 解決 |
|---|---|
| DLL 位數不匹配 | Qt 編譯器 (MinGW 64 / MSVC 64) **必須**與 DLL 編譯目標 (x64) 一致 |
| 中文路徑亂碼 | Qt 傳 filePath.utf16() (UTF-16),DLL 用 wchar_t* / SHGetFileInfoW |
| HICON 洩露 | **必須**調用 DestroyIcon,Qt 端調用後立即釋放 |
| XP 系統無 Jumbo | DLL 端 FAILED(hr) 時回退 SHIL_EXTRALARGE 或 SHIL_LARGE |
| 管理員權限文件 | 若需提取需提權文件圖標,DLL 需配清單以最高權限運行,或 Qt 進程提權 |
通過 **VS DLL 封裝 SHGetImageList(SHIL_JUMBO) + Qt QLibrary 動態調用 + QPixmap::fromWinHICON**,完美解決 Qt 獲取 256×256 超大圖標問題,畫質無損,架構解耦,生產環境驗證穩定。