 |
Club Builder Foro de C++Builder en español
|
| Ver tema anterior :: Ver tema siguiente |
| Autor |
Mensaje |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Sab 15 Nov, 2008 8:37 pm Asunto: Crear un resource desde código. |
|
|
Estoy interesado en crear un resource desde código, en concreto me gustaría empezar por leer un icono desde un archivo y añadirlo como un resource de un ejecutable.
Soy capaz de cambiar el icono de un ejecutable así:
| Código: |
void CambiaIcono(char *FuenteExe, char *DestinoExe)
{
HRSRC hRes; // handle para res. info. del ejecutable
HANDLE hUpdateRes; // Handle para actualizar el resource
char *lpResLock; // Puntero data
HRSRC hResLoad; // handle para cargar resource
HMODULE hSrcExe;
int iLoop;
//Cargar ejecutable fuente del que obtener el icono
hSrcExe = LoadLibrary(FuenteExe);
if(hSrcExe == NULL)
return;
// Localizar el ICON resource en el ejecutable.
AnsiString str;
hRes = NULL;
for(iLoop = 1; iLoop<=10 && hRes==NULL; iLoop++)
{
str = str.sprintf("#%d",iLoop);
hRes = FindResource(hSrcExe, str.c_str(), RT_ICON);
}
if(hRes==NULL){
FreeLibrary(hSrcExe);
return;
}
// Cargar el icono.
hResLoad = (HRSRC)LoadResource(hSrcExe, hRes);
if (hResLoad == NULL) {
FreeLibrary(hSrcExe);
return ;
}
// Lock global memory.
lpResLock = (char*)LockResource(hResLoad);
if (lpResLock == NULL){
FreeLibrary(hSrcExe);
return ;
}
// Abrir el fichero donde añadir el icono.
hUpdateRes = BeginUpdateResource(DestinoExe, FALSE);
if (hUpdateRes != NULL){
// Actualizar el resource
if(UpdateResource(hUpdateRes,
RT_ICON,
MAKEINTRESOURCE(1),
MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
lpResLock,
SizeofResource(hSrcExe, hRes))!=FALSE)
{
// Escribir los cambios y cerrar.
EndUpdateResource(hUpdateRes, FALSE);
}
}
FreeLibrary(hSrcExe);
}
|
He intentado cargar un icono desde un archivo.ico y usar el buffer en el lpResLock pero no funciona.
Un detalle curioso es que tras cambiar el icono por el de otra aplicación y cargar el archivo final con el editor de recursos Resource Workshop que viene con el Builder, El nuevo icono no aparece y si el antiguo. En el explorador sale el nuevo....
Si a alguien se le ocurren nuevas ideas las agradezco.
Saludos.
EDITO:
He corregido errores del código. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Dom 16 Nov, 2008 5:08 pm Asunto: |
|
|
Asumo que el asunto no es fácil, y es posible que no lo haya concretado bien.
La pregunta concreta, basada en el código anterior es: ¿Como puedo convertir un HICON en un HRSRC?.
| Código: | HICON hIcon; //con mi icono leido del archivo.icon o de lo que sea.
.
.
HRSRC hResIcon = Convertir_Icon_a_Recurso(hIcon); // Esta es la questión
|
Aquí dejo el boceto del código que voy a escribir:
| 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);
}
} |
Bueno, espero que alguien pueda echarme una mano. Gracias.
Saludos. |
|
| Volver arriba |
|
 |
Cesar C. Salazar Gonzalez Master


Registrado: 01 Oct 2002Mensajes: 2155Ubicación: San Cristóbal de Las Casas, Chiapas
|
Publicado: Dom 16 Nov, 2008 6:03 pm Asunto: |
|
|
Al final de esta página puedes encontrar la solución, pues el ejemplo de como cargar un Icon desde una librerira y asingarselo viene la Final
http://msdn.microsoft.com/en-us/library/ms648051(VS.85).aspx
El ejemplo en si permite extraer un icono de una libreria (exe,dll,ico) y "dibuarlo" pero realmente el codigo esta entendible, para adaptarlo a tus necesidades.
Saludos. _________________
 |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Dom 16 Nov, 2008 6:39 pm Asunto: |
