1 /*
2  * Copyright (c) 2012, 2020, 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 
PrintError()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 
ChangeIcon(HANDLE update,const wstring & iconTarget)99 bool ChangeIcon(HANDLE update, const wstring& iconTarget) {
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     for (int i = 0; i < lpid->idCount; i++) {
158         LPBYTE lpBuffer = (LPBYTE) malloc(lpid->idEntries[i].dwBytesInRes);
159         SetFilePointer(icon, lpid->idEntries[i].dwImageOffset,
160                 NULL, FILE_BEGIN);
161         ReadFile(icon, lpBuffer, lpid->idEntries[i].dwBytesInRes,
162                 &dwBytesRead, NULL);
163         if (!UpdateResource(update, RT_ICON,
164                 MAKEINTRESOURCE(lpgid->idEntries[i].nID),
165                 language, &lpBuffer[0], lpid->idEntries[i].dwBytesInRes)) {
166             free(lpBuffer);
167             free(lpid);
168             free(lpgid);
169             CloseHandle(icon);
170             PrintError();
171             return false;
172         }
173         free(lpBuffer);
174     }
175 
176     free(lpid);
177     CloseHandle(icon);
178 
179     if (!UpdateResource(update, RT_GROUP_ICON, MAKEINTRESOURCE(1),
180             language, &lpgid[0], (sizeof (WORD) * 3)
181             + (sizeof (GRPICONDIRENTRY) * lpgid->idCount))) {
182         free(lpgid);
183         PrintError();
184         return false;
185     }
186 
187     free(lpgid);
188 
189     return true;
190 }
191