aboutsummaryrefslogtreecommitdiff
path: root/src/tools/heat/UtilHarvesterMutator.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/heat/UtilHarvesterMutator.cs')
-rw-r--r--src/tools/heat/UtilHarvesterMutator.cs218
1 files changed, 218 insertions, 0 deletions
diff --git a/src/tools/heat/UtilHarvesterMutator.cs b/src/tools/heat/UtilHarvesterMutator.cs
new file mode 100644
index 00000000..af2584e3
--- /dev/null
+++ b/src/tools/heat/UtilHarvesterMutator.cs
@@ -0,0 +1,218 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Harvesters
4{
5 using System;
6 using System.Collections;
7 using System.IO;
8 using System.Reflection;
9 using System.Runtime.InteropServices;
10 using WixToolset.Data;
11 using WixToolset.Harvesters.Data;
12 using WixToolset.Harvesters.Extensibility;
13 using Wix = WixToolset.Harvesters.Serialize;
14
15 /// <summary>
16 /// The WiX Toolset harvester mutator.
17 /// </summary>
18 public sealed class UtilHarvesterMutator : BaseMutatorExtension
19 {
20 // Flags for SetErrorMode() native method.
21 private const UInt32 SEM_FAILCRITICALERRORS = 0x0001;
22 private const UInt32 SEM_NOGPFAULTERRORBOX = 0x0002;
23 private const UInt32 SEM_NOALIGNMENTFAULTEXCEPT = 0x0004;
24 private const UInt32 SEM_NOOPENFILEERRORBOX = 0x8000;
25
26 // Remember whether we were able to call OaEnablePerUserTLibRegistration
27 private bool calledPerUserTLibReg;
28
29 /// <summary>
30 /// allow process to handle serious system errors.
31 /// </summary>
32 [DllImport("Kernel32.dll")]
33 private static extern void SetErrorMode(UInt32 uiMode);
34
35 /// <summary>
36 /// enable the RegisterTypeLib API to use the appropriate override mapping for non-admin users on Vista
37 /// </summary>
38 [DllImport("Oleaut32.dll")]
39 private static extern void OaEnablePerUserTLibRegistration();
40
41 public UtilHarvesterMutator()
42 {
43 this.calledPerUserTLibReg = false;
44
45 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
46
47 try
48 {
49 OaEnablePerUserTLibRegistration();
50 this.calledPerUserTLibReg = true;
51 }
52 catch (EntryPointNotFoundException)
53 {
54 }
55 }
56
57 /// <summary>
58 /// Gets the sequence of this mutator extension.
59 /// </summary>
60 /// <value>The sequence of this mutator extension.</value>
61 public override int Sequence
62 {
63 get { return 100; }
64 }
65
66 /// <summary>
67 /// Mutate a WiX document.
68 /// </summary>
69 /// <param name="wix">The Wix document element.</param>
70 public override void Mutate(Wix.Wix wix)
71 {
72 this.MutateElement(null, wix);
73 }
74
75 /// <summary>
76 /// Mutate an element.
77 /// </summary>
78 /// <param name="parentElement">The parent of the element to mutate.</param>
79 /// <param name="element">The element to mutate.</param>
80 private void MutateElement(Wix.IParentElement parentElement, Wix.ISchemaElement element)
81 {
82 if (element is Wix.File)
83 {
84 this.MutateFile(parentElement, (Wix.File)element);
85 }
86
87 // mutate the child elements
88 if (element is Wix.IParentElement)
89 {
90 ArrayList childElements = new ArrayList();
91
92 // copy the child elements to a temporary array (to allow them to be deleted/moved)
93 foreach (Wix.ISchemaElement childElement in ((Wix.IParentElement)element).Children)
94 {
95 childElements.Add(childElement);
96 }
97
98 foreach (Wix.ISchemaElement childElement in childElements)
99 {
100 this.MutateElement((Wix.IParentElement)element, childElement);
101 }
102 }
103 }
104
105 /// <summary>
106 /// Mutate a file.
107 /// </summary>
108 /// <param name="parentElement">The parent of the element to mutate.</param>
109 /// <param name="file">The file to mutate.</param>
110 private void MutateFile(Wix.IParentElement parentElement, Wix.File file)
111 {
112 if (null != file.Source)
113 {
114 string fileExtension = Path.GetExtension(file.Source);
115 string fileSource = this.Core.ResolveFilePath(file.Source);
116
117 if (String.Equals(".ax", fileExtension, StringComparison.OrdinalIgnoreCase) || // DirectShow filter
118 String.Equals(".dll", fileExtension, StringComparison.OrdinalIgnoreCase) ||
119 String.Equals(".exe", fileExtension, StringComparison.OrdinalIgnoreCase) ||
120 String.Equals(".ocx", fileExtension, StringComparison.OrdinalIgnoreCase)) // ActiveX
121 {
122 // try the assembly harvester
123 try
124 {
125 AssemblyHarvester assemblyHarvester = new AssemblyHarvester();
126
127 this.Core.Messaging.Write(HarvesterVerboses.HarvestingAssembly(fileSource));
128 Wix.RegistryValue[] registryValues = assemblyHarvester.HarvestRegistryValues(fileSource);
129
130 foreach (Wix.RegistryValue registryValue in registryValues)
131 {
132 parentElement.AddChild(registryValue);
133 }
134
135 // also try self-reg since we could have a mixed-mode assembly
136 this.HarvestSelfReg(parentElement, fileSource);
137 }
138 catch (BadImageFormatException) // not an assembly, try raw DLL.
139 {
140 this.HarvestSelfReg(parentElement, fileSource);
141 }
142 catch (Exception ex)
143 {
144 this.Core.Messaging.Write(HarvesterWarnings.AssemblyHarvestFailed(fileSource, ex.Message));
145 }
146 }
147 else if (String.Equals(".olb", fileExtension, StringComparison.OrdinalIgnoreCase) || // type library
148 String.Equals(".tlb", fileExtension, StringComparison.OrdinalIgnoreCase)) // type library
149 {
150 // try the type library harvester
151 try
152 {
153 TypeLibraryHarvester typeLibHarvester = new TypeLibraryHarvester();
154
155 this.Core.Messaging.Write(HarvesterVerboses.HarvestingTypeLib(fileSource));
156 Wix.RegistryValue[] registryValues = typeLibHarvester.HarvestRegistryValues(fileSource);
157
158 foreach (Wix.RegistryValue registryValue in registryValues)
159 {
160 parentElement.AddChild(registryValue);
161 }
162 }
163 catch (COMException ce)
164 {
165 // 0x8002801C (TYPE_E_REGISTRYACCESS)
166 // If we don't have permission to harvest typelibs, it's likely because we're on
167 // Vista or higher and aren't an Admin, or don't have the appropriate QFE installed.
168 if (!this.calledPerUserTLibReg && (0x8002801c == unchecked((uint)ce.ErrorCode)))
169 {
170 this.Core.Messaging.Write(WarningMessages.InsufficientPermissionHarvestTypeLib());
171 }
172 else if (0x80029C4A == unchecked((uint)ce.ErrorCode)) // generic can't load type library
173 {
174 this.Core.Messaging.Write(HarvesterWarnings.TypeLibLoadFailed(fileSource, ce.Message));
175 }
176 }
177 }
178 }
179 }
180
181 /// <summary>
182 /// Calls self-reg harvester.
183 /// </summary>
184 /// <param name="parentElement">The parent element.</param>
185 /// <param name="fileSource">The file source.</param>
186 private void HarvestSelfReg(Wix.IParentElement parentElement, string fileSource)
187 {
188 // try the self-reg harvester
189 try
190 {
191 DllHarvester dllHarvester = new DllHarvester();
192
193 this.Core.Messaging.Write(HarvesterVerboses.HarvestingSelfReg(fileSource));
194 Wix.RegistryValue[] registryValues = dllHarvester.HarvestRegistryValues(fileSource);
195
196 foreach (Wix.RegistryValue registryValue in registryValues)
197 {
198 parentElement.AddChild(registryValue);
199 }
200 }
201 catch (TargetInvocationException tie)
202 {
203 if (tie.InnerException is EntryPointNotFoundException)
204 {
205 // No DllRegisterServer(), which is fine by me.
206 }
207 else
208 {
209 this.Core.Messaging.Write(HarvesterWarnings.SelfRegHarvestFailed(fileSource, tie.Message));
210 }
211 }
212 catch (Exception ex)
213 {
214 this.Core.Messaging.Write(HarvesterWarnings.SelfRegHarvestFailed(fileSource, ex.Message));
215 }
216 }
217 }
218}