|
|
Gracias Cesar. Esa página la había leído, como otras muchas mas. El ejemplo que viene, como tu bien dices, extrae un icono del resource de un ejecutable o dll. CreateIconFromResource.
Lo que necesito es CreateResourceFromIcon. No existe esa API ni consigo encontrar algo que me sirva para escribir la función. He visto http://www.purebasic.fr/german/viewtopic.php?t=7669&sid=544ff2b45854e82ae0b7b8282b608395, pero no me sirve.
Un simple Cast (HRSRC)hIcon, evidentemente no funciona, pues los mapeos en memoria son parecidos pero no iguales. Ya he hecho pruebas escribiendo en disco los resultados y comparándolos. El ICO tiene una especie de cabecera de tamaño 22 bytes, al menos en los iconos con los que he probado. Imagino que esa cabecera cambiará según tipo y colores.
El caso es que no he conseguido, todavía, realizar con éxito la conversión, por eso lo traigo al foro.
Saludos. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Lun 17 Nov, 2008 1:54 am Asunto: |
|
|
Bueno, siguiendo con el tema de la cabecera de 22 bytes, he probado a cargar un icono desde un archivo.ico y he despreciado los primeros 22 bytes. Lo he tratado, entonces, como si fuera un HRSRC y... Parece que funciona. He probado con iconos de 256 colores y mas, de momento no falla.
Las primeras pruebas con un TImageList son prometedoras, pero tengo que probar mas. Me preocupa el tema del número de colores.
El código que desarrollado está basado en el boceto que expuse tres post mas arriba.
La verdad es que me gustaría que hubiese una forma de hacerlo con APIs ya que sería mas universal, pero lo que estoy desarrollando parece que es prometedor.
Saludos. |
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Lun 17 Nov, 2008 6:14 pm Asunto: |
|
|
| escafandra escribió: | | siguiendo con el tema de la cabecera de 22 bytes, he probado a cargar un icono desde un archivo.ico y he despreciado los primeros 22 bytes |
Aquí tienes un enlace de Microsoft donde habla sobre esa cabecera.. también se comenta que esa cabecera es ligeramente diferente cuando es un icono independiente o cuando se va a usar como recurso:
http://msdn.microsoft.com/en-us/library/ms997538.aspx
Esto también explica lo que comentas más arriba, la razón por la que desde el explorador ves un icono y desde un editor de recursos otro. Y es porque has grabado el icono (RT_ICON), pero te falta grabar el "índice" (RT_GROUP_ICON).
Explicándolo brevemente, habría que quitar la cabecera de cada icono (esos 22 bytes) y grabarlo como RT_ICON, y luego una cabecera global y las cabeceras de cada icono como un recurso RT_GROUP_ICON.. no se si me explico.. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mar 18 Nov, 2008 12:37 am Asunto: |
|
|
Gracias _Leo por mostrar tu interés y dedicar tu tiempo. Esa página que me muestras, que había visto, pero a la que no le presté el debido interés, confirma mi observación de la cabecera de 22 bytes de un archivo.ico.
De hecho tengo buenos resultados desechándola, con lo que me voy directamente al ICONIMAGE que es lo que representa HRSRC en un resource:
| Código: | HRSRC hRes = hRes = FindResource(...);
HGLOBAL GlobalRes = LoadResource(ModuleExe, hRes);
ICONIMAGE *IconImage = (ICONIMAGE*)LockResource(GlobalRes);
|
En mi Builder no vienen estructuras como ICONDIR, ICONDIRENTRY, ICONIMAGE, GRPICONDIR o GRPICONDIRENTRY. Pero al tenerlas definidas en http://msdn.microsoft.com/en-us/library/ms997538.aspx, me van a ser de mucha ayuda, sobre todo para hacer más general el código.
Me he dado cuenta que los Iconos guardados en un TImageList pierden colores, se reducen a 16. Debe tratarlos como dependientes de dispositivo y elimina la paleta de colores.
Todavía no tengo muy claro como llegar desde un HICON al ICONIMAGE*, lo hago utilizando un MemoryStream pero preferiría hacerlo directamente con API o manejo de punteros, es decir, sin componentes.
| _Leo escribió: | | Esto también explica lo que comentas más arriba, la razón por la que desde el explorador ves un icono y desde un editor de recursos otro. Y es porque has grabado el icono (RT_ICON), pero te falta grabar el "índice" (RT_GROUP_ICON). |
El caso es que ResourceWorkshop no ve bien los iconos añadidos, pero otros editores de recursos si los ven. El ResourceWorkshop que uso es la versión 4.5, ¿algo vieja?.
Saludos. |
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Mar 18 Nov, 2008 4:21 am Asunto: |
|
|
Un pequeño ejemplo de lo que explicaba más arriba por si te sirve. No utiliza ningún componente y tampoco hago ninguna comprobación de errores para dejarlo lo más simple posible:
(Si lo que buscas es compatibilidad con otros compiladores y por eso no quieres usar componentes, también lo he probado en VC++)
| Código: | #include <fstream>
#include <vector>
#pragma pack(push, 2)
// Cabecera del archivo .ico
struct ICONDIR { WORD reserved, type, count; };
// Se repite por cada icono que contenga el archivo, como indica count
struct ICONDIRENTRY { BYTE width, height, colors, reserved;
WORD planes, bits; DWORD bytes, offset; };
// Cabecera del icono como recurso
struct GRPICONDIR { WORD reserved, type, count; };
// Se repite por cada icono que contendra el grupo, como indica count
struct GRPICONDIRENTRY { BYTE width, height, colors, reserved;
WORD planes, bits; DWORD bytes; WORD id; };
#pragma pack(pop)
void AddIconToExe(char* exe, char* icon)
{
// Abrimos el ejecutable en modo de lectura binaria
std::ifstream fIco(icon, std::ios::binary);
HANDLE hUpdateRes = BeginUpdateResource(exe, FALSE);
// Lee la cabecera del .ico que indica cuantos iconos hay
ICONDIR iconDir;
fIco.read(reinterpret_cast<char*>(&iconDir), sizeof(ICONDIR));
// Lee la cabecera de cada icono en el archivo .ico
std::vector<ICONDIRENTRY> iconDirEntry(iconDir.count);
fIco.read(reinterpret_cast<char*>(&iconDirEntry[0]),
sizeof(ICONDIRENTRY) * iconDir.count);
// Copia la cabera .ico a la cabecera del recurso
GRPICONDIR grpIconDir;
memcpy(&grpIconDir, &iconDir, sizeof(ICONDIR));
// Convierte cada cabecera de icono a la cabecera de recurso
std::vector<GRPICONDIRENTRY> grpIconDirEntry(grpIconDir.count);
for (int i = 0; i < grpIconDir.count; i++)
{
memcpy(&grpIconDirEntry[i], &iconDirEntry[i], sizeof(GRPICONDIRENTRY));
// Ponemos manualmente la unica parte de la cabecera que es diferente
grpIconDirEntry[i].id = i + 100;
// Vamos grabando en el .exe los datos graficos de cada icono
std::vector<char> buffer(iconDirEntry[i].bytes);
fIco.seekg(iconDirEntry[i].offset, std::ios::beg);
fIco.read(&buffer[0], iconDirEntry[i].bytes);
UpdateResource(hUpdateRes, RT_ICON,
MAKEINTRESOURCE(grpIconDirEntry[i].id),
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
&buffer[0], buffer.size());
}
// Juntamos la cabecera principal con las de cada icono
std::vector<char> header(sizeof(GRPICONDIR)
+ (sizeof(GRPICONDIRENTRY) * grpIconDir.count));
memcpy(&header[0], &grpIconDir, sizeof(GRPICONDIR));
memcpy(&header[sizeof(GRPICONDIR)], &grpIconDirEntry[0],
sizeof(GRPICONDIRENTRY) * grpIconDir.count);
// Y la grabamos comp "indice" o cabecera de grupo de iconos
UpdateResource(hUpdateRes, RT_GROUP_ICON,
"PRUEBA",
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
&header[0], header.size());
EndUpdateResource(hUpdateRes, FALSE);
} |
Y como ejemplo de uso:
| Código: | AddIconToExe("prueba.exe", "icono.ico"); |
- Como "id" de cada icono empiezo a contar desde 100 en el ejemplo, lo ideal sería leer los iconos y buscar los huecos libres..
- También si lo que quieres es sustituir el icono principal que es el que busca el explorador (el primer grupo que encuentra) habría que enumerar la lista de grupos y usar el nombre del primero..
| escafandra escribió: | | Me he dado cuenta que los Iconos guardados en un TImageList pierden colores, se reducen a 16. Debe tratarlos como dependientes de dispositivo y elimina la paleta de colores. |
He hecho una prueba creando un icono de 128x128 pixels con 24bits de color y lo he cargado en el TImageList desde el IDE, lo he usado para dibujar en el form: "ImageList1->Draw(Canvas, 0, 0, 0, true);" luego lo he usado en un TToolButton y ha funcionado bien. Si quieres probar el icono: (He usado el BCB6+Upd4 en Windows XP+SP3)
http://telefonica.net/web/ljfg/temp/icono128x128x24.zip
(Solo a modo de experimento para comprobar lo de los colores, ya que supongo que esta versión en muchos sitios espera iconos de 16x16 o 32x32) |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mar 18 Nov, 2008 10:00 pm Asunto: |
|
|
Gracias _Leo, tu código funciona muy bien.
Cuando me refería al cambio de los colores de un icono en un TListView, no lo hacía al dibujar su imagen en un Canvas o TImage sino al hecho de que si uso un icono de esa lista para incluirlo en un ejecutable, pierde colores. También falla en los colores si lo paso a un TImage y luego uso esa copia del icono. Sin embargo, si el mismo icono (el mismo archivo fuente del icono) lo añado con tu código o con los que yo hice, no pierde colores.
Ejemplo:
| Código: |
TIcon *Icon = new TIcon;
// Leo un icono.
Icon->LoadFromFile(FuenteICO);
// Lo dibujo el el Formulario, sólo para verlo....
Form3->Image1->Picture->Icon->Handle = Icon->Handle;
TMemoryStream *Stream = new TMemoryStream;
// Esto también cambia el número de colores, como el un TListView
Form3->Image1->Picture->Icon->SaveToStream(Stream);
lpResLock = (BYTE*)LockResource((BYTE*)Stream->Memory+22);
// 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,
Stream->Size)!=FALSE)
{
// Escribir los cambios y cerrar.
EndUpdateResource(hUpdateRes, FALSE);
}
}
|
Sin embargo si uso el icono original, los colores son perfectos. Claro, que en ambos casos utilizo el truco de pasar por un TMemoryStream para manejarlo en memoria.... Si lo leo directamente de un fichero completo y uso el buffer de lectura, también funciona bien, como cabía esperar.
Lo que no se, es si tiene que ver con el Handle del icono en cada caso. He probado a hacerlo desde el Handle (HICON) sin pasar por un TMemoryStream, pero no consigo incorporar el icono.
Gracias por tu tiempo, _Leo.
Un saludo.
Edito:
Cambio
lpResLock = (BYTE*)Stream->Memory+22);
por:
lpResLock = (BYTE*)LockResource((BYTE*)Stream->Memory+22); |
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Mie 19 Nov, 2008 2:28 pm Asunto: |
|
|
| escafandra escribió: | | También falla en los colores si lo paso a un TImage y luego uso esa copia del icono |
Cierto, no te había entendido bien anteriormente. En vez de asignar el icono con:
| Código: | Image1->Picture->Icon->Handle = Icon->Handle; |
Prueba con esto:
| Código: | Image1->Picture->Icon->Assign(Icon); |
He hecho una prueba así con el icono que te he puesto antes en el BCB6 y me funciona:
| Código: | TIcon* Icon = new TIcon;
// Leo un icono.
Icon->LoadFromFile("icono128x128x24.ico");
// o lo cargo desde el TImageList
// ImageList1->GetIcon(0, Icon);
// Lo dibujo el el Formulario, sólo para verlo....
// Image1->Picture->Icon->Assign(Icon);
TMemoryStream* Stream = new TMemoryStream;
Icon->SaveToStream(Stream);
BYTE* lpResLock = (BYTE*)Stream->Memory + 22;
// ... |
| escafandra escribió: | | He probado a hacerlo desde el Handle (HICON) sin pasar por un TMemoryStream, pero no consigo incorporar el icono. |
TMemoryStream en este caso ahorra muchísimo trabajo, si quisieras hacerlo usando el API tendrías que pasarlo a memoria para poder manipularlo y lleva bastante más trabajo, tendrías que mirar las funciones: GetIconInfo y GetDIBits. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mie 19 Nov, 2008 9:24 pm Asunto: |
|
|
Si, tienes razón, _Leo. Si realizo la asignación con Image1->Picture->Icon->Assign(Icon); no se distorsionan los colores.
No entiendo porqué ocurre, pienso que no debería, es posible que estemos ante un bug. Esto plantéa una dificultad en los HICON tomados de las API si queremos compatibilizarlos con TIcon del Builder o de Delphi (property Handle: HICON read GetHandle write SetHandle;)
Por si puede ser de interés a otros, en lo referente a la lectura del archivo del icono, lo he implementado leyéndolo de golpe el un buffer para luego:
| Código: | ICONDIR *IconDir = (ICONDIR*)lpBuffer;
int n=0; // para la primera imagen.....
BYTE *IconImage = (BYTE*)IconDir + IconDir->idEntries[n].dwImageOffset;
|
De esta forma ahorro mucho código.
Claro que para esto tenemos que preparan bien las cabeceras para alinear a WORD al compilar, de lo contrario no funciona al alterarse los tamaños de las estructuras de las cabeceras:
| Código: | #pragma pack( push )
#pragma pack( 2 )
....
// Definición de cabeceras...
....
#pragma pack( pop ) |
Muchar gracias _Leo por tu dedicación.
Saludos. |
|
| Volver arriba |
|
 |
