packages feed

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;
}