Kirjautuminen

Haku

Tehtävät

Keskustelu: Yleinen keskustelu: Iconin lukeminen tiedostosta

etsubu [18.09.2011 12:36:54]

#

Moi!
Oli tässä projekti menossa, että ohjelman pitäisi pystyä lukemaan exe tiedostosta sen iconi niin, että se tallentaisi sen kuvan muodossa .ico
Näitä ohjelmia on netti täynnä ja itsellänikin on myös yksi, mutta tämä ohjelma on osa isompaa projektia ja sen olisi välttämätöntä pystyä tekemään näin. Sain sen lukemaan yhdestä tiedostosta kuvan ulos, mutta se ei toimi muihin tiedostoihin.
Tietäisikö kukaan mitä kannattaisi tutkiskella jos tämän haluaisi toteuttaa?

Merri [18.09.2011 15:47:01]

#

Windowsin API:lla kutsuen funktioita LoadLibrary, LoadBitmap, DeleteObject ja FreeLibrary pääsee aika pitkälle. MSDN:n foorumeilla on jonkin verran asiaa ja jopa koodiesimerkkejä.

etsubu [18.09.2011 16:40:50]

#

Kiitoksiaa vastauksesta koitin katsella noita funktioita, mutta en ymmärrä täysin.
Onko LoadBitmap se joka lataa exe tiedoston kuvan vai mitä se pitää sisällään?

Merri [18.09.2011 16:55:46]

#

Kappas, LoadImage on näemmä se, jota pitäisi nykyään käyttää. Tuo linkki näyttää Microsoftin dokumentaation, jota on hyvä opetella lukemaan.

LoadImagen palauttama arvo siis kertoo handlen kuvaan, jota voi sitten käsitellä muita kuviin liittyviä API-funktioita käyttäen. Nämä kuvat kulkevat muistaakseni nimellä DIB eli Device Independent Bitmap, eli yksi hakusana lisää käytettäväksi. Niitä voi olla aluksi vähän vaikea hahmottaa, mutta sanotaan että yhteneväisyys BMP-tiedostomuotoon on varsin suuri.

Voi olla että kuvakkeen pystyy tallentamaan suoraan tiedostoksi API-kutsuja käyttäen, mutta tässä kohtaa tietämykseni raja alkaa tulla vastaan. En ole koskaan kuvaketiedoston tallennusta toteuttanut. Ainakin kuvaketiedostoon voi tallentaa useita kuvia.

Deffi [18.09.2011 20:08:20]

#

Ei ole ihan niin triviaali juttu. .ico-tiedostot voivat sisältää useita eri kokosia kuvia ja ne kaikki pitäis saada talteen, että ikoni näyttää oikealta kaikissa tilanteissa. Tietääkseni HICONia ei voi kirjoittaa levylle mitenkään helposti. Oikeaoppinen(?) ikonin repiminen resursseista:

Tästä voi olla hyötyä: ICO (file format)

Pitkä esimerkkikoodi siitä kuinka homma hoituu C:llä:

/**
 * icodump.c - extracts icon from a given executable
 *
 * gcc icodump.c -Wall -o icodump.exe
 *
 * ~ deffi
 */

#include <windows.h>
#include <stdio.h>

// http://en.wikipedia.org/wiki/ICO_%28file_format%29#Outline
typedef struct _ICONDIRENTRY {
   BYTE width;
   BYTE height;
   BYTE colors;
   BYTE reserved;
   WORD planes;
   WORD bpp;
   DWORD size;
   //union {
   //    DWORD offset; // used when writing the ico to the disk
       WORD id; // used in RT_GROUP_ICON
   //};
} __attribute__((packed)) ICONDIRENTRY, *LPICONDIRENTRY;

typedef struct _ICONDIR {
    WORD reserved;
    WORD type; // 0 for .cur and 1 for .ico
    WORD img_count;
    ICONDIRENTRY entry[0];
} __attribute__((packed)) ICONDIR;

