Bueno, en el post anterior comentaba la forma de conseguir incluir en un ejecutable o dll un nuevo icono como un recurso. Comentaba también ciertas limitaciones del Builder y el delphi, en ediciones algo antiguas, para el manejo de los colores de un icono pasado por su Handle HICON. Hice refencia a la posibilidad de mapear el HICON en memoria.
Aquí dejo un ejemplo de como pasar un HICON a memoria, en este caso un bloque con el formato del archivo del icono.ico que puede ser volcado al disco como un .ico.
Nos sirve también para crear un recurso en un ejecutable o dll. Para esto temdremos que pasar, como en el post anterior, un puntero al ICONIMAGE para así poder crear el recurso.
El archivo de definiciones es el mismo que en el post anterior.
El código:
Código:
# include "Iconos.h"
//---------------------------------------------------------------------------
long
NColors(WORD bitCount)
{
if (bitCount == 1 || bitCount == 4 || bitCount == 8)
return 1 << bitCount;
else if (bitCount >= 24)
return 0;
return -1;
}
//---------------------------------------------------------------------------
void* hIconToMem(HICON hIcon, int BitCountPerPixel, int* Size)
{
// Localizo la información del icono y su tamaño en un fichero.ico
HDC hDC = ::GetDC(NULL); // ScreenDC
ICONINFO IconInfo;
BITMAP bmpAND={0};
BITMAP bmpXOR={0};
bool I = GetIconInfo(hIcon, &IconInfo);
GetObject(IconInfo.hbmMask, sizeof(BITMAP), &bmpAND);
GetObject(IconInfo.hbmColor, sizeof(BITMAP), &bmpXOR);
if(BitCountPerPixel==0) BitCountPerPixel=bmpXOR.bmPlanes*bmpXOR.bmBitsPixel;
int RawDataSizeAND=((((bmpAND.bmWidth*bmpAND.bmBitsPixel)+31) & ~31) >> 3)*bmpAND.bmHeight;
int RawDataSizeXOR=((((bmpXOR.bmWidth*BitCountPerPixel)+31) & ~31) >> 3)*bmpXOR.bmHeight;
int RawDataSize = RawDataSizeAND + RawDataSizeXOR;
int PalSize=(BitCountPerPixel>8 ? 0 :1 << BitCountPerPixel)<<2; // RGBQUAD 4
int AllSize= sizeof(ICONDIR)+sizeof(BITMAPINFOHEADER)+PalSize+RawDataSizeAND+RawDataSizeXOR;
int Width = bmpAND.bmWidth;
int Height = bmpAND.bmHeight;
// Reservo memoria para el fichero
BYTE* FileIconMem = (BYTE*)VirtualAlloc(0, AllSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
ICONDIR* IconDir = (ICONDIR*)FileIconMem;
// Obtengo los Bits de cada parte Mask y Color
BITMAPINFO bmiAND;
BITMAPINFO *bmiICON = (BITMAPINFO*)(FileIconMem + sizeof(ICONDIR));
LPVOID lpBitsXOR = (BITMAPINFO*)(FileIconMem + sizeof(ICONDIR) + sizeof(BITMAPINFOHEADER) + PalSize);
LPVOID lpBitsAND = (BITMAPINFO*)((BYTE*)lpBitsXOR + RawDataSizeXOR);
// Preparo la cabecera del Icon
IconDir->idReserved = 0;
IconDir->idType = 1;
IconDir->idCount = 1;
IconDir->idEntries[0].bWidth = Width;
IconDir->idEntries[0].bHeight = Height;
IconDir->idEntries[0].bColorCount = NColors(BitCountPerPixel);
IconDir->idEntries[0].bReserved = 0;
IconDir->idEntries[0].wPlanes = 0; // Color Planes
IconDir->idEntries[0].wBitCount = 0;//BitCountPerPixel; // Bits per pixel
IconDir->idEntries[0].dwBytesInRes = AllSize-sizeof(ICONDIR); // How many bytes in this resource?
IconDir->idEntries[0].dwImageOffset = sizeof(ICONDIR); // Where in the file is this image?
LPICONIMAGE IconImage = (LPICONIMAGE)(bmiICON);
memset(IconImage, 0, sizeof(BITMAPINFOHEADER));
IconImage->icHeader.biSize = sizeof(BITMAPINFOHEADER);
IconImage->icHeader.biWidth = Width;
IconImage->icHeader.biHeight = Height;
IconImage->icHeader.biPlanes = 1;
IconImage->icHeader.biBitCount = BitCountPerPixel;
IconImage->icHeader.biSizeImage = RawDataSize;
// Preparo BITMAPINFOHEADER para la Mascara (bmiAND)
memcpy(&bmiAND, bmiICON, sizeof(BITMAPINFOHEADER));
bmiAND.bmiHeader.biSizeImage = RawDataSizeAND;
bmiAND.bmiHeader.biBitCount = 1;
bmiAND.bmiHeader.biClrUsed = 1;
bmiAND.bmiHeader.biClrImportant = 1;
// Recupero los bits de cada hBitmap del icono
GetDIBits(hDC, IconInfo.hbmColor, 0, Height, lpBitsXOR, bmiICON, DIB_RGB_COLORS);
GetDIBits(hDC, IconInfo.hbmMask, 0, Height, lpBitsAND, &bmiAND, DIB_RGB_COLORS);
// Sumo las dos alturas de ambos bitmaps del icono
IconImage->icHeader.biHeight = Height*2;
ReleaseDC(0, hDC);
// Salida
*Size = AllSize;
return FileIconMem;
}
Un ejemplo de uso y para ver como funciona:
Código:
TIcon *Icon = new TIcon;
Icon->LoadFromFile("MI_ICONO.ICO");
// Convertimos el HICON a imagen en memoria del .ico
int Size;
void* FileIconMem = hIconToMem(Icon->Handle, 32, &Size);
HANDLE hFile=CreateFile("FilePath.ico", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
DWORD dwWritten;
WriteFile(hFile, FileIconMem, Size, &dwWritten, 0);
CloseHandle(hFile);
VirtualFree(FileIconMem, 0, MEM_RELEASE);
// Lo recuperamos para ver que ha pasado
Icon->LoadFromFile("FilePath.ico");
Image1->Picture->Icon->Assign(Icon);
Sirva esto para animar a indagar en los entresijos gráficos de windows...
Saludos.