diff options
Diffstat (limited to 'src/tools/heat/UtilHarvesterMutator.cs')
-rw-r--r-- | src/tools/heat/UtilHarvesterMutator.cs | 218 |
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 | |||
3 | namespace 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 | } | ||