aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.Resources/ResourceCollection.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.Resources/ResourceCollection.cs340
1 files changed, 340 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.Resources/ResourceCollection.cs b/src/dtf/WixToolset.Dtf.Resources/ResourceCollection.cs
new file mode 100644
index 00000000..5d9e5653
--- /dev/null
+++ b/src/dtf/WixToolset.Dtf.Resources/ResourceCollection.cs
@@ -0,0 +1,340 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Dtf.Resources
4{
5 using System;
6 using System.IO;
7 using System.Text;
8 using System.Reflection;
9 using System.Collections;
10 using System.Collections.Generic;
11 using System.Globalization;
12 using System.Runtime.InteropServices;
13 using System.Diagnostics.CodeAnalysis;
14
15 /// <summary>
16 /// Allows reading and editing of resource data in a Win32 PE file.
17 /// </summary>
18 /// <remarks>
19 /// To use this class:<list type="number">
20 /// <item>Create a new ResourceCollection</item>
21 /// <item>Locate resources for the collection by calling one of the <see cref="ResourceCollection.Find(string)"/> methods</item>
22 /// <item>Load data of one or more <see cref="Resource"/>s from a file by calling the <see cref="Load"/> method of the
23 /// Resource class, or load them all at once (more efficient) with the <see cref="Load"/> method of the ResourceCollection.</item>
24 /// <item>Read and/or edit data of the individual Resource objects using the methods on that class.</item>
25 /// <item>Save data of one or more <see cref="Resource"/>s to a file by calling the <see cref="Save"/> method of the
26 /// Resource class, or save them all at once (more efficient) with the <see cref="Save"/> method of the ResourceCollection.</item>
27 /// </list>
28 /// </remarks>
29 public class ResourceCollection : ICollection<Resource>
30 {
31 private List<Resource> resources;
32
33 /// <summary>
34 /// Creates a new, empty ResourceCollection.
35 /// </summary>
36 public ResourceCollection()
37 {
38 this.resources = new List<Resource>();
39 }
40
41 /// <summary>
42 /// Locates all resources in a file, including all resource types and languages. For each located resource,
43 /// a <see cref="Resource"/> instance (or subclass) is added to the collection.
44 /// </summary>
45 /// <param name="resFile">The file to be searched for resources.</param>
46 /// <exception cref="IOException">resources could not be read from the file</exception>
47 public void Find(string resFile)
48 {
49 this.Clear();
50
51 IntPtr module = NativeMethods.LoadLibraryEx(resFile, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
52 if (module == IntPtr.Zero)
53 {
54 int err = Marshal.GetLastWin32Error();
55 throw new IOException(String.Format(CultureInfo.InvariantCulture, "Failed to load resource file. Error code: {0}", err));
56 }
57 try
58 {
59 if (!NativeMethods.EnumResourceTypes(module, new NativeMethods.EnumResTypesProc(this.EnumResTypes), IntPtr.Zero))
60 {
61 int err = Marshal.GetLastWin32Error();
62 throw new IOException(String.Format(CultureInfo.InvariantCulture, "Failed to enumerate resources. Error code: {0}", err));
63 }
64 }
65 finally
66 {
67 NativeMethods.FreeLibrary(module);
68 }
69 }
70
71 /// <summary>
72 /// Locates all resources in a file of a given type, including all languages. For each located resource,
73 /// a <see cref="Resource"/> instance (or subclass) is added to the collection.
74 /// </summary>
75 /// <param name="resFile">The file to be searched for resources.</param>
76 /// <param name="type">The type of resource to search for; may be one of the ResourceType constants or a user-defined type.</param>
77 /// <exception cref="IOException">resources could not be read from the file</exception>
78 public void Find(string resFile, ResourceType type)
79 {
80 this.Clear();
81
82 IntPtr module = NativeMethods.LoadLibraryEx(resFile, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
83 try
84 {
85 if (!NativeMethods.EnumResourceNames(module, (string) type, new NativeMethods.EnumResNamesProc(this.EnumResNames), IntPtr.Zero))
86 {
87 int err = Marshal.GetLastWin32Error();
88 throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceNames error. Error code: {0}", err));
89 }
90 }
91 finally
92 {
93 NativeMethods.FreeLibrary(module);
94 }
95 }
96
97 /// <summary>
98 /// Locates all resources in a file of a given type and language. For each located resource,
99 /// a <see cref="Resource"/> instance (or subclass) is added to the collection.
100 /// </summary>
101 /// <param name="resFile">The file to be searched for resources.</param>
102 /// <param name="type">The type of resource to search for; may be one of the ResourceType constants or a user-defined type.</param>
103 /// <param name="name">The name of the resource to search for.</param>
104 /// <exception cref="IOException">resources could not be read from the file</exception>
105 public void Find(string resFile, ResourceType type, string name)
106 {
107 this.Clear();
108
109 IntPtr module = NativeMethods.LoadLibraryEx(resFile, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
110 try
111 {
112 if (!NativeMethods.EnumResourceLanguages(module, (string) type, name, new NativeMethods.EnumResLangsProc(this.EnumResLangs), IntPtr.Zero))
113 {
114 int err = Marshal.GetLastWin32Error();
115 throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceLanguages error. Error code: {0}", err));
116 }
117 }
118 finally
119 {
120 NativeMethods.FreeLibrary(module);
121 }
122 }
123
124 private bool EnumResTypes(IntPtr module, IntPtr type, IntPtr param)
125 {
126 if (!NativeMethods.EnumResourceNames(module, type, new NativeMethods.EnumResNamesProc(EnumResNames), IntPtr.Zero))
127 {
128 int err = Marshal.GetLastWin32Error();
129 throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceNames error! Error code: {0}", err));
130 }
131 return true;
132 }
133
134 private bool EnumResNames(IntPtr module, IntPtr type, IntPtr name, IntPtr param)
135 {
136 if (!NativeMethods.EnumResourceLanguages(module, type, name, new NativeMethods.EnumResLangsProc(EnumResLangs), IntPtr.Zero))
137 {
138 int err = Marshal.GetLastWin32Error();
139 throw new IOException(String.Format(CultureInfo.InvariantCulture, "EnumResourceLanguages error. Error code: {0}", err));
140 }
141 return true;
142 }
143
144 private bool EnumResLangs(IntPtr module, IntPtr type, IntPtr name, ushort langId, IntPtr param)
145 {
146 Resource res;
147 if (((int) type) == ResourceType.Version.IntegerValue)
148 {
149 res = new VersionResource(ResourceNameToString(name), langId);
150 }
151 else
152 {
153 res = new Resource(ResourceNameToString(type), ResourceNameToString(name), langId);
154 }
155
156 if (!this.Contains(res))
157 {
158 this.Add(res);
159 }
160
161 return true;
162 }
163
164 private static string ResourceNameToString(IntPtr resName)
165 {
166 if ((resName.ToInt64() >> 16) == 0)
167 {
168 return "#" + resName.ToString();
169 }
170 else
171 {
172 return Marshal.PtrToStringAuto(resName);
173 }
174 }
175
176 /// <summary>
177 /// For all resources in the collection, loads their data from a resource file.
178 /// </summary>
179 /// <param name="file">The file from which resources are loaded.</param>
180 public void Load(string file)
181 {
182 IntPtr module = NativeMethods.LoadLibraryEx(file, IntPtr.Zero, NativeMethods.LOAD_LIBRARY_AS_DATAFILE);
183 try
184 {
185 foreach (Resource res in this)
186 {
187 res.Load(module);
188 }
189 }
190 finally
191 {
192 NativeMethods.FreeLibrary(module);
193 }
194 }
195
196 /// <summary>
197 /// For all resources in the collection, saves their data to a resource file.
198 /// </summary>
199 /// <param name="file">The file to which resources are saved.</param>
200 public void Save(string file)
201 {
202 IntPtr updateHandle = IntPtr.Zero;
203 try
204 {
205 updateHandle = NativeMethods.BeginUpdateResource(file, false);
206 foreach (Resource res in this)
207 {
208 res.Save(updateHandle);
209 }
210 if (!NativeMethods.EndUpdateResource(updateHandle, false))
211 {
212 int err = Marshal.GetLastWin32Error();
213 throw new IOException(String.Format(CultureInfo.InvariantCulture, "Failed to save resource. Error {0}", err));
214 }
215 updateHandle = IntPtr.Zero;
216 }
217 finally
218 {
219 if (updateHandle != IntPtr.Zero)
220 {
221 NativeMethods.EndUpdateResource(updateHandle, true);
222 }
223 }
224 }
225
226 /// <summary>
227 /// Gets or sets the element at the specified index.
228 /// </summary>
229 public Resource this[int index]
230 {
231 get
232 {
233 return (Resource) this.resources[index];
234 }
235 set
236 {
237 this.resources[index] = value;
238 }
239 }
240
241 /// <summary>
242 /// Adds a new item to the collection.
243 /// </summary>
244 /// <param name="item">The Resource to add.</param>
245 public void Add(Resource item)
246 {
247 this.resources.Add(item);
248 }
249
250 /// <summary>
251 /// Removes an item to the collection.
252 /// </summary>
253 /// <param name="item">The Resource to remove.</param>
254 public bool Remove(Resource item)
255 {
256 return this.resources.Remove(item);
257 }
258
259 /// <summary>
260 /// Gets the index of an item in the collection.
261 /// </summary>
262 /// <param name="item">The Resource to search for.</param>
263 /// <returns>The index of the item, or -1 if not found.</returns>
264 public int IndexOf(Resource item)
265 {
266 return this.resources.IndexOf(item);
267 }
268
269 /// <summary>
270 /// Inserts a item into the collection.
271 /// </summary>
272 /// <param name="index">The insertion index.</param>
273 /// <param name="item">The Resource to insert.</param>
274 public void Insert(int index, Resource item)
275 {
276 this.resources.Insert(index, item);
277 }
278
279 /// <summary>
280 /// Tests if the collection contains an item.
281 /// </summary>
282 /// <param name="item">The Resource to search for.</param>
283 /// <returns>true if the item is found; false otherwise</returns>
284 public bool Contains(Resource item)
285 {
286 return this.resources.Contains(item);
287 }
288
289 /// <summary>
290 /// Copies the collection into an array.
291 /// </summary>
292 /// <param name="array">The array to copy into.</param>
293 /// <param name="arrayIndex">The starting index in the destination array.</param>
294 public void CopyTo(Resource[] array, int arrayIndex)
295 {
296 this.resources.CopyTo(array, arrayIndex);
297 }
298
299 /// <summary>
300 /// Removes all resources from the collection.
301 /// </summary>
302 public void Clear()
303 {
304 this.resources.Clear();
305 }
306
307 /// <summary>
308 /// Gets the number of resources in the collection.
309 /// </summary>
310 public int Count
311 {
312 get
313 {
314 return this.resources.Count;
315 }
316 }
317
318 /// <summary>
319 /// Gets an enumerator over all resources in the collection.
320 /// </summary>
321 /// <returns></returns>
322 public IEnumerator<Resource> GetEnumerator()
323 {
324 return this.resources.GetEnumerator();
325 }
326
327 IEnumerator IEnumerable.GetEnumerator()
328 {
329 return ((IEnumerable) this.resources).GetEnumerator();
330 }
331
332 bool ICollection<Resource>.IsReadOnly
333 {
334 get
335 {
336 return false;
337 }
338 }
339 }
340}