windows 如何将 HICON 保存到 .ico 文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2289894/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I save HICON to an .ico file?
提问by MichaelY
I am extracting an icon from .exe/.dll and want to save it in an .ico file. What is the best way to do this?
我正在从 .exe/.dll 中提取一个图标,并希望将其保存在一个 .ico 文件中。做这个的最好方式是什么?
I have tried to use ::OleCreatePictureIndirect()
and then IPicture->SaveAsFile()
. It works but transparent parts of the icon are painted black (and obviously are not transparent any more :( ).
我曾尝试使用::OleCreatePictureIndirect()
然后IPicture->SaveAsFile()
. 它可以工作,但图标的透明部分被涂成黑色(显然不再透明:()。
I tried manual parsing. It works OK but is cumbersome and I am afraid of complications with Vista icons/.icl files/etc.
我试过手动解析。它工作正常,但很麻烦,我担心 Vista 图标/.icl 文件/等会出现并发症。
Please, help. Thanks.
请帮忙。谢谢。
回答by Hans Passant
You can save HICON
s with the IPicture::SaveAsFile()
method. Here's a sample C++ program that uses it:
您可以HICON
使用该IPicture::SaveAsFile()
方法保存s 。这是一个使用它的示例 C++ 程序:
#include "stdafx.h"
#include <windows.h>
#include <olectl.h>
#pragma comment(lib, "oleaut32.lib")
HRESULT SaveIcon(HICON hIcon, const wchar_t* path) {
// Create the IPicture intrface
PICTDESC desc = { sizeof(PICTDESC) };
desc.picType = PICTYPE_ICON;
desc.icon.hicon = hIcon;
IPicture* pPicture = 0;
HRESULT hr = OleCreatePictureIndirect(&desc, IID_IPicture, FALSE, (void**)&pPicture);
if (FAILED(hr)) return hr;
// Create a stream and save the image
IStream* pStream = 0;
CreateStreamOnHGlobal(0, TRUE, &pStream);
LONG cbSize = 0;
hr = pPicture->SaveAsFile(pStream, TRUE, &cbSize);
// Write the stream content to the file
if (!FAILED(hr)) {
HGLOBAL hBuf = 0;
GetHGlobalFromStream(pStream, &hBuf);
void* buffer = GlobalLock(hBuf);
HANDLE hFile = CreateFile(path, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (!hFile) hr = HRESULT_FROM_WIN32(GetLastError());
else {
DWORD written = 0;
WriteFile(hFile, buffer, cbSize, &written, 0);
CloseHandle(hFile);
}
GlobalUnlock(buffer);
}
// Cleanup
pStream->Release();
pPicture->Release();
return hr;
}
int _tmain(int argc, _TCHAR* argv[])
{
HICON hIcon = (HICON)LoadImage(0, L"c:\windows\system32\perfcentercpl.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
if (!hIcon) return GetLastError();
HRESULT hr = SaveIcon(hIcon, L"c:\temp\test.ico");
return hr;
}
回答by Lukas Koblovsky
This code handles transparency correctly.
此代码正确处理透明度。
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
//
// ICONS (.ICO type 1) are structured like this:
//
// ICONHEADER (just 1)
// ICONDIR [1...n] (an array, 1 for each image)
// [BITMAPINFOHEADER+COLOR_BITS+MASK_BITS] [1...n] (1 after the other, for each image)
//
// CURSORS (.ICO type 2) are identical in structure, but use
// two monochrome bitmaps (real XOR and AND masks, this time).
//
typedef struct
{
WORD idReserved; // must be 0
WORD idType; // 1 = ICON, 2 = CURSOR
WORD idCount; // number of images (and ICONDIRs)
// ICONDIR [1...n]
// ICONIMAGE [1...n]
} ICONHEADER;
//
// An array of ICONDIRs immediately follow the ICONHEADER
//
typedef struct
{
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes; // for cursors, this field = wXHotSpot
WORD wBitCount; // for cursors, this field = wYHotSpot
DWORD dwBytesInRes;
DWORD dwImageOffset; // file-offset to the start of ICONIMAGE
} ICONDIR;
//
// After the ICONDIRs follow the ICONIMAGE structures -
// consisting of a BITMAPINFOHEADER, (optional) RGBQUAD array, then
// the color and mask bitmap bits (all packed together
//
typedef struct
{
BITMAPINFOHEADER biHeader; // header for color bitmap (no mask header)
//RGBQUAD rgbColors[1...n];
//BYTE bXOR[1]; // DIB bits for color bitmap
//BYTE bAND[1]; // DIB bits for mask bitmap
} ICONIMAGE;
//
// Write the ICO header to disk
//
static UINT WriteIconHeader(HANDLE hFile, int nImages)
{
ICONHEADER iconheader;
DWORD nWritten;
// Setup the icon header
iconheader.idReserved = 0; // Must be 0
iconheader.idType = 1; // Type 1 = ICON (type 2 = CURSOR)
iconheader.idCount = nImages; // number of ICONDIRs
// Write the header to disk
WriteFile( hFile, &iconheader, sizeof(iconheader), &nWritten, 0);
// following ICONHEADER is a series of ICONDIR structures (idCount of them, in fact)
return nWritten;
}
//
// Return the number of BYTES the bitmap will take ON DISK
//
static UINT NumBitmapBytes(BITMAP *pBitmap)
{
int nWidthBytes = pBitmap->bmWidthBytes;
// bitmap scanlines MUST be a multiple of 4 bytes when stored
// inside a bitmap resource, so round up if necessary
if(nWidthBytes & 3)
nWidthBytes = (nWidthBytes + 4) & ~3;
return nWidthBytes * pBitmap->bmHeight;
}
//
// Return number of bytes written
//
static UINT WriteIconImageHeader(HANDLE hFile, BITMAP *pbmpColor, BITMAP *pbmpMask)
{
BITMAPINFOHEADER biHeader;
DWORD nWritten;
UINT nImageBytes;
// calculate how much space the COLOR and MASK bitmaps take
nImageBytes = NumBitmapBytes(pbmpColor) + NumBitmapBytes(pbmpMask);
// write the ICONIMAGE to disk (first the BITMAPINFOHEADER)
ZeroMemory(&biHeader, sizeof(biHeader));
// Fill in only those fields that are necessary
biHeader.biSize = sizeof(biHeader);
biHeader.biWidth = pbmpColor->bmWidth;
biHeader.biHeight = pbmpColor->bmHeight * 2; // height of color+mono
biHeader.biPlanes = pbmpColor->bmPlanes;
biHeader.biBitCount = pbmpColor->bmBitsPixel;
biHeader.biSizeImage = nImageBytes;
// write the BITMAPINFOHEADER
WriteFile(hFile, &biHeader, sizeof(biHeader), &nWritten, 0);
// write the RGBQUAD color table (for 16 and 256 colour icons)
if(pbmpColor->bmBitsPixel == 2 || pbmpColor->bmBitsPixel == 8)
{
}
return nWritten;
}
//
// Wrapper around GetIconInfo and GetObject(BITMAP)
//
static BOOL GetIconBitmapInfo(HICON hIcon, ICONINFO *pIconInfo, BITMAP *pbmpColor, BITMAP *pbmpMask)
{
if(!GetIconInfo(hIcon, pIconInfo))
return FALSE;
if(!GetObject(pIconInfo->hbmColor, sizeof(BITMAP), pbmpColor))
return FALSE;
if(!GetObject(pIconInfo->hbmMask, sizeof(BITMAP), pbmpMask))
return FALSE;
return TRUE;
}
//
// Write one icon directory entry - specify the index of the image
//
static UINT WriteIconDirectoryEntry(HANDLE hFile, int nIdx, HICON hIcon, UINT nImageOffset)
{
ICONINFO iconInfo;
ICONDIR iconDir;
BITMAP bmpColor;
BITMAP bmpMask;
DWORD nWritten;
UINT nColorCount;
UINT nImageBytes;
GetIconBitmapInfo(hIcon, &iconInfo, &bmpColor, &bmpMask);
nImageBytes = NumBitmapBytes(&bmpColor) + NumBitmapBytes(&bmpMask);
if(bmpColor.bmBitsPixel >= 8)
nColorCount = 0;
else
nColorCount = 1 << (bmpColor.bmBitsPixel * bmpColor.bmPlanes);
// Create the ICONDIR structure
iconDir.bWidth = (BYTE)bmpColor.bmWidth;
iconDir.bHeight = (BYTE)bmpColor.bmHeight;
iconDir.bColorCount = nColorCount;
iconDir.bReserved = 0;
iconDir.wPlanes = bmpColor.bmPlanes;
iconDir.wBitCount = bmpColor.bmBitsPixel;
iconDir.dwBytesInRes = sizeof(BITMAPINFOHEADER) + nImageBytes;
iconDir.dwImageOffset = nImageOffset;
// Write to disk
WriteFile(hFile, &iconDir, sizeof(iconDir), &nWritten, 0);
// Free resources
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
return nWritten;
}
static UINT WriteIconData(HANDLE hFile, HBITMAP hBitmap)
{
BITMAP bmp;
int i;
BYTE * pIconData;
UINT nBitmapBytes;
DWORD nWritten;
GetObject(hBitmap, sizeof(BITMAP), &bmp);
nBitmapBytes = NumBitmapBytes(&bmp);
pIconData = (BYTE *)malloc(nBitmapBytes);
GetBitmapBits(hBitmap, nBitmapBytes, pIconData);
// bitmaps are stored inverted (vertically) when on disk..
// so write out each line in turn, starting at the bottom + working
// towards the top of the bitmap. Also, the bitmaps are stored in packed
// in memory - scanlines are NOT 32bit aligned, just 1-after-the-other
for(i = bmp.bmHeight - 1; i >= 0; i--)
{
// Write the bitmap scanline
WriteFile(
hFile,
pIconData + (i * bmp.bmWidthBytes), // calculate offset to the line
bmp.bmWidthBytes, // 1 line of BYTES
&nWritten,
0);
// extend to a 32bit boundary (in the file) if necessary
if(bmp.bmWidthBytes & 3)
{
DWORD padding = 0;
WriteFile(hFile, &padding, 4 - bmp.bmWidthBytes, &nWritten, 0);
}
}
free(pIconData);
return nBitmapBytes;
}
//
// Create a .ICO file, using the specified array of HICON images
//
BOOL SaveIcon3(TCHAR *szIconFile, HICON hIcon[], int nNumIcons)
{
HANDLE hFile;
int i;
int * pImageOffset;
if(hIcon == 0 || nNumIcons < 1)
return FALSE;
// Save icon to disk:
hFile = CreateFile(szIconFile, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if(hFile == INVALID_HANDLE_VALUE)
return FALSE;
//
// Write the iconheader first of all
//
WriteIconHeader(hFile, nNumIcons);
//
// Leave space for the IconDir entries
//
SetFilePointer(hFile, sizeof(ICONDIR) * nNumIcons, 0, FILE_CURRENT);
pImageOffset = (int *)malloc(nNumIcons * sizeof(int));
//
// Now write the actual icon images!
//
for(i = 0; i < nNumIcons; i++)
{
ICONINFO iconInfo;
BITMAP bmpColor, bmpMask;
GetIconBitmapInfo(hIcon[i], &iconInfo, &bmpColor, &bmpMask);
// record the file-offset of the icon image for when we write the icon directories
pImageOffset[i] = SetFilePointer(hFile, 0, 0, FILE_CURRENT);
// bitmapinfoheader + colortable
WriteIconImageHeader(hFile, &bmpColor, &bmpMask);
// color and mask bitmaps
WriteIconData(hFile, iconInfo.hbmColor);
WriteIconData(hFile, iconInfo.hbmMask);
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
}
//
// Lastly, skip back and write the icon directories.
//
SetFilePointer(hFile, sizeof(ICONHEADER), 0, FILE_BEGIN);
for(i = 0; i < nNumIcons; i++)
{
WriteIconDirectoryEntry(hFile, i, hIcon[i], pImageOffset[i]);
}
free(pImageOffset);
// finished!
CloseHandle(hFile);
return TRUE;
}
int saveIcon(TCHAR* filename, TCHAR* iconFile) {
HICON hIconLarge;
HICON hIconSmall;
BOOL ret;
if ( ExtractIconEx(filename, 0, &hIconLarge, &hIconSmall, 1) == 0 ) {
return 1;
}
ret = SaveIcon3(iconFile, &hIconSmall, 1);
if ( ret ) {
return 0;
}
return -1;
}
int _tmain(int argc, TCHAR* argv[]) {
if ( argc < 3 ) {
printf("Usage: <exe/dll file> <output ico file>");
return EXIT_FAILURE;
}
_tprintf(_T("src = %s\n"), argv[1]);
_tprintf(_T("dest = %s\n"), argv[2]);
saveIcon(argv[1], argv[2]);
return 0;
}
回答by Lukas Koblovsky
I had the same problem and therefore I wrote a function to save icons from an HICON handle to a ICO file. The SaveIcon()
function shown below support colors depths of 4, 8, 24, and 32 bits. The PNG icon format is not supported.
我遇到了同样的问题,因此我编写了一个函数来将图标从 HICON 句柄保存到 ICO 文件。下面SaveIcon()
显示的函数支持 4、8、24 和 32 位的颜色深度。不支持 PNG 图标格式。
The function works by constructing the ICO file directly. Fortunately, this is not too difficult, because the ICO format is almost identical to the BMP file format; furthermore, the BMP file format is almost identical to the in-memory representation returned by GetDIBits()
.
该函数通过直接构建 ICO 文件来工作。幸运的是,这并不太难,因为ICO格式与BMP文件格式几乎相同;此外,BMP 文件格式几乎与GetDIBits()
.
Here is the SaveIcon()
function, together with a small test function (_tmain
):
这是SaveIcon()
函数,以及一个小的测试函数 ( _tmain
):
#include <afx.h>
#include <afxwin.h>
#include <atlbase.h>
struct ICONDIRENTRY
{
UCHAR nWidth;
UCHAR nHeight;
UCHAR nNumColorsInPalette; // 0 if no palette
UCHAR nReserved; // should be 0
WORD nNumColorPlanes; // 0 or 1
WORD nBitsPerPixel;
ULONG nDataLength; // length in bytes
ULONG nOffset; // offset of BMP or PNG data from beginning of file
};
// Helper class to release GDI object handle when scope ends:
class CGdiHandle
{
public:
CGdiHandle(HGDIOBJ handle) : m_handle(handle) {};
~CGdiHandle(){DeleteObject(m_handle);};
private:
HGDIOBJ m_handle;
};
// Save icon referenced by handle 'hIcon' as file with name 'szPath'.
// The generated ICO file has the color depth specified in 'nColorBits'.
//
bool SaveIcon(HICON hIcon, int nColorBits, const TCHAR* szPath)
{
ASSERT(nColorBits == 4 || nColorBits == 8 || nColorBits == 24 || nColorBits == 32);
if (offsetof(ICONDIRENTRY, nOffset) != 12)
{
return false;
}
CDC dc;
dc.Attach(::GetDC(NULL)); // ensure that DC is released when function ends
// Open file for writing:
CFile file;
if (!file.Open(szPath, CFile::modeWrite | CFile::modeCreate))
{
return false;
}
// Write header:
UCHAR icoHeader[6] = {0, 0, 1, 0, 1, 0}; // ICO file with 1 image
file.Write(icoHeader, sizeof(icoHeader));
// Get information about icon:
ICONINFO iconInfo;
GetIconInfo(hIcon, &iconInfo);
CGdiHandle handle1(iconInfo.hbmColor), handle2(iconInfo.hbmMask); // free bitmaps when function ends
BITMAPINFO bmInfo = {0};
bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmInfo.bmiHeader.biBitCount = 0; // don't get the color table
if (!GetDIBits(dc, iconInfo.hbmColor, 0, 0, NULL, &bmInfo, DIB_RGB_COLORS))
{
return false;
}
// Allocate size of bitmap info header plus space for color table:
int nBmInfoSize = sizeof(BITMAPINFOHEADER);
if (nColorBits < 24)
{
nBmInfoSize += sizeof(RGBQUAD) * (int)(1 << nColorBits);
}
CAutoVectorPtr<UCHAR> bitmapInfo;
bitmapInfo.Allocate(nBmInfoSize);
BITMAPINFO* pBmInfo = (BITMAPINFO*)(UCHAR*)bitmapInfo;
memcpy(pBmInfo, &bmInfo, sizeof(BITMAPINFOHEADER));
// Get bitmap data:
ASSERT(bmInfo.bmiHeader.biSizeImage != 0);
CAutoVectorPtr<UCHAR> bits;
bits.Allocate(bmInfo.bmiHeader.biSizeImage);
pBmInfo->bmiHeader.biBitCount = nColorBits;
pBmInfo->bmiHeader.biCompression = BI_RGB;
if (!GetDIBits(dc, iconInfo.hbmColor, 0, bmInfo.bmiHeader.biHeight, (UCHAR*)bits, pBmInfo, DIB_RGB_COLORS))
{
return false;
}
// Get mask data:
BITMAPINFO maskInfo = {0};
maskInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
maskInfo.bmiHeader.biBitCount = 0; // don't get the color table
if (!GetDIBits(dc, iconInfo.hbmMask, 0, 0, NULL, &maskInfo, DIB_RGB_COLORS))
{
return false;
}
ASSERT(maskInfo.bmiHeader.biBitCount == 1);
CAutoVectorPtr<UCHAR> maskBits;
maskBits.Allocate(maskInfo.bmiHeader.biSizeImage);
CAutoVectorPtr<UCHAR> maskInfoBytes;
maskInfoBytes.Allocate(sizeof(BITMAPINFO) + 2 * sizeof(RGBQUAD));
BITMAPINFO* pMaskInfo = (BITMAPINFO*)(UCHAR*)maskInfoBytes;
memcpy(pMaskInfo, &maskInfo, sizeof(maskInfo));
if (!GetDIBits(dc, iconInfo.hbmMask, 0, maskInfo.bmiHeader.biHeight, (UCHAR*)maskBits, pMaskInfo, DIB_RGB_COLORS))
{
return false;
}
// Write directory entry:
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);
file.Write(&dir, sizeof(dir));
// Write DIB header (including color table):
int nBitsSize = pBmInfo->bmiHeader.biSizeImage;
pBmInfo->bmiHeader.biHeight *= 2; // because the header is for both image and mask
pBmInfo->bmiHeader.biCompression = 0;
pBmInfo->bmiHeader.biSizeImage += pMaskInfo->bmiHeader.biSizeImage; // because the header is for both image and mask
file.Write(&pBmInfo->bmiHeader, nBmInfoSize);
// Write image data:
file.Write((UCHAR*)bits, nBitsSize);
// Write mask data:
file.Write((UCHAR*)maskBits, pMaskInfo->bmiHeader.biSizeImage);
file.Close();
return true;
}
// Test program for SaveIcon() function.
//
// Usage: first argument is input ICO file (must be 32x32 pixels); second argument is output ICO file
//
int _tmain(int argc, _TCHAR* argv[])
{
ASSERT(argc == 3);
// Load a 32x32 icon:
HICON hIcon = (HICON)LoadImage(0, argv[1], IMAGE_ICON, 32, 32, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
ASSERT(hIcon != NULL);
// Save with 24-bits colors:
if (!SaveIcon(hIcon, 24, argv[2]))
{
_ftprintf(stderr, _T("Error: saving icon to %s failed"), argv[2]);
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
回答by HelllRow Stas
a lot of thanks to user128300. I used his snipet and made some minor changes to get rid of MFC/atx/atl libraries dependency (also it fixes problem with Windows.h that SMUsamaShah mentioned). And i redirected output to vector buffer, but preserved optinal output to a file:
非常感谢 user128300。我使用了他的 snipet 并做了一些小改动来摆脱 MFC/atx/atl 库的依赖(它还解决了 SMUsamaShah 提到的 Windows.h 的问题)。我将输出重定向到向量缓冲区,但将可选输出保留到文件中:
#include <Windows.h>
#include <shellapi.h>
struct ICONDIRENTRY
{
UCHAR nWidth;
UCHAR nHeight;
UCHAR nNumColorsInPalette; // 0 if no palette
UCHAR nReserved; // should be 0
WORD nNumColorPlanes; // 0 or 1
WORD nBitsPerPixel;
ULONG nDataLength; // length in bytes
ULONG nOffset; // offset of BMP or PNG data from beginning of file
};
#define WRITE_ICO_TO_FILE
bool GetIconData(HICON hIcon, int nColorBits, std::vector<char> &buff)
{
if (offsetof(ICONDIRENTRY, nOffset) != 12)
{
return false;
}
HDC dc = CreateCompatibleDC(NULL);
#ifdef WRITE_ICO_TO_FILE
CFile file;
if (!file.Open(L"S:\icotest.ico", CFile::modeWrite | CFile::modeCreate))
{
return false;
}
#endif
// Write header:
char icoHeader[6] = { 0, 0, 1, 0, 1, 0 }; // ICO file with 1 image
#ifdef WRITE_ICO_TO_FILE
file.Write(icoHeader, sizeof(icoHeader));
#endif
buff.insert(buff.end(), reinterpret_cast<const char *>(icoHeader), reinterpret_cast<const char *>(icoHeader) + sizeof(icoHeader));
// Get information about icon:
ICONINFO iconInfo;
GetIconInfo(hIcon, &iconInfo);
BITMAPINFO bmInfo = { 0 };
bmInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmInfo.bmiHeader.biBitCount = 0; // don't get the color table
if (!GetDIBits(dc, iconInfo.hbmColor, 0, 0, NULL, &bmInfo, DIB_RGB_COLORS))
{
return false;
}
// Allocate size of bitmap info header plus space for color table:
int nBmInfoSize = sizeof(BITMAPINFOHEADER);
if (nColorBits < 24)
{
nBmInfoSize += sizeof(RGBQUAD) * (int)(1 << nColorBits);
}
std::vector<UCHAR> bitmapInfo;
bitmapInfo.resize(nBmInfoSize);
BITMAPINFO* pBmInfo = (BITMAPINFO *)bitmapInfo.data();
memcpy(pBmInfo, &bmInfo, sizeof(BITMAPINFOHEADER));
// Get bitmap data:
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;
}
// Get mask data:
BITMAPINFO maskInfo = { 0 };
maskInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
maskInfo.bmiHeader.biBitCount = 0; // don't get the color table
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;
}
// Write directory entry:
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);
#ifdef WRITE_ICO_TO_FILE
file.Write(&dir, sizeof(dir));
#endif
buff.insert(buff.end(), reinterpret_cast<const char *>(&dir), reinterpret_cast<const char *>(&dir) + sizeof(dir));
// Write DIB header (including color table):
int nBitsSize = pBmInfo->bmiHeader.biSizeImage;
pBmInfo->bmiHeader.biHeight *= 2; // because the header is for both image and mask
pBmInfo->bmiHeader.biCompression = 0;
pBmInfo->bmiHeader.biSizeImage += pMaskInfo->bmiHeader.biSizeImage; // because the header is for both image and mask
#ifdef WRITE_ICO_TO_FILE
file.Write(&pBmInfo->bmiHeader, nBmInfoSize);
#endif
buff.insert(buff.end(), reinterpret_cast<const char *>(&pBmInfo->bmiHeader), reinterpret_cast<const char *>(&pBmInfo->bmiHeader) + nBmInfoSize);
// Write image data:
#ifdef WRITE_ICO_TO_FILE
file.Write((UCHAR*)bits, nBitsSize);
#endif
buff.insert(buff.end(), reinterpret_cast<const char *>(bits.data()), reinterpret_cast<const char *>(bits.data()) + nBitsSize);
// Write mask data:
#ifdef WRITE_ICO_TO_FILE
file.Write((UCHAR*)maskBits, pMaskInfo->bmiHeader.biSizeImage);
#endif
buff.insert(buff.end(), reinterpret_cast<const char *>(maskBits.data()), reinterpret_cast<const char *>(maskBits.data()) + pMaskInfo->bmiHeader.biSizeImage);
#ifdef WRITE_ICO_TO_FILE
file.Close();
#endif
DeleteObject(iconInfo.hbmColor);
DeleteObject(iconInfo.hbmMask);
DeleteDC(dc);
return true;
}