/* retrieves the name of the first RT_GROUP_ICON */
BOOL CALLBACK EnumResNames(HANDLE module, LPCTSTR type, LPTSTR name,
        LONG_PTR param) {

    if(IS_INTRESOURCE(name))
        *(int*)param = (int)name;
    else *(char**)param = strdup(name);

    return FALSE;
}

int main(int argc, char *argv[]) {
    char *buf, *out;
    FILE *hout = NULL;

    /* input parsing */
    if(argc < 2 || argc > 3) {
        printf("Usage: %s target.exe [out.ico]\n", argv[0]);
        return 1;
    }
    if(argc == 3)
        out = argv[2];
    else {
        buf = malloc(strlen(argv[1]) + strlen(".ico"));
        sprintf(buf, "%s%s", argv[1], ".ico");
        out = buf;
    }

    /* load PE */
    HANDLE hpe = LoadLibraryEx(argv[1], NULL, LOAD_LIBRARY_AS_DATAFILE);
    if(!hpe) {
        printf("LoadLibrary(\"%s\") failed!\n", argv[1]);
        return 2;
    }

    /* extract icon */
    HRSRC reshdr, resicon;
    HGLOBAL hhdr, hicon;
    DWORD hdrsz, iconsz;
    void *hdrdata, *icondata;
    char *grpname;
    hhdr = hicon = grpname = NULL;

    /* find the first icon group (RT_GROUP_ICON) */
    grpname = 0;
    EnumResourceNames(hpe, RT_GROUP_ICON, (ENUMRESNAMEPROC)EnumResNames,
            (LONG_PTR)&grpname);
    reshdr = FindResource(hpe, grpname, RT_GROUP_ICON);
    if(!reshdr) { printf("404 icon not found!\n"); goto exit; }
    hdrsz = SizeofResource(hpe, reshdr);
    hhdr = LoadResource(hpe, reshdr);
    hdrdata = LockResource(hhdr);

    /* prepare the output file */
    hout = fopen(out, "w+b");
    if(!hout) { printf("fopen(\"%s\", \"w+b\") failed!", out); goto exit; }

    /* write ICONDIR */
    ICONDIR* idir = hdrdata;
    ICONDIRENTRY* ientry;
    fwrite(idir, 1, sizeof(ICONDIR), hout);

    /* calculate the offset where the first icon will be written to */
    /* +2 because offset-field is used */
    DWORD offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY)+2)*idir->img_count;

    /* write icon directory entry for each icon */
    int i;
    for(i = 0; i < idir->img_count; i++, offset += ientry->size) {
        ientry = &idir->entry[i];
        fwrite(ientry, 1, sizeof(ICONDIRENTRY)-2, hout);
        fwrite(&offset, 4, 1, hout);
    }

    /* write icons */
    for(i = 0; i < idir->img_count; i++) {
        ientry = &idir->entry[i];

        /* locate icon */
        resicon = FindResource(hpe, MAKEINTRESOURCE(ientry->id), RT_ICON);
        iconsz = SizeofResource(hpe, resicon);
        hicon = LoadResource(hpe, resicon);
        icondata = LockResource(hicon);

        fwrite(icondata, 1, iconsz, hout);
        FreeResource(hicon);
        hicon = NULL;
    }

    printf("done! %s (%lu bytes)\n", out, ftell(hout));

exit:
    if(hout) fclose(hout);
    if(hhdr) FreeResource(hhdr);
    if(hicon) FreeResource(hicon);
    if(hpe) FreeLibrary(hpe);
    if(argc == 2) free(out);
    return 0;
}

etsubu [22.09.2011 19:25:22]

#

Kiitos Deffi tuo esimerkki on hyvin hyödylllinen, mutta kun koitin kääntää sitä dev c++:salla sain virheen:
[Linker error] undefined reference to `IS_INTRESOURCE'
Koodi siis on toimiva, mutta pitääkö minun liittää jokin kirjasto kiinni?

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta