Ver Mensaje Individual
  #4  
Antiguo 21-11-2008
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.210
Reputación: 22
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Cita:
Empezado por cHackAll Ver Mensaje
Tenía planeado responder (despues de entender lo que querias y averiguar como conseguirlo ), pero como en algun lugar del ciber-espacio comenté mi PC quedo en estado de coma y pues lo olvide por completo... ésto no es una escusa ni disculpa pero creo que el echo que no aparente "importar" no deberia ser un motivo para no compartir tus conocimientos con la comunidad y las "nuevas generaciones" de desarrollo.

Saludos
Nadie debe disculparse por no responder, ni nadie tiene que darse por ofendido por no obtener respuesta. No es este mi caso. Si comenté falta de interés sobre el tema, no fue por las respuestas sino por las lecturas, 11 hasta ese momento. Entiendo, además, que es un tema demasiado específico y sin demasiada utilidad.

En cualquier caso, pensando en que tienes razón, y sin ánimo de no compartir, siempre lejos de mi intención, publico mi humilde código, siempre mejorable. Pero el post va a ser un poco largo.....

Me di cuenta que un archivo.ico tiene una cabecera de al menos 22 bytes, al compararlo con lo obtenido al leer un icono del recurso de un .exe o .dll. Despreciándolos se llega a un código funcional pero no universal, pues un .ico puede albergar mas de un icono, y en ese caso la cabecera es mas grande. La información necesaria está aquí.

Y ahora un poco de código:

Por si el tema de las definiciones de las cabeceras no queda claro, publico cómo lo he usado. Archivo Iconos.h
Código:
#ifndef iconosH
#define iconosH
//---------------------------------------------------------------------------
// Tomado de http://msdn.microsoft.com/en-us/library/ms997538.aspx 
// Modificado del original. 

// Necesario para alinear a Word el compilador
#pragma pack( push )
#pragma pack( 2 )

// These first two structs represent how the icon information is stored
// when it is bound into a EXE or DLL file. Structure members are WORD
// aligned and the last member of the structure is the ID instead of
// the imageoffset.

typedef struct
{
    BYTE    bWidth;               // Width of the image
    BYTE    bHeight;              // Height of the image (times 2)
    BYTE    bColorCount;          // Number of colors in image (0 if >=8bpp)
    BYTE    bReserved;            // Reserved
    WORD    wPlanes;              // Color Planes
    WORD    wBitCount;            // Bits per pixel
    DWORD    dwBytesInRes;         // how many bytes in this resource?
    WORD    nID;                  // the ID
} MEMICONDIRENTRY, *LPMEMICONDIRENTRY, GRPICONDIRENTRY, *LPGRPICONDIRENTRY;

typedef struct
{
    WORD            idReserved;   // Reserved
    WORD            idType;       // resource type (1 for icons)
    WORD            idCount;      // how many images?
    MEMICONDIRENTRY    idEntries[1]; // the entries for each image
} MEMICONDIR, *LPMEMICONDIR, GRPICONDIR, *LPGRPICONDIR;


// These next two structs represent how the icon information is stored
// in an ICO file.
typedef struct
{
    BYTE    bWidth;               // Width of the image
    BYTE    bHeight;              // Height of the image (times 2)
    BYTE    bColorCount;          // Number of colors in image (0 if >=8bpp)
    BYTE    bReserved;            // Reserved
    WORD    wPlanes;              // Color Planes
    WORD    wBitCount;            // Bits per pixel
    DWORD    dwBytesInRes;         // how many bytes in this resource?
    DWORD    dwImageOffset;        // where in the file is this image
} ICONDIRENTRY, *LPICONDIRENTRY;

typedef struct
{
    WORD             idReserved;   // Reserved
    WORD             idType;       // resource type (1 for icons)
    WORD             idCount;      // how many images?
    ICONDIRENTRY idEntries[1]; // the entries for each image
} ICONDIR, *LPICONDIR;

#pragma pack( pop )

//---------------------------------------------------------------------------
#endif
Función CambiaIcono:
Código:
bool CambiaIcono(char *FuenteICO, char *DestinoExe, char* ResName, bool BorraIconResPrevio=false)
{
   HANDLE hFile;
   LPBYTE lpBuffer;
   LPBYTE lpResLock;
   bool Result = true;

   if(!FuenteICO || !*FuenteICO) return false;
   if(!DestinoExe || !*DestinoExe) return false;
   if(!ResName || !*ResName) return false;
   
   // Abrimos el icono.ico en modo de lectura binaria
   DWORD dwFileSize, dwBytesRead;

   hFile = CreateFile(FuenteICO, GENERIC_READ, 0, NULL, OPEN_EXISTING,
                   FILE_ATTRIBUTE_NORMAL, NULL);

   if (INVALID_HANDLE_VALUE != hFile){
       dwFileSize = GetFileSize(hFile, NULL);
       lpBuffer = new BYTE[dwFileSize];
       ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL);
       CloseHandle(hFile);
   }

   // Convierto el Buffer a formato Icono con cabeceras...
   ICONDIR *IconDir = (ICONDIR*)lpBuffer;
   // Crea espacio para las cabeceras del icono recurso
   int HeaderSize = sizeof(GRPICONDIR)+(sizeof(GRPICONDIRENTRY)*(IconDir->idCount-1));
   BYTE *HeaderIconRec = new BYTE[HeaderSize];
   GRPICONDIR *grpIconDir = (GRPICONDIR*)HeaderIconRec;
   // Copio la cabecera común con IconDir
   memcpy(grpIconDir, IconDir, sizeof(GRPICONDIR)-sizeof(GRPICONDIRENTRY));

   // Abrimos el recurso del exe
   HANDLE hUpdateRes = BeginUpdateResource(DestinoExe, BorraIconResPrevio);
   for(int n=0; n<grpIconDir->idCount; n++){
     // Copio las cabeceras
     memcpy(&grpIconDir->idEntries[n], &IconDir->idEntries[n], sizeof(GRPICONDIRENTRY));
     grpIconDir->idEntries[n].nID = n + 100;
     // Localizo la imagen del icono a pasar al .exe
     BYTE *IconImage = (BYTE*)IconDir + IconDir->idEntries[n].dwImageOffset;
     lpResLock = (BYTE*)LockResource(IconImage);
     // Abrir el fichero donde añadir el icono.
     if (hUpdateRes != NULL){
       // Actualizar el resource destino
       Result &= UpdateResource(hUpdateRes,
         RT_ICON,
         MAKEINTRESOURCE(grpIconDir->idEntries[n].nID),
         MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
         lpResLock,
         IconDir->idEntries[n].dwBytesInRes);
     }
   }

   // Y la grabamos comp "indice" o cabecera de grupo de iconos
   Result &= UpdateResource(hUpdateRes, RT_GROUP_ICON,
        ResName,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
        grpIconDir, HeaderSize);

   // Escribir los cambios y cerrar.
   EndUpdateResource(hUpdateRes, FALSE);

   delete lpBuffer;
   delete HeaderIconRec;

   return Result;
}
El código añade un icono al ejecutable que queramos, o puede sustituir los iconos del mismo por el nuestro.

Otra forma de hacerlo puede ser mapeando en memoria un HICON utilizando las mismas estructuras y las API GetIconInfo y GetDIBits. Claro que si es engorroso utilizar GetDIBits, siempre se puede hechar mano de las VCL:

Código:
TIcon Icon = new TIcon;
Icon->Handle = hIcon;    // el HICON a convertir
TMemoryStream  *Stream = new TMemoryStream;
Icon->SaveToStream(Stream);  // Stream->Memory sería el buffer a usar
// Convierto el Buffer a formato Icono con cabeceras...
ICONDIR *IconDir = (ICONDIR*)Stream->Memory;
La desventaja de este cómodo método es que sólo es satisfactorio para iconos de 16 colores, si tiene mas se reducen, al menos en BCB 5 y 6. Me imagino que en delphi 5 y 6 pasará lo mismo. Creo que las versiones de 2008 no tienen este problema. De forma que puede merecer la pena desarollar la idea del mapeo en memoria de un HICON. Yo, de momento no he tenido tiempo de hacerlo.

Bueno no me extiendo mas, y espero, como señala cHackAll, que sirva de ayuda o ejemplo de partida.

Saludos.

Última edición por escafandra fecha: 21-11-2008 a las 23:19:11.
Responder Con Cita