Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

Crear un resource desde código.

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Consultas
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: Crear un resource desde código. Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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.
_________________
Cool
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email MSN Messenger
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

_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
Ver perfil de usuario Enviar mensaje privado
Mensaje    Asunto: Responder citando

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
Ver perfil de usuario Enviar mensaje privado
Mostrar mensajes de anteriores:   
Cambiar a:  
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


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.