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?
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ä.
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?
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.
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 HICON
ia ei voi kirjoittaa levylle mitenkään helposti. Oikeaoppinen(?) ikonin repiminen resursseista:
LOAD_LIBRARY_AS_DATAFILE
)RT_ICON_GROUP
sovelluksen resursseista (EnumResourceNames)ICONDIR
"headeri" levylleICONDIR
in perään kirjoitetaan ICONDIRENTRY
jokaiselle ryhmän ikonilleTä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; }
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?
Aihe on jo aika vanha, joten et voi enää vastata siihen.