Ver Mensaje Individual
  #8  
Antiguo 23-12-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
Continúo con la extracción de iconos de la sección de recursos de un ejecutable.

GetFileMemIconFromModule está diseñada para extraer un grupo de imágenes del recurso en un buffer que pueda ser escrito directamente a un archivo.ico. El formato es un buffer con una cabecera ICONDIR, sus entradas a las imágenes y éstas mismas. Un archivo de este tipo, a diferencia con la sección de recursos de un ejecutable, sólo tiene un grupo de iconos definido en su cabecera, aunque lo habitual es que, ese grupo sólo tenga una imagen, nada impide que tenga muchas más de diferente resolución y número de colores.

Código:
//------------------------------------------------------------------------------
// Devuelve en Buffer Una imagen de archivo.ico para poder guardar en disco.
// Devuelve el tamaño de la memoria de archivo de un Icono de un hModule
// Retorna 0 si falla, 1 si Buffer==0 y AllSize si devuelve el valor en Buffer.
// Si Buffer = NULL, devuelve en Size el tamaño necesario para el buffer
// Id: Indice del Grupo de iconos como si fuese una array comenzando por 0
int GetFileMemIconFromModule(HMODULE hModule, int Id, void* Buffer, int *Size)
{
    LPICONDIR IconDir;
    LPICONDIRENTRY IconEntry;
    LPICONIMAGE  resIconImage;
    LPGRPICONDIR grpIconDir;
    HRSRC hRes;        // handle para res. info. del ejecutable
    int IconsCount = 0;
    int AllSize = sizeof(ICONDIR)-sizeof(ICONDIRENTRY);
    DWORD ImageOffset;

    // Cuento cuantos iconos tiene el recurso y la memoria necesaria
    hRes = FindResource(hModule, Id, RT_GROUP_ICON);
    if(hRes){
       grpIconDir = (LPGRPICONDIR)LoadResource(hModule, hRes);
       IconsCount = grpIconDir->idCount;
       for(int n=0; n<IconsCount; n++)
         AllSize += sizeof(ICONDIRENTRY) + grpIconDir->idEntries[n].dwBytesInRes;
    }

    if(IconsCount==0){
      *Size = 0;
      return 0;
    }
    if(Buffer == 0 ){
      *Size = AllSize;
      return 1;
    }
    if(*Size < AllSize) return 0;

    // Preparo la Cabecera General grpIconDir
    setmem(Buffer, 0, AllSize);
    IconDir  = (LPICONDIR)Buffer;
    IconDir->idReserved = 0;
    IconDir->idType = 1;
    IconDir->idCount = IconsCount;
    // IconEntry apunta a la entrada del primer icono IconDir->idEntries[0]
//    IconEntry = LPICONDIRENTRY(Buffer + sizeof(ICONDIR) - sizeof(ICONDIRENTRY));
    IconEntry = &IconDir->idEntries[0];

    // Localizar el ICON resource en el ejecutable y sus Imagenes.
    hRes = NULL;
    ImageOffset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY)*(IconDir->idCount-1));
    // Recorro las imágenes del recurso y preparo las entradas y las imágenes en el Buffer
    for(int n=0; n<IconsCount; n++){
      int nID = grpIconDir->idEntries[n].nID;
      hRes = ::FindResource(hModule, MAKEINTRESOURCE(nID), RT_ICON);
      resIconImage = (ICONIMAGE*)LoadResource(hModule, hRes);
      IconEntry[n].bWidth = resIconImage->icHeader.biWidth;
      IconEntry[n].bHeight = resIconImage->icHeader.biHeight/2;
      IconEntry[n].bColorCount =  NColors(resIconImage->icHeader.biBitCount);
      IconEntry[n].bReserved = 0;
      IconEntry[n].wPlanes = 1;
      IconEntry[n].wBitCount = resIconImage->icHeader.biBitCount;
      IconEntry[n].dwBytesInRes = SizeofResource(hModule, hRes);
      IconEntry[n].dwImageOffset = ImageOffset;
      // Copio la imagen
      memcpy((BYTE*)Buffer+ImageOffset, resIconImage, IconEntry[n].dwBytesInRes);
      ImageOffset += IconEntry[n].dwBytesInRes;
    }

    return AllSize;
}
Como puede observarse, al igual que la función ExtractResIconFromModule, se recorren todas las imágenes del grupo. El código puede ser base para otro que obtenga uno o varios iconos en particular, según determinado criterio, y proporcionar un buffer sólo con esas imágenes. Para eso será necesario calcular previamente el tamaño del buffer y luego rellenarlo cuidadosamente.

Para ilustrar el uso de esta función propongo un código que guarda el grupo de iconos en un archivo de iconos.ico, SaveResIconToFile:
Código:
//------------------------------------------------------------------------------
// Guarda en disco File.ico el grupo de Icono de un exe o dll
// Id: Indice del Grupo de iconos como si fuese una array comenzando por 0
bool SaveResIconToFile(char *FuenteExe, char* DestFileName, int Id)
{
   BYTE* Buffer;
   int Size;
   HMODULE hModule;
   hModule = LoadLibrary(FuenteExe);

   // Calculo el tamaño necesario para el Buffer
   GetFileMemIconFromModule(hModule, Id, 0, &Size);
   Buffer = new BYTE[Size];
   
   // Extraigo del ejecutable (hModule) el grupo de iconos que obtengo en el Buffer
   // Este Buffer es una imagen en memoria de un archivo.ico que se puede guardar directamente.
   int S = GetFileMemIconFromModule(hModule, Id, Buffer, &Size);
   if(S==0) return false;

   // Creo y guardo el archivo de iconos
   HANDLE hFile = CreateFile(DestFileName, GENERIC_WRITE, 0, NULL,
                   CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

   unsigned long dwBytesWritten;

   if (INVALID_HANDLE_VALUE != hFile){
       WriteFile(hFile, Buffer, Size, &dwBytesWritten, NULL);
       CloseHandle(hFile);
   }

   FreeLibrary(hModule);
   delete [] Buffer;
   return (dwBytesWritten == Size);
}
Como comentaba mas arriba, pueden crearse mas funciones para escojer iconos concretos y to todo el grupo, las bases están puestas en esta serie de post.

Saludos.
Responder Con Cita