1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <windows.h>
  28 #include <stdlib.h>
  29 #include <string>
  30 #include <malloc.h>
  31 
  32 using namespace std;
  33 
  34 // http://msdn.microsoft.com/en-us/library/ms997538.aspx
  35 
  36 typedef struct _ICONDIRENTRY {
  37     BYTE bWidth;
  38     BYTE bHeight;
  39     BYTE bColorCount;
  40     BYTE bReserved;
  41     WORD wPlanes;
  42     WORD wBitCount;
  43     DWORD dwBytesInRes;
  44     DWORD dwImageOffset;
  45 } ICONDIRENTRY, * LPICONDIRENTRY;
  46 
  47 typedef struct _ICONDIR {
  48     WORD idReserved;
  49     WORD idType;
  50     WORD idCount;
  51     ICONDIRENTRY idEntries[1];
  52 } ICONDIR, * LPICONDIR;
  53 
  54 // #pragmas are used here to insure that the structure's
  55 // packing in memory matches the packing of the EXE or DLL.
  56 #pragma pack(push)
  57 #pragma pack(2)
  58 
  59 typedef struct _GRPICONDIRENTRY {
  60     BYTE bWidth;
  61     BYTE bHeight;
  62     BYTE bColorCount;
  63     BYTE bReserved;
  64     WORD wPlanes;
  65     WORD wBitCount;
  66     DWORD dwBytesInRes;
  67     WORD nID;
  68 } GRPICONDIRENTRY, * LPGRPICONDIRENTRY;
  69 #pragma pack(pop)
  70 
  71 #pragma pack(push)
  72 #pragma pack(2)
  73 
  74 typedef struct _GRPICONDIR {
  75     WORD idReserved;
  76     WORD idType;
  77     WORD idCount;
  78     GRPICONDIRENTRY idEntries[1];
  79 } GRPICONDIR, * LPGRPICONDIR;
  80 #pragma pack(pop)
  81 
  82 void PrintError() {
  83     LPVOID message = NULL;
  84     DWORD error = GetLastError();
  85 
  86     if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
  87             | FORMAT_MESSAGE_FROM_SYSTEM
  88             | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
  89             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  90             (LPTSTR) & message, 0, NULL) != 0) {
  91         printf("%S", (LPTSTR) message);
  92         LocalFree(message);
  93     }
  94 }
  95 
  96 // Note: We do not check here that iconTarget is valid icon.
  97 // Java code will already do this for us.
  98 
  99 bool ChangeIcon(wstring iconTarget, wstring launcher) {
 100     WORD language = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
 101 
 102     HANDLE icon = CreateFile(iconTarget.c_str(), GENERIC_READ, 0, NULL,
 103             OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 104     if (icon == INVALID_HANDLE_VALUE) {
 105         PrintError();
 106         return false;
 107     }
 108 
 109     // Reading .ICO file
 110     WORD idReserved, idType, idCount;
 111 
 112     DWORD dwBytesRead;
 113     ReadFile(icon, &idReserved, sizeof (WORD), &dwBytesRead, NULL);
 114     ReadFile(icon, &idType, sizeof (WORD), &dwBytesRead, NULL);
 115     ReadFile(icon, &idCount, sizeof (WORD), &dwBytesRead, NULL);
 116 
 117     LPICONDIR lpid = (LPICONDIR) malloc(
 118             sizeof (ICONDIR) + (sizeof (ICONDIRENTRY) * (idCount - 1)));
 119     if (lpid == NULL) {
 120         CloseHandle(icon);
 121         printf("Error: Failed to allocate memory\n");
 122         return false;
 123     }
 124 
 125     lpid->idReserved = idReserved;
 126     lpid->idType = idType;
 127     lpid->idCount = idCount;
 128 
 129     ReadFile(icon, &lpid->idEntries[0], sizeof (ICONDIRENTRY) * lpid->idCount,
 130             &dwBytesRead, NULL);
 131 
 132     LPGRPICONDIR lpgid = (LPGRPICONDIR) malloc(
 133             sizeof (GRPICONDIR) + (sizeof (GRPICONDIRENTRY) * (idCount - 1)));
 134     if (lpid == NULL) {
 135         CloseHandle(icon);
 136         free(lpid);
 137         printf("Error: Failed to allocate memory\n");
 138         return false;
 139     }
 140 
 141     lpgid->idReserved = idReserved;
 142     lpgid->idType = idType;
 143     lpgid->idCount = idCount;
 144 
 145     for (int i = 0; i < lpgid->idCount; i++) {
 146         lpgid->idEntries[i].bWidth = lpid->idEntries[i].bWidth;
 147         lpgid->idEntries[i].bHeight = lpid->idEntries[i].bHeight;
 148         lpgid->idEntries[i].bColorCount = lpid->idEntries[i].bColorCount;
 149         lpgid->idEntries[i].bReserved = lpid->idEntries[i].bReserved;
 150         lpgid->idEntries[i].wPlanes = lpid->idEntries[i].wPlanes;
 151         lpgid->idEntries[i].wBitCount = lpid->idEntries[i].wBitCount;
 152         lpgid->idEntries[i].dwBytesInRes = lpid->idEntries[i].dwBytesInRes;
 153         lpgid->idEntries[i].nID = i + 1;
 154     }
 155 
 156     // Store images in .EXE
 157     HANDLE update = BeginUpdateResource(launcher.c_str(), FALSE);
 158     if (update == NULL) {
 159         free(lpid);
 160         free(lpgid);
 161         CloseHandle(icon);
 162         PrintError();
 163         return false;
 164     }
 165 
 166     for (int i = 0; i < lpid->idCount; i++) {
 167         LPBYTE lpBuffer = (LPBYTE) malloc(lpid->idEntries[i].dwBytesInRes);
 168         SetFilePointer(icon, lpid->idEntries[i].dwImageOffset,
 169                 NULL, FILE_BEGIN);
 170         ReadFile(icon, lpBuffer, lpid->idEntries[i].dwBytesInRes,
 171                 &dwBytesRead, NULL);
 172         if (!UpdateResource(update, RT_ICON,
 173                 MAKEINTRESOURCE(lpgid->idEntries[i].nID),
 174                 language, &lpBuffer[0], lpid->idEntries[i].dwBytesInRes)) {
 175             free(lpBuffer);
 176             free(lpid);
 177             free(lpgid);
 178             CloseHandle(icon);
 179             PrintError();
 180             return false;
 181         }
 182         free(lpBuffer);
 183     }
 184 
 185     free(lpid);
 186     CloseHandle(icon);
 187 
 188     if (!UpdateResource(update, RT_GROUP_ICON, MAKEINTRESOURCE(1),
 189             language, &lpgid[0], (sizeof (WORD) * 3)
 190             + (sizeof (GRPICONDIRENTRY) * lpgid->idCount))) {
 191         free(lpgid);
 192         PrintError();
 193         return false;
 194     }
 195 
 196     free(lpgid);
 197 
 198     if (EndUpdateResource(update, FALSE) == FALSE) {
 199         PrintError();
 200         return false;
 201     }
 202 
 203     return true;
 204 }