diff options
Diffstat (limited to 'src/tools/heat/UtilFinalizeHarvesterMutator.cs')
-rw-r--r-- | src/tools/heat/UtilFinalizeHarvesterMutator.cs | 1220 |
1 files changed, 0 insertions, 1220 deletions
diff --git a/src/tools/heat/UtilFinalizeHarvesterMutator.cs b/src/tools/heat/UtilFinalizeHarvesterMutator.cs deleted file mode 100644 index 7097759b..00000000 --- a/src/tools/heat/UtilFinalizeHarvesterMutator.cs +++ /dev/null | |||
@@ -1,1220 +0,0 @@ | |||
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 | |||
3 | namespace WixToolset.Harvesters | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Collections.Specialized; | ||
9 | using System.Globalization; | ||
10 | using System.IO; | ||
11 | using System.Runtime.InteropServices; | ||
12 | using System.Text; | ||
13 | using WixToolset.Harvesters.Data; | ||
14 | using WixToolset.Harvesters.Extensibility; | ||
15 | using Wix = WixToolset.Harvesters.Serialize; | ||
16 | |||
17 | /// <summary> | ||
18 | /// The finalize harvester mutator for the WiX Toolset Utility Extension. | ||
19 | /// </summary> | ||
20 | public sealed class UtilFinalizeHarvesterMutator : BaseMutatorExtension | ||
21 | { | ||
22 | private ArrayList components; | ||
23 | private ArrayList directories; | ||
24 | private SortedList directoryPaths; | ||
25 | private Hashtable filePaths; | ||
26 | private ArrayList files; | ||
27 | private ArrayList registryValues; | ||
28 | private List<Wix.Payload> payloads; | ||
29 | private bool suppressCOMElements; | ||
30 | private bool suppressVB6COMElements; | ||
31 | private string preprocessorVariable; | ||
32 | |||
33 | /// <summary> | ||
34 | /// Instantiate a new UtilFinalizeHarvesterMutator. | ||
35 | /// </summary> | ||
36 | public UtilFinalizeHarvesterMutator() | ||
37 | { | ||
38 | this.components = new ArrayList(); | ||
39 | this.directories = new ArrayList(); | ||
40 | this.directoryPaths = new SortedList(); | ||
41 | this.filePaths = new Hashtable(); | ||
42 | this.files = new ArrayList(); | ||
43 | this.registryValues = new ArrayList(); | ||
44 | this.payloads = new List<Wix.Payload>(); | ||
45 | } | ||
46 | |||
47 | /// <summary> | ||
48 | /// Gets or sets the preprocessor variable for substitution. | ||
49 | /// </summary> | ||
50 | /// <value>The preprocessor variable for substitution.</value> | ||
51 | public string PreprocessorVariable | ||
52 | { | ||
53 | get { return this.preprocessorVariable; } | ||
54 | set { this.preprocessorVariable = value; } | ||
55 | } | ||
56 | |||
57 | /// <summary> | ||
58 | /// Gets the sequence of the extension. | ||
59 | /// </summary> | ||
60 | /// <value>The sequence of the extension.</value> | ||
61 | public override int Sequence | ||
62 | { | ||
63 | get { return 2000; } | ||
64 | } | ||
65 | |||
66 | /// <summary> | ||
67 | /// Gets or sets the option to suppress COM elements. | ||
68 | /// </summary> | ||
69 | /// <value>The option to suppress COM elements.</value> | ||
70 | public bool SuppressCOMElements | ||
71 | { | ||
72 | get { return this.suppressCOMElements; } | ||
73 | set { this.suppressCOMElements = value; } | ||
74 | } | ||
75 | |||
76 | /// <summary> | ||
77 | /// Gets or sets the option to suppress VB6 COM elements. | ||
78 | /// </summary> | ||
79 | /// <value>The option to suppress VB6 COM elements.</value> | ||
80 | public bool SuppressVB6COMElements | ||
81 | { | ||
82 | get { return this.suppressVB6COMElements; } | ||
83 | set { this.suppressVB6COMElements = value; } | ||
84 | } | ||
85 | |||
86 | /// <summary> | ||
87 | /// Mutate a WiX document. | ||
88 | /// </summary> | ||
89 | /// <param name="wix">The Wix document element.</param> | ||
90 | public override void Mutate(Wix.Wix wix) | ||
91 | { | ||
92 | this.components.Clear(); | ||
93 | this.directories.Clear(); | ||
94 | this.directoryPaths.Clear(); | ||
95 | this.filePaths.Clear(); | ||
96 | this.files.Clear(); | ||
97 | this.registryValues.Clear(); | ||
98 | this.payloads.Clear(); | ||
99 | |||
100 | // index elements in this wix document | ||
101 | this.IndexElement(wix); | ||
102 | |||
103 | this.MutateDirectories(); | ||
104 | this.MutateFiles(); | ||
105 | this.MutateRegistryValues(); | ||
106 | this.MutatePayloads(); | ||
107 | |||
108 | // must occur after all the registry values have been formatted | ||
109 | this.MutateComponents(); | ||
110 | } | ||
111 | |||
112 | /// <summary> | ||
113 | /// Index an element. | ||
114 | /// </summary> | ||
115 | /// <param name="element">The element to index.</param> | ||
116 | private void IndexElement(Wix.ISchemaElement element) | ||
117 | { | ||
118 | if (element is Wix.Component) | ||
119 | { | ||
120 | // Component elements only need to be indexed if COM registry values will be strongly typed | ||
121 | if (!this.suppressCOMElements) | ||
122 | { | ||
123 | this.components.Add(element); | ||
124 | } | ||
125 | } | ||
126 | else if (element is Wix.Directory) | ||
127 | { | ||
128 | this.directories.Add(element); | ||
129 | } | ||
130 | else if (element is Wix.File) | ||
131 | { | ||
132 | this.files.Add(element); | ||
133 | } | ||
134 | else if (element is Wix.RegistryValue) | ||
135 | { | ||
136 | this.registryValues.Add(element); | ||
137 | } | ||
138 | else if (element is Wix.Payload payloadElement) | ||
139 | { | ||
140 | this.payloads.Add(payloadElement); | ||
141 | } | ||
142 | |||
143 | // index the child elements | ||
144 | if (element is Wix.IParentElement) | ||
145 | { | ||
146 | foreach (Wix.ISchemaElement childElement in ((Wix.IParentElement)element).Children) | ||
147 | { | ||
148 | this.IndexElement(childElement); | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /// <summary> | ||
154 | /// Mutate the components. | ||
155 | /// </summary> | ||
156 | private void MutateComponents() | ||
157 | { | ||
158 | if (this.suppressVB6COMElements) | ||
159 | { | ||
160 | // Search for VB6 specific COM registrations | ||
161 | foreach (Wix.Component component in this.components) | ||
162 | { | ||
163 | ArrayList vb6RegistryValues = new ArrayList(); | ||
164 | |||
165 | foreach (Wix.RegistryValue registryValue in component[typeof(Wix.RegistryValue)]) | ||
166 | { | ||
167 | if (Wix.RegistryValue.ActionType.write == registryValue.Action && Wix.RegistryRootType.HKCR == registryValue.Root) | ||
168 | { | ||
169 | string[] parts = registryValue.Key.Split('\\'); | ||
170 | |||
171 | if (String.Equals(parts[0], "CLSID", StringComparison.OrdinalIgnoreCase)) | ||
172 | { | ||
173 | // Search for the VB6 CLSID {D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731} | ||
174 | if (2 <= parts.Length) | ||
175 | { | ||
176 | if (String.Equals(parts[1], "{D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731}", StringComparison.OrdinalIgnoreCase)) | ||
177 | { | ||
178 | if (!vb6RegistryValues.Contains(registryValue)) | ||
179 | { | ||
180 | vb6RegistryValues.Add(registryValue); | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | } | ||
185 | else if (String.Equals(parts[0], "TypeLib", StringComparison.OrdinalIgnoreCase)) | ||
186 | { | ||
187 | // Search for the VB6 TypeLibs {EA544A21-C82D-11D1-A3E4-00A0C90AEA82} or {000204EF-0000-0000-C000-000000000046} | ||
188 | if (2 <= parts.Length) | ||
189 | { | ||
190 | if (String.Equals(parts[1], "{EA544A21-C82D-11D1-A3E4-00A0C90AEA82}", StringComparison.OrdinalIgnoreCase) || | ||
191 | String.Equals(parts[1], "{000204EF-0000-0000-C000-000000000046}", StringComparison.OrdinalIgnoreCase)) | ||
192 | { | ||
193 | if (!vb6RegistryValues.Contains(registryValue)) | ||
194 | { | ||
195 | vb6RegistryValues.Add(registryValue); | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | else if (String.Equals(parts[0], "Interface", StringComparison.OrdinalIgnoreCase)) | ||
201 | { | ||
202 | // Search for any Interfaces that reference the VB6 TypeLibs {EA544A21-C82D-11D1-A3E4-00A0C90AEA82} or {000204EF-0000-0000-C000-000000000046} | ||
203 | if (3 <= parts.Length) | ||
204 | { | ||
205 | if (String.Equals(parts[2], "TypeLib", StringComparison.OrdinalIgnoreCase)) | ||
206 | { | ||
207 | if (String.Equals(registryValue.Value, "{EA544A21-C82D-11D1-A3E4-00A0C90AEA82}", StringComparison.OrdinalIgnoreCase) || | ||
208 | String.Equals(registryValue.Value, "{000204EF-0000-0000-C000-000000000046}", StringComparison.OrdinalIgnoreCase)) | ||
209 | { | ||
210 | // Having found a match we have to loop through again finding the matching Interface entries | ||
211 | foreach (Wix.RegistryValue regValue in component[typeof(Wix.RegistryValue)]) | ||
212 | { | ||
213 | if (Wix.RegistryValue.ActionType.write == regValue.Action && Wix.RegistryRootType.HKCR == regValue.Root) | ||
214 | { | ||
215 | string[] rvparts = regValue.Key.Split('\\'); | ||
216 | if (String.Equals(rvparts[0], "Interface", StringComparison.OrdinalIgnoreCase)) | ||
217 | { | ||
218 | if (2 <= rvparts.Length) | ||
219 | { | ||
220 | if (String.Equals(rvparts[1], parts[1], StringComparison.OrdinalIgnoreCase)) | ||
221 | { | ||
222 | if (!vb6RegistryValues.Contains(regValue)) | ||
223 | { | ||
224 | vb6RegistryValues.Add(regValue); | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | } | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | // Remove all the VB6 specific COM registry values | ||
239 | foreach (Object entry in vb6RegistryValues) | ||
240 | { | ||
241 | component.RemoveChild((Wix.RegistryValue)entry); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | foreach (Wix.Component component in this.components) | ||
247 | { | ||
248 | SortedList indexedElements = CollectionsUtil.CreateCaseInsensitiveSortedList(); | ||
249 | SortedList indexedRegistryValues = CollectionsUtil.CreateCaseInsensitiveSortedList(); | ||
250 | List<Wix.RegistryValue> duplicateRegistryValues = new List<Wix.RegistryValue>(); | ||
251 | |||
252 | // index all the File elements | ||
253 | foreach (Wix.File file in component[typeof(Wix.File)]) | ||
254 | { | ||
255 | indexedElements.Add(String.Concat("file/", file.Id), file); | ||
256 | } | ||
257 | |||
258 | // group all the registry values by the COM element they would correspond to and | ||
259 | // create a COM element for each group | ||
260 | foreach (Wix.RegistryValue registryValue in component[typeof(Wix.RegistryValue)]) | ||
261 | { | ||
262 | if (!String.IsNullOrEmpty(registryValue.Key) && Wix.RegistryValue.ActionType.write == registryValue.Action && Wix.RegistryRootType.HKCR == registryValue.Root && Wix.RegistryValue.TypeType.@string == registryValue.Type) | ||
263 | { | ||
264 | string index = null; | ||
265 | string[] parts = registryValue.Key.Split('\\'); | ||
266 | |||
267 | // create a COM element for COM registration and index it | ||
268 | if (1 <= parts.Length) | ||
269 | { | ||
270 | if (String.Equals(parts[0], "AppID", StringComparison.OrdinalIgnoreCase)) | ||
271 | { | ||
272 | // only work with GUID AppIds here | ||
273 | if (2 <= parts.Length && parts[1].StartsWith("{", StringComparison.Ordinal) && parts[1].EndsWith("}", StringComparison.Ordinal)) | ||
274 | { | ||
275 | index = String.Concat(parts[0], '/', parts[1]); | ||
276 | |||
277 | if (!indexedElements.Contains(index)) | ||
278 | { | ||
279 | Wix.AppId appId = new Wix.AppId(); | ||
280 | appId.Id = parts[1].ToUpper(CultureInfo.InvariantCulture); | ||
281 | indexedElements.Add(index, appId); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | else if (String.Equals(parts[0], "CLSID", StringComparison.OrdinalIgnoreCase)) | ||
286 | { | ||
287 | if (2 <= parts.Length) | ||
288 | { | ||
289 | index = String.Concat(parts[0], '/', parts[1]); | ||
290 | |||
291 | if (!indexedElements.Contains(index)) | ||
292 | { | ||
293 | Wix.Class wixClass = new Wix.Class(); | ||
294 | wixClass.Id = parts[1].ToUpper(CultureInfo.InvariantCulture); | ||
295 | indexedElements.Add(index, wixClass); | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | else if (String.Equals(parts[0], "Component Categories", StringComparison.OrdinalIgnoreCase)) | ||
300 | { | ||
301 | // If this is the .NET Component Category it should not end up in the authoring. Therefore, add | ||
302 | // the registry key to the duplicate list to ensure it gets removed later. | ||
303 | if (String.Equals(parts[1], "{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}", StringComparison.OrdinalIgnoreCase)) | ||
304 | { | ||
305 | duplicateRegistryValues.Add(registryValue); | ||
306 | } | ||
307 | else | ||
308 | { | ||
309 | // TODO: add support for Component Categories to the compiler. | ||
310 | } | ||
311 | } | ||
312 | else if (String.Equals(parts[0], "Interface", StringComparison.OrdinalIgnoreCase)) | ||
313 | { | ||
314 | if (2 <= parts.Length) | ||
315 | { | ||
316 | index = String.Concat(parts[0], '/', parts[1]); | ||
317 | |||
318 | if (!indexedElements.Contains(index)) | ||
319 | { | ||
320 | Wix.Interface wixInterface = new Wix.Interface(); | ||
321 | wixInterface.Id = parts[1].ToUpper(CultureInfo.InvariantCulture); | ||
322 | indexedElements.Add(index, wixInterface); | ||
323 | } | ||
324 | } | ||
325 | } | ||
326 | else if (String.Equals(parts[0], "TypeLib", StringComparison.Ordinal)) | ||
327 | { | ||
328 | if (3 <= parts.Length) | ||
329 | { | ||
330 | // use a special index to ensure progIds are processed before classes | ||
331 | index = String.Concat(".typelib/", parts[1], '/', parts[2]); | ||
332 | |||
333 | if (!indexedElements.Contains(index)) | ||
334 | { | ||
335 | Version version = TypeLibraryHarvester.ParseHexVersion(parts[2]); | ||
336 | if (version != null) | ||
337 | { | ||
338 | Wix.TypeLib typeLib = new Wix.TypeLib(); | ||
339 | typeLib.Id = parts[1].ToUpper(CultureInfo.InvariantCulture); | ||
340 | typeLib.MajorVersion = version.Major; | ||
341 | typeLib.MinorVersion = version.Minor; | ||
342 | indexedElements.Add(index, typeLib); | ||
343 | } | ||
344 | else // not a valid type library registry value | ||
345 | { | ||
346 | index = null; | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | else if (parts[0].StartsWith(".", StringComparison.Ordinal)) | ||
352 | { | ||
353 | // extension | ||
354 | } | ||
355 | else // ProgId (hopefully) | ||
356 | { | ||
357 | // use a special index to ensure progIds are processed before classes | ||
358 | index = String.Concat(".progid/", parts[0]); | ||
359 | |||
360 | if (!indexedElements.Contains(index)) | ||
361 | { | ||
362 | Wix.ProgId progId = new Wix.ProgId(); | ||
363 | progId.Id = parts[0]; | ||
364 | indexedElements.Add(index, progId); | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | |||
369 | // index the RegistryValue element according to the COM element it corresponds to | ||
370 | if (null != index) | ||
371 | { | ||
372 | SortedList registryValues = (SortedList)indexedRegistryValues[index]; | ||
373 | |||
374 | if (null == registryValues) | ||
375 | { | ||
376 | registryValues = CollectionsUtil.CreateCaseInsensitiveSortedList(); | ||
377 | indexedRegistryValues.Add(index, registryValues); | ||
378 | } | ||
379 | |||
380 | try | ||
381 | { | ||
382 | registryValues.Add(String.Concat(registryValue.Key, '/', registryValue.Name), registryValue); | ||
383 | } | ||
384 | catch (ArgumentException) | ||
385 | { | ||
386 | duplicateRegistryValues.Add(registryValue); | ||
387 | |||
388 | if (String.IsNullOrEmpty(registryValue.Value)) | ||
389 | { | ||
390 | this.Core.Messaging.Write(HarvesterWarnings.DuplicateDllRegistryEntry(String.Concat(registryValue.Key, '/', registryValue.Name), component.Id)); | ||
391 | } | ||
392 | else | ||
393 | { | ||
394 | this.Core.Messaging.Write(HarvesterWarnings.DuplicateDllRegistryEntry(String.Concat(registryValue.Key, '/', registryValue.Name), registryValue.Value, component.Id)); | ||
395 | } | ||
396 | } | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | |||
401 | foreach (Wix.RegistryValue removeRegistryEntry in duplicateRegistryValues) | ||
402 | { | ||
403 | component.RemoveChild(removeRegistryEntry); | ||
404 | } | ||
405 | |||
406 | // set various values on the COM elements from their corresponding registry values | ||
407 | Hashtable indexedProcessedRegistryValues = new Hashtable(); | ||
408 | foreach (DictionaryEntry entry in indexedRegistryValues) | ||
409 | { | ||
410 | Wix.ISchemaElement element = (Wix.ISchemaElement)indexedElements[entry.Key]; | ||
411 | string parentIndex = null; | ||
412 | SortedList registryValues = (SortedList)entry.Value; | ||
413 | |||
414 | // element-specific variables (for really tough situations) | ||
415 | string classAppId = null; | ||
416 | bool threadingModelSet = false; | ||
417 | |||
418 | foreach (Wix.RegistryValue registryValue in registryValues.Values) | ||
419 | { | ||
420 | string[] parts = registryValue.Key.ToLower(CultureInfo.InvariantCulture).Split('\\'); | ||
421 | bool processed = false; | ||
422 | |||
423 | if (element is Wix.AppId) | ||
424 | { | ||
425 | Wix.AppId appId = (Wix.AppId)element; | ||
426 | |||
427 | if (2 == parts.Length) | ||
428 | { | ||
429 | if (null == registryValue.Name) | ||
430 | { | ||
431 | appId.Description = registryValue.Value; | ||
432 | processed = true; | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | else if (element is Wix.Class) | ||
437 | { | ||
438 | Wix.Class wixClass = (Wix.Class)element; | ||
439 | |||
440 | if (2 == parts.Length) | ||
441 | { | ||
442 | if (null == registryValue.Name) | ||
443 | { | ||
444 | wixClass.Description = registryValue.Value; | ||
445 | processed = true; | ||
446 | } | ||
447 | else if (String.Equals(registryValue.Name, "AppID", StringComparison.OrdinalIgnoreCase)) | ||
448 | { | ||
449 | classAppId = registryValue.Value; | ||
450 | processed = true; | ||
451 | } | ||
452 | } | ||
453 | else if (3 == parts.Length) | ||
454 | { | ||
455 | Wix.Class.ContextType contextType = Wix.Class.ContextType.None; | ||
456 | |||
457 | switch (parts[2]) | ||
458 | { | ||
459 | case "control": | ||
460 | wixClass.Control = Wix.YesNoType.yes; | ||
461 | processed = true; | ||
462 | break; | ||
463 | case "inprochandler": | ||
464 | if (null == registryValue.Name) | ||
465 | { | ||
466 | if (null == wixClass.Handler) | ||
467 | { | ||
468 | wixClass.Handler = "1"; | ||
469 | processed = true; | ||
470 | } | ||
471 | else if ("2" == wixClass.Handler) | ||
472 | { | ||
473 | wixClass.Handler = "3"; | ||
474 | processed = true; | ||
475 | } | ||
476 | } | ||
477 | break; | ||
478 | case "inprochandler32": | ||
479 | if (null == registryValue.Name) | ||
480 | { | ||
481 | if (null == wixClass.Handler) | ||
482 | { | ||
483 | wixClass.Handler = "2"; | ||
484 | processed = true; | ||
485 | } | ||
486 | else if ("1" == wixClass.Handler) | ||
487 | { | ||
488 | wixClass.Handler = "3"; | ||
489 | processed = true; | ||
490 | } | ||
491 | } | ||
492 | break; | ||
493 | case "inprocserver": | ||
494 | contextType = Wix.Class.ContextType.InprocServer; | ||
495 | break; | ||
496 | case "inprocserver32": | ||
497 | contextType = Wix.Class.ContextType.InprocServer32; | ||
498 | break; | ||
499 | case "insertable": | ||
500 | wixClass.Insertable = Wix.YesNoType.yes; | ||
501 | processed = true; | ||
502 | break; | ||
503 | case "localserver": | ||
504 | contextType = Wix.Class.ContextType.LocalServer; | ||
505 | break; | ||
506 | case "localserver32": | ||
507 | contextType = Wix.Class.ContextType.LocalServer32; | ||
508 | break; | ||
509 | case "progid": | ||
510 | if (null == registryValue.Name) | ||
511 | { | ||
512 | Wix.ProgId progId = (Wix.ProgId)indexedElements[String.Concat(".progid/", registryValue.Value)]; | ||
513 | |||
514 | // verify that the versioned ProgId appears under this Class element | ||
515 | // if not, toss the entire element | ||
516 | if (null == progId || wixClass != progId.ParentElement) | ||
517 | { | ||
518 | element = null; | ||
519 | } | ||
520 | else | ||
521 | { | ||
522 | processed = true; | ||
523 | } | ||
524 | } | ||
525 | break; | ||
526 | case "programmable": | ||
527 | wixClass.Programmable = Wix.YesNoType.yes; | ||
528 | processed = true; | ||
529 | break; | ||
530 | case "typelib": | ||
531 | if (null == registryValue.Name) | ||
532 | { | ||
533 | foreach (DictionaryEntry indexedEntry in indexedElements) | ||
534 | { | ||
535 | string key = (string)indexedEntry.Key; | ||
536 | Wix.ISchemaElement possibleTypeLib = (Wix.ISchemaElement)indexedEntry.Value; | ||
537 | |||
538 | if (key.StartsWith(".typelib/", StringComparison.Ordinal) && | ||
539 | 0 == String.Compare(key, 9, registryValue.Value, 0, registryValue.Value.Length, StringComparison.OrdinalIgnoreCase)) | ||
540 | { | ||
541 | // ensure the TypeLib is nested under the same thing we want the Class under | ||
542 | if (null == parentIndex || indexedElements[parentIndex] == possibleTypeLib.ParentElement) | ||
543 | { | ||
544 | parentIndex = key; | ||
545 | processed = true; | ||
546 | } | ||
547 | } | ||
548 | } | ||
549 | } | ||
550 | break; | ||
551 | case "version": | ||
552 | if (null == registryValue.Name) | ||
553 | { | ||
554 | wixClass.Version = registryValue.Value; | ||
555 | processed = true; | ||
556 | } | ||
557 | break; | ||
558 | case "versionindependentprogid": | ||
559 | if (null == registryValue.Name) | ||
560 | { | ||
561 | Wix.ProgId progId = (Wix.ProgId)indexedElements[String.Concat(".progid/", registryValue.Value)]; | ||
562 | |||
563 | // verify that the version independent ProgId appears somewhere | ||
564 | // under this Class element - if not, toss the entire element | ||
565 | if (null == progId || wixClass != progId.ParentElement) | ||
566 | { | ||
567 | // check the parent of the parent | ||
568 | if (null == progId || null == progId.ParentElement || wixClass != progId.ParentElement.ParentElement) | ||
569 | { | ||
570 | element = null; | ||
571 | } | ||
572 | } | ||
573 | |||
574 | processed = true; | ||
575 | } | ||
576 | break; | ||
577 | } | ||
578 | |||
579 | if (Wix.Class.ContextType.None != contextType) | ||
580 | { | ||
581 | wixClass.Context |= contextType; | ||
582 | |||
583 | if (null == registryValue.Name) | ||
584 | { | ||
585 | if ((registryValue.Value.StartsWith("[!", StringComparison.Ordinal) || registryValue.Value.StartsWith("[#", StringComparison.Ordinal)) | ||
586 | && registryValue.Value.EndsWith("]", StringComparison.Ordinal)) | ||
587 | { | ||
588 | parentIndex = String.Concat("file/", registryValue.Value.Substring(2, registryValue.Value.Length - 3)); | ||
589 | processed = true; | ||
590 | } | ||
591 | else if (String.Equals(Path.GetFileName(registryValue.Value), "mscoree.dll", StringComparison.OrdinalIgnoreCase)) | ||
592 | { | ||
593 | wixClass.ForeignServer = "mscoree.dll"; | ||
594 | processed = true; | ||
595 | } | ||
596 | else if (String.Equals(Path.GetFileName(registryValue.Value), "msvbvm60.dll", StringComparison.OrdinalIgnoreCase)) | ||
597 | { | ||
598 | wixClass.ForeignServer = "msvbvm60.dll"; | ||
599 | processed = true; | ||
600 | } | ||
601 | else | ||
602 | { | ||
603 | // Some servers are specifying relative paths (which the above code doesn't find) | ||
604 | // If there's any ambiguity leave it alone and let the developer figure it out when it breaks in the compiler | ||
605 | |||
606 | bool possibleDuplicate = false; | ||
607 | string possibleParentIndex = null; | ||
608 | |||
609 | foreach (Wix.File file in this.files) | ||
610 | { | ||
611 | if (String.Equals(registryValue.Value, Path.GetFileName(file.Source), StringComparison.OrdinalIgnoreCase)) | ||
612 | { | ||
613 | if (null == possibleParentIndex) | ||
614 | { | ||
615 | possibleParentIndex = String.Concat("file/", file.Id); | ||
616 | } | ||
617 | else | ||
618 | { | ||
619 | possibleDuplicate = true; | ||
620 | break; | ||
621 | } | ||
622 | } | ||
623 | } | ||
624 | |||
625 | if (!possibleDuplicate) | ||
626 | { | ||
627 | if (null == possibleParentIndex) | ||
628 | { | ||
629 | wixClass.ForeignServer = registryValue.Value; | ||
630 | processed = true; | ||
631 | } | ||
632 | else | ||
633 | { | ||
634 | parentIndex = possibleParentIndex; | ||
635 | wixClass.RelativePath = Wix.YesNoType.yes; | ||
636 | processed = true; | ||
637 | } | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | else if (String.Equals(registryValue.Name, "ThreadingModel", StringComparison.OrdinalIgnoreCase)) | ||
642 | { | ||
643 | Wix.Class.ThreadingModelType threadingModel; | ||
644 | |||
645 | if (String.Equals(registryValue.Value, "apartment", StringComparison.OrdinalIgnoreCase)) | ||
646 | { | ||
647 | threadingModel = Wix.Class.ThreadingModelType.apartment; | ||
648 | processed = true; | ||
649 | } | ||
650 | else if (String.Equals(registryValue.Value, "both", StringComparison.OrdinalIgnoreCase)) | ||
651 | { | ||
652 | threadingModel = Wix.Class.ThreadingModelType.both; | ||
653 | processed = true; | ||
654 | } | ||
655 | else if (String.Equals(registryValue.Value, "free", StringComparison.OrdinalIgnoreCase)) | ||
656 | { | ||
657 | threadingModel = Wix.Class.ThreadingModelType.free; | ||
658 | processed = true; | ||
659 | } | ||
660 | else if (String.Equals(registryValue.Value, "neutral", StringComparison.OrdinalIgnoreCase)) | ||
661 | { | ||
662 | threadingModel = Wix.Class.ThreadingModelType.neutral; | ||
663 | processed = true; | ||
664 | } | ||
665 | else if (String.Equals(registryValue.Value, "rental", StringComparison.OrdinalIgnoreCase)) | ||
666 | { | ||
667 | threadingModel = Wix.Class.ThreadingModelType.rental; | ||
668 | processed = true; | ||
669 | } | ||
670 | else if (String.Equals(registryValue.Value, "single", StringComparison.OrdinalIgnoreCase)) | ||
671 | { | ||
672 | threadingModel = Wix.Class.ThreadingModelType.single; | ||
673 | processed = true; | ||
674 | } | ||
675 | else | ||
676 | { | ||
677 | continue; | ||
678 | } | ||
679 | |||
680 | if (!threadingModelSet || wixClass.ThreadingModel == threadingModel) | ||
681 | { | ||
682 | wixClass.ThreadingModel = threadingModel; | ||
683 | threadingModelSet = true; | ||
684 | } | ||
685 | else | ||
686 | { | ||
687 | element = null; | ||
688 | break; | ||
689 | } | ||
690 | } | ||
691 | } | ||
692 | } | ||
693 | else if (4 == parts.Length) | ||
694 | { | ||
695 | if (String.Equals(parts[2], "implemented categories", StringComparison.Ordinal)) | ||
696 | { | ||
697 | switch (parts[3]) | ||
698 | { | ||
699 | case "{7dd95801-9882-11cf-9fa9-00aa006c42c4}": | ||
700 | wixClass.SafeForScripting = Wix.YesNoType.yes; | ||
701 | processed = true; | ||
702 | break; | ||
703 | case "{7dd95802-9882-11cf-9fa9-00aa006c42c4}": | ||
704 | wixClass.SafeForInitializing = Wix.YesNoType.yes; | ||
705 | processed = true; | ||
706 | break; | ||
707 | } | ||
708 | } | ||
709 | } | ||
710 | } | ||
711 | else if (element is Wix.Interface) | ||
712 | { | ||
713 | Wix.Interface wixInterface = (Wix.Interface)element; | ||
714 | |||
715 | if (2 == parts.Length && null == registryValue.Name) | ||
716 | { | ||
717 | wixInterface.Name = registryValue.Value; | ||
718 | processed = true; | ||
719 | } | ||
720 | else if (3 == parts.Length) | ||
721 | { | ||
722 | switch (parts[2]) | ||
723 | { | ||
724 | case "proxystubclsid": | ||
725 | if (null == registryValue.Name) | ||
726 | { | ||
727 | wixInterface.ProxyStubClassId = registryValue.Value.ToUpper(CultureInfo.InvariantCulture); | ||
728 | processed = true; | ||
729 | } | ||
730 | break; | ||
731 | case "proxystubclsid32": | ||
732 | if (null == registryValue.Name) | ||
733 | { | ||
734 | wixInterface.ProxyStubClassId32 = registryValue.Value.ToUpper(CultureInfo.InvariantCulture); | ||
735 | processed = true; | ||
736 | } | ||
737 | break; | ||
738 | case "nummethods": | ||
739 | if (null == registryValue.Name) | ||
740 | { | ||
741 | wixInterface.NumMethods = Convert.ToInt32(registryValue.Value, CultureInfo.InvariantCulture); | ||
742 | processed = true; | ||
743 | } | ||
744 | break; | ||
745 | case "typelib": | ||
746 | if (String.Equals("Version", registryValue.Name, StringComparison.OrdinalIgnoreCase)) | ||
747 | { | ||
748 | parentIndex = String.Concat(parentIndex, registryValue.Value); | ||
749 | processed = true; | ||
750 | } | ||
751 | else if (null == registryValue.Name) // TypeLib guid | ||
752 | { | ||
753 | parentIndex = String.Concat(".typelib/", registryValue.Value, '/', parentIndex); | ||
754 | processed = true; | ||
755 | } | ||
756 | break; | ||
757 | } | ||
758 | } | ||
759 | } | ||
760 | else if (element is Wix.ProgId) | ||
761 | { | ||
762 | Wix.ProgId progId = (Wix.ProgId)element; | ||
763 | |||
764 | if (null == registryValue.Name) | ||
765 | { | ||
766 | if (1 == parts.Length) | ||
767 | { | ||
768 | progId.Description = registryValue.Value; | ||
769 | processed = true; | ||
770 | } | ||
771 | else if (2 == parts.Length) | ||
772 | { | ||
773 | if (String.Equals(parts[1], "CLSID", StringComparison.OrdinalIgnoreCase)) | ||
774 | { | ||
775 | parentIndex = String.Concat("CLSID/", registryValue.Value); | ||
776 | processed = true; | ||
777 | } | ||
778 | else if (String.Equals(parts[1], "CurVer", StringComparison.OrdinalIgnoreCase)) | ||
779 | { | ||
780 | // If a progId points to its own ProgId with CurVer, it isn't meaningful, so ignore it | ||
781 | if (!String.Equals(progId.Id, registryValue.Value, StringComparison.OrdinalIgnoreCase)) | ||
782 | { | ||
783 | // this registry value should usually be processed second so the | ||
784 | // version independent ProgId should be under the versioned one | ||
785 | parentIndex = String.Concat(".progid/", registryValue.Value); | ||
786 | processed = true; | ||
787 | } | ||
788 | } | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | else if (element is Wix.TypeLib) | ||
793 | { | ||
794 | Wix.TypeLib typeLib = (Wix.TypeLib)element; | ||
795 | |||
796 | if (null == registryValue.Name) | ||
797 | { | ||
798 | if (3 == parts.Length) | ||
799 | { | ||
800 | typeLib.Description = registryValue.Value; | ||
801 | processed = true; | ||
802 | } | ||
803 | else if (4 == parts.Length) | ||
804 | { | ||
805 | if (String.Equals(parts[3], "flags", StringComparison.OrdinalIgnoreCase)) | ||
806 | { | ||
807 | int flags = Convert.ToInt32(registryValue.Value, CultureInfo.InvariantCulture); | ||
808 | |||
809 | if (0x1 == (flags & 0x1)) | ||
810 | { | ||
811 | typeLib.Restricted = Wix.YesNoType.yes; | ||
812 | } | ||
813 | |||
814 | if (0x2 == (flags & 0x2)) | ||
815 | { | ||
816 | typeLib.Control = Wix.YesNoType.yes; | ||
817 | } | ||
818 | |||
819 | if (0x4 == (flags & 0x4)) | ||
820 | { | ||
821 | typeLib.Hidden = Wix.YesNoType.yes; | ||
822 | } | ||
823 | |||
824 | if (0x8 == (flags & 0x8)) | ||
825 | { | ||
826 | typeLib.HasDiskImage = Wix.YesNoType.yes; | ||
827 | } | ||
828 | |||
829 | processed = true; | ||
830 | } | ||
831 | else if (String.Equals(parts[3], "helpdir", StringComparison.OrdinalIgnoreCase)) | ||
832 | { | ||
833 | if (registryValue.Value.StartsWith("[", StringComparison.Ordinal) && (registryValue.Value.EndsWith("]", StringComparison.Ordinal) | ||
834 | || registryValue.Value.EndsWith("]\\", StringComparison.Ordinal))) | ||
835 | { | ||
836 | typeLib.HelpDirectory = registryValue.Value.Substring(1, registryValue.Value.LastIndexOf(']') - 1); | ||
837 | } | ||
838 | else if (0 == String.Compare(registryValue.Value, Environment.SystemDirectory, StringComparison.OrdinalIgnoreCase)) // VB6 DLLs register their help directory as SystemFolder | ||
839 | { | ||
840 | typeLib.HelpDirectory = "SystemFolder"; | ||
841 | } | ||
842 | else if (null != component.Directory) // -sfrag has not been specified | ||
843 | { | ||
844 | typeLib.HelpDirectory = component.Directory; | ||
845 | } | ||
846 | else if (component.ParentElement is Wix.Directory) // -sfrag has been specified | ||
847 | { | ||
848 | typeLib.HelpDirectory = ((Wix.Directory)component.ParentElement).Id; | ||
849 | } | ||
850 | else if (component.ParentElement is Wix.DirectoryRef) // -sfrag has been specified | ||
851 | { | ||
852 | typeLib.HelpDirectory = ((Wix.DirectoryRef)component.ParentElement).Id; | ||
853 | } | ||
854 | |||
855 | //If the helpdir has not matched a known directory, drop it because it cannot be resolved. | ||
856 | processed = true; | ||
857 | } | ||
858 | } | ||
859 | else if (5 == parts.Length && (String.Equals("win32", parts[4], StringComparison.OrdinalIgnoreCase) || String.Equals("win64", parts[4], StringComparison.OrdinalIgnoreCase))) | ||
860 | { | ||
861 | typeLib.Language = Convert.ToInt32(parts[3], CultureInfo.InvariantCulture); | ||
862 | |||
863 | if ((registryValue.Value.StartsWith("[!", StringComparison.Ordinal) || registryValue.Value.StartsWith("[#", StringComparison.Ordinal)) | ||
864 | && registryValue.Value.EndsWith("]", StringComparison.Ordinal)) | ||
865 | { | ||
866 | parentIndex = String.Concat("file/", registryValue.Value.Substring(2, registryValue.Value.Length - 3)); | ||
867 | } | ||
868 | |||
869 | processed = true; | ||
870 | } | ||
871 | } | ||
872 | } | ||
873 | |||
874 | // index the processed registry values by their corresponding COM element | ||
875 | if (processed) | ||
876 | { | ||
877 | indexedProcessedRegistryValues.Add(registryValue, element); | ||
878 | } | ||
879 | } | ||
880 | |||
881 | // parent the COM element | ||
882 | if (null != element) | ||
883 | { | ||
884 | if (null != parentIndex) | ||
885 | { | ||
886 | Wix.IParentElement parentElement = (Wix.IParentElement)indexedElements[parentIndex]; | ||
887 | |||
888 | if (null != parentElement) | ||
889 | { | ||
890 | parentElement.AddChild(element); | ||
891 | } | ||
892 | } | ||
893 | else if (0 < indexedProcessedRegistryValues.Count) | ||
894 | { | ||
895 | component.AddChild(element); | ||
896 | } | ||
897 | |||
898 | // special handling for AppID since it doesn't fit the general model | ||
899 | if (null != classAppId) | ||
900 | { | ||
901 | Wix.AppId appId = (Wix.AppId)indexedElements[String.Concat("AppID/", classAppId)]; | ||
902 | |||
903 | // move the Class element under the AppId (and put the AppId under its old parent) | ||
904 | if (null != appId) | ||
905 | { | ||
906 | // move the AppId element | ||
907 | ((Wix.IParentElement)appId.ParentElement).RemoveChild(appId); | ||
908 | ((Wix.IParentElement)element.ParentElement).AddChild(appId); | ||
909 | |||
910 | // move the Class element | ||
911 | ((Wix.IParentElement)element.ParentElement).RemoveChild(element); | ||
912 | appId.AddChild(element); | ||
913 | } | ||
914 | } | ||
915 | } | ||
916 | } | ||
917 | |||
918 | // remove the RegistryValue elements which were converted into COM elements | ||
919 | // that were successfully nested under the Component element | ||
920 | foreach (DictionaryEntry entry in indexedProcessedRegistryValues) | ||
921 | { | ||
922 | Wix.ISchemaElement element = (Wix.ISchemaElement)entry.Value; | ||
923 | Wix.RegistryValue registryValue = (Wix.RegistryValue)entry.Key; | ||
924 | |||
925 | while (null != element) | ||
926 | { | ||
927 | if (element == component) | ||
928 | { | ||
929 | ((Wix.IParentElement)registryValue.ParentElement).RemoveChild(registryValue); | ||
930 | break; | ||
931 | } | ||
932 | |||
933 | element = element.ParentElement; | ||
934 | } | ||
935 | } | ||
936 | } | ||
937 | } | ||
938 | |||
939 | /// <summary> | ||
940 | /// Mutate the directories. | ||
941 | /// </summary> | ||
942 | private void MutateDirectories() | ||
943 | { | ||
944 | foreach (Wix.Directory directory in this.directories) | ||
945 | { | ||
946 | string path = directory.FileSource; | ||
947 | |||
948 | // create a new directory element without the FileSource attribute | ||
949 | if (null != path) | ||
950 | { | ||
951 | Wix.Directory newDirectory = new Wix.Directory(); | ||
952 | |||
953 | newDirectory.Id = directory.Id; | ||
954 | newDirectory.Name = directory.Name; | ||
955 | |||
956 | foreach (Wix.ISchemaElement element in directory.Children) | ||
957 | { | ||
958 | newDirectory.AddChild(element); | ||
959 | } | ||
960 | |||
961 | ((Wix.IParentElement)directory.ParentElement).AddChild(newDirectory); | ||
962 | ((Wix.IParentElement)directory.ParentElement).RemoveChild(directory); | ||
963 | |||
964 | if (null != newDirectory.Id) | ||
965 | { | ||
966 | this.directoryPaths[path.ToLower(CultureInfo.InvariantCulture)] = String.Concat("[", newDirectory.Id, "]"); | ||
967 | } | ||
968 | } | ||
969 | } | ||
970 | } | ||
971 | |||
972 | /// <summary> | ||
973 | /// Mutate the files. | ||
974 | /// </summary> | ||
975 | private void MutateFiles() | ||
976 | { | ||
977 | string sourceDirSubstitution = this.preprocessorVariable; | ||
978 | if (sourceDirSubstitution != null) | ||
979 | { | ||
980 | string prefix = "$("; | ||
981 | if (sourceDirSubstitution.StartsWith("wix.", StringComparison.Ordinal)) | ||
982 | { | ||
983 | prefix = "!("; | ||
984 | } | ||
985 | sourceDirSubstitution = String.Concat(prefix, sourceDirSubstitution, ")"); | ||
986 | } | ||
987 | |||
988 | foreach (Wix.File file in this.files) | ||
989 | { | ||
990 | if (null != file.Id && null != file.Source) | ||
991 | { | ||
992 | string fileSource = this.Core.ResolveFilePath(file.Source); | ||
993 | |||
994 | // index the long path | ||
995 | this.filePaths[fileSource.ToLower(CultureInfo.InvariantCulture)] = String.Concat("[#", file.Id, "]"); | ||
996 | |||
997 | // index the long path as a URL for assembly harvesting | ||
998 | Uri fileUri = new Uri(fileSource); | ||
999 | this.filePaths[fileUri.ToString().ToLower(CultureInfo.InvariantCulture)] = String.Concat("file:///[#", file.Id, "]"); | ||
1000 | |||
1001 | // index the short path | ||
1002 | string shortPath = NativeMethods.GetShortPathName(fileSource); | ||
1003 | this.filePaths[shortPath.ToLower(CultureInfo.InvariantCulture)] = String.Concat("[!", file.Id, "]"); | ||
1004 | |||
1005 | // escape literal $ characters | ||
1006 | file.Source = file.Source.Replace("$", "$$"); | ||
1007 | |||
1008 | if (null != sourceDirSubstitution && file.Source.StartsWith("SourceDir\\", StringComparison.Ordinal)) | ||
1009 | { | ||
1010 | file.Source = file.Source.Substring(9).Insert(0, sourceDirSubstitution); | ||
1011 | } | ||
1012 | } | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | /// <summary> | ||
1017 | /// Mutate the payloads. | ||
1018 | /// </summary> | ||
1019 | private void MutatePayloads() | ||
1020 | { | ||
1021 | string sourceDirSubstitution = this.preprocessorVariable; | ||
1022 | if (sourceDirSubstitution == null) | ||
1023 | { | ||
1024 | return; | ||
1025 | } | ||
1026 | |||
1027 | string prefix = "$("; | ||
1028 | if (sourceDirSubstitution.StartsWith("wix.", StringComparison.Ordinal)) | ||
1029 | { | ||
1030 | prefix = "!("; | ||
1031 | } | ||
1032 | sourceDirSubstitution = String.Concat(prefix, sourceDirSubstitution, ")"); | ||
1033 | |||
1034 | foreach (var payload in this.payloads) | ||
1035 | { | ||
1036 | if (payload.SourceFile != null && payload.SourceFile.StartsWith("SourceDir\\", StringComparison.Ordinal)) | ||
1037 | { | ||
1038 | payload.SourceFile = payload.SourceFile.Substring(9).Insert(0, sourceDirSubstitution); | ||
1039 | } | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | /// <summary> | ||
1044 | /// Mutate an individual registry string, according to a collection of replacement items. | ||
1045 | /// </summary> | ||
1046 | /// <param name="value">The string to mutate.</param> | ||
1047 | /// <param name="replace">The collection of items to replace within the string.</param> | ||
1048 | /// <value>The mutated registry string.</value> | ||
1049 | private string MutateRegistryString(string value, ICollection replace) | ||
1050 | { | ||
1051 | int index; | ||
1052 | string lowercaseValue = value.ToLower(CultureInfo.InvariantCulture); | ||
1053 | |||
1054 | foreach (DictionaryEntry entry in replace) | ||
1055 | { | ||
1056 | while (0 <= (index = lowercaseValue.IndexOf((string)entry.Key, StringComparison.Ordinal))) | ||
1057 | { | ||
1058 | value = value.Remove(index, ((string)entry.Key).Length); | ||
1059 | value = value.Insert(index, (string)entry.Value); | ||
1060 | lowercaseValue = value.ToLower(CultureInfo.InvariantCulture); | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | return value; | ||
1065 | } | ||
1066 | |||
1067 | /// <summary> | ||
1068 | /// Mutate the registry values. | ||
1069 | /// </summary> | ||
1070 | private void MutateRegistryValues() | ||
1071 | { | ||
1072 | if (this.SuppressVB6COMElements && this.SuppressCOMElements) | ||
1073 | { | ||
1074 | var vb6RegistryValues = new List<Wix.RegistryValue>(); | ||
1075 | foreach (Wix.RegistryValue registryValue in this.registryValues) | ||
1076 | { | ||
1077 | if (IsVb6RegistryValue(registryValue)) | ||
1078 | { | ||
1079 | if (!vb6RegistryValues.Contains(registryValue)) | ||
1080 | { | ||
1081 | vb6RegistryValues.Add(registryValue); | ||
1082 | } | ||
1083 | } | ||
1084 | } | ||
1085 | |||
1086 | // Remove all the VB6 specific COM registry values | ||
1087 | foreach (var reg in vb6RegistryValues) | ||
1088 | { | ||
1089 | if (reg.ParentElement is Wix.Component component) | ||
1090 | { | ||
1091 | component.RemoveChild(reg); | ||
1092 | } | ||
1093 | this.registryValues.Remove(reg); | ||
1094 | } | ||
1095 | } | ||
1096 | |||
1097 | |||
1098 | ArrayList reversedDirectoryPaths = new ArrayList(); | ||
1099 | |||
1100 | // reverse the indexed directory paths to ensure the longest paths are found first | ||
1101 | foreach (DictionaryEntry entry in this.directoryPaths) | ||
1102 | { | ||
1103 | reversedDirectoryPaths.Insert(0, entry); | ||
1104 | } | ||
1105 | |||
1106 | foreach (Wix.RegistryValue registryValue in this.registryValues) | ||
1107 | { | ||
1108 | // Multi-string values are stored as children - their "Value" member is null | ||
1109 | if (Wix.RegistryValue.TypeType.multiString == registryValue.Type) | ||
1110 | { | ||
1111 | foreach (Wix.MultiStringValue multiStringValue in registryValue.Children) | ||
1112 | { | ||
1113 | // first replace file paths with their MSI tokens | ||
1114 | multiStringValue.Value = this.MutateRegistryString(multiStringValue.Value, (ICollection)this.filePaths); | ||
1115 | // next replace directory paths with their MSI tokens | ||
1116 | multiStringValue.Value = this.MutateRegistryString(multiStringValue.Value, (ICollection)reversedDirectoryPaths); | ||
1117 | } | ||
1118 | } | ||
1119 | else | ||
1120 | { | ||
1121 | // first replace file paths with their MSI tokens | ||
1122 | registryValue.Value = this.MutateRegistryString(registryValue.Value, (ICollection)this.filePaths); | ||
1123 | // next replace directory paths with their MSI tokens | ||
1124 | registryValue.Value = this.MutateRegistryString(registryValue.Value, (ICollection)reversedDirectoryPaths); | ||
1125 | } | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | private static bool IsVb6RegistryValue(Wix.RegistryValue registryValue) | ||
1130 | { | ||
1131 | if (Wix.RegistryValue.ActionType.write == registryValue.Action && Wix.RegistryRootType.HKCR == registryValue.Root) | ||
1132 | { | ||
1133 | string[] parts = registryValue.Key.Split('\\'); | ||
1134 | if (String.Equals(parts[0], "CLSID", StringComparison.OrdinalIgnoreCase)) | ||
1135 | { | ||
1136 | // Search for the VB6 CLSID {D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731} | ||
1137 | if (2 <= parts.Length) | ||
1138 | { | ||
1139 | if (String.Equals(parts[1], "{D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731}", StringComparison.OrdinalIgnoreCase)) | ||
1140 | { | ||
1141 | return true; | ||
1142 | } | ||
1143 | } | ||
1144 | } | ||
1145 | else if (String.Equals(parts[0], "TypeLib", StringComparison.OrdinalIgnoreCase)) | ||
1146 | { | ||
1147 | // Search for the VB6 TypeLibs {EA544A21-C82D-11D1-A3E4-00A0C90AEA82} or {000204EF-0000-0000-C000-000000000046} | ||
1148 | if (2 <= parts.Length) | ||
1149 | { | ||
1150 | if (String.Equals(parts[1], "{EA544A21-C82D-11D1-A3E4-00A0C90AEA82}", StringComparison.OrdinalIgnoreCase) || | ||
1151 | String.Equals(parts[1], "{000204EF-0000-0000-C000-000000000046}", StringComparison.OrdinalIgnoreCase)) | ||
1152 | { | ||
1153 | return true; | ||
1154 | } | ||
1155 | } | ||
1156 | } | ||
1157 | else if (String.Equals(parts[0], "Interface", StringComparison.OrdinalIgnoreCase)) | ||
1158 | { | ||
1159 | // Search for any Interfaces that reference the VB6 TypeLibs {EA544A21-C82D-11D1-A3E4-00A0C90AEA82} or {000204EF-0000-0000-C000-000000000046} | ||
1160 | if (3 <= parts.Length) | ||
1161 | { | ||
1162 | if (String.Equals(parts[2], "TypeLib", StringComparison.OrdinalIgnoreCase)) | ||
1163 | { | ||
1164 | if (String.Equals(registryValue.Value, "{EA544A21-C82D-11D1-A3E4-00A0C90AEA82}", StringComparison.OrdinalIgnoreCase) || | ||
1165 | String.Equals(registryValue.Value, "{000204EF-0000-0000-C000-000000000046}", StringComparison.OrdinalIgnoreCase)) | ||
1166 | { | ||
1167 | return true; | ||
1168 | } | ||
1169 | } | ||
1170 | } | ||
1171 | } | ||
1172 | } | ||
1173 | return false; | ||
1174 | } | ||
1175 | |||
1176 | /// <summary> | ||
1177 | /// The native methods for grabbing machine-specific short file paths. | ||
1178 | /// </summary> | ||
1179 | private class NativeMethods | ||
1180 | { | ||
1181 | /// <summary> | ||
1182 | /// Gets the short name for a file. | ||
1183 | /// </summary> | ||
1184 | /// <param name="fullPath">Fullpath to file on disk.</param> | ||
1185 | /// <returns>Short name for file.</returns> | ||
1186 | internal static string GetShortPathName(string fullPath) | ||
1187 | { | ||
1188 | var bufferSize = (int)GetShortPathName(fullPath, null, 0); | ||
1189 | if (0 == bufferSize) | ||
1190 | { | ||
1191 | int err = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); | ||
1192 | throw new System.Runtime.InteropServices.COMException(String.Concat("Failed to get short path buffer size for file: ", fullPath), err); | ||
1193 | } | ||
1194 | |||
1195 | bufferSize += 1; | ||
1196 | var shortPath = new StringBuilder(bufferSize, bufferSize); | ||
1197 | |||
1198 | uint result = GetShortPathName(fullPath, shortPath, bufferSize); | ||
1199 | |||
1200 | if (0 == result) | ||
1201 | { | ||
1202 | int err = System.Runtime.InteropServices.Marshal.GetLastWin32Error(); | ||
1203 | throw new System.Runtime.InteropServices.COMException(String.Concat("Failed to get short path name for file: ", fullPath), err); | ||
1204 | } | ||
1205 | |||
1206 | return shortPath.ToString(); | ||
1207 | } | ||
1208 | |||
1209 | /// <summary> | ||
1210 | /// Gets the short name for a file. | ||
1211 | /// </summary> | ||
1212 | /// <param name="longPath">Long path to convert to short path.</param> | ||
1213 | /// <param name="shortPath">Short path from long path.</param> | ||
1214 | /// <param name="buffer">Size of short path.</param> | ||
1215 | /// <returns>zero if success.</returns> | ||
1216 | [DllImport("kernel32.dll", EntryPoint = "GetShortPathNameW", CharSet = CharSet.Unicode, ExactSpelling = true, SetLastError = true)] | ||
1217 | internal static extern uint GetShortPathName(string longPath, StringBuilder shortPath, [MarshalAs(UnmanagedType.U4)]int buffer); | ||
1218 | } | ||
1219 | } | ||
1220 | } | ||