Vista la demanda para guardar correctamente un Icono dado por su Handle (HICON) desde delphi, publico una implementación en delphi:
Estructuras necesarias:
Código Delphi
[-]
{$ALIGN 1}
type TICONDIRENTRY = record
bWidth: BYTE; bHeight: BYTE; bColorCount: BYTE; bReserved: BYTE; wPlanes: WORD; wBitCount: WORD; dwBytesInRes: DWORD; dwImageOffset: DWORD; end; PICONDIRENTRY = ^TICONDIRENTRY;
type TICONDIR = record
idReserved: WORD; idType: WORD; idCount: WORD; idEntries: array[0..0] of TICONDIRENTRY; end; PICONDIR = ^TICONDIR;
type tagICONIMAGE= record
icHeader: BITMAPINFOHEADER; icColors: array[0..0] of RGBQUAD; icXORarray: array[0..0] of BYTE; icANDarray: array[0..0] of BYTE; end; PICONIMAGE = ^tagICONIMAGE;
{$ALIGN OFF}
La primera función auxiliar,
NColors, consigue el número de colores según el valor de
BitCountPerPixel. Observar que para valores de 24 y 32 el resultado es cero:
Código Delphi
[-]function NColors(bitCount: WORD): integer;
begin
Result:= -1;
if (bitCount = 1) or (bitCount = 4) or (bitCount = 8) then
Result:= 1 shl bitCount
else if (bitCount >= 24) then
Result:= 0;
end;
Ahora la función
hIconToMem que se encargará de conseguir una imagen en memoria de un fichero.ico a partir de un Handle HICON. El código está lo suficientemente comentado:
Código Delphi
[-]function hIconToMem(hIcon: Thandle; BitCountPerPixel: integer; var Size: integer): Pointer;
var
hDC: Thandle;
IconInfo: TICONINFO;
bmpAND, bmpXOR: BITMAP;
FileIconMem: Pointer;
RawDataSizeAND, RawDataSizeXOR, RawDataSize, PalSize, AllSize, Width, Height: integer;
IconDir: PICONDIR;
bmiAND: BITMAPINFO;
bmiICON: PBITMAPINFO;
lpBitsXOR, lpBitsAND: Pointer;
IconImage: PICONIMAGE;
begin
hDC:= GetDC(0); ZeroMemory(@bmpAND, sizeof(BITMAP));
ZeroMemory(@bmpXOR, sizeof(BITMAP));
GetIconInfo(hIcon, IconInfo);
GetObject(IconInfo.hbmMask, sizeof(BITMAP), @bmpAND);
GetObject(IconInfo.hbmColor, sizeof(BITMAP), @bmpXOR);
if(BitCountPerPixel=0) then BitCountPerPixel:= bmpXOR.bmPlanes*bmpXOR.bmBitsPixel;
RawDataSizeAND:= ((((bmpAND.bmWidth*bmpAND.bmBitsPixel)+31) and not 31) shr 3)*bmpAND.bmHeight;
RawDataSizeXOR:= ((((bmpXOR.bmWidth*BitCountPerPixel)+31) and not 31) shr 3)*bmpXOR.bmHeight;
RawDataSize:= RawDataSizeAND + RawDataSizeXOR;
PalSize:=0; if(BitCountPerPixel<=8) then PalSize:= (1 shl BitCountPerPixel) shl 2; AllSize:= sizeof(TICONDIR)+sizeof(BITMAPINFOHEADER)+PalSize+RawDataSizeAND+RawDataSizeXOR;
Width := bmpAND.bmWidth;
Height := bmpAND.bmHeight;
FileIconMem:= VirtualAlloc(0, AllSize, MEM_COMMIT, PAGE_READWRITE);
IconDir:= PICONDIR(FileIconMem);
bmiICON:= PBITMAPINFO(DWORD(FileIconMem) + sizeof(TICONDIR));
lpBitsXOR:= PBITMAPINFO(DWORD(FileIconMem) + sizeof(TICONDIR) + sizeof(BITMAPINFOHEADER) + PalSize);
lpBitsAND:= PBITMAPINFO(DWORD(lpBitsXOR) + RawDataSizeXOR);
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; IconDir.idEntries[0].wBitCount:= 0; IconDir.idEntries[0].dwBytesInRes:= AllSize-sizeof(TICONDIR); IconDir.idEntries[0].dwImageOffset:= sizeof(TICONDIR); IconImage:= PICONIMAGE(bmiICON);
ZeroMemory(IconImage, 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;
CopyMemory(@bmiAND, bmiICON, sizeof(BITMAPINFOHEADER));
bmiAND.bmiHeader.biSizeImage:= RawDataSizeAND;
bmiAND.bmiHeader.biBitCount:= 1;
bmiAND.bmiHeader.biClrUsed:= 1;
bmiAND.bmiHeader.biClrImportant:= 1;
GetDIBits(hDC, IconInfo.hbmColor, 0, Height, lpBitsXOR, bmiICON^, DIB_RGB_COLORS);
GetDIBits(hDC, IconInfo.hbmMask, 0, Height, lpBitsAND, bmiAND, DIB_RGB_COLORS);
IconImage.icHeader.biHeight:= Height*2;
Size:= AllSize;
Result:= FileIconMem;
end;
Un ejemplo para guardar en un archivo nuestro icono dado por su Handle:
Código Delphi
[-]function HIconToFile(hIcon: THandle; FileName: String): Boolean;
var
FileIconMem: Pointer;
Size: integer;
hFile: Cardinal;
begin
Result:= false;
FileIconMem:= hIconToMem(hIcon, 32, Size);
hFile := CreateFile(PCHAR(FileName), GENERIC_WRITE, 0, nil, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0);
if(_lwrite(hFile, FileIconMem, Size) = Size) then
Result:= true;
CloseHandle(hFile);
VirtualFree(FileIconMem, 0, MEM_RELEASE);
end;
Más información
aquí.
Saludos.