Aprovecho un ratito para publicar otra parte:
Explicado los conceptos preliminares y la enumeración de recursos, pasamos a la extracción se los recursos. He escrito dos funciones bastante similares.
La primera,
ExtractResIconFromModule, extrae un grupo de imágenes de la sección de recursos de un ejecutable o dll. La extracción es un buffer que contiene el binario del resource. La segunda, GetFileMemIconFromModule, hace lo propio pero en un buffer imagen de un archivo.ico. De cada uno se estos buffer se podrá extraer, entonces, una imagen de un icono individual, pero esto lo realizarán otras funciones.
ExtractResIconFromModule, extrae un grupo de imágenes en un buffer de memoria con cabecera GRPICONDIR (o MEMICONDIR) con las entradas a cada imagen y estas. Este buffer puede usarse para pasar el recurso entero tipo RT_GROUP_ICON a una dll o ejecutable. Esto lo realizará otra función,
AddIconToExe.
Código:
//---------------------------------------------------------------------------
// Devuelve un ResMem Icon de un hModule
// 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.
// Precisa de un Buffer previo de tamaño Size
// 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 ExtractResIconFromModule(HMODULE hModule, int Id, void* Buffer, int* Size)
{
LPGRPICONDIR grpIconDir;
LPGRPICONDIR grpSrcIconDir;
LPGRPICONDIRENTRY grpIconEntry;
LPICONIMAGE grpIconImage;
LPICONIMAGE resIconImage;
BYTE* IconMem = (BYTE*)Buffer;
HRSRC hRes; // handle para res. info. del ejecutable
int IconsCount = 0;
int AllSize = sizeof(GRPICONDIR);
// Cuento cuantos iconos tiene el recurso y la memoria necesaria
hRes = FindResource(hModule, Id, RT_GROUP_ICON);
if(hRes){
grpSrcIconDir = (LPGRPICONDIR)LoadResource(hModule, hRes);
IconsCount = grpSrcIconDir->idCount;
for(int n=0; n<IconsCount; n++)
AllSize += sizeof(ICONDIRENTRY) + grpSrcIconDir->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
grpIconDir = (LPGRPICONDIR)IconMem;
grpIconDir->idReserved = 0;
grpIconDir->idType = 1;
grpIconDir->idCount = IconsCount;
grpIconEntry = LPMEMICONDIRENTRY(IconMem + sizeof(GRPICONDIR) - sizeof(GRPICONDIRENTRY));
// Localizar el ICON resource en el ejecutable y sus Imagenes.
hRes = NULL;
grpIconImage = (LPICONIMAGE)((BYTE*)grpIconDir + sizeof(GRPICONDIR) + (sizeof(GRPICONDIRENTRY)*(grpIconDir->idCount-1)));
for(int n=0; n<IconsCount; n++){
int nID = grpSrcIconDir->idEntries[n].nID;
hRes = ::FindResource(hModule, MAKEINTRESOURCE(nID), RT_ICON);
// Preparo las cabeceras Entrada de cada Imagen
resIconImage = (ICONIMAGE*)LoadResource(hModule, hRes);
grpIconEntry[n].bWidth = resIconImage->icHeader.biWidth;
grpIconEntry[n].bHeight = resIconImage->icHeader.biHeight/2;
grpIconEntry[n].bColorCount = NColors(resIconImage->icHeader.biBitCount);
grpIconEntry[n].bReserved = 0;
grpIconEntry[n].wPlanes = 1;
grpIconEntry[n].wBitCount = resIconImage->icHeader.biBitCount;
grpIconEntry[n].dwBytesInRes = SizeofResource(hModule, hRes);
grpIconEntry[n].nID = n;
// Copio la imagen
memcpy(grpIconImage, resIconImage, grpIconEntry[n].dwBytesInRes);
// grpIconImage = (LPICONIMAGE)((BYTE*)grpIconImage + grpIconDir->idEntries[n-1].dwBytesInRes);
grpIconImage = (LPICONIMAGE)((BYTE*)grpIconImage + grpIconEntry[n].dwBytesInRes);
}
return AllSize;
}
Y para ilustrar el uso de esta función voy a colocar el código de
AddIconToExe, que añade el recurso extraído con
ExtractResIconFromModule, en un ejecutable o una dll:
Código:
//---------------------------------------------------------------------------
// grpIconDir : Buffer con el recurso del tipo RT_GROUP_ICON extraido con ExtractResIconFromModule
// DestinoExe: Nombre de un ejecutable o dll
// ResName: Nombre que se le dará al recurso añadico al ejecutable o dll
// BorraIconResPrevio: Si es trae se borraran los recursos previos RT_GROUP_ICON del ejecutable o dll
bool AddIconToExe(LPGRPICONDIR grpIconDir, char *DestinoExe, char* ResName, bool BorraIconResPrevio)
{
LPGRPICONDIRENTRY IconEntry;
LPICONIMAGE IconImage;
LPBYTE lpResLock;
bool Result = true;
if(!grpIconDir) return false;
if(!DestinoExe || !*DestinoExe) return false;
if(!ResName || !*ResName) return false;
// Crea espacio para las cabeceras del icono recurso
int HeaderSize = sizeof(GRPICONDIR)+(sizeof(GRPICONDIRENTRY)*(grpIconDir->idCount-1));
HANDLE hUpdateRes = BeginUpdateResource(DestinoExe, BorraIconResPrevio);
// Localizo la primera imagen del icono a pasar al .exe
IconImage = (LPICONIMAGE)((BYTE*)grpIconDir + sizeof(GRPICONDIR) + (sizeof(GRPICONDIRENTRY)*(grpIconDir->idCount-1)));
for(int n=0; n<grpIconDir->idCount; n++){
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,
grpIconDir->idEntries[n].dwBytesInRes);
}
// Localizo la siguiente Imagen
IconImage = (LPICONIMAGE)((BYTE*)IconImage + grpIconDir->idEntries[n].dwBytesInRes);
}
// Y la grabamos como "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.
Result &= EndUpdateResource(hUpdateRes, FALSE);
return Result;
}
Y para terminar de ilustrar estas funciones, propongo esta otra que hace uso de las dos:
Código:
//------------------------------------------------------------------------------
// Pasa todas las imágenes del primer Grupo Icono (principal por defecto del ejecutable)
// de un exe (o dll) a otro
bool AddIconToExe(char *FuenteExe, char *DestinoExe, char* ResName, bool BorraIconResPrevio)
{
bool Result;
BYTE* Buffer;
int Size;
LPGRPICONDIR grpIconDir;
HMODULE hModule;
hModule = LoadLibrary(FuenteExe);
// Calculo el tamaño necesario para el Buffer
ExtractResIconFromModule (hModule, 0, 0, &Size);
Buffer = new BYTE[Size];
// Extraigo del ejecutable (hModule) el primer grupo de iconos que obtengo en el Buffer
ExtractResIconFromModule(hModule, 0, Buffer, &Size);
grpIconDir = (LPGRPICONDIR)Buffer;
FreeLibrary(hModule);
if(grpIconDir) // Si el Buffer es válido
Result = AddIconToExe(grpIconDir, DestinoExe, ResName, BorraIconResPrevio);
else // Si el buffer no es válido
Result = false;
// Libero la memoria del Grupo de iconos antes de retornar.
delete [] Buffer;
return Result;
}
En el siguiente post publicaré el modo de guardar en un archivo, un Grupo de Iconos con las funciones
GetFileMemIconFromModule y
SaveResIconToFile.
Saludos.
PD: Edito para añadir otro ejemplo:
AddIconToExe