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