diff options
Diffstat (limited to 'src/WixToolset.Core/Compiler_2.cs')
-rw-r--r-- | src/WixToolset.Core/Compiler_2.cs | 5615 |
1 files changed, 5615 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Compiler_2.cs b/src/WixToolset.Core/Compiler_2.cs new file mode 100644 index 00000000..f42c9da1 --- /dev/null +++ b/src/WixToolset.Core/Compiler_2.cs | |||
@@ -0,0 +1,5615 @@ | |||
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.Core | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections; | ||
7 | using System.Collections.Generic; | ||
8 | using System.Diagnostics.CodeAnalysis; | ||
9 | using System.Globalization; | ||
10 | using System.IO; | ||
11 | using System.Xml.Linq; | ||
12 | using WixToolset.Data; | ||
13 | using WixToolset.Data.Tuples; | ||
14 | using WixToolset.Data.WindowsInstaller; | ||
15 | using WixToolset.Extensibility; | ||
16 | |||
17 | /// <summary> | ||
18 | /// Compiler of the WiX toolset. | ||
19 | /// </summary> | ||
20 | internal partial class Compiler : ICompiler | ||
21 | { | ||
22 | /// <summary> | ||
23 | /// Parses an odbc driver or translator element. | ||
24 | /// </summary> | ||
25 | /// <param name="node">Element to parse.</param> | ||
26 | /// <param name="componentId">Identifier of parent component.</param> | ||
27 | /// <param name="fileId">Default identifer for driver/translator file.</param> | ||
28 | /// <param name="table">Table we're processing for.</param> | ||
29 | private void ParseODBCDriverOrTranslator(XElement node, string componentId, string fileId, TupleDefinitionType tableName) | ||
30 | { | ||
31 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
32 | Identifier id = null; | ||
33 | var driver = fileId; | ||
34 | string name = null; | ||
35 | var setup = fileId; | ||
36 | |||
37 | foreach (var attrib in node.Attributes()) | ||
38 | { | ||
39 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
40 | { | ||
41 | switch (attrib.Name.LocalName) | ||
42 | { | ||
43 | case "Id": | ||
44 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
45 | break; | ||
46 | case "File": | ||
47 | driver = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
48 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", driver); | ||
49 | break; | ||
50 | case "Name": | ||
51 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
52 | break; | ||
53 | case "SetupFile": | ||
54 | setup = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
55 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", setup); | ||
56 | break; | ||
57 | default: | ||
58 | this.Core.UnexpectedAttribute(node, attrib); | ||
59 | break; | ||
60 | } | ||
61 | } | ||
62 | else | ||
63 | { | ||
64 | this.Core.ParseExtensionAttribute(node, attrib); | ||
65 | } | ||
66 | } | ||
67 | |||
68 | if (null == name) | ||
69 | { | ||
70 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
71 | } | ||
72 | |||
73 | if (null == id) | ||
74 | { | ||
75 | id = this.Core.CreateIdentifier("odb", name, fileId, setup); | ||
76 | } | ||
77 | |||
78 | // drivers have a few possible children | ||
79 | if (TupleDefinitionType.ODBCDriver == tableName) | ||
80 | { | ||
81 | // process any data sources for the driver | ||
82 | foreach (var child in node.Elements()) | ||
83 | { | ||
84 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
85 | { | ||
86 | switch (child.Name.LocalName) | ||
87 | { | ||
88 | case "ODBCDataSource": | ||
89 | string ignoredKeyPath = null; | ||
90 | this.ParseODBCDataSource(child, componentId, name, out ignoredKeyPath); | ||
91 | break; | ||
92 | case "Property": | ||
93 | this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCAttribute); | ||
94 | break; | ||
95 | default: | ||
96 | this.Core.UnexpectedElement(node, child); | ||
97 | break; | ||
98 | } | ||
99 | } | ||
100 | else | ||
101 | { | ||
102 | this.Core.ParseExtensionElement(node, child); | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | this.Core.ParseForExtensionElements(node); | ||
109 | } | ||
110 | |||
111 | if (!this.Core.EncounteredError) | ||
112 | { | ||
113 | var row = this.Core.CreateRow(sourceLineNumbers, tableName, id); | ||
114 | row.Set(1, componentId); | ||
115 | row.Set(2, name); | ||
116 | row.Set(3, driver); | ||
117 | row.Set(4, setup); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Parses a Property element underneath an ODBC driver or translator. | ||
123 | /// </summary> | ||
124 | /// <param name="node">Element to parse.</param> | ||
125 | /// <param name="parentId">Identifier of parent driver or translator.</param> | ||
126 | /// <param name="tableName">Name of the table to create property in.</param> | ||
127 | private void ParseODBCProperty(XElement node, string parentId, TupleDefinitionType tableName) | ||
128 | { | ||
129 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
130 | string id = null; | ||
131 | string propertyValue = null; | ||
132 | |||
133 | foreach (var attrib in node.Attributes()) | ||
134 | { | ||
135 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
136 | { | ||
137 | switch (attrib.Name.LocalName) | ||
138 | { | ||
139 | case "Id": | ||
140 | id = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
141 | break; | ||
142 | case "Value": | ||
143 | propertyValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
144 | break; | ||
145 | default: | ||
146 | this.Core.UnexpectedAttribute(node, attrib); | ||
147 | break; | ||
148 | } | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | this.Core.ParseExtensionAttribute(node, attrib); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | if (null == id) | ||
157 | { | ||
158 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
159 | } | ||
160 | |||
161 | this.Core.ParseForExtensionElements(node); | ||
162 | |||
163 | if (!this.Core.EncounteredError) | ||
164 | { | ||
165 | var row = this.Core.CreateRow(sourceLineNumbers, tableName); | ||
166 | row.Set(0, parentId); | ||
167 | row.Set(1, id); | ||
168 | row.Set(2, propertyValue); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | /// <summary> | ||
173 | /// Parse an odbc data source element. | ||
174 | /// </summary> | ||
175 | /// <param name="node">Element to parse.</param> | ||
176 | /// <param name="componentId">Identifier of parent component.</param> | ||
177 | /// <param name="driverName">Default name of driver.</param> | ||
178 | /// <param name="possibleKeyPath">Identifier of this element in case it is a keypath.</param> | ||
179 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
180 | private YesNoType ParseODBCDataSource(XElement node, string componentId, string driverName, out string possibleKeyPath) | ||
181 | { | ||
182 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
183 | Identifier id = null; | ||
184 | var keyPath = YesNoType.NotSet; | ||
185 | string name = null; | ||
186 | var registration = CompilerConstants.IntegerNotSet; | ||
187 | |||
188 | foreach (var attrib in node.Attributes()) | ||
189 | { | ||
190 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
191 | { | ||
192 | switch (attrib.Name.LocalName) | ||
193 | { | ||
194 | case "Id": | ||
195 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
196 | break; | ||
197 | case "DriverName": | ||
198 | driverName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
199 | break; | ||
200 | case "KeyPath": | ||
201 | keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
202 | break; | ||
203 | case "Name": | ||
204 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
205 | break; | ||
206 | case "Registration": | ||
207 | var registrationValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
208 | switch (registrationValue) | ||
209 | { | ||
210 | case "machine": | ||
211 | registration = 0; | ||
212 | break; | ||
213 | case "user": | ||
214 | registration = 1; | ||
215 | break; | ||
216 | case "": | ||
217 | break; | ||
218 | default: | ||
219 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Registration", registrationValue, "machine", "user")); | ||
220 | break; | ||
221 | } | ||
222 | break; | ||
223 | default: | ||
224 | this.Core.UnexpectedAttribute(node, attrib); | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | this.Core.ParseExtensionAttribute(node, attrib); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | if (CompilerConstants.IntegerNotSet == registration) | ||
235 | { | ||
236 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Registration")); | ||
237 | registration = CompilerConstants.IllegalInteger; | ||
238 | } | ||
239 | |||
240 | if (null == id) | ||
241 | { | ||
242 | id = this.Core.CreateIdentifier("odc", name, driverName, registration.ToString()); | ||
243 | } | ||
244 | |||
245 | foreach (var child in node.Elements()) | ||
246 | { | ||
247 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
248 | { | ||
249 | switch (child.Name.LocalName) | ||
250 | { | ||
251 | case "Property": | ||
252 | this.ParseODBCProperty(child, id.Id, TupleDefinitionType.ODBCSourceAttribute); | ||
253 | break; | ||
254 | default: | ||
255 | this.Core.UnexpectedElement(node, child); | ||
256 | break; | ||
257 | } | ||
258 | } | ||
259 | else | ||
260 | { | ||
261 | this.Core.ParseExtensionElement(node, child); | ||
262 | } | ||
263 | } | ||
264 | |||
265 | if (!this.Core.EncounteredError) | ||
266 | { | ||
267 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ODBCDataSource, id); | ||
268 | row.Set(1, componentId); | ||
269 | row.Set(2, name); | ||
270 | row.Set(3, driverName); | ||
271 | row.Set(4, registration); | ||
272 | } | ||
273 | |||
274 | possibleKeyPath = id.Id; | ||
275 | return keyPath; | ||
276 | } | ||
277 | |||
278 | /// <summary> | ||
279 | /// Parses a package element. | ||
280 | /// </summary> | ||
281 | /// <param name="node">Element to parse.</param> | ||
282 | /// <param name="productAuthor">Default package author.</param> | ||
283 | /// <param name="moduleId">The module guid - this is necessary until Module/@Guid is removed.</param> | ||
284 | private void ParsePackageElement(XElement node, string productAuthor, string moduleId) | ||
285 | { | ||
286 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
287 | var codepage = "1252"; | ||
288 | var comments = String.Format(CultureInfo.InvariantCulture, "This installer database contains the logic and data required to install {0}.", this.activeName); | ||
289 | var keywords = "Installer"; | ||
290 | var msiVersion = 100; // lowest released version, really should be specified | ||
291 | var packageAuthor = productAuthor; | ||
292 | string packageCode = null; | ||
293 | var packageLanguages = this.activeLanguage; | ||
294 | var packageName = this.activeName; | ||
295 | string platform = null; | ||
296 | string platformValue = null; | ||
297 | var security = YesNoDefaultType.Default; | ||
298 | var sourceBits = (this.compilingModule ? 2 : 0); | ||
299 | IntermediateTuple row; | ||
300 | var installPrivilegeSeen = false; | ||
301 | var installScopeSeen = false; | ||
302 | |||
303 | switch (this.CurrentPlatform) | ||
304 | { | ||
305 | case Platform.X86: | ||
306 | platform = "Intel"; | ||
307 | break; | ||
308 | case Platform.X64: | ||
309 | platform = "x64"; | ||
310 | msiVersion = 200; | ||
311 | break; | ||
312 | case Platform.IA64: | ||
313 | platform = "Intel64"; | ||
314 | msiVersion = 200; | ||
315 | break; | ||
316 | case Platform.ARM: | ||
317 | platform = "Arm"; | ||
318 | msiVersion = 500; | ||
319 | break; | ||
320 | default: | ||
321 | throw new ArgumentException("Unknown platform enumeration '{0}' encountered.", this.CurrentPlatform.ToString()); | ||
322 | } | ||
323 | |||
324 | foreach (var attrib in node.Attributes()) | ||
325 | { | ||
326 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
327 | { | ||
328 | switch (attrib.Name.LocalName) | ||
329 | { | ||
330 | case "Id": | ||
331 | packageCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, this.compilingProduct); | ||
332 | break; | ||
333 | case "AdminImage": | ||
334 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
335 | { | ||
336 | sourceBits = sourceBits | 4; | ||
337 | } | ||
338 | break; | ||
339 | case "Comments": | ||
340 | comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
341 | break; | ||
342 | case "Compressed": | ||
343 | // merge modules must always be compressed, so this attribute is invalid | ||
344 | if (this.compilingModule) | ||
345 | { | ||
346 | this.Core.Write(WarningMessages.DeprecatedPackageCompressedAttribute(sourceLineNumbers)); | ||
347 | // this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Compressed", "Module")); | ||
348 | } | ||
349 | else if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
350 | { | ||
351 | sourceBits = sourceBits | 2; | ||
352 | } | ||
353 | break; | ||
354 | case "Description": | ||
355 | packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
356 | break; | ||
357 | case "InstallPrivileges": | ||
358 | var installPrivileges = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
359 | switch (installPrivileges) | ||
360 | { | ||
361 | case "elevated": | ||
362 | // this is the default setting | ||
363 | installPrivilegeSeen = true; | ||
364 | break; | ||
365 | case "limited": | ||
366 | sourceBits = sourceBits | 8; | ||
367 | installPrivilegeSeen = true; | ||
368 | break; | ||
369 | case "": | ||
370 | break; | ||
371 | default: | ||
372 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installPrivileges, "elevated", "limited")); | ||
373 | break; | ||
374 | } | ||
375 | break; | ||
376 | case "InstallScope": | ||
377 | var installScope = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
378 | switch (installScope) | ||
379 | { | ||
380 | case "perMachine": | ||
381 | { | ||
382 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Property, new Identifier("ALLUSERS", AccessModifier.Public)); | ||
383 | row.Set(1, "1"); | ||
384 | installScopeSeen = true; | ||
385 | } | ||
386 | break; | ||
387 | case "perUser": | ||
388 | sourceBits = sourceBits | 8; | ||
389 | installScopeSeen = true; | ||
390 | break; | ||
391 | case "": | ||
392 | break; | ||
393 | default: | ||
394 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, installScope, "perMachine", "perUser")); | ||
395 | break; | ||
396 | } | ||
397 | break; | ||
398 | case "InstallerVersion": | ||
399 | msiVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
400 | break; | ||
401 | case "Keywords": | ||
402 | keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
403 | break; | ||
404 | case "Languages": | ||
405 | packageLanguages = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
406 | break; | ||
407 | case "Manufacturer": | ||
408 | packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
409 | if ("PUT-COMPANY-NAME-HERE" == packageAuthor) | ||
410 | { | ||
411 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, packageAuthor)); | ||
412 | } | ||
413 | break; | ||
414 | case "Platform": | ||
415 | if (null != platformValue) | ||
416 | { | ||
417 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platforms")); | ||
418 | } | ||
419 | |||
420 | platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
421 | switch (platformValue) | ||
422 | { | ||
423 | case "intel": | ||
424 | this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "x86")); | ||
425 | goto case "x86"; | ||
426 | case "x86": | ||
427 | platform = "Intel"; | ||
428 | break; | ||
429 | case "x64": | ||
430 | platform = "x64"; | ||
431 | break; | ||
432 | case "intel64": | ||
433 | this.Core.Write(WarningMessages.DeprecatedAttributeValue(sourceLineNumbers, platformValue, node.Name.LocalName, attrib.Name.LocalName, "ia64")); | ||
434 | goto case "ia64"; | ||
435 | case "ia64": | ||
436 | platform = "Intel64"; | ||
437 | break; | ||
438 | case "arm": | ||
439 | platform = "Arm"; | ||
440 | break; | ||
441 | case "": | ||
442 | break; | ||
443 | default: | ||
444 | this.Core.Write(ErrorMessages.InvalidPlatformValue(sourceLineNumbers, platformValue)); | ||
445 | break; | ||
446 | } | ||
447 | break; | ||
448 | case "Platforms": | ||
449 | if (null != platformValue) | ||
450 | { | ||
451 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
452 | } | ||
453 | |||
454 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Platform")); | ||
455 | platformValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
456 | platform = platformValue; | ||
457 | break; | ||
458 | case "ReadOnly": | ||
459 | security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
460 | break; | ||
461 | case "ShortNames": | ||
462 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
463 | { | ||
464 | sourceBits = sourceBits | 1; | ||
465 | this.useShortFileNames = true; | ||
466 | } | ||
467 | break; | ||
468 | case "SummaryCodepage": | ||
469 | codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib, true); | ||
470 | break; | ||
471 | default: | ||
472 | this.Core.UnexpectedAttribute(node, attrib); | ||
473 | break; | ||
474 | } | ||
475 | } | ||
476 | else | ||
477 | { | ||
478 | this.Core.ParseExtensionAttribute(node, attrib); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | if (installPrivilegeSeen && installScopeSeen) | ||
483 | { | ||
484 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "InstallPrivileges", "InstallScope")); | ||
485 | } | ||
486 | |||
487 | if ((0 != String.Compare(platform, "Intel", StringComparison.OrdinalIgnoreCase)) && 200 > msiVersion) | ||
488 | { | ||
489 | msiVersion = 200; | ||
490 | this.Core.Write(WarningMessages.RequiresMsi200for64bitPackage(sourceLineNumbers)); | ||
491 | } | ||
492 | |||
493 | if ((0 == String.Compare(platform, "Arm", StringComparison.OrdinalIgnoreCase)) && 500 > msiVersion) | ||
494 | { | ||
495 | msiVersion = 500; | ||
496 | this.Core.Write(WarningMessages.RequiresMsi500forArmPackage(sourceLineNumbers)); | ||
497 | } | ||
498 | |||
499 | if (null == packageAuthor) | ||
500 | { | ||
501 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
502 | } | ||
503 | |||
504 | if (this.compilingModule) | ||
505 | { | ||
506 | if (null == packageCode) | ||
507 | { | ||
508 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
509 | } | ||
510 | |||
511 | // merge modules use the modularization guid as the package code | ||
512 | if (null != moduleId) | ||
513 | { | ||
514 | packageCode = moduleId; | ||
515 | } | ||
516 | |||
517 | // merge modules are always compressed | ||
518 | sourceBits = 2; | ||
519 | } | ||
520 | else // product | ||
521 | { | ||
522 | if (null == packageCode) | ||
523 | { | ||
524 | packageCode = "*"; | ||
525 | } | ||
526 | |||
527 | if ("*" != packageCode) | ||
528 | { | ||
529 | this.Core.Write(WarningMessages.PackageCodeSet(sourceLineNumbers)); | ||
530 | } | ||
531 | } | ||
532 | |||
533 | this.Core.ParseForExtensionElements(node); | ||
534 | |||
535 | if (!this.Core.EncounteredError) | ||
536 | { | ||
537 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
538 | row.Set(0, 1); | ||
539 | row.Set(1, codepage); | ||
540 | |||
541 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
542 | row.Set(0, 2); | ||
543 | row.Set(1, "Installation Database"); | ||
544 | |||
545 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
546 | row.Set(0, 3); | ||
547 | row.Set(1, packageName); | ||
548 | |||
549 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
550 | row.Set(0, 4); | ||
551 | row.Set(1, packageAuthor); | ||
552 | |||
553 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
554 | row.Set(0, 5); | ||
555 | row.Set(1, keywords); | ||
556 | |||
557 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
558 | row.Set(0, 6); | ||
559 | row.Set(1, comments); | ||
560 | |||
561 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
562 | row.Set(0, 7); | ||
563 | row.Set(1, String.Format(CultureInfo.InvariantCulture, "{0};{1}", platform, packageLanguages)); | ||
564 | |||
565 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
566 | row.Set(0, 9); | ||
567 | row.Set(1, packageCode); | ||
568 | |||
569 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
570 | row.Set(0, 14); | ||
571 | row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture)); | ||
572 | |||
573 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
574 | row.Set(0, 15); | ||
575 | row.Set(1, sourceBits.ToString(CultureInfo.InvariantCulture)); | ||
576 | |||
577 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
578 | row.Set(0, 19); | ||
579 | switch (security) | ||
580 | { | ||
581 | case YesNoDefaultType.No: // no restriction | ||
582 | row.Set(1, "0"); | ||
583 | break; | ||
584 | case YesNoDefaultType.Default: // read-only recommended | ||
585 | row.Set(1, "2"); | ||
586 | break; | ||
587 | case YesNoDefaultType.Yes: // read-only enforced | ||
588 | row.Set(1, "4"); | ||
589 | break; | ||
590 | } | ||
591 | } | ||
592 | } | ||
593 | |||
594 | /// <summary> | ||
595 | /// Parses a patch metadata element. | ||
596 | /// </summary> | ||
597 | /// <param name="node">Element to parse.</param> | ||
598 | private void ParsePatchMetadataElement(XElement node) | ||
599 | { | ||
600 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
601 | var allowRemoval = YesNoType.NotSet; | ||
602 | string classification = null; | ||
603 | string creationTimeUtc = null; | ||
604 | string description = null; | ||
605 | string displayName = null; | ||
606 | string manufacturerName = null; | ||
607 | string minorUpdateTargetRTM = null; | ||
608 | string moreInfoUrl = null; | ||
609 | var optimizeCA = CompilerConstants.IntegerNotSet; | ||
610 | var optimizedInstallMode = YesNoType.NotSet; | ||
611 | string targetProductName = null; | ||
612 | |||
613 | foreach (var attrib in node.Attributes()) | ||
614 | { | ||
615 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
616 | { | ||
617 | switch (attrib.Name.LocalName) | ||
618 | { | ||
619 | case "AllowRemoval": | ||
620 | allowRemoval = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
621 | break; | ||
622 | case "Classification": | ||
623 | classification = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
624 | break; | ||
625 | case "CreationTimeUTC": | ||
626 | creationTimeUtc = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
627 | break; | ||
628 | case "Description": | ||
629 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
630 | break; | ||
631 | case "DisplayName": | ||
632 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
633 | break; | ||
634 | case "ManufacturerName": | ||
635 | manufacturerName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
636 | break; | ||
637 | case "MinorUpdateTargetRTM": | ||
638 | minorUpdateTargetRTM = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
639 | break; | ||
640 | case "MoreInfoURL": | ||
641 | moreInfoUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
642 | break; | ||
643 | case "OptimizedInstallMode": | ||
644 | optimizedInstallMode = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
645 | break; | ||
646 | case "TargetProductName": | ||
647 | targetProductName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
648 | break; | ||
649 | default: | ||
650 | this.Core.UnexpectedAttribute(node, attrib); | ||
651 | break; | ||
652 | } | ||
653 | } | ||
654 | else | ||
655 | { | ||
656 | this.Core.ParseExtensionAttribute(node, attrib); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | if (YesNoType.NotSet == allowRemoval) | ||
661 | { | ||
662 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "AllowRemoval")); | ||
663 | } | ||
664 | |||
665 | if (null == classification) | ||
666 | { | ||
667 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Classification")); | ||
668 | } | ||
669 | |||
670 | if (null == description) | ||
671 | { | ||
672 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); | ||
673 | } | ||
674 | |||
675 | if (null == displayName) | ||
676 | { | ||
677 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayName")); | ||
678 | } | ||
679 | |||
680 | if (null == manufacturerName) | ||
681 | { | ||
682 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ManufacturerName")); | ||
683 | } | ||
684 | |||
685 | if (null == moreInfoUrl) | ||
686 | { | ||
687 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "MoreInfoURL")); | ||
688 | } | ||
689 | |||
690 | if (null == targetProductName) | ||
691 | { | ||
692 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetProductName")); | ||
693 | } | ||
694 | |||
695 | foreach (var child in node.Elements()) | ||
696 | { | ||
697 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
698 | { | ||
699 | switch (child.Name.LocalName) | ||
700 | { | ||
701 | case "CustomProperty": | ||
702 | this.ParseCustomPropertyElement(child); | ||
703 | break; | ||
704 | case "OptimizeCustomActions": | ||
705 | optimizeCA = this.ParseOptimizeCustomActionsElement(child); | ||
706 | break; | ||
707 | default: | ||
708 | this.Core.UnexpectedElement(node, child); | ||
709 | break; | ||
710 | } | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | this.Core.ParseExtensionElement(node, child); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | if (!this.Core.EncounteredError) | ||
719 | { | ||
720 | if (YesNoType.NotSet != allowRemoval) | ||
721 | { | ||
722 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
723 | row.Set(1, "AllowRemoval"); | ||
724 | row.Set(2, YesNoType.Yes == allowRemoval ? "1" : "0"); | ||
725 | } | ||
726 | |||
727 | if (null != classification) | ||
728 | { | ||
729 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
730 | row.Set(1, "Classification"); | ||
731 | row.Set(2, classification); | ||
732 | } | ||
733 | |||
734 | if (null != creationTimeUtc) | ||
735 | { | ||
736 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
737 | row.Set(1, "CreationTimeUTC"); | ||
738 | row.Set(2, creationTimeUtc); | ||
739 | } | ||
740 | |||
741 | if (null != description) | ||
742 | { | ||
743 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
744 | row.Set(1, "Description"); | ||
745 | row.Set(2, description); | ||
746 | } | ||
747 | |||
748 | if (null != displayName) | ||
749 | { | ||
750 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
751 | row.Set(1, "DisplayName"); | ||
752 | row.Set(2, displayName); | ||
753 | } | ||
754 | |||
755 | if (null != manufacturerName) | ||
756 | { | ||
757 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
758 | row.Set(1, "ManufacturerName"); | ||
759 | row.Set(2, manufacturerName); | ||
760 | } | ||
761 | |||
762 | if (null != minorUpdateTargetRTM) | ||
763 | { | ||
764 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
765 | row.Set(1, "MinorUpdateTargetRTM"); | ||
766 | row.Set(2, minorUpdateTargetRTM); | ||
767 | } | ||
768 | |||
769 | if (null != moreInfoUrl) | ||
770 | { | ||
771 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
772 | row.Set(1, "MoreInfoURL"); | ||
773 | row.Set(2, moreInfoUrl); | ||
774 | } | ||
775 | |||
776 | if (CompilerConstants.IntegerNotSet != optimizeCA) | ||
777 | { | ||
778 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
779 | row.Set(1, "OptimizeCA"); | ||
780 | row.Set(2, optimizeCA.ToString(CultureInfo.InvariantCulture)); | ||
781 | } | ||
782 | |||
783 | if (YesNoType.NotSet != optimizedInstallMode) | ||
784 | { | ||
785 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
786 | row.Set(1, "OptimizedInstallMode"); | ||
787 | row.Set(2, YesNoType.Yes == optimizedInstallMode ? "1" : "0"); | ||
788 | } | ||
789 | |||
790 | if (null != targetProductName) | ||
791 | { | ||
792 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
793 | row.Set(1, "TargetProductName"); | ||
794 | row.Set(2, targetProductName); | ||
795 | } | ||
796 | } | ||
797 | } | ||
798 | |||
799 | /// <summary> | ||
800 | /// Parses a custom property element for the PatchMetadata table. | ||
801 | /// </summary> | ||
802 | /// <param name="node">Element to parse.</param> | ||
803 | private void ParseCustomPropertyElement(XElement node) | ||
804 | { | ||
805 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
806 | string company = null; | ||
807 | string property = null; | ||
808 | string value = null; | ||
809 | |||
810 | foreach (var attrib in node.Attributes()) | ||
811 | { | ||
812 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
813 | { | ||
814 | switch (attrib.Name.LocalName) | ||
815 | { | ||
816 | case "Company": | ||
817 | company = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
818 | break; | ||
819 | case "Property": | ||
820 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
821 | break; | ||
822 | case "Value": | ||
823 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
824 | break; | ||
825 | default: | ||
826 | this.Core.UnexpectedAttribute(node, attrib); | ||
827 | break; | ||
828 | } | ||
829 | } | ||
830 | else | ||
831 | { | ||
832 | this.Core.ParseExtensionAttribute(node, attrib); | ||
833 | } | ||
834 | } | ||
835 | |||
836 | if (null == company) | ||
837 | { | ||
838 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Company")); | ||
839 | } | ||
840 | |||
841 | if (null == property) | ||
842 | { | ||
843 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
844 | } | ||
845 | |||
846 | if (null == value) | ||
847 | { | ||
848 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
849 | } | ||
850 | |||
851 | this.Core.ParseForExtensionElements(node); | ||
852 | |||
853 | if (!this.Core.EncounteredError) | ||
854 | { | ||
855 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.PatchMetadata); | ||
856 | row.Set(0, company); | ||
857 | row.Set(1, property); | ||
858 | row.Set(2, value); | ||
859 | } | ||
860 | } | ||
861 | |||
862 | /// <summary> | ||
863 | /// Parses the OptimizeCustomActions element. | ||
864 | /// </summary> | ||
865 | /// <param name="node">Element to parse.</param> | ||
866 | /// <returns>The combined integer value for callers to store as appropriate.</returns> | ||
867 | private int ParseOptimizeCustomActionsElement(XElement node) | ||
868 | { | ||
869 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
870 | var optimizeCA = OptimizeCA.None; | ||
871 | |||
872 | foreach (var attrib in node.Attributes()) | ||
873 | { | ||
874 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
875 | { | ||
876 | switch (attrib.Name.LocalName) | ||
877 | { | ||
878 | case "SkipAssignment": | ||
879 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
880 | { | ||
881 | optimizeCA |= OptimizeCA.SkipAssignment; | ||
882 | } | ||
883 | break; | ||
884 | case "SkipImmediate": | ||
885 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
886 | { | ||
887 | optimizeCA |= OptimizeCA.SkipImmediate; | ||
888 | } | ||
889 | break; | ||
890 | case "SkipDeferred": | ||
891 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
892 | { | ||
893 | optimizeCA |= OptimizeCA.SkipDeferred; | ||
894 | } | ||
895 | break; | ||
896 | default: | ||
897 | this.Core.UnexpectedAttribute(node, attrib); | ||
898 | break; | ||
899 | } | ||
900 | } | ||
901 | else | ||
902 | { | ||
903 | this.Core.ParseExtensionAttribute(node, attrib); | ||
904 | } | ||
905 | } | ||
906 | |||
907 | return (int)optimizeCA; | ||
908 | } | ||
909 | |||
910 | /// <summary> | ||
911 | /// Parses a patch information element. | ||
912 | /// </summary> | ||
913 | /// <param name="node">Element to parse.</param> | ||
914 | private void ParsePatchInformationElement(XElement node) | ||
915 | { | ||
916 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
917 | var codepage = "1252"; | ||
918 | string comments = null; | ||
919 | var keywords = "Installer,Patching,PCP,Database"; | ||
920 | var msiVersion = 1; // Should always be 1 for patches | ||
921 | string packageAuthor = null; | ||
922 | var packageName = this.activeName; | ||
923 | var security = YesNoDefaultType.Default; | ||
924 | |||
925 | foreach (var attrib in node.Attributes()) | ||
926 | { | ||
927 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
928 | { | ||
929 | switch (attrib.Name.LocalName) | ||
930 | { | ||
931 | case "AdminImage": | ||
932 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
933 | break; | ||
934 | case "Comments": | ||
935 | comments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
936 | break; | ||
937 | case "Compressed": | ||
938 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
939 | break; | ||
940 | case "Description": | ||
941 | packageName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
942 | break; | ||
943 | case "Keywords": | ||
944 | keywords = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
945 | break; | ||
946 | case "Languages": | ||
947 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
948 | break; | ||
949 | case "Manufacturer": | ||
950 | packageAuthor = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
951 | break; | ||
952 | case "Platforms": | ||
953 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
954 | break; | ||
955 | case "ReadOnly": | ||
956 | security = this.Core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); | ||
957 | break; | ||
958 | case "ShortNames": | ||
959 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName)); | ||
960 | break; | ||
961 | case "SummaryCodepage": | ||
962 | codepage = this.Core.GetAttributeLocalizableCodePageValue(sourceLineNumbers, attrib); | ||
963 | break; | ||
964 | default: | ||
965 | this.Core.UnexpectedAttribute(node, attrib); | ||
966 | break; | ||
967 | } | ||
968 | } | ||
969 | else | ||
970 | { | ||
971 | this.Core.ParseExtensionAttribute(node, attrib); | ||
972 | } | ||
973 | } | ||
974 | |||
975 | this.Core.ParseForExtensionElements(node); | ||
976 | |||
977 | if (!this.Core.EncounteredError) | ||
978 | { | ||
979 | // PID_CODEPAGE | ||
980 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
981 | row.Set(0, 1); | ||
982 | row.Set(1, codepage); | ||
983 | |||
984 | // PID_TITLE | ||
985 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
986 | row.Set(0, 2); | ||
987 | row.Set(1, "Patch"); | ||
988 | |||
989 | // PID_SUBJECT | ||
990 | if (null != packageName) | ||
991 | { | ||
992 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
993 | row.Set(0, 3); | ||
994 | row.Set(1, packageName); | ||
995 | } | ||
996 | |||
997 | // PID_AUTHOR | ||
998 | if (null != packageAuthor) | ||
999 | { | ||
1000 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1001 | row.Set(0, 4); | ||
1002 | row.Set(1, packageAuthor); | ||
1003 | } | ||
1004 | |||
1005 | // PID_KEYWORDS | ||
1006 | if (null != keywords) | ||
1007 | { | ||
1008 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1009 | row.Set(0, 5); | ||
1010 | row.Set(1, keywords); | ||
1011 | } | ||
1012 | |||
1013 | // PID_COMMENTS | ||
1014 | if (null != comments) | ||
1015 | { | ||
1016 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1017 | row.Set(0, 6); | ||
1018 | row.Set(1, comments); | ||
1019 | } | ||
1020 | |||
1021 | // PID_PAGECOUNT | ||
1022 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1023 | row.Set(0, 14); | ||
1024 | row.Set(1, msiVersion.ToString(CultureInfo.InvariantCulture)); | ||
1025 | |||
1026 | // PID_WORDCOUNT | ||
1027 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1028 | row.Set(0, 15); | ||
1029 | row.Set(1, "0"); | ||
1030 | |||
1031 | // PID_SECURITY | ||
1032 | row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType._SummaryInformation); | ||
1033 | row.Set(0, 19); | ||
1034 | switch (security) | ||
1035 | { | ||
1036 | case YesNoDefaultType.No: // no restriction | ||
1037 | row.Set(1, "0"); | ||
1038 | break; | ||
1039 | case YesNoDefaultType.Default: // read-only recommended | ||
1040 | row.Set(1, "2"); | ||
1041 | break; | ||
1042 | case YesNoDefaultType.Yes: // read-only enforced | ||
1043 | row.Set(1, "4"); | ||
1044 | break; | ||
1045 | } | ||
1046 | } | ||
1047 | } | ||
1048 | |||
1049 | /// <summary> | ||
1050 | /// Parses a permission element. | ||
1051 | /// </summary> | ||
1052 | /// <param name="node">Element to parse.</param> | ||
1053 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
1054 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
1055 | private void ParsePermissionElement(XElement node, string objectId, string tableName) | ||
1056 | { | ||
1057 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1058 | var bits = new BitArray(32); | ||
1059 | string domain = null; | ||
1060 | var permission = 0; | ||
1061 | string[] specialPermissions = null; | ||
1062 | string user = null; | ||
1063 | |||
1064 | switch (tableName) | ||
1065 | { | ||
1066 | case "CreateFolder": | ||
1067 | specialPermissions = Common.FolderPermissions; | ||
1068 | break; | ||
1069 | case "File": | ||
1070 | specialPermissions = Common.FilePermissions; | ||
1071 | break; | ||
1072 | case "Registry": | ||
1073 | specialPermissions = Common.RegistryPermissions; | ||
1074 | break; | ||
1075 | default: | ||
1076 | this.Core.UnexpectedElement(node.Parent, node); | ||
1077 | return; // stop processing this element since no valid permissions are available | ||
1078 | } | ||
1079 | |||
1080 | foreach (var attrib in node.Attributes()) | ||
1081 | { | ||
1082 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1083 | { | ||
1084 | switch (attrib.Name.LocalName) | ||
1085 | { | ||
1086 | case "Domain": | ||
1087 | domain = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1088 | break; | ||
1089 | case "User": | ||
1090 | user = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1091 | break; | ||
1092 | case "FileAllRights": | ||
1093 | // match the WinNT.h mask FILE_ALL_ACCESS for value 0x001F01FF (aka 1 1111 0000 0001 1111 1111 or 2032127) | ||
1094 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[16] = bits[17] = bits[18] = bits[19] = bits[20] = true; | ||
1095 | break; | ||
1096 | case "SpecificRightsAll": | ||
1097 | // match the WinNT.h mask SPECIFIC_RIGHTS_ALL for value 0x0000FFFF (aka 1111 1111 1111 1111) | ||
1098 | bits[0] = bits[1] = bits[2] = bits[3] = bits[4] = bits[5] = bits[6] = bits[7] = bits[8] = bits[9] = bits[10] = bits[11] = bits[12] = bits[13] = bits[14] = bits[15] = true; | ||
1099 | break; | ||
1100 | default: | ||
1101 | var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1102 | if (!this.Core.TrySetBitFromName(Common.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16)) | ||
1103 | { | ||
1104 | if (!this.Core.TrySetBitFromName(Common.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28)) | ||
1105 | { | ||
1106 | if (!this.Core.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0)) | ||
1107 | { | ||
1108 | this.Core.UnexpectedAttribute(node, attrib); | ||
1109 | break; | ||
1110 | } | ||
1111 | } | ||
1112 | } | ||
1113 | break; | ||
1114 | } | ||
1115 | } | ||
1116 | else | ||
1117 | { | ||
1118 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1119 | } | ||
1120 | } | ||
1121 | |||
1122 | permission = this.Core.CreateIntegerFromBitArray(bits); | ||
1123 | |||
1124 | if (null == user) | ||
1125 | { | ||
1126 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "User")); | ||
1127 | } | ||
1128 | |||
1129 | if (Int32.MinValue == permission) // just GENERIC_READ, which is MSI_NULL | ||
1130 | { | ||
1131 | this.Core.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers)); | ||
1132 | } | ||
1133 | |||
1134 | this.Core.ParseForExtensionElements(node); | ||
1135 | |||
1136 | if (!this.Core.EncounteredError) | ||
1137 | { | ||
1138 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.LockPermissions); | ||
1139 | row.Set(0, objectId); | ||
1140 | row.Set(1, tableName); | ||
1141 | row.Set(2, domain); | ||
1142 | row.Set(3, user); | ||
1143 | row.Set(4, permission); | ||
1144 | } | ||
1145 | } | ||
1146 | |||
1147 | /// <summary> | ||
1148 | /// Parses an extended permission element. | ||
1149 | /// </summary> | ||
1150 | /// <param name="node">Element to parse.</param> | ||
1151 | /// <param name="objectId">Identifier of object to be secured.</param> | ||
1152 | /// <param name="tableName">Name of table that contains objectId.</param> | ||
1153 | private void ParsePermissionExElement(XElement node, string objectId, string tableName) | ||
1154 | { | ||
1155 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1156 | string condition = null; | ||
1157 | Identifier id = null; | ||
1158 | string sddl = null; | ||
1159 | |||
1160 | switch (tableName) | ||
1161 | { | ||
1162 | case "CreateFolder": | ||
1163 | case "File": | ||
1164 | case "Registry": | ||
1165 | case "ServiceInstall": | ||
1166 | break; | ||
1167 | default: | ||
1168 | this.Core.UnexpectedElement(node.Parent, node); | ||
1169 | return; // stop processing this element since nothing will be valid. | ||
1170 | } | ||
1171 | |||
1172 | foreach (var attrib in node.Attributes()) | ||
1173 | { | ||
1174 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1175 | { | ||
1176 | switch (attrib.Name.LocalName) | ||
1177 | { | ||
1178 | case "Id": | ||
1179 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1180 | break; | ||
1181 | case "Sddl": | ||
1182 | sddl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1183 | break; | ||
1184 | default: | ||
1185 | this.Core.UnexpectedAttribute(node, attrib); | ||
1186 | break; | ||
1187 | } | ||
1188 | } | ||
1189 | else | ||
1190 | { | ||
1191 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1192 | } | ||
1193 | } | ||
1194 | |||
1195 | if (null == sddl) | ||
1196 | { | ||
1197 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Sddl")); | ||
1198 | } | ||
1199 | |||
1200 | if (null == id) | ||
1201 | { | ||
1202 | id = this.Core.CreateIdentifier("pme", objectId, tableName, sddl); | ||
1203 | } | ||
1204 | |||
1205 | foreach (var child in node.Elements()) | ||
1206 | { | ||
1207 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1208 | { | ||
1209 | switch (child.Name.LocalName) | ||
1210 | { | ||
1211 | case "Condition": | ||
1212 | if (null != condition) | ||
1213 | { | ||
1214 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1215 | this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName)); | ||
1216 | } | ||
1217 | |||
1218 | condition = this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
1219 | break; | ||
1220 | default: | ||
1221 | this.Core.UnexpectedElement(node, child); | ||
1222 | break; | ||
1223 | } | ||
1224 | } | ||
1225 | else | ||
1226 | { | ||
1227 | this.Core.ParseExtensionElement(node, child); | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | if (!this.Core.EncounteredError) | ||
1232 | { | ||
1233 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiLockPermissionsEx, id); | ||
1234 | row.Set(1, objectId); | ||
1235 | row.Set(2, tableName); | ||
1236 | row.Set(3, sddl); | ||
1237 | row.Set(4, condition); | ||
1238 | } | ||
1239 | } | ||
1240 | |||
1241 | /// <summary> | ||
1242 | /// Parses a product element. | ||
1243 | /// </summary> | ||
1244 | /// <param name="node">Element to parse.</param> | ||
1245 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] | ||
1246 | private void ParseProductElement(XElement node) | ||
1247 | { | ||
1248 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1249 | var codepage = 65001; | ||
1250 | string productCode = null; | ||
1251 | string upgradeCode = null; | ||
1252 | string manufacturer = null; | ||
1253 | string version = null; | ||
1254 | string symbols = null; | ||
1255 | |||
1256 | this.activeName = null; | ||
1257 | this.activeLanguage = null; | ||
1258 | |||
1259 | foreach (var attrib in node.Attributes()) | ||
1260 | { | ||
1261 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1262 | { | ||
1263 | switch (attrib.Name.LocalName) | ||
1264 | { | ||
1265 | case "Id": | ||
1266 | productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, true); | ||
1267 | break; | ||
1268 | case "Codepage": | ||
1269 | codepage = this.Core.GetAttributeCodePageValue(sourceLineNumbers, attrib); | ||
1270 | break; | ||
1271 | case "Language": | ||
1272 | this.activeLanguage = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
1273 | break; | ||
1274 | case "Manufacturer": | ||
1275 | manufacturer = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
1276 | if ("PUT-COMPANY-NAME-HERE" == manufacturer) | ||
1277 | { | ||
1278 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, manufacturer)); | ||
1279 | } | ||
1280 | break; | ||
1281 | case "Name": | ||
1282 | this.activeName = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.MustHaveNonWhitespaceCharacters); | ||
1283 | if ("PUT-PRODUCT-NAME-HERE" == this.activeName) | ||
1284 | { | ||
1285 | this.Core.Write(WarningMessages.PlaceholderValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, this.activeName)); | ||
1286 | } | ||
1287 | break; | ||
1288 | case "UpgradeCode": | ||
1289 | upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
1290 | break; | ||
1291 | case "Version": // if the attribute is valid version, use the attribute value as is (so "1.0000.01.01" would *not* get translated to "1.0.1.1"). | ||
1292 | var verifiedVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
1293 | if (!String.IsNullOrEmpty(verifiedVersion)) | ||
1294 | { | ||
1295 | version = attrib.Value; | ||
1296 | } | ||
1297 | break; | ||
1298 | default: | ||
1299 | this.Core.UnexpectedAttribute(node, attrib); | ||
1300 | break; | ||
1301 | } | ||
1302 | } | ||
1303 | else | ||
1304 | { | ||
1305 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1306 | } | ||
1307 | } | ||
1308 | |||
1309 | if (null == productCode) | ||
1310 | { | ||
1311 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1312 | } | ||
1313 | |||
1314 | if (null == this.activeLanguage) | ||
1315 | { | ||
1316 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
1317 | } | ||
1318 | |||
1319 | if (null == manufacturer) | ||
1320 | { | ||
1321 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Manufacturer")); | ||
1322 | } | ||
1323 | |||
1324 | if (null == this.activeName) | ||
1325 | { | ||
1326 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
1327 | } | ||
1328 | |||
1329 | if (null == upgradeCode) | ||
1330 | { | ||
1331 | this.Core.Write(WarningMessages.MissingUpgradeCode(sourceLineNumbers)); | ||
1332 | } | ||
1333 | |||
1334 | if (null == version) | ||
1335 | { | ||
1336 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); | ||
1337 | } | ||
1338 | else if (!CompilerCore.IsValidProductVersion(version)) | ||
1339 | { | ||
1340 | this.Core.Write(ErrorMessages.InvalidProductVersion(sourceLineNumbers, version)); | ||
1341 | } | ||
1342 | |||
1343 | if (this.Core.EncounteredError) | ||
1344 | { | ||
1345 | return; | ||
1346 | } | ||
1347 | |||
1348 | try | ||
1349 | { | ||
1350 | this.compilingProduct = true; | ||
1351 | this.Core.CreateActiveSection(productCode, SectionType.Product, codepage, this.Context.CompilationId); | ||
1352 | |||
1353 | this.AddProperty(sourceLineNumbers, new Identifier("Manufacturer", AccessModifier.Public), manufacturer, false, false, false, true); | ||
1354 | this.AddProperty(sourceLineNumbers, new Identifier("ProductCode", AccessModifier.Public), productCode, false, false, false, true); | ||
1355 | this.AddProperty(sourceLineNumbers, new Identifier("ProductLanguage", AccessModifier.Public), this.activeLanguage, false, false, false, true); | ||
1356 | this.AddProperty(sourceLineNumbers, new Identifier("ProductName", AccessModifier.Public), this.activeName, false, false, false, true); | ||
1357 | this.AddProperty(sourceLineNumbers, new Identifier("ProductVersion", AccessModifier.Public), version, false, false, false, true); | ||
1358 | if (null != upgradeCode) | ||
1359 | { | ||
1360 | this.AddProperty(sourceLineNumbers, new Identifier("UpgradeCode", AccessModifier.Public), upgradeCode, false, false, false, true); | ||
1361 | } | ||
1362 | |||
1363 | var contextValues = new Dictionary<string, string> | ||
1364 | { | ||
1365 | ["ProductLanguage"] = this.activeLanguage, | ||
1366 | ["ProductVersion"] = version, | ||
1367 | ["UpgradeCode"] = upgradeCode | ||
1368 | }; | ||
1369 | |||
1370 | var featureDisplay = 0; | ||
1371 | foreach (var child in node.Elements()) | ||
1372 | { | ||
1373 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1374 | { | ||
1375 | switch (child.Name.LocalName) | ||
1376 | { | ||
1377 | case "_locDefinition": | ||
1378 | break; | ||
1379 | case "AdminExecuteSequence": | ||
1380 | case "AdminUISequence": | ||
1381 | case "AdvertiseExecuteSequence": | ||
1382 | case "InstallExecuteSequence": | ||
1383 | case "InstallUISequence": | ||
1384 | this.ParseSequenceElement(child, child.Name.LocalName); | ||
1385 | break; | ||
1386 | case "AppId": | ||
1387 | this.ParseAppIdElement(child, null, YesNoType.Yes, null, null, null); | ||
1388 | break; | ||
1389 | case "Binary": | ||
1390 | this.ParseBinaryElement(child); | ||
1391 | break; | ||
1392 | case "ComplianceCheck": | ||
1393 | this.ParseComplianceCheckElement(child); | ||
1394 | break; | ||
1395 | case "Component": | ||
1396 | this.ParseComponentElement(child, ComplexReferenceParentType.Unknown, null, null, CompilerConstants.IntegerNotSet, null, null); | ||
1397 | break; | ||
1398 | case "ComponentGroup": | ||
1399 | this.ParseComponentGroupElement(child, ComplexReferenceParentType.Unknown, null); | ||
1400 | break; | ||
1401 | case "Condition": | ||
1402 | this.ParseConditionElement(child, node.Name.LocalName, null, null); | ||
1403 | break; | ||
1404 | case "CustomAction": | ||
1405 | this.ParseCustomActionElement(child); | ||
1406 | break; | ||
1407 | case "CustomActionRef": | ||
1408 | this.ParseSimpleRefElement(child, "CustomAction"); | ||
1409 | break; | ||
1410 | case "CustomTable": | ||
1411 | this.ParseCustomTableElement(child); | ||
1412 | break; | ||
1413 | case "Directory": | ||
1414 | this.ParseDirectoryElement(child, null, CompilerConstants.IntegerNotSet, String.Empty); | ||
1415 | break; | ||
1416 | case "DirectoryRef": | ||
1417 | this.ParseDirectoryRefElement(child); | ||
1418 | break; | ||
1419 | case "EmbeddedChainer": | ||
1420 | this.ParseEmbeddedChainerElement(child); | ||
1421 | break; | ||
1422 | case "EmbeddedChainerRef": | ||
1423 | this.ParseSimpleRefElement(child, "MsiEmbeddedChainer"); | ||
1424 | break; | ||
1425 | case "EnsureTable": | ||
1426 | this.ParseEnsureTableElement(child); | ||
1427 | break; | ||
1428 | case "Feature": | ||
1429 | this.ParseFeatureElement(child, ComplexReferenceParentType.Product, productCode, ref featureDisplay); | ||
1430 | break; | ||
1431 | case "FeatureRef": | ||
1432 | this.ParseFeatureRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
1433 | break; | ||
1434 | case "FeatureGroupRef": | ||
1435 | this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Product, productCode); | ||
1436 | break; | ||
1437 | case "Icon": | ||
1438 | this.ParseIconElement(child); | ||
1439 | break; | ||
1440 | case "InstanceTransforms": | ||
1441 | this.ParseInstanceTransformsElement(child); | ||
1442 | break; | ||
1443 | case "MajorUpgrade": | ||
1444 | this.ParseMajorUpgradeElement(child, contextValues); | ||
1445 | break; | ||
1446 | case "Media": | ||
1447 | this.ParseMediaElement(child, null); | ||
1448 | break; | ||
1449 | case "MediaTemplate": | ||
1450 | this.ParseMediaTemplateElement(child, null); | ||
1451 | break; | ||
1452 | case "Package": | ||
1453 | this.ParsePackageElement(child, manufacturer, null); | ||
1454 | break; | ||
1455 | case "PackageCertificates": | ||
1456 | case "PatchCertificates": | ||
1457 | this.ParseCertificatesElement(child); | ||
1458 | break; | ||
1459 | case "Property": | ||
1460 | this.ParsePropertyElement(child); | ||
1461 | break; | ||
1462 | case "PropertyRef": | ||
1463 | this.ParseSimpleRefElement(child, "Property"); | ||
1464 | break; | ||
1465 | case "SetDirectory": | ||
1466 | this.ParseSetDirectoryElement(child); | ||
1467 | break; | ||
1468 | case "SetProperty": | ||
1469 | this.ParseSetPropertyElement(child); | ||
1470 | break; | ||
1471 | case "SFPCatalog": | ||
1472 | string parentName = null; | ||
1473 | this.ParseSFPCatalogElement(child, ref parentName); | ||
1474 | break; | ||
1475 | case "SymbolPath": | ||
1476 | if (null != symbols) | ||
1477 | { | ||
1478 | symbols += ";" + this.ParseSymbolPathElement(child); | ||
1479 | } | ||
1480 | else | ||
1481 | { | ||
1482 | symbols = this.ParseSymbolPathElement(child); | ||
1483 | } | ||
1484 | break; | ||
1485 | case "UI": | ||
1486 | this.ParseUIElement(child); | ||
1487 | break; | ||
1488 | case "UIRef": | ||
1489 | this.ParseSimpleRefElement(child, "WixUI"); | ||
1490 | break; | ||
1491 | case "Upgrade": | ||
1492 | this.ParseUpgradeElement(child); | ||
1493 | break; | ||
1494 | case "WixVariable": | ||
1495 | this.ParseWixVariableElement(child); | ||
1496 | break; | ||
1497 | default: | ||
1498 | this.Core.UnexpectedElement(node, child); | ||
1499 | break; | ||
1500 | } | ||
1501 | } | ||
1502 | else | ||
1503 | { | ||
1504 | this.Core.ParseExtensionElement(node, child); | ||
1505 | } | ||
1506 | } | ||
1507 | |||
1508 | if (!this.Core.EncounteredError) | ||
1509 | { | ||
1510 | if (null != symbols) | ||
1511 | { | ||
1512 | var symbolRow = (WixDeltaPatchSymbolPathsTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixDeltaPatchSymbolPaths); | ||
1513 | symbolRow.Id = productCode; | ||
1514 | symbolRow.Type = SymbolPathType.Product; | ||
1515 | symbolRow.SymbolPaths = symbols; | ||
1516 | } | ||
1517 | } | ||
1518 | } | ||
1519 | finally | ||
1520 | { | ||
1521 | this.compilingProduct = false; | ||
1522 | } | ||
1523 | } | ||
1524 | |||
1525 | /// <summary> | ||
1526 | /// Parses a progid element | ||
1527 | /// </summary> | ||
1528 | /// <param name="node">Element to parse.</param> | ||
1529 | /// <param name="componentId">Identifier of parent component.</param> | ||
1530 | /// <param name="advertise">Flag if progid is advertised.</param> | ||
1531 | /// <param name="classId">CLSID related to ProgId.</param> | ||
1532 | /// <param name="description">Default description of ProgId</param> | ||
1533 | /// <param name="parent">Optional parent ProgId</param> | ||
1534 | /// <param name="foundExtension">Set to true if an extension is found; used for error-checking.</param> | ||
1535 | /// <param name="firstProgIdForClass">Whether or not this ProgId is the first one found in the parent class.</param> | ||
1536 | /// <returns>This element's Id.</returns> | ||
1537 | private string ParseProgIdElement(XElement node, string componentId, YesNoType advertise, string classId, string description, string parent, ref bool foundExtension, YesNoType firstProgIdForClass) | ||
1538 | { | ||
1539 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1540 | string icon = null; | ||
1541 | var iconIndex = CompilerConstants.IntegerNotSet; | ||
1542 | string noOpen = null; | ||
1543 | string progId = null; | ||
1544 | var progIdAdvertise = YesNoType.NotSet; | ||
1545 | |||
1546 | foreach (var attrib in node.Attributes()) | ||
1547 | { | ||
1548 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1549 | { | ||
1550 | switch (attrib.Name.LocalName) | ||
1551 | { | ||
1552 | case "Id": | ||
1553 | progId = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1554 | break; | ||
1555 | case "Advertise": | ||
1556 | progIdAdvertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1557 | break; | ||
1558 | case "Description": | ||
1559 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
1560 | break; | ||
1561 | case "Icon": | ||
1562 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
1563 | break; | ||
1564 | case "IconIndex": | ||
1565 | iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue); | ||
1566 | break; | ||
1567 | case "NoOpen": | ||
1568 | noOpen = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
1569 | break; | ||
1570 | default: | ||
1571 | this.Core.UnexpectedAttribute(node, attrib); | ||
1572 | break; | ||
1573 | } | ||
1574 | } | ||
1575 | else | ||
1576 | { | ||
1577 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1581 | if ((YesNoType.No == advertise && YesNoType.Yes == progIdAdvertise) || (YesNoType.Yes == advertise && YesNoType.No == progIdAdvertise)) | ||
1582 | { | ||
1583 | this.Core.Write(ErrorMessages.AdvertiseStateMustMatch(sourceLineNumbers, advertise.ToString(), progIdAdvertise.ToString())); | ||
1584 | } | ||
1585 | else | ||
1586 | { | ||
1587 | advertise = progIdAdvertise; | ||
1588 | } | ||
1589 | |||
1590 | if (YesNoType.NotSet == advertise) | ||
1591 | { | ||
1592 | advertise = YesNoType.No; | ||
1593 | } | ||
1594 | |||
1595 | if (null != parent && (null != icon || CompilerConstants.IntegerNotSet != iconIndex)) | ||
1596 | { | ||
1597 | this.Core.Write(ErrorMessages.VersionIndependentProgIdsCannotHaveIcons(sourceLineNumbers)); | ||
1598 | } | ||
1599 | |||
1600 | var firstProgIdForNestedClass = YesNoType.Yes; | ||
1601 | foreach (var child in node.Elements()) | ||
1602 | { | ||
1603 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1604 | { | ||
1605 | switch (child.Name.LocalName) | ||
1606 | { | ||
1607 | case "Extension": | ||
1608 | this.ParseExtensionElement(child, componentId, advertise, progId); | ||
1609 | foundExtension = true; | ||
1610 | break; | ||
1611 | case "ProgId": | ||
1612 | // Only allow one nested ProgId. If we have a child, we should not have a parent. | ||
1613 | if (null == parent) | ||
1614 | { | ||
1615 | if (YesNoType.Yes == advertise) | ||
1616 | { | ||
1617 | this.ParseProgIdElement(child, componentId, advertise, null, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
1618 | } | ||
1619 | else if (YesNoType.No == advertise) | ||
1620 | { | ||
1621 | this.ParseProgIdElement(child, componentId, advertise, classId, description, progId, ref foundExtension, firstProgIdForNestedClass); | ||
1622 | } | ||
1623 | |||
1624 | firstProgIdForNestedClass = YesNoType.No; // any ProgId after this one is definitely not the first. | ||
1625 | } | ||
1626 | else | ||
1627 | { | ||
1628 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
1629 | this.Core.Write(ErrorMessages.ProgIdNestedTooDeep(childSourceLineNumbers)); | ||
1630 | } | ||
1631 | break; | ||
1632 | default: | ||
1633 | this.Core.UnexpectedElement(node, child); | ||
1634 | break; | ||
1635 | } | ||
1636 | } | ||
1637 | else | ||
1638 | { | ||
1639 | this.Core.ParseExtensionElement(node, child); | ||
1640 | } | ||
1641 | } | ||
1642 | |||
1643 | if (YesNoType.Yes == advertise) | ||
1644 | { | ||
1645 | if (!this.Core.EncounteredError) | ||
1646 | { | ||
1647 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ProgId); | ||
1648 | row.Set(0, progId); | ||
1649 | row.Set(1, parent); | ||
1650 | row.Set(2, classId); | ||
1651 | row.Set(3, description); | ||
1652 | if (null != icon) | ||
1653 | { | ||
1654 | row.Set(4, icon); | ||
1655 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
1656 | } | ||
1657 | |||
1658 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
1659 | { | ||
1660 | row.Set(5, iconIndex); | ||
1661 | } | ||
1662 | |||
1663 | this.Core.EnsureTable(sourceLineNumbers, "Class"); | ||
1664 | } | ||
1665 | } | ||
1666 | else if (YesNoType.No == advertise) | ||
1667 | { | ||
1668 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, progId, String.Empty, description, componentId); | ||
1669 | if (null != classId) | ||
1670 | { | ||
1671 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\CLSID"), String.Empty, classId, componentId); | ||
1672 | if (null != parent) // if this is a version independent ProgId | ||
1673 | { | ||
1674 | if (YesNoType.Yes == firstProgIdForClass) | ||
1675 | { | ||
1676 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\VersionIndependentProgID"), String.Empty, progId, componentId); | ||
1677 | } | ||
1678 | |||
1679 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\CurVer"), String.Empty, parent, componentId); | ||
1680 | } | ||
1681 | else | ||
1682 | { | ||
1683 | if (YesNoType.Yes == firstProgIdForClass) | ||
1684 | { | ||
1685 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat("CLSID\\", classId, "\\ProgID"), String.Empty, progId, componentId); | ||
1686 | } | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | if (null != icon) // ProgId's Default Icon | ||
1691 | { | ||
1692 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", icon); | ||
1693 | |||
1694 | icon = String.Format(CultureInfo.InvariantCulture, "\"[#{0}]\"", icon); | ||
1695 | |||
1696 | if (CompilerConstants.IntegerNotSet != iconIndex) | ||
1697 | { | ||
1698 | icon = String.Concat(icon, ",", iconIndex); | ||
1699 | } | ||
1700 | |||
1701 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(progId, "\\DefaultIcon"), String.Empty, icon, componentId); | ||
1702 | } | ||
1703 | } | ||
1704 | |||
1705 | if (null != noOpen) | ||
1706 | { | ||
1707 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, progId, "NoOpen", noOpen, componentId); // ProgId NoOpen name | ||
1708 | } | ||
1709 | |||
1710 | // raise an error for an orphaned ProgId | ||
1711 | if (YesNoType.Yes == advertise && !foundExtension && null == parent && null == classId) | ||
1712 | { | ||
1713 | this.Core.Write(WarningMessages.OrphanedProgId(sourceLineNumbers, progId)); | ||
1714 | } | ||
1715 | |||
1716 | return progId; | ||
1717 | } | ||
1718 | |||
1719 | /// <summary> | ||
1720 | /// Parses a property element. | ||
1721 | /// </summary> | ||
1722 | /// <param name="node">Element to parse.</param> | ||
1723 | private void ParsePropertyElement(XElement node) | ||
1724 | { | ||
1725 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1726 | Identifier id = null; | ||
1727 | var admin = false; | ||
1728 | var complianceCheck = false; | ||
1729 | var hidden = false; | ||
1730 | var secure = false; | ||
1731 | var suppressModularization = YesNoType.NotSet; | ||
1732 | string value = null; | ||
1733 | |||
1734 | foreach (var attrib in node.Attributes()) | ||
1735 | { | ||
1736 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1737 | { | ||
1738 | switch (attrib.Name.LocalName) | ||
1739 | { | ||
1740 | case "Id": | ||
1741 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1742 | break; | ||
1743 | case "Admin": | ||
1744 | admin = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1745 | break; | ||
1746 | case "ComplianceCheck": | ||
1747 | complianceCheck = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1748 | break; | ||
1749 | case "Hidden": | ||
1750 | hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1751 | break; | ||
1752 | case "Secure": | ||
1753 | secure = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1754 | break; | ||
1755 | case "SuppressModularization": | ||
1756 | suppressModularization = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1757 | break; | ||
1758 | case "Value": | ||
1759 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1760 | break; | ||
1761 | default: | ||
1762 | this.Core.UnexpectedAttribute(node, attrib); | ||
1763 | break; | ||
1764 | } | ||
1765 | } | ||
1766 | else | ||
1767 | { | ||
1768 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1769 | } | ||
1770 | } | ||
1771 | |||
1772 | if (null == id) | ||
1773 | { | ||
1774 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
1775 | id = Identifier.Invalid; | ||
1776 | } | ||
1777 | else if ("ProductID" == id.Id) | ||
1778 | { | ||
1779 | this.Core.Write(WarningMessages.ProductIdAuthored(sourceLineNumbers)); | ||
1780 | } | ||
1781 | else if ("SecureCustomProperties" == id.Id || "AdminProperties" == id.Id || "MsiHiddenProperties" == id.Id) | ||
1782 | { | ||
1783 | this.Core.Write(ErrorMessages.CannotAuthorSpecialProperties(sourceLineNumbers, id.Id)); | ||
1784 | } | ||
1785 | |||
1786 | var innerText = this.Core.GetTrimmedInnerText(node); | ||
1787 | if (null != value) | ||
1788 | { | ||
1789 | // cannot specify both the value attribute and inner text | ||
1790 | if (!String.IsNullOrEmpty(innerText)) | ||
1791 | { | ||
1792 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
1793 | } | ||
1794 | } | ||
1795 | else // value attribute not specified, use inner text if any. | ||
1796 | { | ||
1797 | value = innerText; | ||
1798 | } | ||
1799 | |||
1800 | if ("ErrorDialog" == id.Id) | ||
1801 | { | ||
1802 | this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", value); | ||
1803 | } | ||
1804 | |||
1805 | foreach (var child in node.Elements()) | ||
1806 | { | ||
1807 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1808 | { | ||
1809 | { | ||
1810 | switch (child.Name.LocalName) | ||
1811 | { | ||
1812 | case "ProductSearch": | ||
1813 | this.ParseProductSearchElement(child, id.Id); | ||
1814 | secure = true; | ||
1815 | break; | ||
1816 | default: | ||
1817 | // let ParseSearchSignatures handle standard AppSearch children and unknown elements | ||
1818 | break; | ||
1819 | } | ||
1820 | } | ||
1821 | } | ||
1822 | } | ||
1823 | |||
1824 | // see if this property is used for appSearch | ||
1825 | var signatures = this.ParseSearchSignatures(node); | ||
1826 | |||
1827 | // If we're doing CCP then there must be a signature. | ||
1828 | if (complianceCheck && 0 == signatures.Count) | ||
1829 | { | ||
1830 | this.Core.Write(ErrorMessages.SearchElementRequiredWithAttribute(sourceLineNumbers, node.Name.LocalName, "ComplianceCheck", "yes")); | ||
1831 | } | ||
1832 | |||
1833 | foreach (var sig in signatures) | ||
1834 | { | ||
1835 | if (complianceCheck && !this.Core.EncounteredError) | ||
1836 | { | ||
1837 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.CCPSearch, new Identifier(sig, AccessModifier.Private)); | ||
1838 | } | ||
1839 | |||
1840 | this.AddAppSearch(sourceLineNumbers, id, sig); | ||
1841 | } | ||
1842 | |||
1843 | // If we're doing AppSearch get that setup. | ||
1844 | if (0 < signatures.Count) | ||
1845 | { | ||
1846 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
1847 | } | ||
1848 | else // just a normal old property. | ||
1849 | { | ||
1850 | // If the property value is empty and none of the flags are set, print out a warning that we're ignoring | ||
1851 | // the element. | ||
1852 | if (String.IsNullOrEmpty(value) && !admin && !secure && !hidden) | ||
1853 | { | ||
1854 | this.Core.Write(WarningMessages.PropertyUseless(sourceLineNumbers, id.Id)); | ||
1855 | } | ||
1856 | else // there is a value and/or a flag set, do that. | ||
1857 | { | ||
1858 | this.AddProperty(sourceLineNumbers, id, value, admin, secure, hidden, false); | ||
1859 | } | ||
1860 | } | ||
1861 | |||
1862 | if (!this.Core.EncounteredError && YesNoType.Yes == suppressModularization) | ||
1863 | { | ||
1864 | this.Core.Write(WarningMessages.PropertyModularizationSuppressed(sourceLineNumbers)); | ||
1865 | |||
1866 | this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixSuppressModularization, id); | ||
1867 | } | ||
1868 | } | ||
1869 | |||
1870 | /// <summary> | ||
1871 | /// Parses a RegistryKey element. | ||
1872 | /// </summary> | ||
1873 | /// <param name="node">Element to parse.</param> | ||
1874 | /// <param name="componentId">Identifier for parent component.</param> | ||
1875 | /// <param name="root">Root specified when element is nested under another Registry element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
1876 | /// <param name="parentKey">Parent key for this Registry element when nested.</param> | ||
1877 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
1878 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
1879 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
1880 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
1881 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
1882 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
1883 | private YesNoType ParseRegistryKeyElement(XElement node, string componentId, RegistryRootType? root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
1884 | { | ||
1885 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
1886 | Identifier id = null; | ||
1887 | var key = parentKey; // default to parent key path | ||
1888 | var forceCreateOnInstall = false; | ||
1889 | var forceDeleteOnUninstall = false; | ||
1890 | var keyPath = YesNoType.NotSet; | ||
1891 | |||
1892 | possibleKeyPath = null; | ||
1893 | |||
1894 | foreach (var attrib in node.Attributes()) | ||
1895 | { | ||
1896 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
1897 | { | ||
1898 | switch (attrib.Name.LocalName) | ||
1899 | { | ||
1900 | case "Id": | ||
1901 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
1902 | break; | ||
1903 | case "Action": | ||
1904 | this.Core.Write(WarningMessages.DeprecatedRegistryKeyActionAttribute(sourceLineNumbers)); | ||
1905 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1906 | switch (actionValue) | ||
1907 | { | ||
1908 | case "create": | ||
1909 | forceCreateOnInstall = true; | ||
1910 | break; | ||
1911 | case "createAndRemoveOnUninstall": | ||
1912 | forceCreateOnInstall = true; | ||
1913 | forceDeleteOnUninstall = true; | ||
1914 | break; | ||
1915 | case "none": | ||
1916 | break; | ||
1917 | case "": | ||
1918 | break; | ||
1919 | default: | ||
1920 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "createAndRemoveOnUninstall", "none")); | ||
1921 | break; | ||
1922 | } | ||
1923 | break; | ||
1924 | case "ForceCreateOnInstall": | ||
1925 | forceCreateOnInstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1926 | break; | ||
1927 | case "ForceDeleteOnUninstall": | ||
1928 | forceDeleteOnUninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
1929 | break; | ||
1930 | case "Key": | ||
1931 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
1932 | if (null != parentKey) | ||
1933 | { | ||
1934 | key = Path.Combine(parentKey, key); | ||
1935 | } | ||
1936 | break; | ||
1937 | case "Root": | ||
1938 | if (root.HasValue) | ||
1939 | { | ||
1940 | this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers)); | ||
1941 | } | ||
1942 | |||
1943 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
1944 | break; | ||
1945 | default: | ||
1946 | this.Core.UnexpectedAttribute(node, attrib); | ||
1947 | break; | ||
1948 | } | ||
1949 | } | ||
1950 | else | ||
1951 | { | ||
1952 | this.Core.ParseExtensionAttribute(node, attrib); | ||
1953 | } | ||
1954 | } | ||
1955 | |||
1956 | var name = forceCreateOnInstall ? (forceDeleteOnUninstall ? "*" : "+") : (forceDeleteOnUninstall ? "-" : null); | ||
1957 | |||
1958 | if (forceCreateOnInstall || forceDeleteOnUninstall) // generates a Registry row, so an Id must be present | ||
1959 | { | ||
1960 | // generate the identifier if it wasn't provided | ||
1961 | if (null == id) | ||
1962 | { | ||
1963 | id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
1964 | } | ||
1965 | } | ||
1966 | else // does not generate a Registry row, so no Id should be present | ||
1967 | { | ||
1968 | if (null != id) | ||
1969 | { | ||
1970 | this.Core.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, node.Name.LocalName, "Id", "ForceCreateOnInstall", "ForceDeleteOnUninstall", "yes", true)); | ||
1971 | } | ||
1972 | } | ||
1973 | |||
1974 | if (!root.HasValue) | ||
1975 | { | ||
1976 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
1977 | } | ||
1978 | |||
1979 | if (null == key) | ||
1980 | { | ||
1981 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
1982 | key = String.Empty; // set the key to something to prevent null reference exceptions | ||
1983 | } | ||
1984 | |||
1985 | foreach (var child in node.Elements()) | ||
1986 | { | ||
1987 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
1988 | { | ||
1989 | string possibleChildKeyPath = null; | ||
1990 | |||
1991 | switch (child.Name.LocalName) | ||
1992 | { | ||
1993 | case "RegistryKey": | ||
1994 | if (YesNoType.Yes == this.ParseRegistryKeyElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
1995 | { | ||
1996 | if (YesNoType.Yes == keyPath) | ||
1997 | { | ||
1998 | this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
1999 | } | ||
2000 | |||
2001 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
2002 | keyPath = YesNoType.Yes; | ||
2003 | } | ||
2004 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
2005 | { | ||
2006 | possibleKeyPath = possibleChildKeyPath; | ||
2007 | } | ||
2008 | break; | ||
2009 | case "RegistryValue": | ||
2010 | if (YesNoType.Yes == this.ParseRegistryValueElement(child, componentId, root, key, win64Component, out possibleChildKeyPath)) | ||
2011 | { | ||
2012 | if (YesNoType.Yes == keyPath) | ||
2013 | { | ||
2014 | this.Core.Write(ErrorMessages.ComponentMultipleKeyPaths(sourceLineNumbers, child.Name.LocalName, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); | ||
2015 | } | ||
2016 | |||
2017 | possibleKeyPath = possibleChildKeyPath; // the child is the key path | ||
2018 | keyPath = YesNoType.Yes; | ||
2019 | } | ||
2020 | else if (null == possibleKeyPath && null != possibleChildKeyPath) | ||
2021 | { | ||
2022 | possibleKeyPath = possibleChildKeyPath; | ||
2023 | } | ||
2024 | break; | ||
2025 | case "Permission": | ||
2026 | if (!forceCreateOnInstall) | ||
2027 | { | ||
2028 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
2029 | } | ||
2030 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
2031 | break; | ||
2032 | case "PermissionEx": | ||
2033 | if (!forceCreateOnInstall) | ||
2034 | { | ||
2035 | this.Core.Write(ErrorMessages.UnexpectedElementWithAttributeValue(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "ForceCreateOnInstall", "yes")); | ||
2036 | } | ||
2037 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
2038 | break; | ||
2039 | default: | ||
2040 | this.Core.UnexpectedElement(node, child); | ||
2041 | break; | ||
2042 | } | ||
2043 | } | ||
2044 | else | ||
2045 | { | ||
2046 | var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
2047 | this.Core.ParseExtensionElement(node, child, context); | ||
2048 | } | ||
2049 | } | ||
2050 | |||
2051 | if (!this.Core.EncounteredError && null != name) | ||
2052 | { | ||
2053 | var tuple = new RegistryTuple(sourceLineNumbers, id) | ||
2054 | { | ||
2055 | Root = root.Value, | ||
2056 | Key = key, | ||
2057 | Name = name, | ||
2058 | Component_ = componentId, | ||
2059 | }; | ||
2060 | |||
2061 | this.Core.AddTuple(tuple); | ||
2062 | } | ||
2063 | |||
2064 | return keyPath; | ||
2065 | } | ||
2066 | |||
2067 | /// <summary> | ||
2068 | /// Parses a RegistryValue element. | ||
2069 | /// </summary> | ||
2070 | /// <param name="node">Element to parse.</param> | ||
2071 | /// <param name="componentId">Identifier for parent component.</param> | ||
2072 | /// <param name="root">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
2073 | /// <param name="parentKey">Root specified when element is nested under a RegistryKey element, otherwise CompilerConstants.IntegerNotSet.</param> | ||
2074 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
2075 | /// <param name="possibleKeyPath">Identifier of this registry key since it could be the component's keypath.</param> | ||
2076 | /// <returns>Yes if this element was marked as the parent component's key path, No if explicitly marked as not being a key path, or NotSet otherwise.</returns> | ||
2077 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
2078 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
2079 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
2080 | private YesNoType ParseRegistryValueElement(XElement node, string componentId, RegistryRootType? root, string parentKey, bool win64Component, out string possibleKeyPath) | ||
2081 | { | ||
2082 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2083 | Identifier id = null; | ||
2084 | var key = parentKey; // default to parent key path | ||
2085 | string name = null; | ||
2086 | string value = null; | ||
2087 | string action = null; | ||
2088 | var valueType = RegistryValueType.String; | ||
2089 | var actionType = RegistryValueActionType.Write; | ||
2090 | var keyPath = YesNoType.NotSet; | ||
2091 | |||
2092 | possibleKeyPath = null; | ||
2093 | |||
2094 | foreach (var attrib in node.Attributes()) | ||
2095 | { | ||
2096 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2097 | { | ||
2098 | switch (attrib.Name.LocalName) | ||
2099 | { | ||
2100 | case "Id": | ||
2101 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2102 | break; | ||
2103 | case "Action": | ||
2104 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2105 | switch (actionValue) | ||
2106 | { | ||
2107 | case "append": | ||
2108 | actionType = RegistryValueActionType.Append; | ||
2109 | break; | ||
2110 | case "prepend": | ||
2111 | actionType = RegistryValueActionType.Prepend; | ||
2112 | break; | ||
2113 | case "write": | ||
2114 | actionType = RegistryValueActionType.Write; | ||
2115 | break; | ||
2116 | case "": | ||
2117 | break; | ||
2118 | default: | ||
2119 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "append", "prepend", "write")); | ||
2120 | break; | ||
2121 | } | ||
2122 | break; | ||
2123 | case "Key": | ||
2124 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2125 | if (null != parentKey) | ||
2126 | { | ||
2127 | if (parentKey.EndsWith("\\", StringComparison.Ordinal)) | ||
2128 | { | ||
2129 | key = String.Concat(parentKey, key); | ||
2130 | } | ||
2131 | else | ||
2132 | { | ||
2133 | key = String.Concat(parentKey, "\\", key); | ||
2134 | } | ||
2135 | } | ||
2136 | break; | ||
2137 | case "KeyPath": | ||
2138 | keyPath = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
2139 | break; | ||
2140 | case "Name": | ||
2141 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2142 | break; | ||
2143 | case "Root": | ||
2144 | if (root.HasValue) | ||
2145 | { | ||
2146 | this.Core.Write(ErrorMessages.RegistryRootInvalid(sourceLineNumbers)); | ||
2147 | } | ||
2148 | |||
2149 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
2150 | break; | ||
2151 | case "Type": | ||
2152 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2153 | switch (typeValue) | ||
2154 | { | ||
2155 | case "binary": | ||
2156 | valueType = RegistryValueType.Binary; | ||
2157 | break; | ||
2158 | case "expandable": | ||
2159 | valueType = RegistryValueType.Expandable; | ||
2160 | break; | ||
2161 | case "integer": | ||
2162 | valueType = RegistryValueType.Integer; | ||
2163 | break; | ||
2164 | case "multiString": | ||
2165 | valueType = RegistryValueType.MultiString; | ||
2166 | break; | ||
2167 | case "string": | ||
2168 | valueType = RegistryValueType.String; | ||
2169 | break; | ||
2170 | case "": | ||
2171 | break; | ||
2172 | default: | ||
2173 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue, "binary", "expandable", "integer", "multiString", "string")); | ||
2174 | break; | ||
2175 | } | ||
2176 | break; | ||
2177 | case "Value": | ||
2178 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
2179 | break; | ||
2180 | default: | ||
2181 | this.Core.UnexpectedAttribute(node, attrib); | ||
2182 | break; | ||
2183 | } | ||
2184 | } | ||
2185 | else | ||
2186 | { | ||
2187 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2188 | } | ||
2189 | } | ||
2190 | |||
2191 | // generate the identifier if it wasn't provided | ||
2192 | if (null == id) | ||
2193 | { | ||
2194 | id = this.Core.CreateIdentifier("reg", componentId, ((int)(root ?? RegistryRootType.Unknown)).ToString(), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
2195 | } | ||
2196 | |||
2197 | if (RegistryValueType.MultiString != valueType && (RegistryValueActionType.Append == actionType || RegistryValueActionType.Prepend == actionType)) | ||
2198 | { | ||
2199 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Action", action, "Type", "multiString")); | ||
2200 | } | ||
2201 | |||
2202 | if (null == key) | ||
2203 | { | ||
2204 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
2205 | } | ||
2206 | |||
2207 | if (!root.HasValue) | ||
2208 | { | ||
2209 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
2210 | } | ||
2211 | |||
2212 | foreach (var child in node.Elements()) | ||
2213 | { | ||
2214 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
2215 | { | ||
2216 | switch (child.Name.LocalName) | ||
2217 | { | ||
2218 | case "MultiStringValue": | ||
2219 | if (RegistryValueType.MultiString != valueType && null != value) | ||
2220 | { | ||
2221 | this.Core.Write(ErrorMessages.RegistryMultipleValuesWithoutMultiString(sourceLineNumbers, node.Name.LocalName, "Value", child.Name.LocalName, "Type")); | ||
2222 | } | ||
2223 | else if (null == value) | ||
2224 | { | ||
2225 | value = Common.GetInnerText(child); | ||
2226 | } | ||
2227 | else | ||
2228 | { | ||
2229 | value = String.Concat(value, "[~]", Common.GetInnerText(child)); | ||
2230 | } | ||
2231 | break; | ||
2232 | case "Permission": | ||
2233 | this.ParsePermissionElement(child, id.Id, "Registry"); | ||
2234 | break; | ||
2235 | case "PermissionEx": | ||
2236 | this.ParsePermissionExElement(child, id.Id, "Registry"); | ||
2237 | break; | ||
2238 | default: | ||
2239 | this.Core.UnexpectedElement(node, child); | ||
2240 | break; | ||
2241 | } | ||
2242 | } | ||
2243 | else | ||
2244 | { | ||
2245 | var context = new Dictionary<string, string>() { { "RegistryId", id.Id }, { "ComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
2246 | this.Core.ParseExtensionElement(node, child, context); | ||
2247 | } | ||
2248 | } | ||
2249 | |||
2250 | //switch (typeType) | ||
2251 | //{ | ||
2252 | //case Wix.RegistryValue.TypeType.binary: | ||
2253 | // value = String.Concat("#x", value); | ||
2254 | // break; | ||
2255 | //case Wix.RegistryValue.TypeType.expandable: | ||
2256 | // value = String.Concat("#%", value); | ||
2257 | // break; | ||
2258 | //case Wix.RegistryValue.TypeType.integer: | ||
2259 | // value = String.Concat("#", value); | ||
2260 | // break; | ||
2261 | //case Wix.RegistryValue.TypeType.multiString: | ||
2262 | // switch (actionType) | ||
2263 | // { | ||
2264 | // case Wix.RegistryValue.ActionType.append: | ||
2265 | // value = String.Concat("[~]", value); | ||
2266 | // break; | ||
2267 | // case Wix.RegistryValue.ActionType.prepend: | ||
2268 | // value = String.Concat(value, "[~]"); | ||
2269 | // break; | ||
2270 | // case Wix.RegistryValue.ActionType.write: | ||
2271 | // default: | ||
2272 | // if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) | ||
2273 | // { | ||
2274 | // value = String.Format(CultureInfo.InvariantCulture, "[~]{0}[~]", value); | ||
2275 | // } | ||
2276 | // break; | ||
2277 | // } | ||
2278 | // break; | ||
2279 | //case Wix.RegistryValue.TypeType.@string: | ||
2280 | // // escape the leading '#' character for string registry keys | ||
2281 | // if (null != value && value.StartsWith("#", StringComparison.Ordinal)) | ||
2282 | // { | ||
2283 | // value = String.Concat("#", value); | ||
2284 | // } | ||
2285 | // break; | ||
2286 | //} | ||
2287 | |||
2288 | // value may be set by child MultiStringValue elements, so it must be checked here | ||
2289 | if (null == value) | ||
2290 | { | ||
2291 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
2292 | } | ||
2293 | else if (0 == value.Length && ("+" == name || "-" == name || "*" == name)) // prevent accidental authoring of special name values | ||
2294 | { | ||
2295 | this.Core.Write(ErrorMessages.RegistryNameValueIncorrect(sourceLineNumbers, node.Name.LocalName, "Name", name)); | ||
2296 | } | ||
2297 | |||
2298 | if (!this.Core.EncounteredError) | ||
2299 | { | ||
2300 | var tuple = new RegistryTuple(sourceLineNumbers, id) | ||
2301 | { | ||
2302 | Root = root.Value, | ||
2303 | Name = name, | ||
2304 | Value = value, | ||
2305 | ValueType = valueType, | ||
2306 | ValueAction = actionType, | ||
2307 | Component_ = componentId, | ||
2308 | }; | ||
2309 | |||
2310 | this.Core.AddTuple(tuple); | ||
2311 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Registry, id); | ||
2312 | //row.Set(1, (int)root); | ||
2313 | //row.Set(2, key); | ||
2314 | //row.Set(3, name); | ||
2315 | //row.Set(4, value); | ||
2316 | //row.Set(5, componentId); | ||
2317 | } | ||
2318 | |||
2319 | // If this was just a regular registry key (that could be the key path) | ||
2320 | // and no child registry key set the possible key path, let's make this | ||
2321 | // Registry/@Id a possible key path. | ||
2322 | if (null == possibleKeyPath) | ||
2323 | { | ||
2324 | possibleKeyPath = id.Id; | ||
2325 | } | ||
2326 | |||
2327 | return keyPath; | ||
2328 | } | ||
2329 | |||
2330 | /// <summary> | ||
2331 | /// Parses a RemoveRegistryKey element. | ||
2332 | /// </summary> | ||
2333 | /// <param name="node">The element to parse.</param> | ||
2334 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
2335 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
2336 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
2337 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
2338 | private void ParseRemoveRegistryKeyElement(XElement node, string componentId) | ||
2339 | { | ||
2340 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2341 | Identifier id = null; | ||
2342 | RemoveRegistryActionType? actionType = null; | ||
2343 | string key = null; | ||
2344 | var name = "-"; | ||
2345 | RegistryRootType? root = null; | ||
2346 | |||
2347 | foreach (var attrib in node.Attributes()) | ||
2348 | { | ||
2349 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2350 | { | ||
2351 | switch (attrib.Name.LocalName) | ||
2352 | { | ||
2353 | case "Id": | ||
2354 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2355 | break; | ||
2356 | case "Action": | ||
2357 | var actionValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2358 | switch (actionValue) | ||
2359 | { | ||
2360 | case "removeOnInstall": | ||
2361 | actionType = RemoveRegistryActionType.RemoveOnInstall; | ||
2362 | break; | ||
2363 | case "removeOnUninstall": | ||
2364 | actionType = RemoveRegistryActionType.RemoveOnUninstall; | ||
2365 | break; | ||
2366 | case "": | ||
2367 | break; | ||
2368 | default: | ||
2369 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, actionValue, "removeOnInstall", "removeOnUninstall")); | ||
2370 | break; | ||
2371 | } | ||
2372 | //if (0 < action.Length) | ||
2373 | //{ | ||
2374 | // if (!Wix.RemoveRegistryKey.TryParseActionType(action, out actionType)) | ||
2375 | // { | ||
2376 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, action, "removeOnInstall", "removeOnUninstall")); | ||
2377 | // } | ||
2378 | //} | ||
2379 | break; | ||
2380 | case "Key": | ||
2381 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2382 | break; | ||
2383 | case "Root": | ||
2384 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
2385 | break; | ||
2386 | default: | ||
2387 | this.Core.UnexpectedAttribute(node, attrib); | ||
2388 | break; | ||
2389 | } | ||
2390 | } | ||
2391 | else | ||
2392 | { | ||
2393 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2394 | } | ||
2395 | } | ||
2396 | |||
2397 | // generate the identifier if it wasn't provided | ||
2398 | if (null == id) | ||
2399 | { | ||
2400 | id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
2401 | } | ||
2402 | |||
2403 | if (!root.HasValue) | ||
2404 | { | ||
2405 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
2406 | } | ||
2407 | |||
2408 | if (null == key) | ||
2409 | { | ||
2410 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
2411 | } | ||
2412 | |||
2413 | if (!actionType.HasValue) | ||
2414 | { | ||
2415 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action")); | ||
2416 | } | ||
2417 | |||
2418 | this.Core.ParseForExtensionElements(node); | ||
2419 | |||
2420 | if (!this.Core.EncounteredError) | ||
2421 | { | ||
2422 | var tuple = new RemoveRegistryTuple(sourceLineNumbers, id) | ||
2423 | { | ||
2424 | Root = root.Value, | ||
2425 | Key = key, | ||
2426 | Name = name, | ||
2427 | Action = actionType.Value, | ||
2428 | Component_ = componentId | ||
2429 | }; | ||
2430 | |||
2431 | this.Core.AddTuple(tuple); | ||
2432 | } | ||
2433 | } | ||
2434 | |||
2435 | /// <summary> | ||
2436 | /// Parses a RemoveRegistryValue element. | ||
2437 | /// </summary> | ||
2438 | /// <param name="node">The element to parse.</param> | ||
2439 | /// <param name="componentId">The component identifier of the parent element.</param> | ||
2440 | [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " + | ||
2441 | "in a change to the way the Registry table is generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " + | ||
2442 | "Furthermore, there is no security hole here, as the strings won't need to make a round trip")] | ||
2443 | private void ParseRemoveRegistryValueElement(XElement node, string componentId) | ||
2444 | { | ||
2445 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2446 | Identifier id = null; | ||
2447 | string key = null; | ||
2448 | string name = null; | ||
2449 | RegistryRootType? root = null; | ||
2450 | |||
2451 | foreach (var attrib in node.Attributes()) | ||
2452 | { | ||
2453 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2454 | { | ||
2455 | switch (attrib.Name.LocalName) | ||
2456 | { | ||
2457 | case "Id": | ||
2458 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2459 | break; | ||
2460 | case "Key": | ||
2461 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2462 | break; | ||
2463 | case "Name": | ||
2464 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2465 | break; | ||
2466 | case "Root": | ||
2467 | root = this.Core.GetAttributeRegistryRootValue(sourceLineNumbers, attrib, true); | ||
2468 | break; | ||
2469 | default: | ||
2470 | this.Core.UnexpectedAttribute(node, attrib); | ||
2471 | break; | ||
2472 | } | ||
2473 | } | ||
2474 | else | ||
2475 | { | ||
2476 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2477 | } | ||
2478 | } | ||
2479 | |||
2480 | // generate the identifier if it wasn't provided | ||
2481 | if (null == id) | ||
2482 | { | ||
2483 | id = this.Core.CreateIdentifier("reg", componentId, ((int)root).ToString(CultureInfo.InvariantCulture.NumberFormat), LowercaseOrNull(key), LowercaseOrNull(name)); | ||
2484 | } | ||
2485 | |||
2486 | if (!root.HasValue) | ||
2487 | { | ||
2488 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Root")); | ||
2489 | } | ||
2490 | |||
2491 | if (null == key) | ||
2492 | { | ||
2493 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
2494 | } | ||
2495 | |||
2496 | this.Core.ParseForExtensionElements(node); | ||
2497 | |||
2498 | if (!this.Core.EncounteredError) | ||
2499 | { | ||
2500 | var tuple = new RemoveRegistryTuple(sourceLineNumbers, id) | ||
2501 | { | ||
2502 | Root = root.Value, | ||
2503 | Key = key, | ||
2504 | Name = name, | ||
2505 | Component_ = componentId | ||
2506 | }; | ||
2507 | |||
2508 | this.Core.AddTuple(tuple); | ||
2509 | } | ||
2510 | } | ||
2511 | |||
2512 | /// <summary> | ||
2513 | /// Parses a remove file element. | ||
2514 | /// </summary> | ||
2515 | /// <param name="node">Element to parse.</param> | ||
2516 | /// <param name="componentId">Identifier of parent component.</param> | ||
2517 | /// <param name="parentDirectory">Identifier of the parent component's directory.</param> | ||
2518 | private void ParseRemoveFileElement(XElement node, string componentId, string parentDirectory) | ||
2519 | { | ||
2520 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2521 | Identifier id = null; | ||
2522 | string directory = null; | ||
2523 | string name = null; | ||
2524 | var on = CompilerConstants.IntegerNotSet; | ||
2525 | string property = null; | ||
2526 | string shortName = null; | ||
2527 | |||
2528 | foreach (var attrib in node.Attributes()) | ||
2529 | { | ||
2530 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2531 | { | ||
2532 | switch (attrib.Name.LocalName) | ||
2533 | { | ||
2534 | case "Id": | ||
2535 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2536 | break; | ||
2537 | case "Directory": | ||
2538 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
2539 | break; | ||
2540 | case "Name": | ||
2541 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, true); | ||
2542 | break; | ||
2543 | case "On": | ||
2544 | var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2545 | switch (onValue) | ||
2546 | { | ||
2547 | case "install": | ||
2548 | on = 1; | ||
2549 | break; | ||
2550 | case "uninstall": | ||
2551 | on = 2; | ||
2552 | break; | ||
2553 | case "both": | ||
2554 | on = 3; | ||
2555 | break; | ||
2556 | default: | ||
2557 | on = CompilerConstants.IllegalInteger; | ||
2558 | break; | ||
2559 | } | ||
2560 | break; | ||
2561 | case "Property": | ||
2562 | property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
2563 | break; | ||
2564 | case "ShortName": | ||
2565 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, true); | ||
2566 | break; | ||
2567 | default: | ||
2568 | this.Core.UnexpectedAttribute(node, attrib); | ||
2569 | break; | ||
2570 | } | ||
2571 | } | ||
2572 | else | ||
2573 | { | ||
2574 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2575 | } | ||
2576 | } | ||
2577 | |||
2578 | if (null == name) | ||
2579 | { | ||
2580 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
2581 | } | ||
2582 | else if (0 < name.Length) | ||
2583 | { | ||
2584 | if (this.Core.IsValidShortFilename(name, true)) | ||
2585 | { | ||
2586 | if (null == shortName) | ||
2587 | { | ||
2588 | shortName = name; | ||
2589 | name = null; | ||
2590 | } | ||
2591 | else | ||
2592 | { | ||
2593 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
2594 | } | ||
2595 | } | ||
2596 | else if (null == shortName) // generate a short file name. | ||
2597 | { | ||
2598 | shortName = this.Core.CreateShortName(name, true, true, node.Name.LocalName, componentId); | ||
2599 | } | ||
2600 | } | ||
2601 | |||
2602 | if (CompilerConstants.IntegerNotSet == on) | ||
2603 | { | ||
2604 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
2605 | on = CompilerConstants.IllegalInteger; | ||
2606 | } | ||
2607 | |||
2608 | if (null != directory && null != property) | ||
2609 | { | ||
2610 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
2611 | } | ||
2612 | |||
2613 | if (null == id) | ||
2614 | { | ||
2615 | id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, LowercaseOrNull(shortName), LowercaseOrNull(name), on.ToString()); | ||
2616 | } | ||
2617 | |||
2618 | this.Core.ParseForExtensionElements(node); | ||
2619 | |||
2620 | if (!this.Core.EncounteredError) | ||
2621 | { | ||
2622 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id); | ||
2623 | row.Set(1, componentId); | ||
2624 | row.Set(2, this.GetMsiFilenameValue(shortName, name)); | ||
2625 | if (null != directory) | ||
2626 | { | ||
2627 | row.Set(3, directory); | ||
2628 | } | ||
2629 | else if (null != property) | ||
2630 | { | ||
2631 | row.Set(3, property); | ||
2632 | } | ||
2633 | else | ||
2634 | { | ||
2635 | row.Set(3, parentDirectory); | ||
2636 | } | ||
2637 | row.Set(4, on); | ||
2638 | } | ||
2639 | } | ||
2640 | |||
2641 | /// <summary> | ||
2642 | /// Parses a RemoveFolder element. | ||
2643 | /// </summary> | ||
2644 | /// <param name="node">Element to parse.</param> | ||
2645 | /// <param name="componentId">Identifier of parent component.</param> | ||
2646 | /// <param name="parentDirectory">Identifier of parent component's directory.</param> | ||
2647 | private void ParseRemoveFolderElement(XElement node, string componentId, string parentDirectory) | ||
2648 | { | ||
2649 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2650 | Identifier id = null; | ||
2651 | string directory = null; | ||
2652 | var on = CompilerConstants.IntegerNotSet; | ||
2653 | string property = null; | ||
2654 | |||
2655 | foreach (var attrib in node.Attributes()) | ||
2656 | { | ||
2657 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2658 | { | ||
2659 | switch (attrib.Name.LocalName) | ||
2660 | { | ||
2661 | case "Id": | ||
2662 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2663 | break; | ||
2664 | case "Directory": | ||
2665 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, parentDirectory); | ||
2666 | break; | ||
2667 | case "On": | ||
2668 | var onValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2669 | switch (onValue) | ||
2670 | { | ||
2671 | case "install": | ||
2672 | on = 1; | ||
2673 | break; | ||
2674 | case "uninstall": | ||
2675 | on = 2; | ||
2676 | break; | ||
2677 | case "both": | ||
2678 | on = 3; | ||
2679 | break; | ||
2680 | default: | ||
2681 | on = CompilerConstants.IllegalInteger; | ||
2682 | break; | ||
2683 | } | ||
2684 | break; | ||
2685 | case "Property": | ||
2686 | property = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
2687 | break; | ||
2688 | default: | ||
2689 | this.Core.UnexpectedAttribute(node, attrib); | ||
2690 | break; | ||
2691 | } | ||
2692 | } | ||
2693 | else | ||
2694 | { | ||
2695 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2696 | } | ||
2697 | } | ||
2698 | |||
2699 | if (CompilerConstants.IntegerNotSet == on) | ||
2700 | { | ||
2701 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "On")); | ||
2702 | on = CompilerConstants.IllegalInteger; | ||
2703 | } | ||
2704 | |||
2705 | if (null != directory && null != property) | ||
2706 | { | ||
2707 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "Directory", directory)); | ||
2708 | } | ||
2709 | |||
2710 | if (null == id) | ||
2711 | { | ||
2712 | id = this.Core.CreateIdentifier("rmf", directory ?? property ?? parentDirectory, on.ToString()); | ||
2713 | } | ||
2714 | |||
2715 | this.Core.ParseForExtensionElements(node); | ||
2716 | |||
2717 | if (!this.Core.EncounteredError) | ||
2718 | { | ||
2719 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RemoveFile, id); | ||
2720 | row.Set(1, componentId); | ||
2721 | //row.Set(2, null); | ||
2722 | if (null != directory) | ||
2723 | { | ||
2724 | row.Set(3, directory); | ||
2725 | } | ||
2726 | else if (null != property) | ||
2727 | { | ||
2728 | row.Set(3, property); | ||
2729 | } | ||
2730 | else | ||
2731 | { | ||
2732 | row.Set(3, parentDirectory); | ||
2733 | } | ||
2734 | row.Set(4, on); | ||
2735 | } | ||
2736 | } | ||
2737 | |||
2738 | /// <summary> | ||
2739 | /// Parses a reserve cost element. | ||
2740 | /// </summary> | ||
2741 | /// <param name="node">Element to parse.</param> | ||
2742 | /// <param name="componentId">Identifier of parent component.</param> | ||
2743 | /// <param name="directoryId">Optional and default identifier of referenced directory.</param> | ||
2744 | private void ParseReserveCostElement(XElement node, string componentId, string directoryId) | ||
2745 | { | ||
2746 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
2747 | Identifier id = null; | ||
2748 | var runFromSource = CompilerConstants.IntegerNotSet; | ||
2749 | var runLocal = CompilerConstants.IntegerNotSet; | ||
2750 | |||
2751 | foreach (var attrib in node.Attributes()) | ||
2752 | { | ||
2753 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2754 | { | ||
2755 | switch (attrib.Name.LocalName) | ||
2756 | { | ||
2757 | case "Id": | ||
2758 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
2759 | break; | ||
2760 | case "Directory": | ||
2761 | directoryId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, directoryId); | ||
2762 | break; | ||
2763 | case "RunFromSource": | ||
2764 | runFromSource = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
2765 | break; | ||
2766 | case "RunLocal": | ||
2767 | runLocal = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
2768 | break; | ||
2769 | default: | ||
2770 | this.Core.UnexpectedAttribute(node, attrib); | ||
2771 | break; | ||
2772 | } | ||
2773 | } | ||
2774 | else | ||
2775 | { | ||
2776 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2777 | } | ||
2778 | } | ||
2779 | |||
2780 | if (null == id) | ||
2781 | { | ||
2782 | id = this.Core.CreateIdentifier("rc", componentId, directoryId); | ||
2783 | } | ||
2784 | |||
2785 | if (CompilerConstants.IntegerNotSet == runFromSource) | ||
2786 | { | ||
2787 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunFromSource")); | ||
2788 | } | ||
2789 | |||
2790 | if (CompilerConstants.IntegerNotSet == runLocal) | ||
2791 | { | ||
2792 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "RunLocal")); | ||
2793 | } | ||
2794 | |||
2795 | this.Core.ParseForExtensionElements(node); | ||
2796 | |||
2797 | if (!this.Core.EncounteredError) | ||
2798 | { | ||
2799 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ReserveCost, id); | ||
2800 | row.Set(1, componentId); | ||
2801 | row.Set(2, directoryId); | ||
2802 | row.Set(3, runLocal); | ||
2803 | row.Set(4, runFromSource); | ||
2804 | } | ||
2805 | } | ||
2806 | |||
2807 | /// <summary> | ||
2808 | /// Parses a sequence element. | ||
2809 | /// </summary> | ||
2810 | /// <param name="node">Element to parse.</param> | ||
2811 | /// <param name="sequenceTable">Name of sequence table.</param> | ||
2812 | private void ParseSequenceElement(XElement node, string sequenceTable) | ||
2813 | { | ||
2814 | // use the proper table name internally | ||
2815 | if ("AdvertiseExecuteSequence" == sequenceTable) | ||
2816 | { | ||
2817 | sequenceTable = "AdvtExecuteSequence"; | ||
2818 | } | ||
2819 | |||
2820 | // Parse each action in the sequence. | ||
2821 | foreach (var child in node.Elements()) | ||
2822 | { | ||
2823 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
2824 | var actionName = child.Name.LocalName; | ||
2825 | string afterAction = null; | ||
2826 | string beforeAction = null; | ||
2827 | string condition = null; | ||
2828 | var customAction = "Custom" == actionName; | ||
2829 | var overridable = false; | ||
2830 | var exitSequence = CompilerConstants.IntegerNotSet; | ||
2831 | var sequence = CompilerConstants.IntegerNotSet; | ||
2832 | var showDialog = "Show" == actionName; | ||
2833 | var specialAction = "InstallExecute" == actionName || "InstallExecuteAgain" == actionName || "RemoveExistingProducts" == actionName || "DisableRollback" == actionName || "ScheduleReboot" == actionName || "ForceReboot" == actionName || "ResolveSource" == actionName; | ||
2834 | var specialStandardAction = "AppSearch" == actionName || "CCPSearch" == actionName || "RMCCPSearch" == actionName || "LaunchConditions" == actionName || "FindRelatedProducts" == actionName; | ||
2835 | var suppress = false; | ||
2836 | |||
2837 | foreach (var attrib in child.Attributes()) | ||
2838 | { | ||
2839 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
2840 | { | ||
2841 | switch (attrib.Name.LocalName) | ||
2842 | { | ||
2843 | case "Action": | ||
2844 | if (customAction) | ||
2845 | { | ||
2846 | actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2847 | this.Core.CreateSimpleReference(childSourceLineNumbers, "CustomAction", actionName); | ||
2848 | } | ||
2849 | else | ||
2850 | { | ||
2851 | this.Core.UnexpectedAttribute(child, attrib); | ||
2852 | } | ||
2853 | break; | ||
2854 | case "After": | ||
2855 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
2856 | { | ||
2857 | afterAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2858 | this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, afterAction); | ||
2859 | } | ||
2860 | else | ||
2861 | { | ||
2862 | this.Core.UnexpectedAttribute(child, attrib); | ||
2863 | } | ||
2864 | break; | ||
2865 | case "Before": | ||
2866 | if (customAction || showDialog || specialAction || specialStandardAction) | ||
2867 | { | ||
2868 | beforeAction = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2869 | this.Core.CreateSimpleReference(childSourceLineNumbers, "WixAction", sequenceTable, beforeAction); | ||
2870 | } | ||
2871 | else | ||
2872 | { | ||
2873 | this.Core.UnexpectedAttribute(child, attrib); | ||
2874 | } | ||
2875 | break; | ||
2876 | case "Dialog": | ||
2877 | if (showDialog) | ||
2878 | { | ||
2879 | actionName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, attrib); | ||
2880 | this.Core.CreateSimpleReference(childSourceLineNumbers, "Dialog", actionName); | ||
2881 | } | ||
2882 | else | ||
2883 | { | ||
2884 | this.Core.UnexpectedAttribute(child, attrib); | ||
2885 | } | ||
2886 | break; | ||
2887 | case "OnExit": | ||
2888 | if (customAction || showDialog || specialAction) | ||
2889 | { | ||
2890 | var exitValue = this.Core.GetAttributeValue(childSourceLineNumbers, attrib); | ||
2891 | switch (exitValue) | ||
2892 | { | ||
2893 | case "success": | ||
2894 | exitSequence = -1; | ||
2895 | break; | ||
2896 | case "cancel": | ||
2897 | exitSequence = -2; | ||
2898 | break; | ||
2899 | case "error": | ||
2900 | exitSequence = -3; | ||
2901 | break; | ||
2902 | case "suspend": | ||
2903 | exitSequence = -4; | ||
2904 | break; | ||
2905 | } | ||
2906 | } | ||
2907 | else | ||
2908 | { | ||
2909 | this.Core.UnexpectedAttribute(child, attrib); | ||
2910 | } | ||
2911 | break; | ||
2912 | case "Overridable": | ||
2913 | overridable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
2914 | break; | ||
2915 | case "Sequence": | ||
2916 | sequence = this.Core.GetAttributeIntegerValue(childSourceLineNumbers, attrib, 1, Int16.MaxValue); | ||
2917 | break; | ||
2918 | case "Suppress": | ||
2919 | suppress = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, attrib); | ||
2920 | break; | ||
2921 | default: | ||
2922 | this.Core.UnexpectedAttribute(node, attrib); | ||
2923 | break; | ||
2924 | } | ||
2925 | } | ||
2926 | else | ||
2927 | { | ||
2928 | this.Core.ParseExtensionAttribute(node, attrib); | ||
2929 | } | ||
2930 | } | ||
2931 | |||
2932 | // Get the condition from the inner text of the element. | ||
2933 | condition = this.Core.GetConditionInnerText(child); | ||
2934 | |||
2935 | if (customAction && "Custom" == actionName) | ||
2936 | { | ||
2937 | this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Action")); | ||
2938 | } | ||
2939 | else if (showDialog && "Show" == actionName) | ||
2940 | { | ||
2941 | this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Dialog")); | ||
2942 | } | ||
2943 | |||
2944 | if (CompilerConstants.IntegerNotSet != sequence) | ||
2945 | { | ||
2946 | if (CompilerConstants.IntegerNotSet != exitSequence) | ||
2947 | { | ||
2948 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "OnExit")); | ||
2949 | } | ||
2950 | else if (null != beforeAction || null != afterAction) | ||
2951 | { | ||
2952 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "Sequence", "Before", "After")); | ||
2953 | } | ||
2954 | } | ||
2955 | else // sequence not specified use OnExit (which may also be not set). | ||
2956 | { | ||
2957 | sequence = exitSequence; | ||
2958 | } | ||
2959 | |||
2960 | if (null != beforeAction && null != afterAction) | ||
2961 | { | ||
2962 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(childSourceLineNumbers, child.Name.LocalName, "After", "Before")); | ||
2963 | } | ||
2964 | else if ((customAction || showDialog || specialAction) && !suppress && CompilerConstants.IntegerNotSet == sequence && null == beforeAction && null == afterAction) | ||
2965 | { | ||
2966 | this.Core.Write(ErrorMessages.NeedSequenceBeforeOrAfter(childSourceLineNumbers, child.Name.LocalName)); | ||
2967 | } | ||
2968 | |||
2969 | // action that is scheduled to occur before/after itself | ||
2970 | if (beforeAction == actionName) | ||
2971 | { | ||
2972 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "Before", beforeAction)); | ||
2973 | } | ||
2974 | else if (afterAction == actionName) | ||
2975 | { | ||
2976 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(childSourceLineNumbers, child.Name.LocalName, "After", afterAction)); | ||
2977 | } | ||
2978 | |||
2979 | // normal standard actions cannot be set overridable by the user (since they are overridable by default) | ||
2980 | if (overridable && WindowsInstallerStandard.IsStandardAction(actionName) && !specialAction) | ||
2981 | { | ||
2982 | this.Core.Write(ErrorMessages.UnexpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Overridable")); | ||
2983 | } | ||
2984 | |||
2985 | // suppress cannot be specified at the same time as Before, After, or Sequence | ||
2986 | if (suppress && (null != afterAction || null != beforeAction || CompilerConstants.IntegerNotSet != sequence || overridable)) | ||
2987 | { | ||
2988 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(childSourceLineNumbers, child.Name.LocalName, "Suppress", "Before", "After", "Sequence", "Overridable")); | ||
2989 | } | ||
2990 | |||
2991 | this.Core.ParseForExtensionElements(child); | ||
2992 | |||
2993 | // add the row and any references needed | ||
2994 | if (!this.Core.EncounteredError) | ||
2995 | { | ||
2996 | if (suppress) | ||
2997 | { | ||
2998 | var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixSuppressAction, new Identifier(AccessModifier.Public, sequenceTable, actionName)); | ||
2999 | row.Set(0, sequenceTable); | ||
3000 | row.Set(1, actionName); | ||
3001 | } | ||
3002 | else | ||
3003 | { | ||
3004 | var row = this.Core.CreateRow(childSourceLineNumbers, TupleDefinitionType.WixAction, new Identifier(AccessModifier.Public, sequenceTable, actionName)); | ||
3005 | row.Set(0, sequenceTable); | ||
3006 | row.Set(1, actionName); | ||
3007 | row.Set(2, condition); | ||
3008 | if (CompilerConstants.IntegerNotSet != sequence) | ||
3009 | { | ||
3010 | row.Set(3, sequence); | ||
3011 | } | ||
3012 | row.Set(4, beforeAction); | ||
3013 | row.Set(5, afterAction); | ||
3014 | row.Set(6, overridable ? 1 : 0); | ||
3015 | } | ||
3016 | } | ||
3017 | } | ||
3018 | } | ||
3019 | |||
3020 | |||
3021 | /// <summary> | ||
3022 | /// Parses a service config element. | ||
3023 | /// </summary> | ||
3024 | /// <param name="node">Element to parse.</param> | ||
3025 | /// <param name="componentId">Identifier of parent component.</param> | ||
3026 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
3027 | private void ParseServiceConfigElement(XElement node, string componentId, string serviceName) | ||
3028 | { | ||
3029 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3030 | Identifier id = null; | ||
3031 | string delayedAutoStart = null; | ||
3032 | string failureActionsWhen = null; | ||
3033 | var name = serviceName; | ||
3034 | var install = false; | ||
3035 | var reinstall = false; | ||
3036 | var uninstall = false; | ||
3037 | string preShutdownDelay = null; | ||
3038 | string requiredPrivileges = null; | ||
3039 | string sid = null; | ||
3040 | |||
3041 | this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
3042 | |||
3043 | foreach (var attrib in node.Attributes()) | ||
3044 | { | ||
3045 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3046 | { | ||
3047 | switch (attrib.Name.LocalName) | ||
3048 | { | ||
3049 | case "Id": | ||
3050 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3051 | break; | ||
3052 | case "DelayedAutoStart": | ||
3053 | delayedAutoStart = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3054 | switch (delayedAutoStart) | ||
3055 | { | ||
3056 | case "no": | ||
3057 | delayedAutoStart = "0"; | ||
3058 | break; | ||
3059 | case "yes": | ||
3060 | delayedAutoStart = "1"; | ||
3061 | break; | ||
3062 | default: | ||
3063 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3064 | break; | ||
3065 | } | ||
3066 | break; | ||
3067 | case "FailureActionsWhen": | ||
3068 | failureActionsWhen = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3069 | switch (failureActionsWhen) | ||
3070 | { | ||
3071 | case "failedToStop": | ||
3072 | failureActionsWhen = "0"; | ||
3073 | break; | ||
3074 | case "failedToStopOrReturnedError": | ||
3075 | failureActionsWhen = "1"; | ||
3076 | break; | ||
3077 | default: | ||
3078 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3079 | break; | ||
3080 | } | ||
3081 | break; | ||
3082 | case "OnInstall": | ||
3083 | install = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3084 | //if (YesNoType.Yes == install) | ||
3085 | //{ | ||
3086 | // events |= MsiInterop.MsidbServiceConfigEventInstall; | ||
3087 | //} | ||
3088 | break; | ||
3089 | case "OnReinstall": | ||
3090 | reinstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3091 | //if (YesNoType.Yes == reinstall) | ||
3092 | //{ | ||
3093 | // events |= MsiInterop.MsidbServiceConfigEventReinstall; | ||
3094 | //} | ||
3095 | break; | ||
3096 | case "OnUninstall": | ||
3097 | uninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3098 | //if (YesNoType.Yes == uninstall) | ||
3099 | //{ | ||
3100 | // events |= MsiInterop.MsidbServiceConfigEventUninstall; | ||
3101 | //} | ||
3102 | break; | ||
3103 | default: | ||
3104 | this.Core.UnexpectedAttribute(node, attrib); | ||
3105 | break; | ||
3106 | case "PreShutdownDelay": | ||
3107 | preShutdownDelay = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
3108 | break; | ||
3109 | case "ServiceName": | ||
3110 | if (!String.IsNullOrEmpty(serviceName)) | ||
3111 | { | ||
3112 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
3113 | } | ||
3114 | |||
3115 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3116 | break; | ||
3117 | case "ServiceSid": | ||
3118 | sid = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3119 | switch (sid) | ||
3120 | { | ||
3121 | case "none": | ||
3122 | sid = "0"; | ||
3123 | break; | ||
3124 | case "restricted": | ||
3125 | sid = "3"; | ||
3126 | break; | ||
3127 | case "unrestricted": | ||
3128 | sid = "1"; | ||
3129 | break; | ||
3130 | default: | ||
3131 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3132 | break; | ||
3133 | } | ||
3134 | break; | ||
3135 | } | ||
3136 | } | ||
3137 | else | ||
3138 | { | ||
3139 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3140 | } | ||
3141 | } | ||
3142 | |||
3143 | // Get the ServiceConfig required privilegs. | ||
3144 | foreach (var child in node.Elements()) | ||
3145 | { | ||
3146 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3147 | { | ||
3148 | switch (child.Name.LocalName) | ||
3149 | { | ||
3150 | case "RequiredPrivilege": | ||
3151 | var privilege = this.Core.GetTrimmedInnerText(child); | ||
3152 | switch (privilege) | ||
3153 | { | ||
3154 | case "assignPrimaryToken": | ||
3155 | privilege = "SeAssignPrimaryTokenPrivilege"; | ||
3156 | break; | ||
3157 | case "audit": | ||
3158 | privilege = "SeAuditPrivilege"; | ||
3159 | break; | ||
3160 | case "backup": | ||
3161 | privilege = "SeBackupPrivilege"; | ||
3162 | break; | ||
3163 | case "changeNotify": | ||
3164 | privilege = "SeChangeNotifyPrivilege"; | ||
3165 | break; | ||
3166 | case "createGlobal": | ||
3167 | privilege = "SeCreateGlobalPrivilege"; | ||
3168 | break; | ||
3169 | case "createPagefile": | ||
3170 | privilege = "SeCreatePagefilePrivilege"; | ||
3171 | break; | ||
3172 | case "createPermanent": | ||
3173 | privilege = "SeCreatePermanentPrivilege"; | ||
3174 | break; | ||
3175 | case "createSymbolicLink": | ||
3176 | privilege = "SeCreateSymbolicLinkPrivilege"; | ||
3177 | break; | ||
3178 | case "createToken": | ||
3179 | privilege = "SeCreateTokenPrivilege"; | ||
3180 | break; | ||
3181 | case "debug": | ||
3182 | privilege = "SeDebugPrivilege"; | ||
3183 | break; | ||
3184 | case "enableDelegation": | ||
3185 | privilege = "SeEnableDelegationPrivilege"; | ||
3186 | break; | ||
3187 | case "impersonate": | ||
3188 | privilege = "SeImpersonatePrivilege"; | ||
3189 | break; | ||
3190 | case "increaseBasePriority": | ||
3191 | privilege = "SeIncreaseBasePriorityPrivilege"; | ||
3192 | break; | ||
3193 | case "increaseQuota": | ||
3194 | privilege = "SeIncreaseQuotaPrivilege"; | ||
3195 | break; | ||
3196 | case "increaseWorkingSet": | ||
3197 | privilege = "SeIncreaseWorkingSetPrivilege"; | ||
3198 | break; | ||
3199 | case "loadDriver": | ||
3200 | privilege = "SeLoadDriverPrivilege"; | ||
3201 | break; | ||
3202 | case "lockMemory": | ||
3203 | privilege = "SeLockMemoryPrivilege"; | ||
3204 | break; | ||
3205 | case "machineAccount": | ||
3206 | privilege = "SeMachineAccountPrivilege"; | ||
3207 | break; | ||
3208 | case "manageVolume": | ||
3209 | privilege = "SeManageVolumePrivilege"; | ||
3210 | break; | ||
3211 | case "profileSingleProcess": | ||
3212 | privilege = "SeProfileSingleProcessPrivilege"; | ||
3213 | break; | ||
3214 | case "relabel": | ||
3215 | privilege = "SeRelabelPrivilege"; | ||
3216 | break; | ||
3217 | case "remoteShutdown": | ||
3218 | privilege = "SeRemoteShutdownPrivilege"; | ||
3219 | break; | ||
3220 | case "restore": | ||
3221 | privilege = "SeRestorePrivilege"; | ||
3222 | break; | ||
3223 | case "security": | ||
3224 | privilege = "SeSecurityPrivilege"; | ||
3225 | break; | ||
3226 | case "shutdown": | ||
3227 | privilege = "SeShutdownPrivilege"; | ||
3228 | break; | ||
3229 | case "syncAgent": | ||
3230 | privilege = "SeSyncAgentPrivilege"; | ||
3231 | break; | ||
3232 | case "systemEnvironment": | ||
3233 | privilege = "SeSystemEnvironmentPrivilege"; | ||
3234 | break; | ||
3235 | case "systemProfile": | ||
3236 | privilege = "SeSystemProfilePrivilege"; | ||
3237 | break; | ||
3238 | case "systemTime": | ||
3239 | case "modifySystemTime": | ||
3240 | privilege = "SeSystemtimePrivilege"; | ||
3241 | break; | ||
3242 | case "takeOwnership": | ||
3243 | privilege = "SeTakeOwnershipPrivilege"; | ||
3244 | break; | ||
3245 | case "tcb": | ||
3246 | case "trustedComputerBase": | ||
3247 | privilege = "SeTcbPrivilege"; | ||
3248 | break; | ||
3249 | case "timeZone": | ||
3250 | case "modifyTimeZone": | ||
3251 | privilege = "SeTimeZonePrivilege"; | ||
3252 | break; | ||
3253 | case "trustedCredManAccess": | ||
3254 | case "trustedCredentialManagerAccess": | ||
3255 | privilege = "SeTrustedCredManAccessPrivilege"; | ||
3256 | break; | ||
3257 | case "undock": | ||
3258 | privilege = "SeUndockPrivilege"; | ||
3259 | break; | ||
3260 | case "unsolicitedInput": | ||
3261 | privilege = "SeUnsolicitedInputPrivilege"; | ||
3262 | break; | ||
3263 | default: | ||
3264 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3265 | break; | ||
3266 | } | ||
3267 | |||
3268 | if (null != requiredPrivileges) | ||
3269 | { | ||
3270 | requiredPrivileges = String.Concat(requiredPrivileges, "[~]"); | ||
3271 | } | ||
3272 | requiredPrivileges = String.Concat(requiredPrivileges, privilege); | ||
3273 | break; | ||
3274 | default: | ||
3275 | this.Core.UnexpectedElement(node, child); | ||
3276 | break; | ||
3277 | } | ||
3278 | } | ||
3279 | else | ||
3280 | { | ||
3281 | this.Core.ParseExtensionElement(node, child); | ||
3282 | } | ||
3283 | } | ||
3284 | |||
3285 | if (String.IsNullOrEmpty(name)) | ||
3286 | { | ||
3287 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
3288 | } | ||
3289 | else if (null == id) | ||
3290 | { | ||
3291 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3292 | } | ||
3293 | |||
3294 | if (!install && !reinstall && !uninstall) | ||
3295 | { | ||
3296 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
3297 | } | ||
3298 | |||
3299 | if (String.IsNullOrEmpty(delayedAutoStart) && String.IsNullOrEmpty(failureActionsWhen) && String.IsNullOrEmpty(preShutdownDelay) && String.IsNullOrEmpty(requiredPrivileges) && String.IsNullOrEmpty(sid)) | ||
3300 | { | ||
3301 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "DelayedAutoStart", "FailureActionsWhen", "PreShutdownDelay", "ServiceSid", "RequiredPrivilege")); | ||
3302 | } | ||
3303 | |||
3304 | if (!this.Core.EncounteredError) | ||
3305 | { | ||
3306 | if (!String.IsNullOrEmpty(delayedAutoStart)) | ||
3307 | { | ||
3308 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".DS"), id.Access)) | ||
3309 | { | ||
3310 | Name = name, | ||
3311 | OnInstall = install, | ||
3312 | OnReinstall = reinstall, | ||
3313 | OnUninstall = uninstall, | ||
3314 | ConfigType = MsiServiceConfigType.DelayedAutoStart, | ||
3315 | Argument = delayedAutoStart, | ||
3316 | Component_ = componentId, | ||
3317 | }; | ||
3318 | |||
3319 | this.Core.AddTuple(tuple); | ||
3320 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".DS"), id.Access)); | ||
3321 | //row.Set(1, name); | ||
3322 | //row.Set(2, events); | ||
3323 | //row.Set(3, 3); | ||
3324 | //row.Set(4, delayedAutoStart); | ||
3325 | //row.Set(5, componentId); | ||
3326 | } | ||
3327 | |||
3328 | if (!String.IsNullOrEmpty(failureActionsWhen)) | ||
3329 | { | ||
3330 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".FA"), id.Access)) | ||
3331 | { | ||
3332 | Name = name, | ||
3333 | OnInstall = install, | ||
3334 | OnReinstall = reinstall, | ||
3335 | OnUninstall = uninstall, | ||
3336 | ConfigType = MsiServiceConfigType.FailureActionsFlag, | ||
3337 | Argument = failureActionsWhen, | ||
3338 | Component_ = componentId, | ||
3339 | }; | ||
3340 | |||
3341 | this.Core.AddTuple(tuple); | ||
3342 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".FA"), id.Access)); | ||
3343 | //row.Set(1, name); | ||
3344 | //row.Set(2, events); | ||
3345 | //row.Set(3, 4); | ||
3346 | //row.Set(4, failureActionsWhen); | ||
3347 | //row.Set(5, componentId); | ||
3348 | } | ||
3349 | |||
3350 | if (!String.IsNullOrEmpty(sid)) | ||
3351 | { | ||
3352 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".SS"), id.Access)) | ||
3353 | { | ||
3354 | Name = name, | ||
3355 | OnInstall = install, | ||
3356 | OnReinstall = reinstall, | ||
3357 | OnUninstall = uninstall, | ||
3358 | ConfigType = MsiServiceConfigType.ServiceSidInfo, | ||
3359 | Argument = sid, | ||
3360 | Component_ = componentId, | ||
3361 | }; | ||
3362 | |||
3363 | this.Core.AddTuple(tuple); | ||
3364 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".SS"), id.Access)); | ||
3365 | //row.Set(1, name); | ||
3366 | //row.Set(2, events); | ||
3367 | //row.Set(3, 5); | ||
3368 | //row.Set(4, sid); | ||
3369 | //row.Set(5, componentId); | ||
3370 | } | ||
3371 | |||
3372 | if (!String.IsNullOrEmpty(requiredPrivileges)) | ||
3373 | { | ||
3374 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".RP"), id.Access)) | ||
3375 | { | ||
3376 | Name = name, | ||
3377 | OnInstall = install, | ||
3378 | OnReinstall = reinstall, | ||
3379 | OnUninstall = uninstall, | ||
3380 | ConfigType = MsiServiceConfigType.RequiredPrivilegesInfo, | ||
3381 | Argument = requiredPrivileges, | ||
3382 | Component_ = componentId, | ||
3383 | }; | ||
3384 | |||
3385 | this.Core.AddTuple(tuple); | ||
3386 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".RP"), id.Access)); | ||
3387 | //row.Set(1, name); | ||
3388 | //row.Set(2, events); | ||
3389 | //row.Set(3, 6); | ||
3390 | //row.Set(4, requiredPrivileges); | ||
3391 | //row.Set(5, componentId); | ||
3392 | } | ||
3393 | |||
3394 | if (!String.IsNullOrEmpty(preShutdownDelay)) | ||
3395 | { | ||
3396 | var tuple = new MsiServiceConfigTuple(sourceLineNumbers, new Identifier(String.Concat(id.Id, ".PD"), id.Access)) | ||
3397 | { | ||
3398 | Name = name, | ||
3399 | OnInstall = install, | ||
3400 | OnReinstall = reinstall, | ||
3401 | OnUninstall = uninstall, | ||
3402 | ConfigType = MsiServiceConfigType.PreshutdownInfo, | ||
3403 | Argument = preShutdownDelay, | ||
3404 | Component_ = componentId, | ||
3405 | }; | ||
3406 | |||
3407 | this.Core.AddTuple(tuple); | ||
3408 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiServiceConfig, new Identifier(String.Concat(id.Id, ".PD"), id.Access)); | ||
3409 | //row.Set(1, name); | ||
3410 | //row.Set(2, events); | ||
3411 | //row.Set(3, 7); | ||
3412 | //row.Set(4, preShutdownDelay); | ||
3413 | //row.Set(5, componentId); | ||
3414 | } | ||
3415 | } | ||
3416 | } | ||
3417 | |||
3418 | /// <summary> | ||
3419 | /// Parses a service config failure actions element. | ||
3420 | /// </summary> | ||
3421 | /// <param name="node">Element to parse.</param> | ||
3422 | /// <param name="componentId">Identifier of parent component.</param> | ||
3423 | /// <param name="serviceName">Optional element containing parent's service name.</param> | ||
3424 | private void ParseServiceConfigFailureActionsElement(XElement node, string componentId, string serviceName) | ||
3425 | { | ||
3426 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3427 | Identifier id = null; | ||
3428 | var name = serviceName; | ||
3429 | var install = false; | ||
3430 | var reinstall = false; | ||
3431 | var uninstall = false; | ||
3432 | int? resetPeriod = null; | ||
3433 | string rebootMessage = null; | ||
3434 | string command = null; | ||
3435 | string actions = null; | ||
3436 | string actionsDelays = null; | ||
3437 | |||
3438 | this.Core.Write(WarningMessages.ServiceConfigFamilyNotSupported(sourceLineNumbers, node.Name.LocalName)); | ||
3439 | |||
3440 | foreach (var attrib in node.Attributes()) | ||
3441 | { | ||
3442 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3443 | { | ||
3444 | switch (attrib.Name.LocalName) | ||
3445 | { | ||
3446 | case "Id": | ||
3447 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3448 | break; | ||
3449 | case "Command": | ||
3450 | command = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
3451 | break; | ||
3452 | case "OnInstall": | ||
3453 | install = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3454 | break; | ||
3455 | case "OnReinstall": | ||
3456 | reinstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3457 | break; | ||
3458 | case "OnUninstall": | ||
3459 | uninstall = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3460 | break; | ||
3461 | case "RebootMessage": | ||
3462 | rebootMessage = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
3463 | break; | ||
3464 | case "ResetPeriod": | ||
3465 | resetPeriod = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
3466 | break; | ||
3467 | case "ServiceName": | ||
3468 | if (!String.IsNullOrEmpty(serviceName)) | ||
3469 | { | ||
3470 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ServiceInstall")); | ||
3471 | } | ||
3472 | |||
3473 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3474 | break; | ||
3475 | default: | ||
3476 | this.Core.UnexpectedAttribute(node, attrib); | ||
3477 | break; | ||
3478 | } | ||
3479 | } | ||
3480 | else | ||
3481 | { | ||
3482 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3483 | } | ||
3484 | } | ||
3485 | |||
3486 | // Get the ServiceConfigFailureActions actions. | ||
3487 | foreach (var child in node.Elements()) | ||
3488 | { | ||
3489 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3490 | { | ||
3491 | switch (child.Name.LocalName) | ||
3492 | { | ||
3493 | case "Failure": | ||
3494 | string action = null; | ||
3495 | string delay = null; | ||
3496 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
3497 | |||
3498 | foreach (var childAttrib in child.Attributes()) | ||
3499 | { | ||
3500 | if (String.IsNullOrEmpty(childAttrib.Name.NamespaceName) || CompilerCore.WixNamespace == childAttrib.Name.Namespace) | ||
3501 | { | ||
3502 | switch (childAttrib.Name.LocalName) | ||
3503 | { | ||
3504 | case "Action": | ||
3505 | action = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3506 | switch (action) | ||
3507 | { | ||
3508 | case "none": | ||
3509 | action = "0"; | ||
3510 | break; | ||
3511 | case "restartComputer": | ||
3512 | action = "2"; | ||
3513 | break; | ||
3514 | case "restartService": | ||
3515 | action = "1"; | ||
3516 | break; | ||
3517 | case "runCommand": | ||
3518 | action = "3"; | ||
3519 | break; | ||
3520 | default: | ||
3521 | // allow everything else to pass through that are hopefully "formatted" Properties. | ||
3522 | break; | ||
3523 | } | ||
3524 | break; | ||
3525 | case "Delay": | ||
3526 | delay = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib); | ||
3527 | break; | ||
3528 | default: | ||
3529 | this.Core.UnexpectedAttribute(child, childAttrib); | ||
3530 | break; | ||
3531 | } | ||
3532 | } | ||
3533 | } | ||
3534 | |||
3535 | if (String.IsNullOrEmpty(action)) | ||
3536 | { | ||
3537 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Action")); | ||
3538 | } | ||
3539 | |||
3540 | if (String.IsNullOrEmpty(delay)) | ||
3541 | { | ||
3542 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, child.Name.LocalName, "Delay")); | ||
3543 | } | ||
3544 | |||
3545 | if (!String.IsNullOrEmpty(actions)) | ||
3546 | { | ||
3547 | actions = String.Concat(actions, "[~]"); | ||
3548 | } | ||
3549 | actions = String.Concat(actions, action); | ||
3550 | |||
3551 | if (!String.IsNullOrEmpty(actionsDelays)) | ||
3552 | { | ||
3553 | actionsDelays = String.Concat(actionsDelays, "[~]"); | ||
3554 | } | ||
3555 | actionsDelays = String.Concat(actionsDelays, delay); | ||
3556 | break; | ||
3557 | default: | ||
3558 | this.Core.UnexpectedElement(node, child); | ||
3559 | break; | ||
3560 | } | ||
3561 | } | ||
3562 | else | ||
3563 | { | ||
3564 | this.Core.ParseExtensionElement(node, child); | ||
3565 | } | ||
3566 | } | ||
3567 | |||
3568 | if (String.IsNullOrEmpty(name)) | ||
3569 | { | ||
3570 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ServiceName")); | ||
3571 | } | ||
3572 | else if (null == id) | ||
3573 | { | ||
3574 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3575 | } | ||
3576 | |||
3577 | if (!install && !reinstall && !uninstall) | ||
3578 | { | ||
3579 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "OnInstall", "OnReinstall", "OnUninstall")); | ||
3580 | } | ||
3581 | |||
3582 | if (!this.Core.EncounteredError) | ||
3583 | { | ||
3584 | var tuple = new MsiServiceConfigFailureActionsTuple(sourceLineNumbers, id) | ||
3585 | { | ||
3586 | Name = name, | ||
3587 | OnInstall = install, | ||
3588 | OnReinstall = reinstall, | ||
3589 | OnUninstall = uninstall, | ||
3590 | ResetPeriod = resetPeriod, | ||
3591 | RebootMessage = rebootMessage, | ||
3592 | Command = command, | ||
3593 | Actions = actions, | ||
3594 | DelayActions = actionsDelays, | ||
3595 | Component_ = componentId, | ||
3596 | }; | ||
3597 | |||
3598 | this.Core.AddTuple(tuple); | ||
3599 | } | ||
3600 | } | ||
3601 | |||
3602 | /// <summary> | ||
3603 | /// Parses a service control element. | ||
3604 | /// </summary> | ||
3605 | /// <param name="node">Element to parse.</param> | ||
3606 | /// <param name="componentId">Identifier of parent component.</param> | ||
3607 | private void ParseServiceControlElement(XElement node, string componentId) | ||
3608 | { | ||
3609 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3610 | string arguments = null; | ||
3611 | Identifier id = null; | ||
3612 | string name = null; | ||
3613 | var installRemove = false; | ||
3614 | var uninstallRemove = false; | ||
3615 | var installStart = false; | ||
3616 | var uninstallStart = false; | ||
3617 | var installStop = false; | ||
3618 | var uninstallStop = false; | ||
3619 | bool? wait = null; | ||
3620 | |||
3621 | foreach (var attrib in node.Attributes()) | ||
3622 | { | ||
3623 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3624 | { | ||
3625 | switch (attrib.Name.LocalName) | ||
3626 | { | ||
3627 | case "Id": | ||
3628 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3629 | break; | ||
3630 | case "Name": | ||
3631 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3632 | break; | ||
3633 | case "Remove": | ||
3634 | var removeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3635 | switch (removeValue) | ||
3636 | { | ||
3637 | case "install": | ||
3638 | installRemove = true; | ||
3639 | break; | ||
3640 | case "uninstall": | ||
3641 | uninstallRemove = true; | ||
3642 | break; | ||
3643 | case "both": | ||
3644 | installRemove = true; | ||
3645 | uninstallRemove = true; | ||
3646 | break; | ||
3647 | case "": | ||
3648 | break; | ||
3649 | } | ||
3650 | break; | ||
3651 | case "Start": | ||
3652 | var startValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3653 | switch (startValue) | ||
3654 | { | ||
3655 | case "install": | ||
3656 | installStart = true; | ||
3657 | break; | ||
3658 | case "uninstall": | ||
3659 | uninstallStart = true; | ||
3660 | break; | ||
3661 | case "both": | ||
3662 | installStart = true; | ||
3663 | uninstallStart = true; | ||
3664 | break; | ||
3665 | case "": | ||
3666 | break; | ||
3667 | } | ||
3668 | break; | ||
3669 | case "Stop": | ||
3670 | var stopValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3671 | switch (stopValue) | ||
3672 | { | ||
3673 | case "install": | ||
3674 | installStop = true; | ||
3675 | break; | ||
3676 | case "uninstall": | ||
3677 | uninstallStop = true; | ||
3678 | break; | ||
3679 | case "both": | ||
3680 | installStop = true; | ||
3681 | uninstallStop = true; | ||
3682 | break; | ||
3683 | case "": | ||
3684 | break; | ||
3685 | } | ||
3686 | break; | ||
3687 | case "Wait": | ||
3688 | wait = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3689 | break; | ||
3690 | default: | ||
3691 | this.Core.UnexpectedAttribute(node, attrib); | ||
3692 | break; | ||
3693 | } | ||
3694 | } | ||
3695 | else | ||
3696 | { | ||
3697 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3698 | } | ||
3699 | } | ||
3700 | |||
3701 | if (null == id) | ||
3702 | { | ||
3703 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3704 | } | ||
3705 | |||
3706 | if (null == name) | ||
3707 | { | ||
3708 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
3709 | } | ||
3710 | |||
3711 | // get the ServiceControl arguments | ||
3712 | foreach (var child in node.Elements()) | ||
3713 | { | ||
3714 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3715 | { | ||
3716 | switch (child.Name.LocalName) | ||
3717 | { | ||
3718 | case "ServiceArgument": | ||
3719 | if (null != arguments) | ||
3720 | { | ||
3721 | arguments = String.Concat(arguments, "[~]"); | ||
3722 | } | ||
3723 | arguments = String.Concat(arguments, this.Core.GetTrimmedInnerText(child)); | ||
3724 | break; | ||
3725 | default: | ||
3726 | this.Core.UnexpectedElement(node, child); | ||
3727 | break; | ||
3728 | } | ||
3729 | } | ||
3730 | else | ||
3731 | { | ||
3732 | this.Core.ParseExtensionElement(node, child); | ||
3733 | } | ||
3734 | } | ||
3735 | |||
3736 | if (!this.Core.EncounteredError) | ||
3737 | { | ||
3738 | var tuple = new ServiceControlTuple(sourceLineNumbers, id) | ||
3739 | { | ||
3740 | Name = name, | ||
3741 | InstallRemove = installRemove, | ||
3742 | UninstallRemove = uninstallRemove, | ||
3743 | InstallStart = installStart, | ||
3744 | UninstallStart = uninstallStart, | ||
3745 | InstallStop = installStop, | ||
3746 | UninstallStop = uninstallStop, | ||
3747 | Arguments = arguments, | ||
3748 | Wait = wait, | ||
3749 | Component_ = componentId | ||
3750 | }; | ||
3751 | |||
3752 | this.Core.AddTuple(tuple); | ||
3753 | } | ||
3754 | } | ||
3755 | |||
3756 | /// <summary> | ||
3757 | /// Parses a service dependency element. | ||
3758 | /// </summary> | ||
3759 | /// <param name="node">Element to parse.</param> | ||
3760 | /// <returns>Parsed sevice dependency name.</returns> | ||
3761 | private string ParseServiceDependencyElement(XElement node) | ||
3762 | { | ||
3763 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3764 | string dependency = null; | ||
3765 | var group = false; | ||
3766 | |||
3767 | foreach (var attrib in node.Attributes()) | ||
3768 | { | ||
3769 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3770 | { | ||
3771 | switch (attrib.Name.LocalName) | ||
3772 | { | ||
3773 | case "Id": | ||
3774 | dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3775 | break; | ||
3776 | case "Group": | ||
3777 | group = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3778 | break; | ||
3779 | default: | ||
3780 | this.Core.UnexpectedAttribute(node, attrib); | ||
3781 | break; | ||
3782 | } | ||
3783 | } | ||
3784 | else | ||
3785 | { | ||
3786 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3787 | } | ||
3788 | } | ||
3789 | |||
3790 | if (null == dependency) | ||
3791 | { | ||
3792 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
3793 | } | ||
3794 | |||
3795 | this.Core.ParseForExtensionElements(node); | ||
3796 | |||
3797 | return group ? String.Concat("+", dependency) : dependency; | ||
3798 | } | ||
3799 | |||
3800 | /// <summary> | ||
3801 | /// Parses a service install element. | ||
3802 | /// </summary> | ||
3803 | /// <param name="node">Element to parse.</param> | ||
3804 | /// <param name="componentId">Identifier of parent component.</param> | ||
3805 | private void ParseServiceInstallElement(XElement node, string componentId, bool win64Component) | ||
3806 | { | ||
3807 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
3808 | Identifier id = null; | ||
3809 | string account = null; | ||
3810 | string arguments = null; | ||
3811 | string dependencies = null; | ||
3812 | string description = null; | ||
3813 | string displayName = null; | ||
3814 | var eraseDescription = false; | ||
3815 | string loadOrderGroup = null; | ||
3816 | string name = null; | ||
3817 | string password = null; | ||
3818 | |||
3819 | var serviceType = ServiceType.OwnProcess; | ||
3820 | var startType = ServiceStartType.Demand; | ||
3821 | var errorControl = ServiceErrorControl.Normal; | ||
3822 | var interactive = false; | ||
3823 | var vital = false; | ||
3824 | |||
3825 | foreach (var attrib in node.Attributes()) | ||
3826 | { | ||
3827 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
3828 | { | ||
3829 | switch (attrib.Name.LocalName) | ||
3830 | { | ||
3831 | case "Id": | ||
3832 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
3833 | break; | ||
3834 | case "Account": | ||
3835 | account = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3836 | break; | ||
3837 | case "Arguments": | ||
3838 | arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3839 | break; | ||
3840 | case "Description": | ||
3841 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3842 | break; | ||
3843 | case "DisplayName": | ||
3844 | displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3845 | break; | ||
3846 | case "EraseDescription": | ||
3847 | eraseDescription = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3848 | break; | ||
3849 | case "ErrorControl": | ||
3850 | var errorControlValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3851 | switch (errorControlValue) | ||
3852 | { | ||
3853 | case "ignore": | ||
3854 | errorControl = ServiceErrorControl.Ignore; | ||
3855 | break; | ||
3856 | case "normal": | ||
3857 | errorControl = ServiceErrorControl.Normal; | ||
3858 | break; | ||
3859 | case "critical": | ||
3860 | errorControl = ServiceErrorControl.Critical; | ||
3861 | break; | ||
3862 | case "": // error case handled by GetAttributeValue() | ||
3863 | break; | ||
3864 | default: | ||
3865 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, errorControlValue, "ignore", "normal", "critical")); | ||
3866 | break; | ||
3867 | } | ||
3868 | break; | ||
3869 | case "Interactive": | ||
3870 | interactive = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3871 | break; | ||
3872 | case "LoadOrderGroup": | ||
3873 | loadOrderGroup = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3874 | break; | ||
3875 | case "Name": | ||
3876 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3877 | break; | ||
3878 | case "Password": | ||
3879 | password = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3880 | break; | ||
3881 | case "Start": | ||
3882 | var startValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3883 | switch (startValue) | ||
3884 | { | ||
3885 | case "auto": | ||
3886 | startType = ServiceStartType.Auto; | ||
3887 | break; | ||
3888 | case "demand": | ||
3889 | startType = ServiceStartType.Demand; | ||
3890 | break; | ||
3891 | case "disabled": | ||
3892 | startType = ServiceStartType.Disabled; | ||
3893 | break; | ||
3894 | case "boot": | ||
3895 | case "system": | ||
3896 | this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue)); | ||
3897 | break; | ||
3898 | case "": | ||
3899 | break; | ||
3900 | default: | ||
3901 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, startValue, "auto", "demand", "disabled")); | ||
3902 | break; | ||
3903 | } | ||
3904 | break; | ||
3905 | case "Type": | ||
3906 | var typeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
3907 | switch (typeValue) | ||
3908 | { | ||
3909 | case "ownProcess": | ||
3910 | serviceType = ServiceType.OwnProcess; | ||
3911 | break; | ||
3912 | case "shareProcess": | ||
3913 | serviceType = ServiceType.ShareProcess; | ||
3914 | break; | ||
3915 | case "kernelDriver": | ||
3916 | case "systemDriver": | ||
3917 | this.Core.Write(ErrorMessages.ValueNotSupported(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, typeValue)); | ||
3918 | break; | ||
3919 | case "": | ||
3920 | break; | ||
3921 | default: | ||
3922 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, node.Name.LocalName, typeValue, "ownProcess", "shareProcess")); | ||
3923 | break; | ||
3924 | } | ||
3925 | break; | ||
3926 | case "Vital": | ||
3927 | vital = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
3928 | break; | ||
3929 | default: | ||
3930 | this.Core.UnexpectedAttribute(node, attrib); | ||
3931 | break; | ||
3932 | } | ||
3933 | } | ||
3934 | else | ||
3935 | { | ||
3936 | this.Core.ParseExtensionAttribute(node, attrib); | ||
3937 | } | ||
3938 | } | ||
3939 | |||
3940 | if (String.IsNullOrEmpty(name)) | ||
3941 | { | ||
3942 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
3943 | } | ||
3944 | else if (null == id) | ||
3945 | { | ||
3946 | id = this.Core.CreateIdentifierFromFilename(name); | ||
3947 | } | ||
3948 | |||
3949 | if (0 == startType) | ||
3950 | { | ||
3951 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Start")); | ||
3952 | } | ||
3953 | |||
3954 | if (eraseDescription) | ||
3955 | { | ||
3956 | description = "[~]"; | ||
3957 | } | ||
3958 | |||
3959 | // get the ServiceInstall dependencies and config | ||
3960 | foreach (var child in node.Elements()) | ||
3961 | { | ||
3962 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
3963 | { | ||
3964 | switch (child.Name.LocalName) | ||
3965 | { | ||
3966 | case "PermissionEx": | ||
3967 | this.ParsePermissionExElement(child, id.Id, "ServiceInstall"); | ||
3968 | break; | ||
3969 | case "ServiceConfig": | ||
3970 | this.ParseServiceConfigElement(child, componentId, name); | ||
3971 | break; | ||
3972 | case "ServiceConfigFailureActions": | ||
3973 | this.ParseServiceConfigFailureActionsElement(child, componentId, name); | ||
3974 | break; | ||
3975 | case "ServiceDependency": | ||
3976 | dependencies = String.Concat(dependencies, this.ParseServiceDependencyElement(child), "[~]"); | ||
3977 | break; | ||
3978 | default: | ||
3979 | this.Core.UnexpectedElement(node, child); | ||
3980 | break; | ||
3981 | } | ||
3982 | } | ||
3983 | else | ||
3984 | { | ||
3985 | var context = new Dictionary<string, string>() { { "ServiceInstallId", id.Id }, { "ServiceInstallName", name }, { "ServiceInstallComponentId", componentId }, { "Win64", win64Component.ToString() } }; | ||
3986 | this.Core.ParseExtensionElement(node, child, context); | ||
3987 | } | ||
3988 | } | ||
3989 | |||
3990 | if (null != dependencies) | ||
3991 | { | ||
3992 | dependencies = String.Concat(dependencies, "[~]"); | ||
3993 | } | ||
3994 | |||
3995 | if (!this.Core.EncounteredError) | ||
3996 | { | ||
3997 | var tuple = new ServiceInstallTuple(sourceLineNumbers, id) | ||
3998 | { | ||
3999 | Name = name, | ||
4000 | DisplayName = displayName, | ||
4001 | ServiceType = serviceType, | ||
4002 | StartType = startType, | ||
4003 | ErrorControl = errorControl, | ||
4004 | LoadOrderGroup = loadOrderGroup, | ||
4005 | Dependencies = dependencies, | ||
4006 | StartName = account, | ||
4007 | Password = password, | ||
4008 | Arguments = arguments, | ||
4009 | Component_ = componentId, | ||
4010 | Description = description, | ||
4011 | Interactive = interactive, | ||
4012 | Vital = vital | ||
4013 | }; | ||
4014 | |||
4015 | this.Core.AddTuple(tuple); | ||
4016 | |||
4017 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ServiceInstall, id); | ||
4018 | //row.Set(1, name); | ||
4019 | //row.Set(2, displayName); | ||
4020 | //row.Set(3, typebits); | ||
4021 | //row.Set(4, startType); | ||
4022 | //row.Set(5, errorbits); | ||
4023 | //row.Set(6, loadOrderGroup); | ||
4024 | //row.Set(7, dependencies); | ||
4025 | //row.Set(8, account); | ||
4026 | //row.Set(9, password); | ||
4027 | //row.Set(10, arguments); | ||
4028 | //row.Set(11, componentId); | ||
4029 | //row.Set(12, description); | ||
4030 | } | ||
4031 | } | ||
4032 | |||
4033 | /// <summary> | ||
4034 | /// Parses a SetDirectory element. | ||
4035 | /// </summary> | ||
4036 | /// <param name="node">Element to parse.</param> | ||
4037 | private void ParseSetDirectoryElement(XElement node) | ||
4038 | { | ||
4039 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4040 | string actionName = null; | ||
4041 | string id = null; | ||
4042 | string condition = null; | ||
4043 | var executionType = CustomActionExecutionType.Immediate; | ||
4044 | var sequences = new[] { SequenceTable.InstallUISequence, SequenceTable.InstallExecuteSequence }; // default to "both" | ||
4045 | string value = null; | ||
4046 | |||
4047 | foreach (var attrib in node.Attributes()) | ||
4048 | { | ||
4049 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4050 | { | ||
4051 | switch (attrib.Name.LocalName) | ||
4052 | { | ||
4053 | case "Action": | ||
4054 | actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4055 | break; | ||
4056 | case "Id": | ||
4057 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4058 | this.Core.CreateSimpleReference(sourceLineNumbers, "Directory", id); | ||
4059 | break; | ||
4060 | case "Sequence": | ||
4061 | var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4062 | switch (sequenceValue) | ||
4063 | { | ||
4064 | case "execute": | ||
4065 | sequences = new[] { SequenceTable.InstallExecuteSequence }; | ||
4066 | break; | ||
4067 | case "first": | ||
4068 | executionType = CustomActionExecutionType.FirstSequence; | ||
4069 | break; | ||
4070 | case "ui": | ||
4071 | sequences = new[] { SequenceTable.InstallUISequence }; | ||
4072 | break; | ||
4073 | case "both": | ||
4074 | break; | ||
4075 | case "": | ||
4076 | break; | ||
4077 | default: | ||
4078 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
4079 | break; | ||
4080 | } | ||
4081 | break; | ||
4082 | case "Value": | ||
4083 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4084 | break; | ||
4085 | default: | ||
4086 | this.Core.UnexpectedAttribute(node, attrib); | ||
4087 | break; | ||
4088 | } | ||
4089 | } | ||
4090 | else | ||
4091 | { | ||
4092 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4093 | } | ||
4094 | } | ||
4095 | |||
4096 | condition = this.Core.GetConditionInnerText(node); | ||
4097 | |||
4098 | if (null == id) | ||
4099 | { | ||
4100 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4101 | } | ||
4102 | else if (String.IsNullOrEmpty(actionName)) | ||
4103 | { | ||
4104 | actionName = String.Concat("Set", id); | ||
4105 | } | ||
4106 | |||
4107 | if (null == value) | ||
4108 | { | ||
4109 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4110 | } | ||
4111 | |||
4112 | this.Core.ParseForExtensionElements(node); | ||
4113 | |||
4114 | if (!this.Core.EncounteredError) | ||
4115 | { | ||
4116 | var tuple = new CustomActionTuple(sourceLineNumbers, new Identifier(AccessModifier.Public, actionName)) | ||
4117 | { | ||
4118 | ExecutionType = executionType, | ||
4119 | SourceType = CustomActionSourceType.Directory, | ||
4120 | TargetType = CustomActionTargetType.TextData, | ||
4121 | Source = id, | ||
4122 | Target = value | ||
4123 | }; | ||
4124 | |||
4125 | this.Core.AddTuple(tuple); | ||
4126 | |||
4127 | foreach (var sequence in sequences) | ||
4128 | { | ||
4129 | var sequenceId = new Identifier(AccessModifier.Public, sequence.ToString(), actionName); | ||
4130 | |||
4131 | var sequenceTuple = new WixActionTuple(sourceLineNumbers, sequenceId) | ||
4132 | { | ||
4133 | SequenceTable = sequence, | ||
4134 | Action = actionName, | ||
4135 | Condition = condition, | ||
4136 | After = "CostInialize", | ||
4137 | Overridable = false | ||
4138 | }; | ||
4139 | |||
4140 | this.Core.AddTuple(tuple); | ||
4141 | } | ||
4142 | } | ||
4143 | } | ||
4144 | |||
4145 | /// <summary> | ||
4146 | /// Parses a SetProperty element. | ||
4147 | /// </summary> | ||
4148 | /// <param name="node">Element to parse.</param> | ||
4149 | private void ParseSetPropertyElement(XElement node) | ||
4150 | { | ||
4151 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4152 | string actionName = null; | ||
4153 | string id = null; | ||
4154 | string afterAction = null; | ||
4155 | string beforeAction = null; | ||
4156 | var executionType = CustomActionExecutionType.Immediate; | ||
4157 | var sequences = new[] { SequenceTable.InstallUISequence, SequenceTable.InstallExecuteSequence }; // default to "both" | ||
4158 | string value = null; | ||
4159 | |||
4160 | foreach (var attrib in node.Attributes()) | ||
4161 | { | ||
4162 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4163 | { | ||
4164 | switch (attrib.Name.LocalName) | ||
4165 | { | ||
4166 | case "Action": | ||
4167 | actionName = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4168 | break; | ||
4169 | case "Id": | ||
4170 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4171 | break; | ||
4172 | case "After": | ||
4173 | afterAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4174 | break; | ||
4175 | case "Before": | ||
4176 | beforeAction = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4177 | break; | ||
4178 | case "Sequence": | ||
4179 | var sequenceValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4180 | switch (sequenceValue) | ||
4181 | { | ||
4182 | case "execute": | ||
4183 | sequences = new[] { SequenceTable.InstallExecuteSequence }; | ||
4184 | break; | ||
4185 | case "first": | ||
4186 | executionType = CustomActionExecutionType.FirstSequence; | ||
4187 | break; | ||
4188 | case "ui": | ||
4189 | sequences = new[] { SequenceTable.InstallUISequence }; | ||
4190 | break; | ||
4191 | case "both": | ||
4192 | break; | ||
4193 | case "": | ||
4194 | break; | ||
4195 | default: | ||
4196 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
4197 | break; | ||
4198 | } | ||
4199 | //if (0 < sequenceValue.Length) | ||
4200 | //{ | ||
4201 | // var sequenceType = Wix.Enums.ParseSequenceType(sequenceValue); | ||
4202 | // switch (sequenceType) | ||
4203 | // { | ||
4204 | // case Wix.SequenceType.execute: | ||
4205 | // sequences = new string[] { "InstallExecuteSequence" }; | ||
4206 | // break; | ||
4207 | // case Wix.SequenceType.ui: | ||
4208 | // sequences = new string[] { "InstallUISequence" }; | ||
4209 | // break; | ||
4210 | // case Wix.SequenceType.first: | ||
4211 | // firstSequence = true; | ||
4212 | // // default puts it in both sequence which is what we want | ||
4213 | // break; | ||
4214 | // case Wix.SequenceType.both: | ||
4215 | // // default so no work necessary. | ||
4216 | // break; | ||
4217 | // default: | ||
4218 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, sequenceValue, "execute", "ui", "both")); | ||
4219 | // break; | ||
4220 | // } | ||
4221 | //} | ||
4222 | break; | ||
4223 | case "Value": | ||
4224 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
4225 | break; | ||
4226 | default: | ||
4227 | this.Core.UnexpectedAttribute(node, attrib); | ||
4228 | break; | ||
4229 | } | ||
4230 | } | ||
4231 | else | ||
4232 | { | ||
4233 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4234 | } | ||
4235 | } | ||
4236 | |||
4237 | var condition = this.Core.GetConditionInnerText(node); | ||
4238 | |||
4239 | if (null == id) | ||
4240 | { | ||
4241 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4242 | } | ||
4243 | else if (String.IsNullOrEmpty(actionName)) | ||
4244 | { | ||
4245 | actionName = String.Concat("Set", id); | ||
4246 | } | ||
4247 | |||
4248 | if (null == value) | ||
4249 | { | ||
4250 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4251 | } | ||
4252 | |||
4253 | if (null != beforeAction && null != afterAction) | ||
4254 | { | ||
4255 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before")); | ||
4256 | } | ||
4257 | else if (null == beforeAction && null == afterAction) | ||
4258 | { | ||
4259 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "After", "Before", "Id")); | ||
4260 | } | ||
4261 | |||
4262 | this.Core.ParseForExtensionElements(node); | ||
4263 | |||
4264 | // add the row and any references needed | ||
4265 | if (!this.Core.EncounteredError) | ||
4266 | { | ||
4267 | // action that is scheduled to occur before/after itself | ||
4268 | if (beforeAction == actionName) | ||
4269 | { | ||
4270 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "Before", beforeAction)); | ||
4271 | } | ||
4272 | else if (afterAction == actionName) | ||
4273 | { | ||
4274 | this.Core.Write(ErrorMessages.ActionScheduledRelativeToItself(sourceLineNumbers, node.Name.LocalName, "After", afterAction)); | ||
4275 | } | ||
4276 | |||
4277 | var tuple = new CustomActionTuple(sourceLineNumbers, new Identifier(AccessModifier.Public, actionName)) | ||
4278 | { | ||
4279 | ExecutionType = executionType, | ||
4280 | SourceType = CustomActionSourceType.Property, | ||
4281 | TargetType = CustomActionTargetType.TextData, | ||
4282 | Source = id, | ||
4283 | Target = value | ||
4284 | }; | ||
4285 | |||
4286 | this.Core.AddTuple(tuple); | ||
4287 | |||
4288 | foreach (var sequence in sequences) | ||
4289 | { | ||
4290 | var sequenceId = new Identifier(AccessModifier.Public, sequence.ToString(), actionName); | ||
4291 | |||
4292 | var sequenceTuple = new WixActionTuple(sourceLineNumbers, sequenceId) | ||
4293 | { | ||
4294 | SequenceTable = sequence, | ||
4295 | Action = actionName, | ||
4296 | Condition = condition, | ||
4297 | Before = beforeAction, | ||
4298 | After = afterAction, | ||
4299 | Overridable = false | ||
4300 | }; | ||
4301 | |||
4302 | this.Core.AddTuple(tuple); | ||
4303 | |||
4304 | if (null != beforeAction) | ||
4305 | { | ||
4306 | if (WindowsInstallerStandard.IsStandardAction(beforeAction)) | ||
4307 | { | ||
4308 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence.ToString(), beforeAction); | ||
4309 | } | ||
4310 | else | ||
4311 | { | ||
4312 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", beforeAction); | ||
4313 | } | ||
4314 | } | ||
4315 | |||
4316 | if (null != afterAction) | ||
4317 | { | ||
4318 | if (WindowsInstallerStandard.IsStandardAction(afterAction)) | ||
4319 | { | ||
4320 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence.ToString(), afterAction); | ||
4321 | } | ||
4322 | else | ||
4323 | { | ||
4324 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", afterAction); | ||
4325 | } | ||
4326 | } | ||
4327 | } | ||
4328 | } | ||
4329 | } | ||
4330 | |||
4331 | /// <summary> | ||
4332 | /// Parses a SFP catalog element. | ||
4333 | /// </summary> | ||
4334 | /// <param name="node">Element to parse.</param> | ||
4335 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
4336 | private void ParseSFPFileElement(XElement node, string parentSFPCatalog) | ||
4337 | { | ||
4338 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4339 | string id = null; | ||
4340 | |||
4341 | foreach (var attrib in node.Attributes()) | ||
4342 | { | ||
4343 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4344 | { | ||
4345 | switch (attrib.Name.LocalName) | ||
4346 | { | ||
4347 | case "Id": | ||
4348 | id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4349 | break; | ||
4350 | default: | ||
4351 | this.Core.UnexpectedAttribute(node, attrib); | ||
4352 | break; | ||
4353 | } | ||
4354 | } | ||
4355 | else | ||
4356 | { | ||
4357 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4358 | } | ||
4359 | } | ||
4360 | |||
4361 | if (null == id) | ||
4362 | { | ||
4363 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4364 | } | ||
4365 | |||
4366 | this.Core.ParseForExtensionElements(node); | ||
4367 | |||
4368 | if (!this.Core.EncounteredError) | ||
4369 | { | ||
4370 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.FileSFPCatalog); | ||
4371 | row.Set(0, id); | ||
4372 | row.Set(1, parentSFPCatalog); | ||
4373 | } | ||
4374 | } | ||
4375 | |||
4376 | /// <summary> | ||
4377 | /// Parses a SFP catalog element. | ||
4378 | /// </summary> | ||
4379 | /// <param name="node">Element to parse.</param> | ||
4380 | /// <param name="parentSFPCatalog">Parent SFPCatalog.</param> | ||
4381 | private void ParseSFPCatalogElement(XElement node, ref string parentSFPCatalog) | ||
4382 | { | ||
4383 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4384 | string parentName = null; | ||
4385 | string dependency = null; | ||
4386 | string name = null; | ||
4387 | string sourceFile = null; | ||
4388 | |||
4389 | foreach (var attrib in node.Attributes()) | ||
4390 | { | ||
4391 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4392 | { | ||
4393 | switch (attrib.Name.LocalName) | ||
4394 | { | ||
4395 | case "Dependency": | ||
4396 | dependency = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4397 | break; | ||
4398 | case "Name": | ||
4399 | name = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
4400 | parentSFPCatalog = name; | ||
4401 | break; | ||
4402 | case "SourceFile": | ||
4403 | sourceFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4404 | break; | ||
4405 | default: | ||
4406 | this.Core.UnexpectedAttribute(node, attrib); | ||
4407 | break; | ||
4408 | } | ||
4409 | } | ||
4410 | else | ||
4411 | { | ||
4412 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4413 | } | ||
4414 | } | ||
4415 | |||
4416 | if (null == name) | ||
4417 | { | ||
4418 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
4419 | } | ||
4420 | |||
4421 | if (null == sourceFile) | ||
4422 | { | ||
4423 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SourceFile")); | ||
4424 | } | ||
4425 | |||
4426 | foreach (var child in node.Elements()) | ||
4427 | { | ||
4428 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4429 | { | ||
4430 | switch (child.Name.LocalName) | ||
4431 | { | ||
4432 | case "SFPCatalog": | ||
4433 | this.ParseSFPCatalogElement(child, ref parentName); | ||
4434 | if (null != dependency && parentName == dependency) | ||
4435 | { | ||
4436 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
4437 | } | ||
4438 | dependency = parentName; | ||
4439 | break; | ||
4440 | case "SFPFile": | ||
4441 | this.ParseSFPFileElement(child, name); | ||
4442 | break; | ||
4443 | default: | ||
4444 | this.Core.UnexpectedElement(node, child); | ||
4445 | break; | ||
4446 | } | ||
4447 | } | ||
4448 | else | ||
4449 | { | ||
4450 | this.Core.ParseExtensionElement(node, child); | ||
4451 | } | ||
4452 | } | ||
4453 | |||
4454 | if (null == dependency) | ||
4455 | { | ||
4456 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dependency")); | ||
4457 | } | ||
4458 | |||
4459 | if (!this.Core.EncounteredError) | ||
4460 | { | ||
4461 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.SFPCatalog); | ||
4462 | row.Set(0, name); | ||
4463 | row.Set(1, sourceFile); | ||
4464 | row.Set(2, dependency); | ||
4465 | } | ||
4466 | } | ||
4467 | |||
4468 | /// <summary> | ||
4469 | /// Parses a shortcut element. | ||
4470 | /// </summary> | ||
4471 | /// <param name="node">Element to parse.</param> | ||
4472 | /// <param name="componentId">Identifer for parent component.</param> | ||
4473 | /// <param name="parentElementLocalName">Local name of parent element.</param> | ||
4474 | /// <param name="defaultTarget">Default identifier of parent (which is usually the target).</param> | ||
4475 | /// <param name="parentKeyPath">Flag to indicate whether the parent element is the keypath of a component or not (will only be true for file parent elements).</param> | ||
4476 | private void ParseShortcutElement(XElement node, string componentId, string parentElementLocalName, string defaultTarget, YesNoType parentKeyPath) | ||
4477 | { | ||
4478 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4479 | Identifier id = null; | ||
4480 | var advertise = false; | ||
4481 | string arguments = null; | ||
4482 | string description = null; | ||
4483 | string descriptionResourceDll = null; | ||
4484 | int? descriptionResourceId = null; | ||
4485 | string directory = null; | ||
4486 | string displayResourceDll = null; | ||
4487 | int? displayResourceId = null; | ||
4488 | int? hotkey = null; | ||
4489 | string icon = null; | ||
4490 | int? iconIndex = null; | ||
4491 | string name = null; | ||
4492 | string shortName = null; | ||
4493 | ShortcutShowType? show = null; | ||
4494 | string target = null; | ||
4495 | string workingDirectory = null; | ||
4496 | |||
4497 | foreach (var attrib in node.Attributes()) | ||
4498 | { | ||
4499 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4500 | { | ||
4501 | switch (attrib.Name.LocalName) | ||
4502 | { | ||
4503 | case "Id": | ||
4504 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4505 | break; | ||
4506 | case "Advertise": | ||
4507 | advertise = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
4508 | break; | ||
4509 | case "Arguments": | ||
4510 | arguments = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4511 | break; | ||
4512 | case "Description": | ||
4513 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4514 | break; | ||
4515 | case "DescriptionResourceDll": | ||
4516 | descriptionResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4517 | break; | ||
4518 | case "DescriptionResourceId": | ||
4519 | descriptionResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4520 | break; | ||
4521 | case "Directory": | ||
4522 | directory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
4523 | break; | ||
4524 | case "DisplayResourceDll": | ||
4525 | displayResourceDll = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4526 | break; | ||
4527 | case "DisplayResourceId": | ||
4528 | displayResourceId = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4529 | break; | ||
4530 | case "Hotkey": | ||
4531 | hotkey = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4532 | break; | ||
4533 | case "Icon": | ||
4534 | icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4535 | this.Core.CreateSimpleReference(sourceLineNumbers, "Icon", icon); | ||
4536 | break; | ||
4537 | case "IconIndex": | ||
4538 | iconIndex = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, Int16.MinValue + 1, Int16.MaxValue); | ||
4539 | break; | ||
4540 | case "Name": | ||
4541 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
4542 | break; | ||
4543 | case "ShortName": | ||
4544 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | ||
4545 | break; | ||
4546 | case "Show": | ||
4547 | var showValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4548 | switch (showValue) | ||
4549 | { | ||
4550 | case "normal": | ||
4551 | show = ShortcutShowType.Normal; | ||
4552 | break; | ||
4553 | case "maximized": | ||
4554 | show = ShortcutShowType.Maximized; | ||
4555 | break; | ||
4556 | case "minimized": | ||
4557 | show = ShortcutShowType.Minimized; | ||
4558 | break; | ||
4559 | case "": | ||
4560 | break; | ||
4561 | default: | ||
4562 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized")); | ||
4563 | break; | ||
4564 | } | ||
4565 | //if (showValue.Length == 0) | ||
4566 | //{ | ||
4567 | // show = CompilerConstants.IllegalInteger; | ||
4568 | //} | ||
4569 | //else | ||
4570 | //{ | ||
4571 | // var showType = Wix.Shortcut.ParseShowType(showValue); | ||
4572 | // switch (showType) | ||
4573 | // { | ||
4574 | // case Wix.Shortcut.ShowType.normal: | ||
4575 | // show = 1; | ||
4576 | // break; | ||
4577 | // case Wix.Shortcut.ShowType.maximized: | ||
4578 | // show = 3; | ||
4579 | // break; | ||
4580 | // case Wix.Shortcut.ShowType.minimized: | ||
4581 | // show = 7; | ||
4582 | // break; | ||
4583 | // default: | ||
4584 | // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Show", showValue, "normal", "maximized", "minimized")); | ||
4585 | // show = CompilerConstants.IllegalInteger; | ||
4586 | // break; | ||
4587 | // } | ||
4588 | //} | ||
4589 | break; | ||
4590 | case "Target": | ||
4591 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4592 | break; | ||
4593 | case "WorkingDirectory": | ||
4594 | workingDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
4595 | break; | ||
4596 | default: | ||
4597 | this.Core.UnexpectedAttribute(node, attrib); | ||
4598 | break; | ||
4599 | } | ||
4600 | } | ||
4601 | else | ||
4602 | { | ||
4603 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4604 | } | ||
4605 | } | ||
4606 | |||
4607 | if (advertise && null != target) | ||
4608 | { | ||
4609 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "Advertise", "yes")); | ||
4610 | } | ||
4611 | |||
4612 | if (null == directory) | ||
4613 | { | ||
4614 | if ("Component" == parentElementLocalName) | ||
4615 | { | ||
4616 | directory = defaultTarget; | ||
4617 | } | ||
4618 | else | ||
4619 | { | ||
4620 | this.Core.Write(ErrorMessages.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Directory", "Component")); | ||
4621 | } | ||
4622 | } | ||
4623 | |||
4624 | if (null != descriptionResourceDll) | ||
4625 | { | ||
4626 | if (!descriptionResourceId.HasValue) | ||
4627 | { | ||
4628 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceDll", "DescriptionResourceId")); | ||
4629 | } | ||
4630 | } | ||
4631 | else | ||
4632 | { | ||
4633 | if (descriptionResourceId.HasValue) | ||
4634 | { | ||
4635 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DescriptionResourceId", "DescriptionResourceDll")); | ||
4636 | } | ||
4637 | } | ||
4638 | |||
4639 | if (null != displayResourceDll) | ||
4640 | { | ||
4641 | if (!displayResourceId.HasValue) | ||
4642 | { | ||
4643 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceDll", "DisplayResourceId")); | ||
4644 | } | ||
4645 | } | ||
4646 | else | ||
4647 | { | ||
4648 | if (displayResourceId.HasValue) | ||
4649 | { | ||
4650 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "DisplayResourceId", "DisplayResourceDll")); | ||
4651 | } | ||
4652 | } | ||
4653 | |||
4654 | if (null == name) | ||
4655 | { | ||
4656 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
4657 | } | ||
4658 | else if (0 < name.Length) | ||
4659 | { | ||
4660 | if (this.Core.IsValidShortFilename(name, false)) | ||
4661 | { | ||
4662 | if (null == shortName) | ||
4663 | { | ||
4664 | shortName = name; | ||
4665 | name = null; | ||
4666 | } | ||
4667 | else | ||
4668 | { | ||
4669 | this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Name", name, "ShortName")); | ||
4670 | } | ||
4671 | } | ||
4672 | else if (null == shortName) // generate a short file name. | ||
4673 | { | ||
4674 | shortName = this.Core.CreateShortName(name, true, false, node.Name.LocalName, componentId, directory); | ||
4675 | } | ||
4676 | } | ||
4677 | |||
4678 | if ("Component" != parentElementLocalName && null != target) | ||
4679 | { | ||
4680 | this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "Target", parentElementLocalName)); | ||
4681 | } | ||
4682 | |||
4683 | if (null == id) | ||
4684 | { | ||
4685 | id = this.Core.CreateIdentifier("sct", directory, LowercaseOrNull(name) ?? LowercaseOrNull(shortName)); | ||
4686 | } | ||
4687 | |||
4688 | foreach (var child in node.Elements()) | ||
4689 | { | ||
4690 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
4691 | { | ||
4692 | switch (child.Name.LocalName) | ||
4693 | { | ||
4694 | case "Icon": | ||
4695 | icon = this.ParseIconElement(child); | ||
4696 | break; | ||
4697 | case "ShortcutProperty": | ||
4698 | this.ParseShortcutPropertyElement(child, id.Id); | ||
4699 | break; | ||
4700 | default: | ||
4701 | this.Core.UnexpectedElement(node, child); | ||
4702 | break; | ||
4703 | } | ||
4704 | } | ||
4705 | else | ||
4706 | { | ||
4707 | this.Core.ParseExtensionElement(node, child); | ||
4708 | } | ||
4709 | } | ||
4710 | |||
4711 | if (!this.Core.EncounteredError) | ||
4712 | { | ||
4713 | if (advertise) | ||
4714 | { | ||
4715 | if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName) | ||
4716 | { | ||
4717 | this.Core.Write(WarningMessages.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget)); | ||
4718 | } | ||
4719 | |||
4720 | target = Guid.Empty.ToString("B"); | ||
4721 | } | ||
4722 | else if (null != target) | ||
4723 | { | ||
4724 | } | ||
4725 | else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName) | ||
4726 | { | ||
4727 | target = String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget); | ||
4728 | } | ||
4729 | else if ("File" == parentElementLocalName) | ||
4730 | { | ||
4731 | target = String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget); | ||
4732 | } | ||
4733 | |||
4734 | var tuple = new ShortcutTuple(sourceLineNumbers, id) | ||
4735 | { | ||
4736 | Directory_ = directory, | ||
4737 | Name = this.GetMsiFilenameValue(shortName, name), | ||
4738 | Component_ = componentId, | ||
4739 | Target = target, | ||
4740 | Arguments = arguments, | ||
4741 | Description = description, | ||
4742 | Hotkey = hotkey, | ||
4743 | Icon_ = icon, | ||
4744 | IconIndex = iconIndex, | ||
4745 | Show = show, | ||
4746 | WorkingDirectory = workingDirectory, | ||
4747 | DisplayResourceDll = displayResourceDll, | ||
4748 | DisplayResourceId = displayResourceId, | ||
4749 | DescriptionResourceDll = descriptionResourceDll, | ||
4750 | DescriptionResourceId = descriptionResourceId, | ||
4751 | }; | ||
4752 | |||
4753 | this.Core.AddTuple(tuple); | ||
4754 | |||
4755 | //var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Shortcut, id); | ||
4756 | //row.Set(1, directory); | ||
4757 | //row.Set(2, this.GetMsiFilenameValue(shortName, name)); | ||
4758 | //row.Set(3, componentId); | ||
4759 | //if (advertise) | ||
4760 | //{ | ||
4761 | // if (YesNoType.Yes != parentKeyPath && "Component" != parentElementLocalName) | ||
4762 | // { | ||
4763 | // this.Core.Write(WarningMessages.UnclearShortcut(sourceLineNumbers, id.Id, componentId, defaultTarget)); | ||
4764 | // } | ||
4765 | // row.Set(4, Guid.Empty.ToString("B")); | ||
4766 | //} | ||
4767 | //else if (null != target) | ||
4768 | //{ | ||
4769 | // row.Set(4, target); | ||
4770 | //} | ||
4771 | //else if ("Component" == parentElementLocalName || "CreateFolder" == parentElementLocalName) | ||
4772 | //{ | ||
4773 | // row.Set(4, String.Format(CultureInfo.InvariantCulture, "[{0}]", defaultTarget)); | ||
4774 | //} | ||
4775 | //else if ("File" == parentElementLocalName) | ||
4776 | //{ | ||
4777 | // row.Set(4, String.Format(CultureInfo.InvariantCulture, "[#{0}]", defaultTarget)); | ||
4778 | //} | ||
4779 | //row.Set(5, arguments); | ||
4780 | //row.Set(6, description); | ||
4781 | //if (CompilerConstants.IntegerNotSet != hotkey) | ||
4782 | //{ | ||
4783 | // row.Set(7, hotkey); | ||
4784 | //} | ||
4785 | //row.Set(8, icon); | ||
4786 | //if (CompilerConstants.IntegerNotSet != iconIndex) | ||
4787 | //{ | ||
4788 | // row.Set(9, iconIndex); | ||
4789 | //} | ||
4790 | |||
4791 | //if (show.HasValue) | ||
4792 | //{ | ||
4793 | // row.Set(10, show.Value); | ||
4794 | //} | ||
4795 | //row.Set(11, workingDirectory); | ||
4796 | //row.Set(12, displayResourceDll); | ||
4797 | //if (CompilerConstants.IntegerNotSet != displayResourceId) | ||
4798 | //{ | ||
4799 | // row.Set(13, displayResourceId); | ||
4800 | //} | ||
4801 | //row.Set(14, descriptionResourceDll); | ||
4802 | //if (CompilerConstants.IntegerNotSet != descriptionResourceId) | ||
4803 | //{ | ||
4804 | // row.Set(15, descriptionResourceId); | ||
4805 | //} | ||
4806 | } | ||
4807 | } | ||
4808 | |||
4809 | /// <summary> | ||
4810 | /// Parses a shortcut property element. | ||
4811 | /// </summary> | ||
4812 | /// <param name="node">Element to parse.</param> | ||
4813 | private void ParseShortcutPropertyElement(XElement node, string shortcutId) | ||
4814 | { | ||
4815 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4816 | Identifier id = null; | ||
4817 | string key = null; | ||
4818 | string value = null; | ||
4819 | |||
4820 | foreach (var attrib in node.Attributes()) | ||
4821 | { | ||
4822 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4823 | { | ||
4824 | switch (attrib.Name.LocalName) | ||
4825 | { | ||
4826 | case "Id": | ||
4827 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
4828 | break; | ||
4829 | case "Key": | ||
4830 | key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4831 | break; | ||
4832 | case "Value": | ||
4833 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4834 | break; | ||
4835 | default: | ||
4836 | this.Core.UnexpectedAttribute(node, attrib); | ||
4837 | break; | ||
4838 | } | ||
4839 | } | ||
4840 | else | ||
4841 | { | ||
4842 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4843 | } | ||
4844 | } | ||
4845 | |||
4846 | if (String.IsNullOrEmpty(key)) | ||
4847 | { | ||
4848 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); | ||
4849 | } | ||
4850 | else if (null == id) | ||
4851 | { | ||
4852 | id = this.Core.CreateIdentifier("scp", shortcutId, key.ToUpperInvariant()); | ||
4853 | } | ||
4854 | |||
4855 | var innerText = this.Core.GetTrimmedInnerText(node); | ||
4856 | if (!String.IsNullOrEmpty(innerText)) | ||
4857 | { | ||
4858 | if (String.IsNullOrEmpty(value)) | ||
4859 | { | ||
4860 | value = innerText; | ||
4861 | } | ||
4862 | else // cannot specify both the value attribute and inner text | ||
4863 | { | ||
4864 | this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4865 | } | ||
4866 | } | ||
4867 | |||
4868 | if (String.IsNullOrEmpty(value)) | ||
4869 | { | ||
4870 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
4871 | } | ||
4872 | |||
4873 | this.Core.ParseForExtensionElements(node); | ||
4874 | |||
4875 | if (!this.Core.EncounteredError) | ||
4876 | { | ||
4877 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.MsiShortcutProperty, id); | ||
4878 | row.Set(1, shortcutId); | ||
4879 | row.Set(2, key); | ||
4880 | row.Set(3, value); | ||
4881 | } | ||
4882 | } | ||
4883 | |||
4884 | /// <summary> | ||
4885 | /// Parses a typelib element. | ||
4886 | /// </summary> | ||
4887 | /// <param name="node">Element to parse.</param> | ||
4888 | /// <param name="componentId">Identifier of parent component.</param> | ||
4889 | /// <param name="fileServer">Identifier of file that acts as typelib server.</param> | ||
4890 | /// <param name="win64Component">true if the component is 64-bit.</param> | ||
4891 | private void ParseTypeLibElement(XElement node, string componentId, string fileServer, bool win64Component) | ||
4892 | { | ||
4893 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
4894 | string id = null; | ||
4895 | var advertise = YesNoType.NotSet; | ||
4896 | var cost = CompilerConstants.IntegerNotSet; | ||
4897 | string description = null; | ||
4898 | var flags = 0; | ||
4899 | string helpDirectory = null; | ||
4900 | var language = CompilerConstants.IntegerNotSet; | ||
4901 | var majorVersion = CompilerConstants.IntegerNotSet; | ||
4902 | var minorVersion = CompilerConstants.IntegerNotSet; | ||
4903 | var resourceId = CompilerConstants.LongNotSet; | ||
4904 | |||
4905 | foreach (var attrib in node.Attributes()) | ||
4906 | { | ||
4907 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
4908 | { | ||
4909 | switch (attrib.Name.LocalName) | ||
4910 | { | ||
4911 | case "Id": | ||
4912 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
4913 | break; | ||
4914 | case "Advertise": | ||
4915 | advertise = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
4916 | break; | ||
4917 | case "Control": | ||
4918 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4919 | { | ||
4920 | flags |= 2; | ||
4921 | } | ||
4922 | break; | ||
4923 | case "Cost": | ||
4924 | cost = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int32.MaxValue); | ||
4925 | break; | ||
4926 | case "Description": | ||
4927 | description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
4928 | break; | ||
4929 | case "HasDiskImage": | ||
4930 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4931 | { | ||
4932 | flags |= 8; | ||
4933 | } | ||
4934 | break; | ||
4935 | case "HelpDirectory": | ||
4936 | helpDirectory = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, attrib, null); | ||
4937 | break; | ||
4938 | case "Hidden": | ||
4939 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4940 | { | ||
4941 | flags |= 4; | ||
4942 | } | ||
4943 | break; | ||
4944 | case "Language": | ||
4945 | language = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue); | ||
4946 | break; | ||
4947 | case "MajorVersion": | ||
4948 | majorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, UInt16.MaxValue); | ||
4949 | break; | ||
4950 | case "MinorVersion": | ||
4951 | minorVersion = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue); | ||
4952 | break; | ||
4953 | case "ResourceId": | ||
4954 | resourceId = this.Core.GetAttributeLongValue(sourceLineNumbers, attrib, Int32.MinValue, Int32.MaxValue); | ||
4955 | break; | ||
4956 | case "Restricted": | ||
4957 | if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) | ||
4958 | { | ||
4959 | flags |= 1; | ||
4960 | } | ||
4961 | break; | ||
4962 | default: | ||
4963 | this.Core.UnexpectedAttribute(node, attrib); | ||
4964 | break; | ||
4965 | } | ||
4966 | } | ||
4967 | else | ||
4968 | { | ||
4969 | this.Core.ParseExtensionAttribute(node, attrib); | ||
4970 | } | ||
4971 | } | ||
4972 | |||
4973 | if (null == id) | ||
4974 | { | ||
4975 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
4976 | } | ||
4977 | |||
4978 | if (CompilerConstants.IntegerNotSet == language) | ||
4979 | { | ||
4980 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); | ||
4981 | language = CompilerConstants.IllegalInteger; | ||
4982 | } | ||
4983 | |||
4984 | // build up the typelib version string for the registry if the major or minor version was specified | ||
4985 | string registryVersion = null; | ||
4986 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
4987 | { | ||
4988 | if (CompilerConstants.IntegerNotSet != majorVersion) | ||
4989 | { | ||
4990 | registryVersion = majorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat); | ||
4991 | } | ||
4992 | else | ||
4993 | { | ||
4994 | registryVersion = "0"; | ||
4995 | } | ||
4996 | |||
4997 | if (CompilerConstants.IntegerNotSet != minorVersion) | ||
4998 | { | ||
4999 | registryVersion = String.Concat(registryVersion, ".", minorVersion.ToString("x", CultureInfo.InvariantCulture.NumberFormat)); | ||
5000 | } | ||
5001 | else | ||
5002 | { | ||
5003 | registryVersion = String.Concat(registryVersion, ".0"); | ||
5004 | } | ||
5005 | } | ||
5006 | |||
5007 | // if the advertise state has not been set, default to non-advertised | ||
5008 | if (YesNoType.NotSet == advertise) | ||
5009 | { | ||
5010 | advertise = YesNoType.No; | ||
5011 | } | ||
5012 | |||
5013 | foreach (var child in node.Elements()) | ||
5014 | { | ||
5015 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5016 | { | ||
5017 | switch (child.Name.LocalName) | ||
5018 | { | ||
5019 | case "AppId": | ||
5020 | this.ParseAppIdElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion); | ||
5021 | break; | ||
5022 | case "Class": | ||
5023 | this.ParseClassElement(child, componentId, YesNoType.NotSet, fileServer, id, registryVersion, null); | ||
5024 | break; | ||
5025 | case "Interface": | ||
5026 | this.ParseInterfaceElement(child, componentId, null, null, id, registryVersion); | ||
5027 | break; | ||
5028 | default: | ||
5029 | this.Core.UnexpectedElement(node, child); | ||
5030 | break; | ||
5031 | } | ||
5032 | } | ||
5033 | else | ||
5034 | { | ||
5035 | this.Core.ParseExtensionElement(node, child); | ||
5036 | } | ||
5037 | } | ||
5038 | |||
5039 | |||
5040 | if (YesNoType.Yes == advertise) | ||
5041 | { | ||
5042 | if (CompilerConstants.LongNotSet != resourceId) | ||
5043 | { | ||
5044 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "ResourceId")); | ||
5045 | } | ||
5046 | |||
5047 | if (0 != flags) | ||
5048 | { | ||
5049 | if (0x1 == (flags & 0x1)) | ||
5050 | { | ||
5051 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Restricted", "Advertise", "yes")); | ||
5052 | } | ||
5053 | |||
5054 | if (0x2 == (flags & 0x2)) | ||
5055 | { | ||
5056 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Control", "Advertise", "yes")); | ||
5057 | } | ||
5058 | |||
5059 | if (0x4 == (flags & 0x4)) | ||
5060 | { | ||
5061 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Hidden", "Advertise", "yes")); | ||
5062 | } | ||
5063 | |||
5064 | if (0x8 == (flags & 0x8)) | ||
5065 | { | ||
5066 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "HasDiskImage", "Advertise", "yes")); | ||
5067 | } | ||
5068 | } | ||
5069 | |||
5070 | if (!this.Core.EncounteredError) | ||
5071 | { | ||
5072 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.TypeLib); | ||
5073 | row.Set(0, id); | ||
5074 | row.Set(1, language); | ||
5075 | row.Set(2, componentId); | ||
5076 | if (CompilerConstants.IntegerNotSet != majorVersion || CompilerConstants.IntegerNotSet != minorVersion) | ||
5077 | { | ||
5078 | row.Set(3, (CompilerConstants.IntegerNotSet != majorVersion ? majorVersion * 256 : 0) + (CompilerConstants.IntegerNotSet != minorVersion ? minorVersion : 0)); | ||
5079 | } | ||
5080 | row.Set(4, description); | ||
5081 | row.Set(5, helpDirectory); | ||
5082 | row.Set(6, Guid.Empty.ToString("B")); | ||
5083 | if (CompilerConstants.IntegerNotSet != cost) | ||
5084 | { | ||
5085 | row.Set(7, cost); | ||
5086 | } | ||
5087 | } | ||
5088 | } | ||
5089 | else if (YesNoType.No == advertise) | ||
5090 | { | ||
5091 | if (CompilerConstants.IntegerNotSet != cost && CompilerConstants.IllegalInteger != cost) | ||
5092 | { | ||
5093 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Cost", "Advertise", "no")); | ||
5094 | } | ||
5095 | |||
5096 | if (null == fileServer) | ||
5097 | { | ||
5098 | this.Core.Write(ErrorMessages.MissingTypeLibFile(sourceLineNumbers, node.Name.LocalName, "File")); | ||
5099 | } | ||
5100 | |||
5101 | if (null == registryVersion) | ||
5102 | { | ||
5103 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "MajorVersion", "MinorVersion", "Advertise", "no")); | ||
5104 | } | ||
5105 | |||
5106 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion], (Default) = [Description] | ||
5107 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}", id, registryVersion), null, description, componentId); | ||
5108 | |||
5109 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\[Language]\[win16|win32|win64], (Default) = [TypeLibPath]\[ResourceId] | ||
5110 | var path = String.Concat("[#", fileServer, "]"); | ||
5111 | if (CompilerConstants.LongNotSet != resourceId) | ||
5112 | { | ||
5113 | path = String.Concat(path, Path.DirectorySeparatorChar, resourceId.ToString(CultureInfo.InvariantCulture.NumberFormat)); | ||
5114 | } | ||
5115 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\{2}\{3}", id, registryVersion, language, (win64Component ? "win64" : "win32")), null, path, componentId); | ||
5116 | |||
5117 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\FLAGS, (Default) = [TypeLibFlags] | ||
5118 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\FLAGS", id, registryVersion), null, flags.ToString(CultureInfo.InvariantCulture.NumberFormat), componentId); | ||
5119 | |||
5120 | if (null != helpDirectory) | ||
5121 | { | ||
5122 | // HKCR\TypeLib\[ID]\[MajorVersion].[MinorVersion]\HELPDIR, (Default) = [HelpDirectory] | ||
5123 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Format(CultureInfo.InvariantCulture, @"TypeLib\{0}\{1}\HELPDIR", id, registryVersion), null, String.Concat("[", helpDirectory, "]"), componentId); | ||
5124 | } | ||
5125 | } | ||
5126 | } | ||
5127 | |||
5128 | /// <summary> | ||
5129 | /// Parses an upgrade element. | ||
5130 | /// </summary> | ||
5131 | /// <param name="node">Element to parse.</param> | ||
5132 | private void ParseUpgradeElement(XElement node) | ||
5133 | { | ||
5134 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5135 | string id = null; | ||
5136 | |||
5137 | foreach (var attrib in node.Attributes()) | ||
5138 | { | ||
5139 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5140 | { | ||
5141 | switch (attrib.Name.LocalName) | ||
5142 | { | ||
5143 | case "Id": | ||
5144 | id = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); | ||
5145 | break; | ||
5146 | default: | ||
5147 | this.Core.UnexpectedAttribute(node, attrib); | ||
5148 | break; | ||
5149 | } | ||
5150 | } | ||
5151 | else | ||
5152 | { | ||
5153 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5154 | } | ||
5155 | } | ||
5156 | |||
5157 | if (null == id) | ||
5158 | { | ||
5159 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5160 | } | ||
5161 | |||
5162 | // process the UpgradeVersion children here | ||
5163 | foreach (var child in node.Elements()) | ||
5164 | { | ||
5165 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5166 | { | ||
5167 | var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); | ||
5168 | |||
5169 | switch (child.Name.LocalName) | ||
5170 | { | ||
5171 | case "Property": | ||
5172 | this.ParsePropertyElement(child); | ||
5173 | this.Core.Write(WarningMessages.DeprecatedUpgradeProperty(childSourceLineNumbers)); | ||
5174 | break; | ||
5175 | case "UpgradeVersion": | ||
5176 | this.ParseUpgradeVersionElement(child, id); | ||
5177 | break; | ||
5178 | default: | ||
5179 | this.Core.UnexpectedElement(node, child); | ||
5180 | break; | ||
5181 | } | ||
5182 | } | ||
5183 | else | ||
5184 | { | ||
5185 | this.Core.ParseExtensionElement(node, child); | ||
5186 | } | ||
5187 | } | ||
5188 | |||
5189 | // No rows created here. All row creation is done in ParseUpgradeVersionElement. | ||
5190 | } | ||
5191 | |||
5192 | /// <summary> | ||
5193 | /// Parse upgrade version element. | ||
5194 | /// </summary> | ||
5195 | /// <param name="node">Element to parse.</param> | ||
5196 | /// <param name="upgradeId">Upgrade code.</param> | ||
5197 | private void ParseUpgradeVersionElement(XElement node, string upgradeId) | ||
5198 | { | ||
5199 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5200 | |||
5201 | string actionProperty = null; | ||
5202 | string language = null; | ||
5203 | string maximum = null; | ||
5204 | string minimum = null; | ||
5205 | var excludeLanguages = false; | ||
5206 | var ignoreFailures = false; | ||
5207 | var includeMax = false; | ||
5208 | var includeMin = true; | ||
5209 | var migrateFeatures = false; | ||
5210 | var onlyDetect = false; | ||
5211 | string removeFeatures = null; | ||
5212 | |||
5213 | foreach (var attrib in node.Attributes()) | ||
5214 | { | ||
5215 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5216 | { | ||
5217 | switch (attrib.Name.LocalName) | ||
5218 | { | ||
5219 | case "ExcludeLanguages": | ||
5220 | excludeLanguages = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5221 | break; | ||
5222 | case "IgnoreRemoveFailure": | ||
5223 | ignoreFailures = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5224 | break; | ||
5225 | case "IncludeMaximum": | ||
5226 | includeMax = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5227 | break; | ||
5228 | case "IncludeMinimum": // this is "yes" by default | ||
5229 | includeMin = YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5230 | break; | ||
5231 | case "Language": | ||
5232 | language = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5233 | break; | ||
5234 | case "Minimum": | ||
5235 | minimum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
5236 | break; | ||
5237 | case "Maximum": | ||
5238 | maximum = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
5239 | break; | ||
5240 | case "MigrateFeatures": | ||
5241 | migrateFeatures = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5242 | break; | ||
5243 | case "OnlyDetect": | ||
5244 | onlyDetect = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); | ||
5245 | break; | ||
5246 | case "Property": | ||
5247 | actionProperty = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
5248 | break; | ||
5249 | case "RemoveFeatures": | ||
5250 | removeFeatures = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5251 | break; | ||
5252 | default: | ||
5253 | this.Core.UnexpectedAttribute(node, attrib); | ||
5254 | break; | ||
5255 | } | ||
5256 | } | ||
5257 | else | ||
5258 | { | ||
5259 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5260 | } | ||
5261 | } | ||
5262 | |||
5263 | if (null == actionProperty) | ||
5264 | { | ||
5265 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property")); | ||
5266 | } | ||
5267 | else if (actionProperty.ToUpper(CultureInfo.InvariantCulture) != actionProperty) | ||
5268 | { | ||
5269 | this.Core.Write(ErrorMessages.SecurePropertyNotUppercase(sourceLineNumbers, node.Name.LocalName, "Property", actionProperty)); | ||
5270 | } | ||
5271 | |||
5272 | if (null == minimum && null == maximum) | ||
5273 | { | ||
5274 | this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Minimum", "Maximum")); | ||
5275 | } | ||
5276 | |||
5277 | this.Core.ParseForExtensionElements(node); | ||
5278 | |||
5279 | if (!this.Core.EncounteredError) | ||
5280 | { | ||
5281 | var tuple = new UpgradeTuple(sourceLineNumbers) | ||
5282 | { | ||
5283 | UpgradeCode = upgradeId, | ||
5284 | VersionMin = minimum, | ||
5285 | VersionMax = maximum, | ||
5286 | Language = language, | ||
5287 | ExcludeLanguages = excludeLanguages, | ||
5288 | IgnoreRemoveFailures = ignoreFailures, | ||
5289 | VersionMaxInclusive = includeMax, | ||
5290 | VersionMinInclusive = includeMin, | ||
5291 | MigrateFeatures = migrateFeatures, | ||
5292 | OnlyDetect = onlyDetect, | ||
5293 | Remove = removeFeatures, | ||
5294 | ActionProperty = actionProperty | ||
5295 | }; | ||
5296 | |||
5297 | this.Core.AddTuple(tuple); | ||
5298 | |||
5299 | // Ensure the action property is secure. | ||
5300 | this.AddWixPropertyRow(sourceLineNumbers, new Identifier(actionProperty, AccessModifier.Private), false, true, false); | ||
5301 | |||
5302 | // Ensure that RemoveExistingProducts is authored in InstallExecuteSequence | ||
5303 | // if at least one row in Upgrade table lacks the OnlyDetect attribute. | ||
5304 | if (onlyDetect) | ||
5305 | { | ||
5306 | this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", "RemoveExistingProducts"); | ||
5307 | } | ||
5308 | } | ||
5309 | } | ||
5310 | |||
5311 | /// <summary> | ||
5312 | /// Parses a verb element. | ||
5313 | /// </summary> | ||
5314 | /// <param name="node">Element to parse.</param> | ||
5315 | /// <param name="extension">Extension verb is releated to.</param> | ||
5316 | /// <param name="progId">Optional progId for extension.</param> | ||
5317 | /// <param name="componentId">Identifier for parent component.</param> | ||
5318 | /// <param name="advertise">Flag if verb is advertised.</param> | ||
5319 | private void ParseVerbElement(XElement node, string extension, string progId, string componentId, YesNoType advertise) | ||
5320 | { | ||
5321 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5322 | string id = null; | ||
5323 | string argument = null; | ||
5324 | string command = null; | ||
5325 | var sequence = CompilerConstants.IntegerNotSet; | ||
5326 | string target = null; | ||
5327 | string targetFile = null; | ||
5328 | string targetProperty = null; | ||
5329 | |||
5330 | foreach (var attrib in node.Attributes()) | ||
5331 | { | ||
5332 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5333 | { | ||
5334 | switch (attrib.Name.LocalName) | ||
5335 | { | ||
5336 | case "Id": | ||
5337 | id = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5338 | break; | ||
5339 | case "Argument": | ||
5340 | argument = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5341 | break; | ||
5342 | case "Command": | ||
5343 | command = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5344 | break; | ||
5345 | case "Sequence": | ||
5346 | sequence = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, Int16.MaxValue); | ||
5347 | break; | ||
5348 | case "Target": | ||
5349 | target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5350 | this.Core.Write(WarningMessages.DeprecatedAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "TargetFile", "TargetProperty")); | ||
5351 | break; | ||
5352 | case "TargetFile": | ||
5353 | targetFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5354 | this.Core.CreateSimpleReference(sourceLineNumbers, "File", targetFile); | ||
5355 | break; | ||
5356 | case "TargetProperty": | ||
5357 | targetProperty = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
5358 | break; | ||
5359 | default: | ||
5360 | this.Core.UnexpectedAttribute(node, attrib); | ||
5361 | break; | ||
5362 | } | ||
5363 | } | ||
5364 | else | ||
5365 | { | ||
5366 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5367 | } | ||
5368 | } | ||
5369 | |||
5370 | if (null == id) | ||
5371 | { | ||
5372 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5373 | } | ||
5374 | |||
5375 | if (null != target && null != targetFile) | ||
5376 | { | ||
5377 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetFile")); | ||
5378 | } | ||
5379 | |||
5380 | if (null != target && null != targetProperty) | ||
5381 | { | ||
5382 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetProperty")); | ||
5383 | } | ||
5384 | |||
5385 | if (null != targetFile && null != targetProperty) | ||
5386 | { | ||
5387 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty")); | ||
5388 | } | ||
5389 | |||
5390 | this.Core.ParseForExtensionElements(node); | ||
5391 | |||
5392 | if (YesNoType.Yes == advertise) | ||
5393 | { | ||
5394 | if (null != target) | ||
5395 | { | ||
5396 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "Target")); | ||
5397 | } | ||
5398 | |||
5399 | if (null != targetFile) | ||
5400 | { | ||
5401 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetFile")); | ||
5402 | } | ||
5403 | |||
5404 | if (null != targetProperty) | ||
5405 | { | ||
5406 | this.Core.Write(ErrorMessages.IllegalAttributeWhenAdvertised(sourceLineNumbers, node.Name.LocalName, "TargetProperty")); | ||
5407 | } | ||
5408 | |||
5409 | if (!this.Core.EncounteredError) | ||
5410 | { | ||
5411 | var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Verb); | ||
5412 | row.Set(0, extension); | ||
5413 | row.Set(1, id); | ||
5414 | if (CompilerConstants.IntegerNotSet != sequence) | ||
5415 | { | ||
5416 | row.Set(2, sequence); | ||
5417 | } | ||
5418 | row.Set(3, command); | ||
5419 | row.Set(4, argument); | ||
5420 | } | ||
5421 | } | ||
5422 | else if (YesNoType.No == advertise) | ||
5423 | { | ||
5424 | if (CompilerConstants.IntegerNotSet != sequence) | ||
5425 | { | ||
5426 | this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Sequence", "Advertise", "no")); | ||
5427 | } | ||
5428 | |||
5429 | if (null == target && null == targetFile && null == targetProperty) | ||
5430 | { | ||
5431 | this.Core.Write(ErrorMessages.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFile", "TargetProperty", "Advertise", "no")); | ||
5432 | } | ||
5433 | |||
5434 | if (null == target) | ||
5435 | { | ||
5436 | if (null != targetFile) | ||
5437 | { | ||
5438 | target = String.Concat("\"[#", targetFile, "]\""); | ||
5439 | } | ||
5440 | |||
5441 | if (null != targetProperty) | ||
5442 | { | ||
5443 | target = String.Concat("\"[", targetProperty, "]\""); | ||
5444 | } | ||
5445 | } | ||
5446 | |||
5447 | if (null != argument) | ||
5448 | { | ||
5449 | target = String.Concat(target, " ", argument); | ||
5450 | } | ||
5451 | |||
5452 | var prefix = (null != progId ? progId : String.Concat(".", extension)); | ||
5453 | |||
5454 | if (null != command) | ||
5455 | { | ||
5456 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(prefix, "\\shell\\", id), String.Empty, command, componentId); | ||
5457 | } | ||
5458 | |||
5459 | this.Core.CreateRegistryRow(sourceLineNumbers, RegistryRootType.ClassesRoot, String.Concat(prefix, "\\shell\\", id, "\\command"), String.Empty, target, componentId); | ||
5460 | } | ||
5461 | } | ||
5462 | |||
5463 | /// <summary> | ||
5464 | /// Parses a Wix element. | ||
5465 | /// </summary> | ||
5466 | /// <param name="node">Element to parse.</param> | ||
5467 | private void ParseWixElement(XElement node) | ||
5468 | { | ||
5469 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5470 | string requiredVersion = null; | ||
5471 | |||
5472 | foreach (var attrib in node.Attributes()) | ||
5473 | { | ||
5474 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5475 | { | ||
5476 | switch (attrib.Name.LocalName) | ||
5477 | { | ||
5478 | case "RequiredVersion": | ||
5479 | requiredVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); | ||
5480 | break; | ||
5481 | default: | ||
5482 | this.Core.UnexpectedAttribute(node, attrib); | ||
5483 | break; | ||
5484 | } | ||
5485 | } | ||
5486 | else | ||
5487 | { | ||
5488 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5489 | } | ||
5490 | } | ||
5491 | |||
5492 | if (null != requiredVersion) | ||
5493 | { | ||
5494 | this.Core.VerifyRequiredVersion(sourceLineNumbers, requiredVersion); | ||
5495 | } | ||
5496 | |||
5497 | foreach (var child in node.Elements()) | ||
5498 | { | ||
5499 | if (CompilerCore.WixNamespace == child.Name.Namespace) | ||
5500 | { | ||
5501 | switch (child.Name.LocalName) | ||
5502 | { | ||
5503 | case "Bundle": | ||
5504 | this.ParseBundleElement(child); | ||
5505 | break; | ||
5506 | case "Fragment": | ||
5507 | this.ParseFragmentElement(child); | ||
5508 | break; | ||
5509 | case "Module": | ||
5510 | this.ParseModuleElement(child); | ||
5511 | break; | ||
5512 | case "PatchCreation": | ||
5513 | this.ParsePatchCreationElement(child); | ||
5514 | break; | ||
5515 | case "Product": | ||
5516 | this.ParseProductElement(child); | ||
5517 | break; | ||
5518 | case "Patch": | ||
5519 | this.ParsePatchElement(child); | ||
5520 | break; | ||
5521 | default: | ||
5522 | this.Core.UnexpectedElement(node, child); | ||
5523 | break; | ||
5524 | } | ||
5525 | } | ||
5526 | else | ||
5527 | { | ||
5528 | this.Core.ParseExtensionElement(node, child); | ||
5529 | } | ||
5530 | } | ||
5531 | } | ||
5532 | |||
5533 | /// <summary> | ||
5534 | /// Parses a WixVariable element. | ||
5535 | /// </summary> | ||
5536 | /// <param name="node">Element to parse.</param> | ||
5537 | private void ParseWixVariableElement(XElement node) | ||
5538 | { | ||
5539 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
5540 | Identifier id = null; | ||
5541 | var overridable = false; | ||
5542 | string value = null; | ||
5543 | |||
5544 | foreach (var attrib in node.Attributes()) | ||
5545 | { | ||
5546 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
5547 | { | ||
5548 | switch (attrib.Name.LocalName) | ||
5549 | { | ||
5550 | case "Id": | ||
5551 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
5552 | break; | ||
5553 | case "Overridable": | ||
5554 | overridable = (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)); | ||
5555 | break; | ||
5556 | case "Value": | ||
5557 | value = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); | ||
5558 | break; | ||
5559 | default: | ||
5560 | this.Core.UnexpectedAttribute(node, attrib); | ||
5561 | break; | ||
5562 | } | ||
5563 | } | ||
5564 | else | ||
5565 | { | ||
5566 | this.Core.ParseExtensionAttribute(node, attrib); | ||
5567 | } | ||
5568 | } | ||
5569 | |||
5570 | if (null == id) | ||
5571 | { | ||
5572 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
5573 | } | ||
5574 | |||
5575 | if (null == value) | ||
5576 | { | ||
5577 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value")); | ||
5578 | } | ||
5579 | |||
5580 | this.Core.ParseForExtensionElements(node); | ||
5581 | |||
5582 | if (!this.Core.EncounteredError) | ||
5583 | { | ||
5584 | var wixVariableRow = (WixVariableTuple)this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixVariable, id); | ||
5585 | wixVariableRow.Value = value; | ||
5586 | wixVariableRow.Overridable = overridable; | ||
5587 | } | ||
5588 | } | ||
5589 | |||
5590 | private CompressionLevel? ParseCompressionLevel(SourceLineNumber sourceLineNumbers, XElement node, XAttribute attribute) | ||
5591 | { | ||
5592 | var compressionLevel = this.Core.GetAttributeValue(sourceLineNumbers, attribute); | ||
5593 | switch (compressionLevel) | ||
5594 | { | ||
5595 | case "high": | ||
5596 | return CompressionLevel.High; | ||
5597 | case "low": | ||
5598 | return CompressionLevel.Low; | ||
5599 | case "medium": | ||
5600 | return CompressionLevel.Medium; | ||
5601 | case "mszip": | ||
5602 | return CompressionLevel.Mszip; | ||
5603 | case "none": | ||
5604 | return CompressionLevel.None; | ||
5605 | case "": | ||
5606 | break; | ||
5607 | default: | ||
5608 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attribute.Name.LocalName, compressionLevel, "high", "low", "medium", "mszip", "none")); | ||
5609 | break; | ||
5610 | } | ||
5611 | |||
5612 | return null; | ||
5613 | } | ||
5614 | } | ||
5615 | } | ||