_Leo Site Admin

Registrado: 11 Ago 2002Mensajes: 1875Ubicación: Lanzarote - Islas Canarias (España)
|
Publicado: Mie 19 Nov, 2008 9:59 pm Asunto: |
|
|
| escafandra escribió: | | No entiendo porqué ocurre, pienso que no debería, es posible que estemos ante un bug. Esto plantéa una dificultad en los HICON tomados de las API si queremos compatibilizarlos con TIcon del Builder o de Delphi (property Handle: HICON read GetHandle write SetHandle;) |
La versión 6 y anteriores siempre que se crea desde HICON lo crea de 4bits(16 colores). En la versión 2009 ya funciona correctamente, no se si en la 2006 y 2007 también. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Jue 20 Nov, 2008 1:05 am Asunto: |
|
|
| _Leo escribió: | | La versión 6 y anteriores siempre que se crea desde HICON lo crea de 4bits(16 colores). En la versión 2009 ya funciona correctamente, no se si en la 2006 y 2007 también. |
Pues este "pequeño" detalle me puede obligar a pasar el HICON a memoria, para poder usar las API sin los problemas que tienen las VCL en este campo, a no ser que encuentre una solución mejor.
Muchas gracias _Leo.
Saludos. |
|
| Volver arriba |
|
 |
escafandra Master

Registrado: 29 Nov 2007Mensajes: 625Ubicación: Madrid - España
|
Publicado: Mie 24 Dic, 2008 3:50 pm Asunto: |
|
|
Vistas las limitaciones de versiones algo antiguas del Builder para el manejo de los colores de un icono pasado por su Handle HICON, He escrito una función para mapear el HICON en memoria. El buffer conseguido puede ser escrito directamente como un archivo.ico
Usa el siguiente archivo cabecera: Iconons.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 |
Y la función hIconToMem:
| 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;
} |
Un ejemplo de uso y para ver como funciona:
| 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. |
|
| Volver arriba |
|
 |
|
|
No puedes publicar temas nuevos en este foro No puedes responder a temas en este foro No puedes editar tus mensajes en este foro No puedes borrar tus mensajes en este foro No puedes votar en las encuestas de este foro
|
© 2002–2026 Club Builder · Funciona con phpBB.
|