bamse-0.9.1: tools/msiIcon.c
/*
* Utility for selecting and extracting an icon resource from a .DLL/.EXE/.ICO
*
* Usage: msiIcon <name>
*
* creates <name>.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 <windows.h>
#include <stdio.h>
#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 <filepath>\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 <windows.h>\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);
}
fwprintf(stderr, L"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;
}