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