File indexing completed on 2024-04-28 04:58:03
0001 /* 0002 icoutils_win.cpp - Extract Microsoft Window icons and images using icoutils package 0003 0004 SPDX-FileCopyrightText: 2013 Andrius da Costa Ribas <andriusmao@gmail.com> 0005 0006 SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #include "icoutils.h" 0010 0011 #include <windows.h> 0012 0013 #include <QBuffer> 0014 #include <QDir> 0015 #include <QFile> 0016 #include <QList> 0017 0018 extern "C" { 0019 // icon structs, as per https://msdn.microsoft.com/en-us/library/ms997538.aspx 0020 #pragma pack(push) 0021 #pragma pack(2) 0022 typedef struct { 0023 BYTE bWidth; // Width, in pixels, of the image 0024 BYTE bHeight; // Height, in pixels, of the image 0025 BYTE bColorCount; // Number of colors in image (0 if >=8bpp) 0026 BYTE bReserved; // Reserved ( must be 0) 0027 WORD wPlanes; // Color Planes 0028 WORD wBitCount; // Bits per pixel 0029 DWORD dwBytesInRes; // How many bytes in this resource? 0030 DWORD dwImageOffset; // Where in the file is this image? 0031 } ICONDIRENTRY, *LPICONDIRENTRY; 0032 0033 typedef struct { 0034 WORD idReserved; // Reserved (must be 0) 0035 WORD idType; // Resource Type (1 for icons) 0036 WORD idCount; // How many images? 0037 ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of 'em) 0038 } ICONDIR, *LPICONDIR; 0039 0040 typedef struct { 0041 BYTE bWidth; // Width, in pixels, of the image 0042 BYTE bHeight; // Height, in pixels, of the image 0043 BYTE bColorCount; // Number of colors in image (0 if >=8bpp) 0044 BYTE bReserved; // Reserved 0045 WORD wPlanes; // Color Planes 0046 WORD wBitCount; // Bits per pixel 0047 DWORD dwBytesInRes; // how many bytes in this resource? 0048 WORD nID; // the ID 0049 } GRPICONDIRENTRY, *LPGRPICONDIRENTRY; 0050 0051 typedef struct { 0052 WORD idReserved; // Reserved (must be 0) 0053 WORD idType; // Resource type (1 for icons) 0054 WORD idCount; // How many images? 0055 GRPICONDIRENTRY idEntries[1]; // The entries for each image 0056 } GRPICONDIR, *LPGRPICONDIR; 0057 #pragma pack(pop) 0058 } 0059 0060 BOOL CALLBACK enumResNameCallback(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam) 0061 { 0062 QList<LPTSTR> *iconResources = (QList<LPTSTR> *)lParam; 0063 LPTSTR copyString; 0064 if (IS_INTRESOURCE(lpszName)) { 0065 copyString = lpszName; 0066 } else { 0067 copyString = new WCHAR[lstrlen(lpszName) + 1]; 0068 lstrcpy(copyString, lpszName); 0069 } 0070 0071 if (lpszType == RT_GROUP_ICON) { 0072 (*iconResources) << copyString; 0073 } 0074 return TRUE; 0075 } 0076 0077 bool IcoUtils::loadIcoImageFromExe(const QString &inputFileName, QIODevice *outputDevice) 0078 { 0079 HMODULE hModule; 0080 LPCTSTR fileName; 0081 QList<LPTSTR> iconResources; 0082 0083 fileName = (TCHAR *)QDir::toNativeSeparators(inputFileName).utf16(); 0084 0085 hModule = LoadLibraryEx(fileName, 0, LOAD_LIBRARY_AS_DATAFILE); 0086 0087 if (!hModule) { 0088 return false; 0089 } 0090 0091 EnumResourceNames(hModule, RT_GROUP_ICON, enumResNameCallback, (LONG_PTR)&iconResources); 0092 0093 if (!iconResources.isEmpty()) { 0094 HRSRC resourceInfo = FindResourceW(hModule, (LPCTSTR)iconResources.at(0), RT_GROUP_ICON); 0095 if (resourceInfo == 0) { 0096 FreeLibrary(hModule); 0097 return false; 0098 } 0099 0100 // we can get rid of the iconResources list now 0101 for (LPTSTR iconRes : qAsConst(iconResources)) { 0102 if (!IS_INTRESOURCE(iconRes)) { 0103 delete[] iconRes; 0104 } 0105 } 0106 0107 HGLOBAL resourceData = LoadResource(hModule, resourceInfo); 0108 LPVOID resourcePointer = LockResource(resourceData); 0109 int resourceSize = SizeofResource(hModule, resourceInfo); 0110 if (resourceSize == 0) { 0111 FreeLibrary(hModule); 0112 return false; 0113 } 0114 0115 LPGRPICONDIR grpIconDir = (LPGRPICONDIR)resourcePointer; 0116 0117 QBuffer outBuffer; 0118 outBuffer.open(QIODevice::ReadWrite); 0119 0120 // helper 0121 const int iconDirHeaderSize = sizeof(grpIconDir->idReserved) + sizeof(grpIconDir->idType) + sizeof(grpIconDir->idCount); 0122 0123 // copy the common part of GRPICONDIR and ICONDIR structures to the file 0124 outBuffer.write((char *)resourcePointer, iconDirHeaderSize); 0125 0126 DWORD imageOffset = iconDirHeaderSize + (grpIconDir->idCount) * sizeof(ICONDIRENTRY); 0127 0128 for (int i = 0; i < (grpIconDir->idCount); ++i) { 0129 // copy the common part of GRPICONDIRENTRY and ICONDIRENTRY structures to the respective ICONDIRENTRY's position 0130 LPGRPICONDIRENTRY grpIconDirEntry = &(grpIconDir->idEntries[i]); 0131 outBuffer.seek(iconDirHeaderSize + i * sizeof(ICONDIRENTRY)); 0132 outBuffer.write((char *)grpIconDirEntry, sizeof(GRPICONDIRENTRY) - sizeof(grpIconDirEntry->nID)); 0133 0134 // now, instead of nID, write the image offset 0135 outBuffer.write((char *)&imageOffset, sizeof(DWORD)); 0136 0137 // find the icon resource 0138 resourceInfo = FindResourceW(hModule, MAKEINTRESOURCE(grpIconDirEntry->nID), RT_ICON); 0139 if (resourceInfo == 0) { 0140 FreeLibrary(hModule); 0141 return false; 0142 } 0143 resourceData = LoadResource(hModule, resourceInfo); 0144 resourcePointer = LockResource(resourceData); 0145 resourceSize = SizeofResource(hModule, resourceInfo); 0146 if (resourceSize == 0) { 0147 FreeLibrary(hModule); 0148 return false; 0149 } 0150 0151 // seek to imageOffset 0152 outBuffer.seek(imageOffset); 0153 // write the icon data 0154 outBuffer.write((char *)resourcePointer, resourceSize); 0155 // increment imageOffset 0156 imageOffset += resourceSize; 0157 } 0158 0159 const bool ok = (outputDevice->write(outBuffer.data()) == outBuffer.size()); 0160 0161 FreeLibrary(hModule); 0162 return ok; 0163 } 0164 0165 FreeLibrary(hModule); 0166 return false; 0167 }