|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 // System headers (alphabetical) |
|
8 #include <fcntl.h> |
|
9 #include <io.h> |
|
10 #include <share.h> |
|
11 #include <stdio.h> |
|
12 #include <stdlib.h> |
|
13 #include <sys/stat.h> |
|
14 #include <windows.h> |
|
15 |
|
16 // Mozilla headers (alphabetical) |
|
17 #include "mozilla/FileUtils.h" // ScopedClose |
|
18 #include "nsAutoPtr.h" // nsAutoArrayPtr |
|
19 |
|
20 /* |
|
21 Icon files are made up of: |
|
22 |
|
23 IconHeader |
|
24 IconDirEntry1 |
|
25 IconDirEntry2 |
|
26 ... |
|
27 IconDirEntryN |
|
28 IconData1 |
|
29 IconData2 |
|
30 ... |
|
31 IconDataN |
|
32 |
|
33 Each IconData must be added as a new RT_ICON resource to the exe. Then |
|
34 an RT_GROUP_ICON resource must be added that contains an equivalent |
|
35 header: |
|
36 |
|
37 IconHeader |
|
38 IconResEntry1 |
|
39 IconResEntry2 |
|
40 ... |
|
41 IconResEntryN |
|
42 */ |
|
43 |
|
44 #pragma pack(push, 2) |
|
45 typedef struct |
|
46 { |
|
47 WORD Reserved; |
|
48 WORD ResourceType; |
|
49 WORD ImageCount; |
|
50 } IconHeader; |
|
51 |
|
52 typedef struct |
|
53 { |
|
54 BYTE Width; |
|
55 BYTE Height; |
|
56 BYTE Colors; |
|
57 BYTE Reserved; |
|
58 WORD Planes; |
|
59 WORD BitsPerPixel; |
|
60 DWORD ImageSize; |
|
61 DWORD ImageOffset; |
|
62 } IconDirEntry; |
|
63 |
|
64 typedef struct |
|
65 { |
|
66 BYTE Width; |
|
67 BYTE Height; |
|
68 BYTE Colors; |
|
69 BYTE Reserved; |
|
70 WORD Planes; |
|
71 WORD BitsPerPixel; |
|
72 DWORD ImageSize; |
|
73 WORD ResourceID; // This field is the one difference to above |
|
74 } IconResEntry; |
|
75 #pragma pack(pop) |
|
76 |
|
77 namespace { |
|
78 /** |
|
79 * ScopedResourceUpdate is a RAII wrapper for Windows resource updating |
|
80 * |
|
81 * Instances |EndUpdateResourceW()| their handles when they go out of scope. |
|
82 * They pass |TRUE| as the second argument to |EndUpdateResourceW()|, which |
|
83 * causes the resource update to be aborted (changes are discarded). |
|
84 */ |
|
85 struct ScopedResourceUpdateTraits |
|
86 { |
|
87 typedef HANDLE type; |
|
88 static type empty() { return nullptr; } |
|
89 static void release(type handle) { |
|
90 if(nullptr != handle) { |
|
91 EndUpdateResourceW(handle, TRUE); // Discard changes |
|
92 } |
|
93 } |
|
94 }; |
|
95 |
|
96 typedef mozilla::Scoped<ScopedResourceUpdateTraits> ScopedResourceUpdate; |
|
97 }; |
|
98 |
|
99 #ifdef __MINGW32__ |
|
100 extern "C" |
|
101 #endif |
|
102 int |
|
103 wmain(int argc, wchar_t** argv) |
|
104 { |
|
105 if (argc != 3) { |
|
106 printf("Usage: redit <exe file> <icon file>\n"); |
|
107 return 1; |
|
108 } |
|
109 |
|
110 mozilla::ScopedClose file; |
|
111 if (0 != _wsopen_s(&file.rwget(), |
|
112 argv[2], |
|
113 _O_BINARY | _O_RDONLY, |
|
114 _SH_DENYWR, |
|
115 _S_IREAD) |
|
116 || (-1 == file)) { |
|
117 fprintf(stderr, "Unable to open icon file.\n"); |
|
118 return 1; |
|
119 } |
|
120 |
|
121 // Load all the data from the icon file |
|
122 long filesize = _filelength(file); |
|
123 nsAutoArrayPtr<BYTE> data(new BYTE[filesize]); |
|
124 if(!data) { |
|
125 fprintf(stderr, "Failed to allocate memory for icon file.\n"); |
|
126 return 1; |
|
127 } |
|
128 _read(file, data, filesize); |
|
129 |
|
130 IconHeader* header = reinterpret_cast<IconHeader*>(data.get()); |
|
131 |
|
132 // Open the target library for updating |
|
133 ScopedResourceUpdate updateRes(BeginUpdateResourceW(argv[1], FALSE)); |
|
134 if (nullptr == updateRes) { |
|
135 fprintf(stderr, "Unable to open library for modification.\n"); |
|
136 return 1; |
|
137 } |
|
138 |
|
139 // Allocate the group resource entry |
|
140 long groupSize = sizeof(IconHeader) |
|
141 + header->ImageCount * sizeof(IconResEntry); |
|
142 nsAutoArrayPtr<BYTE> group(new BYTE[groupSize]); |
|
143 if(!group) { |
|
144 fprintf(stderr, "Failed to allocate memory for new images.\n"); |
|
145 return 1; |
|
146 } |
|
147 memcpy(group, data, sizeof(IconHeader)); |
|
148 |
|
149 IconDirEntry* sourceIcon = |
|
150 reinterpret_cast<IconDirEntry*>(data |
|
151 + sizeof(IconHeader)); |
|
152 IconResEntry* targetIcon = |
|
153 reinterpret_cast<IconResEntry*>(group |
|
154 + sizeof(IconHeader)); |
|
155 |
|
156 for (int id = 1; id <= header->ImageCount; id++) { |
|
157 // Add the individual icon |
|
158 if (!UpdateResourceW(updateRes, RT_ICON, MAKEINTRESOURCE(id), |
|
159 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), |
|
160 data + sourceIcon->ImageOffset, |
|
161 sourceIcon->ImageSize)) { |
|
162 fprintf(stderr, "Unable to update resource (RT_ICON).\n"); |
|
163 return 1; |
|
164 } |
|
165 // Copy the data for this icon |
|
166 // (note that the structs have different sizes) |
|
167 memcpy(targetIcon, sourceIcon, sizeof(IconResEntry)); |
|
168 targetIcon->ResourceID = id; |
|
169 sourceIcon++; |
|
170 targetIcon++; |
|
171 } |
|
172 |
|
173 if (!UpdateResourceW(updateRes, RT_GROUP_ICON, L"MAINICON", |
|
174 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), |
|
175 group, groupSize)) { |
|
176 fprintf(stderr, "Unable to update resource (RT_GROUP_ICON).\n"); |
|
177 return 1; |
|
178 } |
|
179 |
|
180 // Save the modifications |
|
181 if(!EndUpdateResourceW(updateRes.forget(), FALSE)) { |
|
182 fprintf(stderr, "Unable to write changes to library.\n"); |
|
183 return 1; |
|
184 } |
|
185 |
|
186 return 0; |
|
187 } |