/* * Utility for selecting and extracting an icon resource from a .DLL/.EXE/.ICO * * Usage: msiIcon * * creates .exe containing your icon of choice as a resource. Apart from * the icon resource data, the .exe contains just a trivial entry point. * * sof 2/02 */ #include #include #include "msiIcon.h" typedef BOOL (WINAPI *PickIconDlgTy)(HWND,LPWSTR,DWORD,LPDWORD); static BOOL WriteIcon(LPWSTR fName, LPWSTR dllName, DWORD idx); int main(int argc, char* argv[]) { HINSTANCE hShell; PickIconDlgTy pickIconDlg; DWORD iconIdx; WCHAR iconHome[MAX_PATH+1]; char cmd[MAX_PATH+1]; DWORD maxFileLen = MAX_PATH; BOOL hitOk = FALSE; FILE* fp; int rc = 0; if ( argc != 2) { fprintf(stderr, "usage: %s \n", argv[0]); fprintf(stderr, " e.g., %s myIcons/htmlFile\n", argv[0]); return 1; } /* The icon picker isn't exposed via a documented API, * so look it up (@ ordinal 62 of shell32.dll). */ hShell = LoadLibrary("shell32.dll"); if ( hShell == (HINSTANCE)NULL ) { fprintf(stderr, "unable to load shell32.dll\n"); return 1; } pickIconDlg = (PickIconDlgTy)GetProcAddress(hShell,(LPCSTR)LOWORD(62)); if ( (FARPROC)pickIconDlg == NULL ) { fprintf(stderr, "couldn't locate PickIconDlg in shell32.dll\n"); return 1; } /* Invoke the dialog, passing it initially shell32.dll ToDo: start with user-specified DLL/EXE instead . */ wcscpy(iconHome,L"shell32.dll"); hitOk = pickIconDlg(NULL,iconHome, maxFileLen,&iconIdx); if (hitOk) { /* Looks as if the user meant business - go ahead and extract the icon. */ if (WriteIcon(L"iconPrep__.ico", iconHome, iconIdx)) { if ( (fp = fopen("iconPrep__.rc", "w+")) == NULL) { fprintf(stderr, "unable to open '%s'\n", "iconPrep__.rc"); rc = 1; goto cleanup; } fprintf(fp,"0 ICON \"iconPrep__.ico\"\n"); fclose(fp); if ( (fp = fopen("iconPrep__.c", "w+")) == NULL) { fprintf(stderr, "unable to open '%s'\n", "iconPrep__.c"); rc = 1; goto cleanup; } fprintf(fp,"#include \n"); fprintf(fp,"BOOL APIENTRY DllMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved) { return TRUE; }"); fclose(fp); #if 0 // If you've got MSVC tools system("rc iconPrep__.rc"); sprintf(cmd, "cl /nologo -o %s.exe iconPrep__.c iconPrep__.res /link /entry:DllMain /subsystem:windows /opt:nowin98",argv[1]); system(cmd); #else system("windres -i iconPrep__.rc -o iconPrep__.res -O coff"); system("gcc -c iconPrep__.c"); sprintf(cmd, "ld -o %s.exe iconPrep__.o iconPrep__.res -e _DllMain",argv[1]); system(cmd); #endif printf("Successfully created MSI icon file %s.exe\n", argv[1]); // system("del /Q iconPrep__.*"); } } cleanup: CloseHandle(hShell); return rc; } BOOL WriteIconHeader (HANDLE hFile, WORD sz) { DWORD dwW; WORD header[3]; DWORD len = 3*sizeof(WORD); header[0] = 0; // an icon header[1] = 1; // reserved header[2] = sz; return (WriteFile(hFile, header, len, &dwW, NULL) && dwW == len); } /* (Junk) struct used to pass info from the enumerator to the enumerating * procedure. */ typedef struct { HMODULE hLib; DWORD idx; LPTSTR groupIdx; DWORD currentIdx; } Stuff; BOOL CALLBACK EnumProc( HANDLE hModule, LPCTSTR lpszType, LPTSTR lpszName, LPARAM lParam ) { Stuff* state = (Stuff*)lParam; if ( state->currentIdx++ == state->idx ) { if (HIWORD(lpszName)) { /* Gotcha #521: copy that string!! */ state->groupIdx = strdup(lpszName); } else { state->groupIdx = lpszName; } return FALSE; } else { return TRUE; } } BOOL WriteIcon(LPWSTR fName, LPWSTR dllName, DWORD idx ) { HANDLE hFile; HMODULE hLib; HANDLE hRsrc; HANDLE hGlobal; DWORD dwBytesWritten; ICONDIRENTRY id; GRPICONDIR* lpGrpIconDir; ICONIMAGE* lpIconImage; Stuff stuff; int nId, i; DWORD dwSize, dwNumBytes; BOOL rc = TRUE; /* * The index coming back from the PickIconDlg() is the index of * the icon group directory -- that is, its position in the * list of RT_GROUP_ICONs, not its value/name. Had me stumped * for a while, that. */ if ( (hLib = LoadLibraryExW (dllName, NULL, LOAD_LIBRARY_AS_DATAFILE)) == NULL) { if (ExtractIconW(GetModuleHandle(NULL), dllName, -1) == (HICON)1) { // It's an .ico file; copy it. return CopyFileW(dllName, fName, FALSE); } fprintf(stderr, "WriteIcon: Couldn't load '%s'\n", dllName); return FALSE; } stuff.hLib = hLib; stuff.idx = idx; stuff.currentIdx = 0; EnumResourceNames (hLib, RT_GROUP_ICON, EnumProc, (LPARAM)&stuff); if ( (hRsrc = FindResource( hLib, stuff.groupIdx, RT_GROUP_ICON)) == NULL ) { fprintf(stderr, "WriteIcon: Couldn't locate resource '%s'\n", stuff.groupIdx); return FALSE; } if ( (hGlobal = LoadResource (hLib, hRsrc)) == NULL) { fprintf(stderr, "WriteIcon: Couldn't load resource '%s'\n", stuff.groupIdx); return FALSE; } if ( (lpGrpIconDir = LockResource ( hGlobal )) == NULL) { fprintf(stderr, "WriteIcon: Couldn't lock resource '%s'\n", stuff.groupIdx); return FALSE; } if ( (hFile = CreateFileW(fName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE ) { fprintf(stderr, "WriteIcon: Unable to open '%S' for writing\n", fName); return FALSE; } /* Emit ICON header */ if ( !WriteIconHeader(hFile,lpGrpIconDir->idCount) ) { fprintf(stderr, "WriteIcon: Unable to write header to '%S'\n", fName); rc = FALSE ; goto cleanup; } dwSize = 3 * sizeof(WORD) + lpGrpIconDir->idCount * sizeof(ICONDIRENTRY); dwNumBytes = 0; /* Write out the ICONDIRENTRYs */ for (i=0; i < lpGrpIconDir->idCount ; i++) { id.bWidth = lpGrpIconDir->idEntries[i].bWidth; id.bHeight = lpGrpIconDir->idEntries[i].bHeight; id.bColorCount = lpGrpIconDir->idEntries[i].bColorCount; id.bReserved = lpGrpIconDir->idEntries[i].bReserved; id.wPlanes = lpGrpIconDir->idEntries[i].wPlanes; id.wBitCount = lpGrpIconDir->idEntries[i].wBitCount; id.dwBytesInRes = lpGrpIconDir->idEntries[i].dwBytesInRes; dwSize += dwNumBytes; id.dwImageOffset = dwSize; dwNumBytes = id.dwBytesInRes; if( !WriteFile(hFile, &id, sizeof(ICONDIRENTRY), &dwBytesWritten, NULL) || dwBytesWritten != sizeof(ICONDIRENTRY) ) { rc = FALSE; goto cleanup; } } /* ..followed by the icon data. */ for (i=0; i < lpGrpIconDir->idCount ; i++) { hRsrc = FindResourceEx ( hLib, RT_ICON, MAKEINTRESOURCE(lpGrpIconDir->idEntries[i].nID), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); hGlobal = LoadResource ( hLib, hRsrc); lpIconImage = LockResource( hGlobal ); if ( !WriteFile( hFile, lpIconImage, SizeofResource(hLib, hRsrc), &dwBytesWritten, NULL) || dwBytesWritten != SizeofResource(hLib, hRsrc) ) { rc = FALSE; goto cleanup; } } FreeLibrary(hLib); cleanup: CloseHandle(hFile); return rc; }