![]() |
![]() |
| Paypal | FTP | CCD | Buscar | Trucos | Trabajo | Foros |
|
|||||||
| Registrarse | FAQ | Miembros | Calendario | Guía de estilo | Temas de Hoy |
![]() |
|
|
Herramientas | Buscar en Tema | Desplegado |
|
|
|
#1
|
||||
|
||||
|
Crear resource icon por código
Trato de crear por código un resource que contenga un icono, o modificar el de un ejecutable o dll para añadir un icono.
Las API: FindResource LoadResource LockResource BeginUpdateResource UpdateResource EndUpdateResource Me permiten leer un resource de un archivo (.exe o dll) y modificarlo para luego escribir en disco el archivo modificado. He conseguido esto, es decir, leer un resource de un archivo (.exe o dll), y añadírle el icodo del mismo a otro archivo. Lo que no consigo es añadir un icono extraido de un icono.ico, el HRSRC no se corresponde con el Handle de un icono. He escrito el mismo en un archivo y me he dado cuenta de que es "casi el icono", me falta conocer algo que podría ser la cabecera del .ico. Lo que quiero, si no me explico bien es convertir un archivo.ico a una imagen en memoria del tipo HRSRC para incluirlo como un recurso en un ejecutable o dll. Intuyo que debe existir una API, pero no la encuentro. Un poco de código: Código:
HICON hIcon; //con mi icono leido del archivo.icon o de lo que sea.
HRSRC hResIcon;
hResIcon = Convertir_Icon_a_Recurso(hIcon); // Esta es la questión
BYTE *lpResLock = (BYTE*)LockResource(hResIcon);
// Abrir el fichero donde añadir el icono.
HANDLE hUpdateRes = BeginUpdateResource(DestinoExe, FALSE);
if (hUpdateRes != NULL){
// Actualizar el resource destino
if(UpdateResource(hUpdateRes,
RT_ICON,
MAKEINTRESOURCE(1),
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
lpResLock,
SizeofResource)!=FALSE)
{
// Escribir los cambios y cerrar.
EndUpdateResource(hUpdateRes, FALSE);
}
}
Saludos. |
|
#2
|
||||
|
||||
|
Pues lo he conseguido, pero como veo que el tema no tiene mucho interés, lo publicaré sólo si realmente le interesa a alguno.
![]() Saludos. |
|
#3
|
||||
|
||||
|
Cita:
), 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 |
|
#4
|
||||
|
||||
|
Cita:
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
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;
}
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; 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. |
|
#5
|
||||
|
||||
|
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;
}
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);
![]() Saludos. Última edición por escafandra fecha: 26-11-2008 a las 02:08:03. |
|
#6
|
||||
|
||||
|
Dado el interés que se mostró por este tema y que he ido publicando de forma desordenada código para el manejo de iconos en la sección de recursos de un ejecutable o dll, voy a tratar de ordenar ese código siguiendo este hilo. Como esto será un poco largo, lo voy a dividir en varios post.
En primer lugar, he de aclarar que los Iconos de le sección de recursos están agrupados en grupos con una cabecera de tipo GRPICONDIR. En esa cabecera tenemos, entre otras cosas, el número de imágenes que contiene y un array de entradas a cada imagen cada entrada es del tipo MEMICONDIRENTRY o GRPICONDIRENTRY (son lo mismo). Los archivos de iconos se comportan igual pero únicamente contienen un sólo Grupo con una o varias imágenes. Su cabecera es del tipo ICONDIR y este contiene, entre otras cosas, el número de iconos y las entradas correspondientes a cada uno del tipo ICONDIRENTRY. Las definiciones están publicadas aquí y su fuente está aquí. Dicho esto, lo primero que tenemos que conseguir es enumerar los recursos por su tipo, lo que nos interesa es el tipo RT_GROUP_ICON que son los grupos de iconos, es decir enumeraremos esos grupos sabiendo que cada uno puede tener varias imágenes de iconos de distinto tamaño, resolución y número de colores. Código:
//------------------------------------------------------------------------------
// Funciones de enumeración de resources
//------------------------------------------------------------------------------
// Declaraciones previas
// Definición del tipo de función que acepta EnumResourceNames
typedef BOOL (__stdcall *TP)();
// Estructura para comunicar EnumResourceNames con la función de enumeración
struct TResInGr{
int Count;
int Id;
char* ResName;
HRSRC hRes;
};
// Función de enumeración para la cuenta de elementos y encontrar un Resource
BOOL CALLBACK
EnumResGrProc(HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG lParam)
{
TResInGr *Res = (TResInGr*)lParam;
if(Res->Count == Res->Id){
Res->ResName = lpszName;
Res->hRes = ::FindResource(hModule, lpszName, lpszType);
}
Res->Count++;
return true;
}
// Devuelve el Nº de Elementos de lpszType
int GetCountRes(HANDLE hModule, LPCTSTR lpszType)
{
TResInGr Res = {0};
Res.Id = -1;
EnumResourceNames(hModule, lpszType, (TP)EnumResGrProc, LPARAM(&Res));
return Res.Count;
}
// Devuelve el Nº de Elementos de lpszType
int GetCountRes(char *FuenteExe, LPCTSTR lpszType)
{
HANDLE hModule = LoadLibrary(FuenteExe);
int Count = GetCountRes(hModule, lpszType);
FreeLibrary(hModule);
return Count;
}
// Devuelve un HRSRC con Indice Id del array de resources lpszType
// Id: Indice del Grupo de iconos como si fuese una array comenzando por 0
HRSRC FindResource(HMODULE hModule, int Id, LPCTSTR lpszType)
{
TResInGr Res = {0};
Res.Id = Id;
EnumResourceNames(hModule, lpszType, (TP)EnumResGrProc, LPARAM(&Res));
return Res.hRes;
}
Por el momento doy por terminada esta primera parte. Saludos. Última edición por escafandra fecha: 23-12-2008 a las 01:24:12. |
![]() |
|
|
Temas Similares
|
||||
| Tema | Autor | Foro | Respuestas | Último mensaje |
| Border Icon | pmcastilla | Varios | 2 | 10-09-2007 16:49:29 |
| Componente Tray Icon | marceloalegre | Varios | 1 | 06-06-2005 13:51:21 |
| Try Icon | narvaez.om | Varios | 1 | 03-05-2005 22:13:06 |
| Tray Icon con abcTrayIcon | Alexander | Varios | 0 | 29-09-2004 21:22:28 |
| mouse Icon en un TQuery | jymy788 | Varios | 4 | 17-09-2004 13:31:16 |
|