Last active
July 19, 2022 06:17
-
-
Save Far-Se/14d7010964cf96875b9fe9c7e230158b to your computer and use it in GitHub Desktop.
Winapi Convert icon to png with transparency. Extract hicon from dll and store it as uint8 including hbmColor and hbmMask
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Windows.h> | |
#include <shellapi.h> | |
#include <iostream> | |
#include <fstream> | |
#include <vector> | |
using namespace std; | |
HICON getIconFromFile(wstring file, int index = 0) | |
{ | |
HICON hIcon; | |
LPWSTR filePath = const_cast<LPTSTR>(file.c_str()); | |
if (file.find(L".dll") != std::string::npos) | |
{ | |
ExtractIconEx(filePath, index, &hIcon, NULL, 1); | |
} | |
else | |
{ | |
HINSTANCE instance = GetModuleHandle(NULL); | |
WORD iconID = 0; | |
hIcon = ExtractAssociatedIcon(instance, filePath, &iconID); | |
} | |
return hIcon; | |
} | |
struct ICONDIRENTRY | |
{ | |
UCHAR nWidth; | |
UCHAR nHeight; | |
UCHAR nNumColorsInPalette; | |
UCHAR nReserved; | |
WORD nNumColorPlanes; | |
WORD nBitsPerPixel; | |
ULONG nDataLength; | |
ULONG nOffset; | |
}; | |
bool GetIconData(HICON hIcon, int nColorBits, std::vector<char> &buff) | |
{ | |
if (offsetof(ICONDIRENTRY, nOffset) != 12) | |
{ | |
return false; | |
} | |
HDC dc = CreateCompatibleDC(NULL); | |
char icoHeader[6] = {0, 0, 1, 0, 1, 0}; | |
buff.insert(buff.end(), reinterpret_cast<const char *>(icoHeader), reinterpret_cast<const char *>(icoHeader) + sizeof(icoHeader)); | |
ICONINFO iconInfo; | |
GetIconInfo(hIcon, &iconInfo); | |
BITMAPINFO bmInfo = {0}; | |
bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
bmInfo.bmiHeader.biBitCount = 0; | |
if (!GetDIBits(dc, iconInfo.hbmColor, 0, 0, NULL, &bmInfo, DIB_RGB_COLORS)) | |
{ | |
return false; | |
} | |
int nBmInfoSize = sizeof(BITMAPINFOHEADER); | |
if (nColorBits < 24) | |
{ | |
nBmInfoSize += sizeof(RGBQUAD) * (int)(static_cast<unsigned long long>(1) << nColorBits); | |
} | |
std::vector<UCHAR> bitmapInfo; | |
bitmapInfo.resize(nBmInfoSize); | |
BITMAPINFO *pBmInfo = (BITMAPINFO *)bitmapInfo.data(); | |
memcpy(pBmInfo, &bmInfo, sizeof(BITMAPINFOHEADER)); | |
if (!bmInfo.bmiHeader.biSizeImage) | |
return false; | |
std::vector<UCHAR> bits; | |
bits.resize(bmInfo.bmiHeader.biSizeImage); | |
pBmInfo->bmiHeader.biBitCount = nColorBits; | |
pBmInfo->bmiHeader.biCompression = BI_RGB; | |
if (!GetDIBits(dc, iconInfo.hbmColor, 0, bmInfo.bmiHeader.biHeight, bits.data(), pBmInfo, DIB_RGB_COLORS)) | |
{ | |
return false; | |
} | |
BITMAPINFO maskInfo = {0}; | |
maskInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); | |
maskInfo.bmiHeader.biBitCount = 0; | |
if (!GetDIBits(dc, iconInfo.hbmMask, 0, 0, NULL, &maskInfo, DIB_RGB_COLORS) || maskInfo.bmiHeader.biBitCount != 1) | |
return false; | |
std::vector<UCHAR> maskBits; | |
maskBits.resize(maskInfo.bmiHeader.biSizeImage); | |
std::vector<UCHAR> maskInfoBytes; | |
maskInfoBytes.resize(sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD)); | |
BITMAPINFO *pMaskInfo = (BITMAPINFO *)maskInfoBytes.data(); | |
memcpy(pMaskInfo, &maskInfo, sizeof(maskInfo)); | |
if (!GetDIBits(dc, iconInfo.hbmMask, 0, maskInfo.bmiHeader.biHeight, maskBits.data(), pMaskInfo, DIB_RGB_COLORS)) | |
{ | |
return false; | |
} | |
ICONDIRENTRY dir; | |
dir.nWidth = (UCHAR)pBmInfo->bmiHeader.biWidth; | |
dir.nHeight = (UCHAR)pBmInfo->bmiHeader.biHeight; | |
dir.nNumColorsInPalette = (nColorBits == 4 ? 16 : 0); | |
dir.nReserved = 0; | |
dir.nNumColorPlanes = 0; | |
dir.nBitsPerPixel = pBmInfo->bmiHeader.biBitCount; | |
dir.nDataLength = pBmInfo->bmiHeader.biSizeImage + pMaskInfo->bmiHeader.biSizeImage + nBmInfoSize; | |
dir.nOffset = sizeof(dir) + sizeof(icoHeader); | |
buff.insert(buff.end(), reinterpret_cast<const char *>(&dir), reinterpret_cast<const char *>(&dir) + sizeof(dir)); | |
int nBitsSize = pBmInfo->bmiHeader.biSizeImage; | |
pBmInfo->bmiHeader.biHeight *= 2; | |
pBmInfo->bmiHeader.biCompression = 0; | |
pBmInfo->bmiHeader.biSizeImage += pMaskInfo->bmiHeader.biSizeImage; | |
buff.insert(buff.end(), reinterpret_cast<const char *>(&pBmInfo->bmiHeader), reinterpret_cast<const char *>(&pBmInfo->bmiHeader) + nBmInfoSize); | |
buff.insert(buff.end(), reinterpret_cast<const char *>(bits.data()), reinterpret_cast<const char *>(bits.data()) + nBitsSize); | |
buff.insert(buff.end(), reinterpret_cast<const char *>(maskBits.data()), reinterpret_cast<const char *>(maskBits.data()) + pMaskInfo->bmiHeader.biSizeImage); | |
DeleteObject(iconInfo.hbmColor); | |
DeleteObject(iconInfo.hbmMask); | |
DeleteDC(dc); | |
return true; | |
} | |
int main() | |
{ | |
// HICON icon = getIconFromFile(L"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", 0); | |
HICON icon = getIconFromFile(L"C:\\Windows\\system32\\mmres.dll", 12); | |
std::vector<CHAR> buff; | |
bool result = GetIconData(icon, 32, buff); | |
if (!result) | |
{ | |
buff.clear(); | |
result = GetIconData(icon, 24, buff); | |
} | |
// convert buff to uint8_t | |
std::vector<uint8_t> buff_uint8; | |
for (auto i : buff) | |
{ | |
buff_uint8.push_back(i); | |
} | |
std::remove("E:\\test.png"); | |
std::ofstream file("E:\\test.png", std::ios::binary); | |
file.write(buff.data(), buff.size()); | |
file.close(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment