aboutsummaryrefslogtreecommitdiff
path: root/src/wixext/UtilCompiler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/wixext/UtilCompiler.cs')
-rw-r--r--src/wixext/UtilCompiler.cs3911
1 files changed, 3911 insertions, 0 deletions
diff --git a/src/wixext/UtilCompiler.cs b/src/wixext/UtilCompiler.cs
new file mode 100644
index 00000000..da48e412
--- /dev/null
+++ b/src/wixext/UtilCompiler.cs
@@ -0,0 +1,3911 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Util
4{
5 using System;
6 using System.Collections;
7 using System.Collections.Generic;
8 using System.Globalization;
9 using System.Linq;
10 using System.Text;
11 using System.Text.RegularExpressions;
12 using System.Xml.Linq;
13 using WixToolset.Data;
14 using WixToolset.Extensibility;
15
16 /// <summary>
17 /// The compiler for the WiX Toolset Utility Extension.
18 /// </summary>
19 public sealed class UtilCompiler : BaseCompilerExtension
20 {
21 // user creation attributes definitions (from sca.h)
22 internal const int UserDontExpirePasswrd = 0x00000001;
23 internal const int UserPasswdCantChange = 0x00000002;
24 internal const int UserPasswdChangeReqdOnLogin = 0x00000004;
25 internal const int UserDisableAccount = 0x00000008;
26 internal const int UserFailIfExists = 0x00000010;
27 internal const int UserUpdateIfExists = 0x00000020;
28 internal const int UserLogonAsService = 0x00000040;
29 internal const int UserLogonAsBatchJob = 0x00000080;
30
31 internal const int UserDontRemoveOnUninstall = 0x00000100;
32 internal const int UserDontCreateUser = 0x00000200;
33 internal const int UserNonVital = 0x00000400;
34
35 [Flags]
36 internal enum WixFileSearchAttributes
37 {
38 Default = 0x001,
39 MinVersionInclusive = 0x002,
40 MaxVersionInclusive = 0x004,
41 MinSizeInclusive = 0x008,
42 MaxSizeInclusive = 0x010,
43 MinDateInclusive = 0x020,
44 MaxDateInclusive = 0x040,
45 WantVersion = 0x080,
46 WantExists = 0x100,
47 IsDirectory = 0x200,
48 }
49
50 internal enum WixRegistrySearchFormat
51 {
52 Raw,
53 Compatible,
54 }
55
56 [Flags]
57 internal enum WixRegistrySearchAttributes
58 {
59 Raw = 0x01,
60 Compatible = 0x02,
61 ExpandEnvironmentVariables = 0x04,
62 WantValue = 0x08,
63 WantExists = 0x10,
64 Win64 = 0x20,
65 }
66
67 internal enum WixComponentSearchAttributes
68 {
69 KeyPath = 0x1,
70 State = 0x2,
71 WantDirectory = 0x4,
72 }
73
74 [Flags]
75 internal enum WixProductSearchAttributes
76 {
77 Version = 0x01,
78 Language = 0x02,
79 State = 0x04,
80 Assignment = 0x08,
81 UpgradeCode = 0x10,
82 }
83
84 internal enum WixRestartResourceAttributes
85 {
86 Filename = 1,
87 ProcessName,
88 ServiceName,
89 TypeMask = 0xf,
90 }
91
92 internal enum WixRemoveFolderExOn
93 {
94 Install = 1,
95 Uninstall = 2,
96 Both = 3,
97 }
98
99 private static readonly Regex FindPropertyBrackets = new Regex(@"\[(?!\\|\])|(?<!\[\\\]|\[\\|\\\[)\]", RegexOptions.ExplicitCapture | RegexOptions.Compiled);
100
101 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/util";
102
103 /// <summary>
104 /// Types of Internet shortcuts.
105 /// </summary>
106 public enum InternetShortcutType
107 {
108 /// <summary>Create a .lnk file.</summary>
109 Link = 0,
110
111 /// <summary>Create a .url file.</summary>
112 Url,
113 }
114
115 /// <summary>
116 /// Types of permission setting methods.
117 /// </summary>
118 private enum PermissionType
119 {
120 /// <summary>LockPermissions (normal) type permission setting.</summary>
121 LockPermissions,
122
123 /// <summary>FileSharePermissions type permission setting.</summary>
124 FileSharePermissions,
125
126 /// <summary>SecureObjects type permission setting.</summary>
127 SecureObjects,
128 }
129
130 /// <summary>
131 /// Processes an element for the Compiler.
132 /// </summary>
133 /// <param name="parentElement">Parent element of element to process.</param>
134 /// <param name="element">Element to process.</param>
135 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
136 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
137 {
138 this.ParsePossibleKeyPathElement(intermediate, section, parentElement, element, context);
139 }
140
141 /// <summary>
142 /// Processes an element for the Compiler.
143 /// </summary>
144 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
145 /// <param name="parentElement">Parent element of element to process.</param>
146 /// <param name="element">Element to process.</param>
147 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
148 public override ComponentKeyPath ParsePossibleKeyPathElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
149 {
150 ComponentKeyPath possibleKeyPath = null;
151
152 switch (parentElement.Name.LocalName)
153 {
154 case "CreateFolder":
155 string createFolderId = context["DirectoryId"];
156 string createFolderComponentId = context["ComponentId"];
157
158 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
159 bool createFolderWin64 = Boolean.Parse(context["Win64"]);
160
161 switch (element.Name.LocalName)
162 {
163 case "PermissionEx":
164 this.ParsePermissionExElement(intermediate, section, element, createFolderId, createFolderComponentId, createFolderWin64, "CreateFolder");
165 break;
166 default:
167 this.ParseHelper.UnexpectedElement(parentElement, element);
168 break;
169 }
170 break;
171 case "Component":
172 string componentId = context["ComponentId"];
173 string directoryId = context["DirectoryId"];
174 bool componentWin64 = Boolean.Parse(context["Win64"]);
175
176 switch (element.Name.LocalName)
177 {
178 case "EventSource":
179 possibleKeyPath = this.ParseEventSourceElement(intermediate, section, element, componentId);
180 break;
181 case "FileShare":
182 this.ParseFileShareElement(intermediate, section, element, componentId, directoryId);
183 break;
184 case "InternetShortcut":
185 this.ParseInternetShortcutElement(intermediate, section, element, componentId, directoryId);
186 break;
187 case "PerformanceCategory":
188 this.ParsePerformanceCategoryElement(intermediate, section, element, componentId);
189 break;
190 case "RemoveFolderEx":
191 this.ParseRemoveFolderExElement(intermediate, section, element, componentId);
192 break;
193 case "RestartResource":
194 this.ParseRestartResourceElement(intermediate, section, element, componentId);
195 break;
196 case "ServiceConfig":
197 this.ParseServiceConfigElement(intermediate, section, element, componentId, "Component", null);
198 break;
199 case "TouchFile":
200 this.ParseTouchFileElement(intermediate, section, element, componentId, componentWin64);
201 break;
202 case "User":
203 this.ParseUserElement(intermediate, section, element, componentId);
204 break;
205 case "XmlFile":
206 this.ParseXmlFileElement(intermediate, section, element, componentId);
207 break;
208 case "XmlConfig":
209 this.ParseXmlConfigElement(intermediate, section, element, componentId, false);
210 break;
211 default:
212 this.ParseHelper.UnexpectedElement(parentElement, element);
213 break;
214 }
215 break;
216 case "File":
217 string fileId = context["FileId"];
218 string fileComponentId = context["ComponentId"];
219
220 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
221 bool fileWin64 = Boolean.Parse(context["Win64"]);
222
223 switch (element.Name.LocalName)
224 {
225 case "PerfCounter":
226 this.ParsePerfCounterElement(intermediate, section, element, fileComponentId, fileId);
227 break;
228 case "PermissionEx":
229 this.ParsePermissionExElement(intermediate, section, element, fileId, fileComponentId, fileWin64, "File");
230 break;
231 case "PerfCounterManifest":
232 this.ParsePerfCounterManifestElement(intermediate, section, element, fileComponentId, fileId);
233 break;
234 case "EventManifest":
235 this.ParseEventManifestElement(intermediate, section, element, fileComponentId, fileId);
236 break;
237 case "FormatFile":
238 this.ParseFormatFileElement(intermediate, section, element, fileId, fileWin64);
239 break;
240 default:
241 this.ParseHelper.UnexpectedElement(parentElement, element);
242 break;
243 }
244 break;
245 case "Bundle":
246 case "Fragment":
247 case "Module":
248 case "Product":
249 switch (element.Name.LocalName)
250 {
251 case "CloseApplication":
252 this.ParseCloseApplicationElement(intermediate, section, element);
253 break;
254 case "Group":
255 this.ParseGroupElement(intermediate, section, element, null);
256 break;
257 case "RestartResource":
258 // Currently not supported for Bundles.
259 if (parentElement.Name.LocalName != "Bundle")
260 {
261 this.ParseRestartResourceElement(intermediate, section, element, null);
262 }
263 else
264 {
265 this.ParseHelper.UnexpectedElement(parentElement, element);
266 }
267 break;
268 case "User":
269 this.ParseUserElement(intermediate, section, element, null);
270 break;
271 case "ComponentSearch":
272 case "ComponentSearchRef":
273 case "DirectorySearch":
274 case "DirectorySearchRef":
275 case "FileSearch":
276 case "FileSearchRef":
277 case "ProductSearch":
278 case "ProductSearchRef":
279 case "RegistrySearch":
280 case "RegistrySearchRef":
281 // These will eventually be supported under Module/Product, but are not yet.
282 if (parentElement.Name.LocalName == "Bundle" || parentElement.Name.LocalName == "Fragment")
283 {
284 // TODO: When these are supported by all section types, move
285 // these out of the nested switch and back into the surrounding one.
286 switch (element.Name.LocalName)
287 {
288 case "ComponentSearch":
289 this.ParseComponentSearchElement(intermediate, section, element);
290 break;
291 case "ComponentSearchRef":
292 this.ParseComponentSearchRefElement(intermediate, section, element);
293 break;
294 case "DirectorySearch":
295 this.ParseDirectorySearchElement(intermediate, section, element);
296 break;
297 case "DirectorySearchRef":
298 this.ParseWixSearchRefElement(intermediate, section, element);
299 break;
300 case "FileSearch":
301 this.ParseFileSearchElement(intermediate, section, element);
302 break;
303 case "FileSearchRef":
304 this.ParseWixSearchRefElement(intermediate, section, element);
305 break;
306 case "ProductSearch":
307 this.ParseProductSearchElement(intermediate, section, element);
308 break;
309 case "ProductSearchRef":
310 this.ParseWixSearchRefElement(intermediate, section, element);
311 break;
312 case "RegistrySearch":
313 this.ParseRegistrySearchElement(intermediate, section, element);
314 break;
315 case "RegistrySearchRef":
316 this.ParseWixSearchRefElement(intermediate, section, element);
317 break;
318 }
319 }
320 else
321 {
322 this.ParseHelper.UnexpectedElement(parentElement, element);
323 }
324 break;
325 default:
326 this.ParseHelper.UnexpectedElement(parentElement, element);
327 break;
328 }
329 break;
330 case "Registry":
331 case "RegistryKey":
332 case "RegistryValue":
333 string registryId = context["RegistryId"];
334 string registryComponentId = context["ComponentId"];
335
336 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
337 bool registryWin64 = Boolean.Parse(context["Win64"]);
338
339 switch (element.Name.LocalName)
340 {
341 case "PermissionEx":
342 this.ParsePermissionExElement(intermediate, section, element, registryId, registryComponentId, registryWin64, "Registry");
343 break;
344 default:
345 this.ParseHelper.UnexpectedElement(parentElement, element);
346 break;
347 }
348 break;
349 case "ServiceInstall":
350 string serviceInstallId = context["ServiceInstallId"];
351 string serviceInstallName = context["ServiceInstallName"];
352 string serviceInstallComponentId = context["ServiceInstallComponentId"];
353
354 // If this doesn't parse successfully, something really odd is going on, so let the exception get thrown
355 bool serviceInstallWin64 = Boolean.Parse(context["Win64"]);
356
357 switch (element.Name.LocalName)
358 {
359 case "PermissionEx":
360 this.ParsePermissionExElement(intermediate, section, element, serviceInstallId, serviceInstallComponentId, serviceInstallWin64, "ServiceInstall");
361 break;
362 case "ServiceConfig":
363 this.ParseServiceConfigElement(intermediate, section, element, serviceInstallComponentId, "ServiceInstall", serviceInstallName);
364 break;
365 default:
366 this.ParseHelper.UnexpectedElement(parentElement, element);
367 break;
368 }
369 break;
370 default:
371 this.ParseHelper.UnexpectedElement(parentElement, element);
372 break;
373 }
374
375 return possibleKeyPath;
376 }
377
378 /// <summary>
379 /// Parses the common search attributes shared across all searches.
380 /// </summary>
381 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
382 /// <param name="attrib">Attribute to parse.</param>
383 /// <param name="id">Value of the Id attribute.</param>
384 /// <param name="variable">Value of the Variable attribute.</param>
385 /// <param name="condition">Value of the Condition attribute.</param>
386 /// <param name="after">Value of the After attribute.</param>
387 private void ParseCommonSearchAttributes(SourceLineNumber sourceLineNumbers, XAttribute attrib, ref Identifier id, ref string variable, ref string condition, ref string after)
388 {
389 switch (attrib.Name.LocalName)
390 {
391 case "Id":
392 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
393 break;
394 case "Variable":
395 variable = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
396 // TODO: handle standard bundle variables
397 break;
398 case "Condition":
399 condition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
400 break;
401 case "After":
402 after = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
403 break;
404 default:
405 System.Diagnostics.Debug.Assert(false);
406 break;
407 }
408 }
409
410 /// <summary>
411 /// Parses a ComponentSearch element.
412 /// </summary>
413 /// <param name="element">Element to parse.</param>
414 private void ParseComponentSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
415 {
416 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
417 Identifier id = null;
418 string variable = null;
419 string condition = null;
420 string after = null;
421 string guid = null;
422 string productCode = null;
423 Serialize.ComponentSearch.ResultType result = Serialize.ComponentSearch.ResultType.NotSet;
424
425 foreach (XAttribute attrib in element.Attributes())
426 {
427 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
428 {
429 switch (attrib.Name.LocalName)
430 {
431 case "Id":
432 case "Variable":
433 case "Condition":
434 case "After":
435 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
436 break;
437 case "Guid":
438 guid = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
439 break;
440 case "ProductCode":
441 productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib);
442 break;
443 case "Result":
444 string resultValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
445 if (!Serialize.ComponentSearch.TryParseResultType(resultValue, out result))
446 {
447 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName,
448 resultValue,
449 Serialize.ComponentSearch.ResultType.directory.ToString(),
450 Serialize.ComponentSearch.ResultType.state.ToString(),
451 Serialize.ComponentSearch.ResultType.keyPath.ToString()));
452 }
453 break;
454 default:
455 this.ParseHelper.UnexpectedAttribute(element, attrib);
456 break;
457 }
458 }
459 else
460 {
461 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
462 }
463 }
464
465 if (null == variable)
466 {
467 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
468 }
469
470 if (null == guid)
471 {
472 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Guid"));
473 }
474
475 if (null == id)
476 {
477 id = this.ParseHelper.CreateIdentifier("wcs", variable, condition, after, guid, productCode, result.ToString());
478 }
479
480 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
481
482 if (!this.Messaging.EncounteredError)
483 {
484 this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
485 if (after != null)
486 {
487 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
488 // TODO: We're currently defaulting to "always run after", which we will need to change...
489 this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
490 }
491
492 WixComponentSearchAttributes attributes = WixComponentSearchAttributes.KeyPath;
493 switch (result)
494 {
495 case Serialize.ComponentSearch.ResultType.directory:
496 attributes = WixComponentSearchAttributes.WantDirectory;
497 break;
498 case Serialize.ComponentSearch.ResultType.keyPath:
499 attributes = WixComponentSearchAttributes.KeyPath;
500 break;
501 case Serialize.ComponentSearch.ResultType.state:
502 attributes = WixComponentSearchAttributes.State;
503 break;
504 }
505
506 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixComponentSearch", id);
507 row.Set(1, guid);
508 row.Set(2, productCode);
509 row.Set(3, (int)attributes);
510 }
511 }
512
513 /// <summary>
514 /// Parses a ComponentSearchRef element
515 /// </summary>
516 /// <param name="element">Element to parse.</param>
517 private void ParseComponentSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
518 {
519 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
520 string refId = null;
521
522 foreach (XAttribute attrib in element.Attributes())
523 {
524 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
525 {
526 switch (attrib.Name.LocalName)
527 {
528 case "Id":
529 refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
530 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixComponentSearch", refId);
531 break;
532 default:
533 this.ParseHelper.UnexpectedAttribute(element, attrib);
534 break;
535 }
536 }
537 else
538 {
539 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
540 }
541 }
542
543 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
544 }
545
546 /// <summary>
547 /// Parses an event source element.
548 /// </summary>
549 /// <param name="element">Element to parse.</param>
550 /// <param name="componentId">Identifier of parent component.</param>
551 private ComponentKeyPath ParseEventSourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
552 {
553 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
554 string sourceName = null;
555 string logName = null;
556 string categoryMessageFile = null;
557 int categoryCount = CompilerConstants.IntegerNotSet;
558 string eventMessageFile = null;
559 string parameterMessageFile = null;
560 int typesSupported = 0;
561 bool isKeyPath = false;
562
563 foreach (XAttribute attrib in element.Attributes())
564 {
565 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
566 {
567 switch (attrib.Name.LocalName)
568 {
569 case "CategoryCount":
570 categoryCount = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
571 break;
572 case "CategoryMessageFile":
573 categoryMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
574 break;
575 case "EventMessageFile":
576 eventMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
577 break;
578 case "KeyPath":
579 isKeyPath = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
580 break;
581 case "Log":
582 logName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
583 if ("Security" == logName)
584 {
585 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, logName, "Application", "System", "<customEventLog>"));
586 }
587 break;
588 case "Name":
589 sourceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
590 break;
591 case "ParameterMessageFile":
592 parameterMessageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
593 break;
594 case "SupportsErrors":
595 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
596 {
597 typesSupported |= 0x01; // EVENTLOG_ERROR_TYPE
598 }
599 break;
600 case "SupportsFailureAudits":
601 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
602 {
603 typesSupported |= 0x10; // EVENTLOG_AUDIT_FAILURE
604 }
605 break;
606 case "SupportsInformationals":
607 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
608 {
609 typesSupported |= 0x04; // EVENTLOG_INFORMATION_TYPE
610 }
611 break;
612 case "SupportsSuccessAudits":
613 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
614 {
615 typesSupported |= 0x08; // EVENTLOG_AUDIT_SUCCESS
616 }
617 break;
618 case "SupportsWarnings":
619 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
620 {
621 typesSupported |= 0x02; // EVENTLOG_WARNING_TYPE
622 }
623 break;
624 default:
625 this.ParseHelper.UnexpectedAttribute(element, attrib);
626 break;
627 }
628 }
629 else
630 {
631 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
632 }
633 }
634
635 if (null == sourceName)
636 {
637 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
638 }
639
640 if (null == logName)
641 {
642 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventLog"));
643 }
644
645 if (null == eventMessageFile)
646 {
647 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "EventMessageFile"));
648 }
649
650 if (null == categoryMessageFile && 0 < categoryCount)
651 {
652 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryCount", "CategoryMessageFile"));
653 }
654
655 if (null != categoryMessageFile && CompilerConstants.IntegerNotSet == categoryCount)
656 {
657 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "CategoryMessageFile", "CategoryCount"));
658 }
659
660 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
661
662 int registryRoot = 2; // MsiInterop.MsidbRegistryRootLocalMachine
663 string eventSourceKey = String.Format(@"SYSTEM\CurrentControlSet\Services\EventLog\{0}\{1}", logName, sourceName);
664 Identifier id = this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, eventSourceKey, "EventMessageFile", String.Concat("#%", eventMessageFile), componentId, false);
665
666 if (null != categoryMessageFile)
667 {
668 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, eventSourceKey, "CategoryMessageFile", String.Concat("#%", categoryMessageFile), componentId, false);
669 }
670
671 if (CompilerConstants.IntegerNotSet != categoryCount)
672 {
673 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, eventSourceKey, "CategoryCount", String.Concat("#", categoryCount), componentId, false);
674 }
675
676 if (null != parameterMessageFile)
677 {
678 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, eventSourceKey, "ParameterMessageFile", String.Concat("#%", parameterMessageFile), componentId, false);
679 }
680
681 if (0 != typesSupported)
682 {
683 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, eventSourceKey, "TypesSupported", String.Concat("#", typesSupported), componentId, false);
684 }
685
686 return new ComponentKeyPath() { Id = id.Id, Explicit = isKeyPath, Type = ComponentKeyPathType.Registry };
687 }
688
689 /// <summary>
690 /// Parses a close application element.
691 /// </summary>
692 /// <param name="element">Element to parse.</param>
693 private void ParseCloseApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element)
694 {
695 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
696 string condition = null;
697 string description = null;
698 string target = null;
699 string property = null;
700 Identifier id = null;
701 int attributes = 2; // default to CLOSEAPP_ATTRIBUTE_REBOOTPROMPT enabled
702 int sequence = CompilerConstants.IntegerNotSet;
703 int terminateExitCode = CompilerConstants.IntegerNotSet;
704 int timeout = CompilerConstants.IntegerNotSet;
705
706 foreach (XAttribute attrib in element.Attributes())
707 {
708 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
709 {
710 switch (attrib.Name.LocalName)
711 {
712 case "Id":
713 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
714 break;
715 case "Description":
716 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
717 break;
718 case "Property":
719 property = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
720 break;
721 case "Sequence":
722 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
723 break;
724 case "Timeout":
725 timeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
726 break;
727 case "Target":
728 target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
729 break;
730 case "CloseMessage":
731 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
732 {
733 attributes |= 1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
734 }
735 else
736 {
737 attributes &= ~1; // CLOSEAPP_ATTRIBUTE_CLOSEMESSAGE
738 }
739 break;
740 case "EndSessionMessage":
741 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
742 {
743 attributes |= 8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
744 }
745 else
746 {
747 attributes &= ~8; // CLOSEAPP_ATTRIBUTE_ENDSESSIONMESSAGE
748 }
749 break;
750 case "PromptToContinue":
751 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
752 {
753 attributes |= 0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
754 }
755 else
756 {
757 attributes &= ~0x40; // CLOSEAPP_ATTRIBUTE_PROMPTTOCONTINUE
758 }
759 break;
760 case "RebootPrompt":
761 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
762 {
763 attributes |= 2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
764 }
765 else
766 {
767 attributes &= ~2; // CLOSEAPP_ATTRIBUTE_REBOOTPROMPT
768 }
769 break;
770 case "ElevatedCloseMessage":
771 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
772 {
773 attributes |= 4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
774 }
775 else
776 {
777 attributes &= ~4; // CLOSEAPP_ATTRIBUTE_ELEVATEDCLOSEMESSAGE
778 }
779 break;
780 case "ElevatedEndSessionMessage":
781 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
782 {
783 attributes |= 0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
784 }
785 else
786 {
787 attributes &= ~0x10; // CLOSEAPP_ATTRIBUTE_ELEVATEDENDSESSIONMESSAGE
788 }
789 break;
790 case "TerminateProcess":
791 terminateExitCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
792 attributes |= 0x20; // CLOSEAPP_ATTRIBUTE_TERMINATEPROCESS
793 break;
794 default:
795 this.ParseHelper.UnexpectedAttribute(element, attrib);
796 break;
797 }
798 }
799 else
800 {
801 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
802 }
803 }
804
805 if (null == target)
806 {
807 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
808 }
809 else if (null == id)
810 {
811 id = this.ParseHelper.CreateIdentifier("ca", target);
812 }
813
814 if (String.IsNullOrEmpty(description) && 0x40 == (attributes & 0x40))
815 {
816 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "PromptToContinue", "yes", "Description"));
817 }
818
819 if (0x22 == (attributes & 0x22))
820 {
821 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "TerminateProcess", "RebootPrompt", "yes"));
822 }
823
824 // get the condition from the inner text of the element
825 condition = this.ParseHelper.GetConditionInnerText(element);
826
827 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
828
829 // Reference CustomAction since nothing will happen without it
830 if (this.Context.Platform == Platform.ARM)
831 {
832 // Ensure ARM version of the CA is referenced
833 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixCloseApplications_ARM");
834 }
835 else
836 {
837 // All other supported platforms use x86
838 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixCloseApplications");
839 }
840
841 if (!this.Messaging.EncounteredError)
842 {
843 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixCloseApplication", id);
844 row.Set(1, target);
845 row.Set(2, description);
846 row.Set(3, condition);
847 row.Set(4, attributes);
848 if (CompilerConstants.IntegerNotSet != sequence)
849 {
850 row.Set(5, sequence);
851 }
852 row.Set(6, property);
853 if (CompilerConstants.IntegerNotSet != terminateExitCode)
854 {
855 row.Set(7, terminateExitCode);
856 }
857 if (CompilerConstants.IntegerNotSet != timeout)
858 {
859 row.Set(8, timeout * 1000); // make the timeout milliseconds in the table.
860 }
861 }
862 }
863
864 /// <summary>
865 /// Parses a DirectorySearch element.
866 /// </summary>
867 /// <param name="element">Element to parse.</param>
868 private void ParseDirectorySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
869 {
870 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
871 Identifier id = null;
872 string variable = null;
873 string condition = null;
874 string after = null;
875 string path = null;
876 Serialize.DirectorySearch.ResultType result = Serialize.DirectorySearch.ResultType.NotSet;
877
878 foreach (XAttribute attrib in element.Attributes())
879 {
880 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
881 {
882 switch (attrib.Name.LocalName)
883 {
884 case "Id":
885 case "Variable":
886 case "Condition":
887 case "After":
888 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
889 break;
890 case "Path":
891 path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
892 break;
893 case "Result":
894 string resultValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
895 if (!Serialize.DirectorySearch.TryParseResultType(resultValue, out result))
896 {
897 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName,
898 resultValue, Serialize.DirectorySearch.ResultType.exists.ToString()));
899 }
900 break;
901 default:
902 this.ParseHelper.UnexpectedAttribute(element, attrib);
903 break;
904 }
905 }
906 else
907 {
908 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
909 }
910 }
911
912 if (null == variable)
913 {
914 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
915 }
916
917 if (null == path)
918 {
919 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
920 }
921
922 if (null == id)
923 {
924 id = this.ParseHelper.CreateIdentifier("wds", variable, condition, after, path, result.ToString());
925 }
926
927 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
928
929 if (!this.Messaging.EncounteredError)
930 {
931 this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
932 if (after != null)
933 {
934 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
935 // TODO: We're currently defaulting to "always run after", which we will need to change...
936 this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
937 }
938
939 WixFileSearchAttributes attributes = WixFileSearchAttributes.IsDirectory;
940 switch (result)
941 {
942 case Serialize.DirectorySearch.ResultType.exists:
943 attributes |= WixFileSearchAttributes.WantExists;
944 break;
945 }
946
947 this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes);
948 }
949 }
950
951 /// <summary>
952 /// Parses a DirectorySearchRef, FileSearchRef, ProductSearchRef, and RegistrySearchRef elements
953 /// </summary>
954 /// <param name="node">Element to parse.</param>
955 private void ParseWixSearchRefElement(Intermediate intermediate, IntermediateSection section, XElement node)
956 {
957 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
958 string refId = null;
959
960 foreach (XAttribute attrib in node.Attributes())
961 {
962 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
963 {
964 switch (attrib.Name.LocalName)
965 {
966 case "Id":
967 refId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
968 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", refId);
969 break;
970 default:
971 this.ParseHelper.UnexpectedAttribute(node, attrib);
972 break;
973 }
974 }
975 else
976 {
977 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
978 }
979 }
980
981 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
982 }
983
984 /// <summary>
985 /// Parses a FileSearch element.
986 /// </summary>
987 /// <param name="node">Element to parse.</param>
988 private void ParseFileSearchElement(Intermediate intermediate, IntermediateSection section, XElement node)
989 {
990 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
991 Identifier id = null;
992 string variable = null;
993 string condition = null;
994 string after = null;
995 string path = null;
996 Serialize.FileSearch.ResultType result = Serialize.FileSearch.ResultType.NotSet;
997
998 foreach (XAttribute attrib in node.Attributes())
999 {
1000 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1001 {
1002 switch (attrib.Name.LocalName)
1003 {
1004 case "Id":
1005 case "Variable":
1006 case "Condition":
1007 case "After":
1008 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
1009 break;
1010 case "Path":
1011 path = this.ParseHelper.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true);
1012 break;
1013 case "Result":
1014 string resultValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1015 if (!Serialize.FileSearch.TryParseResultType(resultValue, out result))
1016 {
1017 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName,
1018 resultValue,
1019 Serialize.FileSearch.ResultType.exists.ToString(),
1020 Serialize.FileSearch.ResultType.version.ToString()));
1021 }
1022 break;
1023 default:
1024 this.ParseHelper.UnexpectedAttribute(node, attrib);
1025 break;
1026 }
1027 }
1028 else
1029 {
1030 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
1031 }
1032 }
1033
1034 if (null == variable)
1035 {
1036 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Variable"));
1037 }
1038
1039 if (null == path)
1040 {
1041 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Path"));
1042 }
1043
1044 if (null == id)
1045 {
1046 id = this.ParseHelper.CreateIdentifier("wfs", variable, condition, after, path, result.ToString());
1047 }
1048
1049 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
1050
1051 if (!this.Messaging.EncounteredError)
1052 {
1053 this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
1054 if (after != null)
1055 {
1056 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
1057 // TODO: We're currently defaulting to "always run after", which we will need to change...
1058 this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
1059 }
1060
1061 WixFileSearchAttributes attributes = WixFileSearchAttributes.Default;
1062 switch (result)
1063 {
1064 case Serialize.FileSearch.ResultType.exists:
1065 attributes |= WixFileSearchAttributes.WantExists;
1066 break;
1067 case Serialize.FileSearch.ResultType.version:
1068 attributes |= WixFileSearchAttributes.WantVersion;
1069 break;
1070 }
1071
1072 this.CreateWixFileSearchRow(section, sourceLineNumbers, id, path, attributes);
1073 }
1074 }
1075
1076 /// <summary>
1077 /// Creates a row in the WixFileSearch table.
1078 /// </summary>
1079 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1080 /// <param name="id">Identifier of the search (key into the WixSearch table)</param>
1081 /// <param name="path">File/directory path to search for.</param>
1082 /// <param name="attributes"></param>
1083 private void CreateWixFileSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string path, WixFileSearchAttributes attributes)
1084 {
1085 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixFileSearch", id);
1086 row.Set(1, path);
1087 //row.Set(2, minVersion;
1088 //row.Set(3, maxVersion;
1089 //row.Set(4, minSize;
1090 //row.Set(5, maxSize;
1091 //row.Set(6, minDate;
1092 //row.Set(7, maxDate;
1093 //row.Set(8, languages;
1094 row.Set(9, (int)attributes);
1095 }
1096
1097 /// <summary>
1098 /// Creates a row in the WixSearch table.
1099 /// </summary>
1100 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1101 /// <param name="id">Identifier of the search.</param>
1102 /// <param name="variable">The Burn variable to store the result into.</param>
1103 /// <param name="condition">A condition to test before evaluating the search.</param>
1104 private void CreateWixSearchRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string variable, string condition)
1105 {
1106 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixSearch", id);
1107 row.Set(1, variable);
1108 row.Set(2, condition);
1109 }
1110
1111 /// <summary>
1112 ///
1113 /// </summary>
1114 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
1115 /// <param name="id">Identifier of the search (key into the WixSearch table)</param>
1116 /// <param name="parentId">Identifier of the search that comes before (key into the WixSearch table)</param>
1117 /// <param name="attributes">Further details about the relation between id and parentId.</param>
1118 private void CreateWixSearchRelationRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, int attributes)
1119 {
1120 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixSearchRelation", id);
1121 row.Set(1, parentId);
1122 row.Set(2, attributes);
1123 }
1124
1125 /// <summary>
1126 /// Parses a file share element.
1127 /// </summary>
1128 /// <param name="element">Element to parse.</param>
1129 /// <param name="componentId">Identifier of parent component.</param>
1130 /// <param name="directoryId">Identifier of referred to directory.</param>
1131 private void ParseFileShareElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string directoryId)
1132 {
1133 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1134 string description = null;
1135 string name = null;
1136 string id = null;
1137
1138 foreach (XAttribute attrib in element.Attributes())
1139 {
1140 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1141 {
1142 switch (attrib.Name.LocalName)
1143 {
1144 case "Id":
1145 id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1146 break;
1147 case "Name":
1148 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1149 break;
1150 case "Description":
1151 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1152 break;
1153 default:
1154 this.ParseHelper.UnexpectedAttribute(element, attrib);
1155 break;
1156 }
1157 }
1158 else
1159 {
1160 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1161 }
1162 }
1163
1164 if (null == id)
1165 {
1166 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
1167 }
1168
1169 if (null == name)
1170 {
1171 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1172 }
1173
1174 if (!element.Elements().Any())
1175 {
1176 this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "FileSharePermission"));
1177 }
1178
1179 foreach (XElement child in element.Elements())
1180 {
1181 if (this.Namespace == child.Name.Namespace)
1182 {
1183 switch (child.Name.LocalName)
1184 {
1185 case "FileSharePermission":
1186 this.ParseFileSharePermissionElement(intermediate, section, child, id);
1187 break;
1188 default:
1189 this.ParseHelper.UnexpectedElement(element, child);
1190 break;
1191 }
1192 }
1193 else
1194 {
1195 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1196 }
1197 }
1198
1199 // Reference ConfigureSmbInstall and ConfigureSmbUninstall since nothing will happen without it
1200 if (this.Context.Platform == Platform.ARM)
1201 {
1202 // Ensure ARM version of the CA is referenced
1203 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureSmbInstall_ARM");
1204 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureSmbUninstall_ARM");
1205 }
1206 else
1207 {
1208 // All other supported platforms use x86
1209 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureSmbInstall");
1210 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureSmbUninstall");
1211 }
1212
1213 if (!this.Messaging.EncounteredError)
1214 {
1215 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "FileShare");
1216 row.Set(0, id);
1217 row.Set(1, name);
1218 row.Set(2, componentId);
1219 row.Set(3, description);
1220 row.Set(4, directoryId);
1221 }
1222 }
1223
1224 /// <summary>
1225 /// Parses a FileSharePermission element.
1226 /// </summary>
1227 /// <param name="element">Element to parse.</param>
1228 /// <param name="fileShareId">The identifier of the parent FileShare element.</param>
1229 private void ParseFileSharePermissionElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileShareId)
1230 {
1231 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1232 BitArray bits = new BitArray(32);
1233 int permission = 0;
1234 string user = null;
1235
1236 foreach (XAttribute attrib in element.Attributes())
1237 {
1238 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1239 {
1240 switch (attrib.Name.LocalName)
1241 {
1242 case "User":
1243 user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1244 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
1245 break;
1246 default:
1247 YesNoType attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1248 if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
1249 {
1250 if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
1251 {
1252 if (!this.TrySetBitFromName(UtilConstants.FolderPermissions, attrib.Name.LocalName, attribValue, bits, 0))
1253 {
1254 this.ParseHelper.UnexpectedAttribute(element, attrib);
1255 break;
1256 }
1257 }
1258 }
1259 break;
1260 }
1261 }
1262 else
1263 {
1264 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1265 }
1266 }
1267
1268 permission = this.CreateIntegerFromBitArray(bits);
1269
1270 if (null == user)
1271 {
1272 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
1273 }
1274
1275 if (int.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
1276 {
1277 this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
1278 }
1279
1280 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1281
1282 if (!this.Messaging.EncounteredError)
1283 {
1284 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "FileSharePermissions");
1285 row.Set(0, fileShareId);
1286 row.Set(1, user);
1287 row.Set(2, permission);
1288 }
1289 }
1290
1291 /// <summary>
1292 /// Parses a group element.
1293 /// </summary>
1294 /// <param name="element">Node to be parsed.</param>
1295 /// <param name="componentId">Component Id of the parent component of this element.</param>
1296 private void ParseGroupElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1297 {
1298 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1299 string id = null;
1300 string domain = null;
1301 string name = null;
1302
1303 foreach (XAttribute attrib in element.Attributes())
1304 {
1305 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1306 {
1307 switch (attrib.Name.LocalName)
1308 {
1309 case "Id":
1310 id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1311 break;
1312 case "Name":
1313 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1314 break;
1315 case "Domain":
1316 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1317 break;
1318 default:
1319 this.ParseHelper.UnexpectedAttribute(element, attrib);
1320 break;
1321 }
1322 }
1323 else
1324 {
1325 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1326 }
1327 }
1328
1329 if (null == id)
1330 {
1331 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
1332 }
1333
1334 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1335
1336 if (!this.Messaging.EncounteredError)
1337 {
1338 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "Group");
1339 row.Set(0, id);
1340 row.Set(1, componentId);
1341 row.Set(2, name);
1342 row.Set(3, domain);
1343 }
1344 }
1345
1346 /// <summary>
1347 /// Parses a GroupRef element
1348 /// </summary>
1349 /// <param name="element">Element to parse.</param>
1350 /// <param name="userId">Required user id to be joined to the group.</param>
1351 private void ParseGroupRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string userId)
1352 {
1353 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1354 string groupId = null;
1355
1356 foreach (XAttribute attrib in element.Attributes())
1357 {
1358 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1359 {
1360 switch (attrib.Name.LocalName)
1361 {
1362 case "Id":
1363 groupId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1364 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "Group", groupId);
1365 break;
1366 default:
1367 this.ParseHelper.UnexpectedAttribute(element, attrib);
1368 break;
1369 }
1370 }
1371 else
1372 {
1373 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1374 }
1375 }
1376
1377 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1378
1379 if (!this.Messaging.EncounteredError)
1380 {
1381 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "UserGroup");
1382 row.Set(0, userId);
1383 row.Set(1, groupId);
1384 }
1385 }
1386
1387 /// <summary>
1388 /// Parses an InternetShortcut element.
1389 /// </summary>
1390 /// <param name="element">Element to parse.</param>
1391 /// <param name="componentId">Identifier of parent component.</param>
1392 /// <param name="defaultTarget">Default directory if none is specified on the InternetShortcut element.</param>
1393 private void ParseInternetShortcutElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string defaultTarget)
1394 {
1395 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1396 string id = null;
1397 string name = null;
1398 string target = null;
1399 string directoryId = null;
1400 string type = null;
1401 string iconFile = null;
1402 int iconIndex = 0;
1403
1404 foreach (XAttribute attrib in element.Attributes())
1405 {
1406 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1407 {
1408 switch (attrib.Name.LocalName)
1409 {
1410 case "Directory":
1411 directoryId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1412 break;
1413 case "Id":
1414 id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1415 break;
1416 case "Name":
1417 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1418 break;
1419 case "Target":
1420 target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1421 break;
1422 case "Type":
1423 type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1424 break;
1425 case "IconFile":
1426 iconFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1427 break;
1428 case "IconIndex":
1429 iconIndex = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
1430 break;
1431 default:
1432 this.ParseHelper.UnexpectedAttribute(element, attrib);
1433 break;
1434 }
1435 }
1436 else
1437 {
1438 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1439 }
1440 }
1441
1442 // If there was no directoryId specified on the InternetShortcut element, default to the one on
1443 // the parent component.
1444 if (null == directoryId)
1445 {
1446 directoryId = defaultTarget;
1447 }
1448
1449 if (null == id)
1450 {
1451 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
1452 }
1453
1454 // In theory this can never be the case, since InternetShortcut can only be under
1455 // a component element, and if the Directory wasn't specified the default will come
1456 // from the component. However, better safe than sorry, so here's a check to make sure
1457 // it didn't wind up being null after setting it to the defaultTarget.
1458 if (null == directoryId)
1459 {
1460 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory"));
1461 }
1462
1463 if (null == name)
1464 {
1465 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
1466 }
1467
1468 if (null == target)
1469 {
1470 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target"));
1471 }
1472
1473 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
1474
1475 InternetShortcutType shortcutType = InternetShortcutType.Link;
1476 if (0 == String.Compare(type, "url", StringComparison.OrdinalIgnoreCase))
1477 {
1478 shortcutType = InternetShortcutType.Url;
1479 }
1480
1481 if (!this.Messaging.EncounteredError)
1482 {
1483 CreateWixInternetShortcut(intermediate, section, sourceLineNumbers, componentId, directoryId, id, name, target, shortcutType, iconFile, iconIndex);
1484 }
1485 }
1486
1487 /// <summary>
1488 /// Creates the rows needed for WixInternetShortcut to work.
1489 /// </summary>
1490 /// <param name="core">The CompilerCore object used to create rows.</param>
1491 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
1492 /// <param name="componentId">Identifier of parent component.</param>
1493 /// <param name="directoryId">Identifier of directory containing shortcut.</param>
1494 /// <param name="id">Identifier of shortcut.</param>
1495 /// <param name="name">Name of shortcut without extension.</param>
1496 /// <param name="target">Target URL of shortcut.</param>
1497 public void CreateWixInternetShortcut(Intermediate intermediate, IntermediateSection section, SourceLineNumber sourceLineNumbers, string componentId, string directoryId, string shortcutId, string name, string target, InternetShortcutType type, string iconFile, int iconIndex)
1498 {
1499 // add the appropriate extension based on type of shortcut
1500 name = String.Concat(name, InternetShortcutType.Url == type ? ".url" : ".lnk");
1501
1502 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixInternetShortcut");
1503 row.Set(0, shortcutId);
1504 row.Set(1, componentId);
1505 row.Set(2, directoryId);
1506 row.Set(3, name);
1507 row.Set(4, target);
1508 row.Set(5, (int)type);
1509 row.Set(6, iconFile);
1510 row.Set(7, iconIndex);
1511
1512 // Reference custom action because nothing will happen without it
1513 if (this.Context.Platform == Platform.ARM)
1514 {
1515 // Ensure ARM version of the CA is referenced
1516 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixSchedInternetShortcuts_ARM");
1517 }
1518 else
1519 {
1520 // All other supported platforms use x86
1521 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixSchedInternetShortcuts");
1522 }
1523
1524 // make sure we have a CreateFolder table so that the immediate CA can add temporary rows to handle installation and uninstallation
1525 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "CreateFolder");
1526
1527 // use built-in MSI functionality to remove the shortcuts rather than doing so via CA
1528 row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "RemoveFile");
1529 row.Set(0, shortcutId);
1530 row.Set(1, componentId);
1531 row.Set(2, this.ParseHelper.IsValidShortFilename(name, false) ? name : String.Concat(this.ParseHelper.CreateShortName(name, true, false, directoryId, name), "|", name));
1532 row.Set(3, directoryId);
1533 row.Set(4, 2); // msidbRemoveFileInstallModeOnRemove
1534 }
1535
1536 /// <summary>
1537 /// Parses a performance category element.
1538 /// </summary>
1539 /// <param name="element">Element to parse.</param>
1540 /// <param name="componentId">Identifier of parent component.</param>
1541 private void ParsePerformanceCategoryElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
1542 {
1543 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1544 string id = null;
1545 string name = null;
1546 string help = null;
1547 YesNoType multiInstance = YesNoType.No;
1548 int defaultLanguage = 0x09; // default to "english"
1549
1550 ArrayList parsedPerformanceCounters = new ArrayList();
1551
1552 // default to managed performance counter
1553 string library = "netfxperf.dll";
1554 string openEntryPoint = "OpenPerformanceData";
1555 string collectEntryPoint = "CollectPerformanceData";
1556 string closeEntryPoint = "ClosePerformanceData";
1557
1558 foreach (XAttribute attrib in element.Attributes())
1559 {
1560 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1561 {
1562 switch (attrib.Name.LocalName)
1563 {
1564 case "Close":
1565 closeEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1566 break;
1567 case "Collect":
1568 collectEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1569 break;
1570 case "DefaultLanguage":
1571 defaultLanguage = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
1572 break;
1573 case "Help":
1574 help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1575 break;
1576 case "Id":
1577 id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1578 break;
1579 case "Library":
1580 library = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1581 break;
1582 case "MultiInstance":
1583 multiInstance = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1584 break;
1585 case "Name":
1586 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1587 break;
1588 case "Open":
1589 openEntryPoint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1590 break;
1591 default:
1592 this.ParseHelper.UnexpectedAttribute(element, attrib);
1593 break;
1594 }
1595 }
1596 else
1597 {
1598 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
1599 }
1600 }
1601
1602 if (null == id)
1603 {
1604 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
1605 }
1606
1607 if (null == name)
1608 {
1609 name = id;
1610 }
1611
1612 // Process the child counter elements.
1613 foreach (XElement child in element.Elements())
1614 {
1615 if (this.Namespace == child.Name.Namespace)
1616 {
1617 switch (child.Name.LocalName)
1618 {
1619 case "PerformanceCounter":
1620 ParsedPerformanceCounter counter = this.ParsePerformanceCounterElement(intermediate, section, child, defaultLanguage);
1621 if (null != counter)
1622 {
1623 parsedPerformanceCounters.Add(counter);
1624 }
1625 break;
1626 default:
1627 this.ParseHelper.UnexpectedElement(element, child);
1628 break;
1629 }
1630 }
1631 else
1632 {
1633 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
1634 }
1635 }
1636
1637
1638 if (!this.Messaging.EncounteredError)
1639 {
1640 // Calculate the ini and h file content.
1641 string objectName = "OBJECT_1";
1642 string objectLanguage = defaultLanguage.ToString("D3", CultureInfo.InvariantCulture);
1643
1644 StringBuilder sbIniData = new StringBuilder();
1645 sbIniData.AppendFormat("[info]\r\ndrivername={0}\r\nsymbolfile=wixperf.h\r\n\r\n[objects]\r\n{1}_{2}_NAME=\r\n\r\n[languages]\r\n{2}=LANG{2}\r\n\r\n", name, objectName, objectLanguage);
1646 sbIniData.AppendFormat("[text]\r\n{0}_{1}_NAME={2}\r\n", objectName, objectLanguage, name);
1647 if (null != help)
1648 {
1649 sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", objectName, objectLanguage, help);
1650 }
1651
1652 int symbolConstantsCounter = 0;
1653 StringBuilder sbSymbolicConstants = new StringBuilder();
1654 sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", objectName, symbolConstantsCounter);
1655
1656 StringBuilder sbCounterNames = new StringBuilder("[~]");
1657 StringBuilder sbCounterTypes = new StringBuilder("[~]");
1658 for (int i = 0; i < parsedPerformanceCounters.Count; ++i)
1659 {
1660 ParsedPerformanceCounter counter = (ParsedPerformanceCounter)parsedPerformanceCounters[i];
1661 string counterName = String.Concat("DEVICE_COUNTER_", i + 1);
1662
1663 sbIniData.AppendFormat("{0}_{1}_NAME={2}\r\n", counterName, counter.Language, counter.Name);
1664 if (null != counter.Help)
1665 {
1666 sbIniData.AppendFormat("{0}_{1}_HELP={2}\r\n", counterName, counter.Language, counter.Help);
1667 }
1668
1669 symbolConstantsCounter += 2;
1670 sbSymbolicConstants.AppendFormat("#define {0} {1}\r\n", counterName, symbolConstantsCounter);
1671
1672 sbCounterNames.Append(UtilCompiler.FindPropertyBrackets.Replace(counter.Name, this.EscapeProperties));
1673 sbCounterNames.Append("[~]");
1674 sbCounterTypes.Append(counter.Type);
1675 sbCounterTypes.Append("[~]");
1676 }
1677
1678 sbSymbolicConstants.AppendFormat("#define LAST_{0}_COUNTER_OFFSET {1}\r\n", objectName, symbolConstantsCounter);
1679
1680 // Add the calculated INI and H strings to the PerformanceCategory table.
1681 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "PerformanceCategory");
1682 row.Set(0, id);
1683 row.Set(1, componentId);
1684 row.Set(2, name);
1685 row.Set(3, sbIniData.ToString());
1686 row.Set(4, sbSymbolicConstants.ToString());
1687
1688 // Set up the application's performance key.
1689 int registryRoot = 2; // HKLM
1690 string escapedName = UtilCompiler.FindPropertyBrackets.Replace(name, this.EscapeProperties);
1691 string linkageKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Linkage", escapedName);
1692 string performanceKey = String.Format(@"SYSTEM\CurrentControlSet\Services\{0}\Performance", escapedName);
1693
1694 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, linkageKey, "Export", escapedName, componentId, false);
1695 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "-", null, componentId, false);
1696 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "Library", library, componentId, false);
1697 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "Open", openEntryPoint, componentId, false);
1698 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "Collect", collectEntryPoint, componentId, false);
1699 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "Close", closeEntryPoint, componentId, false);
1700 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "IsMultiInstance", YesNoType.Yes == multiInstance ? "#1" : "#0", componentId, false);
1701 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "Counter Names", sbCounterNames.ToString(), componentId, false);
1702 this.ParseHelper.CreateRegistryRow(section, sourceLineNumbers, registryRoot, performanceKey, "Counter Types", sbCounterTypes.ToString(), componentId, false);
1703 }
1704
1705 // Reference InstallPerfCounterData and UninstallPerfCounterData since nothing will happen without them
1706 if (this.Context.Platform == Platform.ARM)
1707 {
1708 // Ensure ARM version of the CAs are referenced
1709 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "InstallPerfCounterData_ARM");
1710 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "UninstallPerfCounterData_ARM");
1711 }
1712 else
1713 {
1714 // All other supported platforms use x86
1715 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "InstallPerfCounterData");
1716 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "UninstallPerfCounterData");
1717 }
1718 }
1719
1720 /// <summary>
1721 /// Gets the performance counter language as a decimal number.
1722 /// </summary>
1723 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
1724 /// <param name="attribute">The attribute containing the value to get.</param>
1725 /// <returns>Numeric representation of the language as per WinNT.h.</returns>
1726 private int GetPerformanceCounterLanguage(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1727 {
1728 int language = 0;
1729 if (String.Empty == attribute.Value)
1730 {
1731 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
1732 }
1733 else
1734 {
1735 switch (attribute.Value)
1736 {
1737 case "afrikaans":
1738 language = 0x36;
1739 break;
1740 case "albanian":
1741 language = 0x1c;
1742 break;
1743 case "arabic":
1744 language = 0x01;
1745 break;
1746 case "armenian":
1747 language = 0x2b;
1748 break;
1749 case "assamese":
1750 language = 0x4d;
1751 break;
1752 case "azeri":
1753 language = 0x2c;
1754 break;
1755 case "basque":
1756 language = 0x2d;
1757 break;
1758 case "belarusian":
1759 language = 0x23;
1760 break;
1761 case "bengali":
1762 language = 0x45;
1763 break;
1764 case "bulgarian":
1765 language = 0x02;
1766 break;
1767 case "catalan":
1768 language = 0x03;
1769 break;
1770 case "chinese":
1771 language = 0x04;
1772 break;
1773 case "croatian":
1774 language = 0x1a;
1775 break;
1776 case "czech":
1777 language = 0x05;
1778 break;
1779 case "danish":
1780 language = 0x06;
1781 break;
1782 case "divehi":
1783 language = 0x65;
1784 break;
1785 case "dutch":
1786 language = 0x13;
1787 break;
1788 case "piglatin":
1789 case "english":
1790 language = 0x09;
1791 break;
1792 case "estonian":
1793 language = 0x25;
1794 break;
1795 case "faeroese":
1796 language = 0x38;
1797 break;
1798 case "farsi":
1799 language = 0x29;
1800 break;
1801 case "finnish":
1802 language = 0x0b;
1803 break;
1804 case "french":
1805 language = 0x0c;
1806 break;
1807 case "galician":
1808 language = 0x56;
1809 break;
1810 case "georgian":
1811 language = 0x37;
1812 break;
1813 case "german":
1814 language = 0x07;
1815 break;
1816 case "greek":
1817 language = 0x08;
1818 break;
1819 case "gujarati":
1820 language = 0x47;
1821 break;
1822 case "hebrew":
1823 language = 0x0d;
1824 break;
1825 case "hindi":
1826 language = 0x39;
1827 break;
1828 case "hungarian":
1829 language = 0x0e;
1830 break;
1831 case "icelandic":
1832 language = 0x0f;
1833 break;
1834 case "indonesian":
1835 language = 0x21;
1836 break;
1837 case "italian":
1838 language = 0x10;
1839 break;
1840 case "japanese":
1841 language = 0x11;
1842 break;
1843 case "kannada":
1844 language = 0x4b;
1845 break;
1846 case "kashmiri":
1847 language = 0x60;
1848 break;
1849 case "kazak":
1850 language = 0x3f;
1851 break;
1852 case "konkani":
1853 language = 0x57;
1854 break;
1855 case "korean":
1856 language = 0x12;
1857 break;
1858 case "kyrgyz":
1859 language = 0x40;
1860 break;
1861 case "latvian":
1862 language = 0x26;
1863 break;
1864 case "lithuanian":
1865 language = 0x27;
1866 break;
1867 case "macedonian":
1868 language = 0x2f;
1869 break;
1870 case "malay":
1871 language = 0x3e;
1872 break;
1873 case "malayalam":
1874 language = 0x4c;
1875 break;
1876 case "manipuri":
1877 language = 0x58;
1878 break;
1879 case "marathi":
1880 language = 0x4e;
1881 break;
1882 case "mongolian":
1883 language = 0x50;
1884 break;
1885 case "nepali":
1886 language = 0x61;
1887 break;
1888 case "norwegian":
1889 language = 0x14;
1890 break;
1891 case "oriya":
1892 language = 0x48;
1893 break;
1894 case "polish":
1895 language = 0x15;
1896 break;
1897 case "portuguese":
1898 language = 0x16;
1899 break;
1900 case "punjabi":
1901 language = 0x46;
1902 break;
1903 case "romanian":
1904 language = 0x18;
1905 break;
1906 case "russian":
1907 language = 0x19;
1908 break;
1909 case "sanskrit":
1910 language = 0x4f;
1911 break;
1912 case "serbian":
1913 language = 0x1a;
1914 break;
1915 case "sindhi":
1916 language = 0x59;
1917 break;
1918 case "slovak":
1919 language = 0x1b;
1920 break;
1921 case "slovenian":
1922 language = 0x24;
1923 break;
1924 case "spanish":
1925 language = 0x0a;
1926 break;
1927 case "swahili":
1928 language = 0x41;
1929 break;
1930 case "swedish":
1931 language = 0x1d;
1932 break;
1933 case "syriac":
1934 language = 0x5a;
1935 break;
1936 case "tamil":
1937 language = 0x49;
1938 break;
1939 case "tatar":
1940 language = 0x44;
1941 break;
1942 case "telugu":
1943 language = 0x4a;
1944 break;
1945 case "thai":
1946 language = 0x1e;
1947 break;
1948 case "turkish":
1949 language = 0x1f;
1950 break;
1951 case "ukrainian":
1952 language = 0x22;
1953 break;
1954 case "urdu":
1955 language = 0x20;
1956 break;
1957 case "uzbek":
1958 language = 0x43;
1959 break;
1960 case "vietnamese":
1961 language = 0x2a;
1962 break;
1963 default:
1964 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
1965 break;
1966 }
1967 }
1968
1969 return language;
1970 }
1971
1972 /// <summary>
1973 /// Parses a performance counter element.
1974 /// </summary>
1975 /// <param name="element">Element to parse.</param>
1976 /// <param name="defaultLanguage">Default language for the performance counter.</param>
1977 private ParsedPerformanceCounter ParsePerformanceCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, int defaultLanguage)
1978 {
1979 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
1980 ParsedPerformanceCounter parsedPerformanceCounter = null;
1981 string name = null;
1982 string help = null;
1983 System.Diagnostics.PerformanceCounterType type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
1984 int language = defaultLanguage;
1985
1986 foreach (XAttribute attrib in element.Attributes())
1987 {
1988 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
1989 {
1990 switch (attrib.Name.LocalName)
1991 {
1992 case "Help":
1993 help = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1994 break;
1995 case "Name":
1996 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
1997 break;
1998 case "Type":
1999 type = this.GetPerformanceCounterType(sourceLineNumbers, attrib);
2000 break;
2001 case "Language":
2002 language = this.GetPerformanceCounterLanguage(sourceLineNumbers, attrib);
2003 break;
2004 default:
2005 this.ParseHelper.UnexpectedAttribute(element, attrib);
2006 break;
2007 }
2008 }
2009 else
2010 {
2011 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2012 }
2013 }
2014
2015 if (null == name)
2016 {
2017 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
2018 }
2019
2020 if (null == help)
2021 {
2022 this.Messaging.Write(UtilWarnings.RequiredAttributeForWindowsXP(sourceLineNumbers, element.Name.LocalName, "Help"));
2023 }
2024
2025 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2026
2027 if (!this.Messaging.EncounteredError)
2028 {
2029 parsedPerformanceCounter = new ParsedPerformanceCounter(name, help, type, language);
2030 }
2031
2032 return parsedPerformanceCounter;
2033 }
2034
2035 /// <summary>
2036 /// Gets the performance counter type.
2037 /// </summary>
2038 /// <param name="sourceLineNumbers">Source line information about the owner element.</param>
2039 /// <param name="attribute">The attribute containing the value to get.</param>
2040 /// <returns>Numeric representation of the language as per WinNT.h.</returns>
2041 private System.Diagnostics.PerformanceCounterType GetPerformanceCounterType(SourceLineNumber sourceLineNumbers, XAttribute attribute)
2042 {
2043 System.Diagnostics.PerformanceCounterType type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2044 if (String.Empty == attribute.Value)
2045 {
2046 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
2047 }
2048 else
2049 {
2050 switch (attribute.Value)
2051 {
2052 case "averageBase":
2053 type = System.Diagnostics.PerformanceCounterType.AverageBase;
2054 break;
2055 case "averageCount64":
2056 type = System.Diagnostics.PerformanceCounterType.AverageCount64;
2057 break;
2058 case "averageTimer32":
2059 type = System.Diagnostics.PerformanceCounterType.AverageTimer32;
2060 break;
2061 case "counterDelta32":
2062 type = System.Diagnostics.PerformanceCounterType.CounterDelta32;
2063 break;
2064 case "counterTimerInverse":
2065 type = System.Diagnostics.PerformanceCounterType.CounterTimerInverse;
2066 break;
2067 case "sampleFraction":
2068 type = System.Diagnostics.PerformanceCounterType.SampleFraction;
2069 break;
2070 case "timer100Ns":
2071 type = System.Diagnostics.PerformanceCounterType.Timer100Ns;
2072 break;
2073 case "counterTimer":
2074 type = System.Diagnostics.PerformanceCounterType.CounterTimer;
2075 break;
2076 case "rawFraction":
2077 type = System.Diagnostics.PerformanceCounterType.RawFraction;
2078 break;
2079 case "timer100NsInverse":
2080 type = System.Diagnostics.PerformanceCounterType.Timer100NsInverse;
2081 break;
2082 case "counterMultiTimer":
2083 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer;
2084 break;
2085 case "counterMultiTimer100Ns":
2086 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100Ns;
2087 break;
2088 case "counterMultiTimerInverse":
2089 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimerInverse;
2090 break;
2091 case "counterMultiTimer100NsInverse":
2092 type = System.Diagnostics.PerformanceCounterType.CounterMultiTimer100NsInverse;
2093 break;
2094 case "elapsedTime":
2095 type = System.Diagnostics.PerformanceCounterType.ElapsedTime;
2096 break;
2097 case "sampleBase":
2098 type = System.Diagnostics.PerformanceCounterType.SampleBase;
2099 break;
2100 case "rawBase":
2101 type = System.Diagnostics.PerformanceCounterType.RawBase;
2102 break;
2103 case "counterMultiBase":
2104 type = System.Diagnostics.PerformanceCounterType.CounterMultiBase;
2105 break;
2106 case "rateOfCountsPerSecond64":
2107 type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond64;
2108 break;
2109 case "rateOfCountsPerSecond32":
2110 type = System.Diagnostics.PerformanceCounterType.RateOfCountsPerSecond32;
2111 break;
2112 case "countPerTimeInterval64":
2113 type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval64;
2114 break;
2115 case "countPerTimeInterval32":
2116 type = System.Diagnostics.PerformanceCounterType.CountPerTimeInterval32;
2117 break;
2118 case "sampleCounter":
2119 type = System.Diagnostics.PerformanceCounterType.SampleCounter;
2120 break;
2121 case "counterDelta64":
2122 type = System.Diagnostics.PerformanceCounterType.CounterDelta64;
2123 break;
2124 case "numberOfItems64":
2125 type = System.Diagnostics.PerformanceCounterType.NumberOfItems64;
2126 break;
2127 case "numberOfItems32":
2128 type = System.Diagnostics.PerformanceCounterType.NumberOfItems32;
2129 break;
2130 case "numberOfItemsHEX64":
2131 type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX64;
2132 break;
2133 case "numberOfItemsHEX32":
2134 type = System.Diagnostics.PerformanceCounterType.NumberOfItemsHEX32;
2135 break;
2136 default:
2137 this.Messaging.Write(ErrorMessages.IllegalEmptyAttributeValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName));
2138 break;
2139 }
2140 }
2141
2142 return type;
2143 }
2144
2145 /// <summary>
2146 /// Parses a perf counter element.
2147 /// </summary>
2148 /// <param name="element">Element to parse.</param>
2149 /// <param name="componentId">Identifier of parent component.</param>
2150 /// <param name="fileId">Identifier of referenced file.</param>
2151 private void ParsePerfCounterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2152 {
2153 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2154 string name = null;
2155
2156 this.Messaging.Write(UtilWarnings.DeprecatedPerfCounterElement(sourceLineNumbers));
2157
2158 foreach (XAttribute attrib in element.Attributes())
2159 {
2160 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2161 {
2162 switch (attrib.Name.LocalName)
2163 {
2164 case "Name":
2165 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2166 break;
2167 default:
2168 this.ParseHelper.UnexpectedAttribute(element, attrib);
2169 break;
2170 }
2171 }
2172 else
2173 {
2174 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2175 }
2176 }
2177
2178 if (null == name)
2179 {
2180 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
2181 }
2182
2183 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2184
2185 if (!this.Messaging.EncounteredError)
2186 {
2187 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "Perfmon");
2188 row.Set(0, componentId);
2189 row.Set(1, $"[#{fileId}]");
2190 row.Set(2, name);
2191 }
2192
2193 // Reference ConfigurePerfmonInstall and ConfigurePerfmonUninstall since nothing will happen without them
2194 if (this.Context.Platform == Platform.ARM)
2195 {
2196 // Ensure ARM version of the CAs are referenced
2197 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonInstall_ARM");
2198 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonUninstall_ARM");
2199 }
2200 else
2201 {
2202 // All other supported platforms use x86
2203 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonInstall");
2204 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonUninstall");
2205 }
2206 }
2207
2208
2209 /// <summary>
2210 /// Parses a perf manifest element.
2211 /// </summary>
2212 /// <param name="element">Element to parse.</param>
2213 /// <param name="componentId">Identifier of parent component.</param>
2214 /// <param name="fileId">Identifier of referenced file.</param>
2215 private void ParsePerfCounterManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2216 {
2217 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2218 string resourceFileDirectory = null;
2219
2220 foreach (XAttribute attrib in element.Attributes())
2221 {
2222 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2223 {
2224 switch (attrib.Name.LocalName)
2225 {
2226 case "ResourceFileDirectory":
2227 resourceFileDirectory = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2228 break;
2229 default:
2230 this.ParseHelper.UnexpectedAttribute(element, attrib);
2231 break;
2232 }
2233 }
2234 else
2235 {
2236 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2237 }
2238 }
2239
2240 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2241
2242 if (!this.Messaging.EncounteredError)
2243 {
2244 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "PerfmonManifest");
2245 row.Set(0, componentId);
2246 row.Set(1, $"[#{fileId}]");
2247 row.Set(2, resourceFileDirectory);
2248 }
2249
2250 if (this.Context.Platform == Platform.ARM)
2251 {
2252 // Ensure ARM version of the CAs are referenced
2253 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonManifestRegister_ARM");
2254 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonManifestUnregister_ARM");
2255 }
2256 else
2257 {
2258 // All other supported platforms use x86
2259 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonManifestRegister");
2260 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigurePerfmonManifestUnregister");
2261 }
2262 }
2263
2264 /// <summary>
2265 /// Parses a format files element.
2266 /// </summary>
2267 /// <param name="element">Element to parse.</param>
2268 /// <param name="fileId">Identifier of referenced file.</param>
2269 /// <param name="win64">Flag to determine whether the component is 64-bit.</param>
2270 private void ParseFormatFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId, bool win64)
2271 {
2272 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2273 string binaryId = null;
2274
2275 foreach (XAttribute attrib in element.Attributes())
2276 {
2277 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2278 {
2279 switch (attrib.Name.LocalName)
2280 {
2281 case "BinaryKey":
2282 binaryId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2283 break;
2284 default:
2285 this.ParseHelper.UnexpectedAttribute(element, attrib);
2286 break;
2287 }
2288 }
2289 else
2290 {
2291 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2292 }
2293 }
2294
2295 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2296
2297 if (null == binaryId)
2298 {
2299 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryKey"));
2300 }
2301
2302 if (!this.Messaging.EncounteredError)
2303 {
2304 switch (this.Context.Platform)
2305 {
2306 case Platform.X86:
2307 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixSchedFormatFiles");
2308 break;
2309 case Platform.X64:
2310 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixSchedFormatFiles_x64");
2311 break;
2312 case Platform.IA64:
2313 case Platform.ARM:
2314 this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, this.Context.Platform.ToString(), element.Name.LocalName));
2315 break;
2316 }
2317
2318 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixFormatFiles");
2319 row.Set(0, binaryId);
2320 row.Set(1, fileId);
2321
2322 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "Binary", binaryId);
2323 }
2324 }
2325
2326 /// <summary>
2327 /// Parses a event manifest element.
2328 /// </summary>
2329 /// <param name="element">Element to parse.</param>
2330 /// <param name="componentId">Identifier of parent component.</param>
2331 /// <param name="fileId">Identifier of referenced file.</param>
2332 private void ParseEventManifestElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
2333 {
2334 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2335 string messageFile = null;
2336 string resourceFile = null;
2337 string parameterFile = null;
2338
2339 foreach (XAttribute attrib in element.Attributes())
2340 {
2341 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2342 {
2343 switch (attrib.Name.LocalName)
2344 {
2345 case "MessageFile":
2346 messageFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2347 break;
2348 case "ResourceFile":
2349 resourceFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2350 break;
2351 case "ParameterFile":
2352 parameterFile = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2353 break;
2354 default:
2355 this.ParseHelper.UnexpectedAttribute(element, attrib);
2356 break;
2357 }
2358 }
2359 else
2360 {
2361 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2362 }
2363 }
2364
2365 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2366
2367 if (!this.Messaging.EncounteredError)
2368 {
2369 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "EventManifest");
2370 row.Set(0, componentId);
2371 row.Set(1, $"[#{fileId}]");
2372
2373 if (null != messageFile)
2374 {
2375 var messageRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "XmlFile");
2376 messageRow.Set(0, String.Concat("Config_", fileId, "MessageFile"));
2377 messageRow.Set(1, $"[#{fileId}]");
2378 messageRow.Set(2, "/*/*/*/*[\\[]@messageFileName[\\]]");
2379 messageRow.Set(3, "messageFileName");
2380 messageRow.Set(4, messageFile);
2381 messageRow.Set(5, 4 | 0x00001000); //bulk write | preserve modified date
2382 messageRow.Set(6, componentId);
2383 }
2384 if (null != parameterFile)
2385 {
2386 var resourceRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "XmlFile");
2387 resourceRow.Set(0, String.Concat("Config_", fileId, "ParameterFile"));
2388 resourceRow.Set(1, $"[#{fileId}]");
2389 resourceRow.Set(2, "/*/*/*/*[\\[]@parameterFileName[\\]]");
2390 resourceRow.Set(3, "parameterFileName");
2391 resourceRow.Set(4, parameterFile);
2392 resourceRow.Set(5, 4 | 0x00001000); //bulk write | preserve modified date
2393 resourceRow.Set(6, componentId);
2394 }
2395 if (null != resourceFile)
2396 {
2397 var resourceRow = this.ParseHelper.CreateRow(section, sourceLineNumbers, "XmlFile");
2398 resourceRow.Set(0, String.Concat("Config_", fileId, "ResourceFile"));
2399 resourceRow.Set(1, $"[#{fileId}]");
2400 resourceRow.Set(2, "/*/*/*/*[\\[]@resourceFileName[\\]]");
2401 resourceRow.Set(3, "resourceFileName");
2402 resourceRow.Set(4, resourceFile);
2403 resourceRow.Set(5, 4 | 0x00001000); //bulk write | preserve modified date
2404 resourceRow.Set(6, componentId);
2405 }
2406
2407 }
2408
2409 if (this.Context.Platform == Platform.ARM)
2410 {
2411 // Ensure ARM version of the CA is referenced
2412 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureEventManifestRegister_ARM");
2413 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureEventManifestUnregister_ARM");
2414 }
2415 else
2416 {
2417 // All other supported platforms use x86
2418 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureEventManifestRegister");
2419 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureEventManifestUnregister");
2420 }
2421
2422 if (null != messageFile || null != parameterFile || null != resourceFile)
2423 {
2424 if (this.Context.Platform == Platform.ARM)
2425 {
2426 // Ensure ARM version of the CA is referenced
2427 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedXmlFile_ARM");
2428 }
2429 else
2430 {
2431 // All other supported platforms use x86
2432 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedXmlFile");
2433 }
2434 }
2435 }
2436
2437 /// <summary>
2438 /// Parses a PermissionEx element.
2439 /// </summary>
2440 /// <param name="element">Element to parse.</param>
2441 /// <param name="objectId">Identifier of object to be secured.</param>
2442 /// <param name="componentId">Identifier of component, used to determine install state.</param>
2443 /// <param name="win64">Flag to determine whether the component is 64-bit.</param>
2444 /// <param name="tableName">Name of table that contains objectId.</param>
2445 private void ParsePermissionExElement(Intermediate intermediate, IntermediateSection section, XElement element, string objectId, string componentId, bool win64, string tableName)
2446 {
2447 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2448 BitArray bits = new BitArray(32);
2449 string domain = null;
2450 int permission = 0;
2451 string[] specialPermissions = null;
2452 string user = null;
2453
2454 PermissionType permissionType = PermissionType.SecureObjects;
2455
2456 switch (tableName)
2457 {
2458 case "CreateFolder":
2459 specialPermissions = UtilConstants.FolderPermissions;
2460 break;
2461 case "File":
2462 specialPermissions = UtilConstants.FilePermissions;
2463 break;
2464 case "Registry":
2465 specialPermissions = UtilConstants.RegistryPermissions;
2466 if (String.IsNullOrEmpty(objectId))
2467 {
2468 this.Messaging.Write(UtilErrors.InvalidRegistryObject(sourceLineNumbers, element.Parent.Name.LocalName));
2469 }
2470 break;
2471 case "ServiceInstall":
2472 specialPermissions = UtilConstants.ServicePermissions;
2473 permissionType = PermissionType.SecureObjects;
2474 break;
2475 default:
2476 this.ParseHelper.UnexpectedElement(element.Parent, element);
2477 break;
2478 }
2479
2480 foreach (XAttribute attrib in element.Attributes())
2481 {
2482 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2483 {
2484 switch (attrib.Name.LocalName)
2485 {
2486 case "Domain":
2487 if (PermissionType.FileSharePermissions == permissionType)
2488 {
2489 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
2490 }
2491 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2492 break;
2493 case "User":
2494 user = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2495 break;
2496 default:
2497 YesNoType attribValue = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2498 if (!this.TrySetBitFromName(UtilConstants.StandardPermissions, attrib.Name.LocalName, attribValue, bits, 16))
2499 {
2500 if (!this.TrySetBitFromName(UtilConstants.GenericPermissions, attrib.Name.LocalName, attribValue, bits, 28))
2501 {
2502 if (!this.TrySetBitFromName(specialPermissions, attrib.Name.LocalName, attribValue, bits, 0))
2503 {
2504 this.ParseHelper.UnexpectedAttribute(element, attrib);
2505 break;
2506 }
2507 }
2508 }
2509 break;
2510 }
2511 }
2512 else
2513 {
2514 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2515 }
2516 }
2517
2518 permission = this.CreateIntegerFromBitArray(bits);
2519
2520 if (null == user)
2521 {
2522 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User"));
2523 }
2524
2525 if (int.MinValue == permission) // just GENERIC_READ, which is MSI_NULL
2526 {
2527 this.Messaging.Write(ErrorMessages.GenericReadNotAllowed(sourceLineNumbers));
2528 }
2529
2530 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2531
2532 if (!this.Messaging.EncounteredError)
2533 {
2534 if (win64)
2535 {
2536 if (this.Context.Platform == Platform.IA64)
2537 {
2538 this.Messaging.Write(ErrorMessages.UnsupportedPlatformForElement(sourceLineNumbers, "ia64", element.Name.LocalName));
2539 }
2540 else
2541 {
2542 // Ensure SchedSecureObjects (x64) is referenced
2543 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedSecureObjects_x64");
2544 }
2545 }
2546 else if (this.Context.Platform == Platform.ARM)
2547 {
2548 // Ensure SchedSecureObjects (arm) is referenced
2549 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedSecureObjects_ARM");
2550 }
2551 else
2552 {
2553 // Ensure SchedSecureObjects (x86) is referenced, to handle this x86 component member
2554 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedSecureObjects");
2555 }
2556
2557 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "SecureObjects");
2558 row.Set(0, objectId);
2559 row.Set(1, tableName);
2560 row.Set(2, domain);
2561 row.Set(3, user);
2562 row.Set(4, permission);
2563 row.Set(5, componentId);
2564 }
2565 }
2566
2567 /// <summary>
2568 /// Parses a ProductSearch element.
2569 /// </summary>
2570 /// <param name="element">Element to parse.</param>
2571 private void ParseProductSearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
2572 {
2573 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2574 Identifier id = null;
2575 string variable = null;
2576 string condition = null;
2577 string after = null;
2578 string productCode = null;
2579 string upgradeCode = null;
2580
2581 Serialize.ProductSearch.ResultType result = Serialize.ProductSearch.ResultType.NotSet;
2582
2583 foreach (XAttribute attrib in element.Attributes())
2584 {
2585 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2586 {
2587 switch (attrib.Name.LocalName)
2588 {
2589 case "Id":
2590 case "Variable":
2591 case "Condition":
2592 case "After":
2593 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
2594 break;
2595 case "ProductCode":
2596 productCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
2597 break;
2598 case "UpgradeCode":
2599 upgradeCode = this.ParseHelper.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
2600 break;
2601 case "Result":
2602 string resultValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2603 if (!Serialize.ProductSearch.TryParseResultType(resultValue, out result))
2604 {
2605 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName,
2606 resultValue,
2607 Serialize.ProductSearch.ResultType.version.ToString(),
2608 Serialize.ProductSearch.ResultType.language.ToString(),
2609 Serialize.ProductSearch.ResultType.state.ToString(),
2610 Serialize.ProductSearch.ResultType.assignment.ToString()));
2611 }
2612 break;
2613 default:
2614 this.ParseHelper.UnexpectedAttribute(element, attrib);
2615 break;
2616 }
2617 }
2618 else
2619 {
2620 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2621 }
2622 }
2623
2624 if (null == variable)
2625 {
2626 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
2627 }
2628
2629 if (null == upgradeCode && null == productCode)
2630 {
2631 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ProductCode", "UpgradeCode", true));
2632 }
2633
2634 if (null != upgradeCode && null != productCode)
2635 {
2636 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "UpgradeCode", "ProductCode"));
2637 }
2638
2639 if (null == id)
2640 {
2641 id = this.ParseHelper.CreateIdentifier("wps", variable, condition, after, (productCode == null ? upgradeCode : productCode), result.ToString());
2642 }
2643
2644 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2645
2646 if (!this.Messaging.EncounteredError)
2647 {
2648 this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
2649 if (after != null)
2650 {
2651 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
2652 // TODO: We're currently defaulting to "always run after", which we will need to change...
2653 this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
2654 }
2655
2656 WixProductSearchAttributes attributes = WixProductSearchAttributes.Version;
2657 switch (result)
2658 {
2659 case Serialize.ProductSearch.ResultType.version:
2660 attributes = WixProductSearchAttributes.Version;
2661 break;
2662 case Serialize.ProductSearch.ResultType.language:
2663 attributes = WixProductSearchAttributes.Language;
2664 break;
2665 case Serialize.ProductSearch.ResultType.state:
2666 attributes = WixProductSearchAttributes.State;
2667 break;
2668 case Serialize.ProductSearch.ResultType.assignment:
2669 attributes = WixProductSearchAttributes.Assignment;
2670 break;
2671 }
2672
2673 // set an additional flag if this is an upgrade code
2674 if (null != upgradeCode)
2675 {
2676 attributes |= WixProductSearchAttributes.UpgradeCode;
2677 }
2678
2679 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixProductSearch");
2680 row.Set(0, id);
2681 row.Set(1, productCode ?? upgradeCode);
2682 row.Set(2, (int)attributes);
2683 }
2684 }
2685
2686 /// <summary>
2687 /// Parses a RegistrySearch element.
2688 /// </summary>
2689 /// <param name="element">Element to parse.</param>
2690 private void ParseRegistrySearchElement(Intermediate intermediate, IntermediateSection section, XElement element)
2691 {
2692 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2693 Identifier id = null;
2694 string variable = null;
2695 string condition = null;
2696 string after = null;
2697 int root = CompilerConstants.IntegerNotSet;
2698 string key = null;
2699 string value = null;
2700 YesNoType expand = YesNoType.NotSet;
2701 YesNoType win64 = YesNoType.NotSet;
2702 Serialize.RegistrySearch.ResultType result = Serialize.RegistrySearch.ResultType.NotSet;
2703 Serialize.RegistrySearch.FormatType format = Serialize.RegistrySearch.FormatType.raw;
2704
2705 foreach (XAttribute attrib in element.Attributes())
2706 {
2707 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2708 {
2709 switch (attrib.Name.LocalName)
2710 {
2711 case "Id":
2712 case "Variable":
2713 case "Condition":
2714 case "After":
2715 this.ParseCommonSearchAttributes(sourceLineNumbers, attrib, ref id, ref variable, ref condition, ref after);
2716 break;
2717 case "Root":
2718 root = this.ParseHelper.GetAttributeMsidbRegistryRootValue(sourceLineNumbers, attrib, false);
2719 break;
2720 case "Key":
2721 key = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2722 break;
2723 case "Value":
2724 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2725 break;
2726 case "ExpandEnvironmentVariables":
2727 expand = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2728 break;
2729 case "Format":
2730 string formatValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2731 if (!String.IsNullOrEmpty(formatValue))
2732 {
2733 if (!Serialize.RegistrySearch.TryParseFormatType(formatValue, out format))
2734 {
2735 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName,
2736 formatValue, Serialize.RegistrySearch.FormatType.raw.ToString(), Serialize.RegistrySearch.FormatType.compatible.ToString()));
2737 }
2738 }
2739 break;
2740 case "Result":
2741 string resultValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2742 if (!Serialize.RegistrySearch.TryParseResultType(resultValue, out result))
2743 {
2744 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, attrib.Parent.Name.LocalName, attrib.Name.LocalName,
2745 resultValue, Serialize.RegistrySearch.ResultType.exists.ToString(), Serialize.RegistrySearch.ResultType.value.ToString()));
2746 }
2747 break;
2748 case "Win64":
2749 win64 = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
2750 break;
2751 default:
2752 this.ParseHelper.UnexpectedAttribute(element, attrib);
2753 break;
2754 }
2755 }
2756 else
2757 {
2758 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2759 }
2760 }
2761
2762 if (null == variable)
2763 {
2764 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Variable"));
2765 }
2766
2767 if (CompilerConstants.IntegerNotSet == root)
2768 {
2769 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Root"));
2770 }
2771
2772 if (null == key)
2773 {
2774 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Key"));
2775 }
2776
2777 if (Serialize.RegistrySearch.ResultType.NotSet == result)
2778 {
2779 result = Serialize.RegistrySearch.ResultType.value;
2780 }
2781
2782 if (null == id)
2783 {
2784 id = this.ParseHelper.CreateIdentifier("wrs", variable, condition, after, root.ToString(), key, value, result.ToString());
2785 }
2786
2787 WixRegistrySearchAttributes attributes = WixRegistrySearchAttributes.Raw;
2788 switch (format)
2789 {
2790 case Serialize.RegistrySearch.FormatType.raw:
2791 attributes = WixRegistrySearchAttributes.Raw;
2792 break;
2793 case Serialize.RegistrySearch.FormatType.compatible:
2794 attributes = WixRegistrySearchAttributes.Compatible;
2795 break;
2796 }
2797
2798 switch (result)
2799 {
2800 case Serialize.RegistrySearch.ResultType.exists:
2801 attributes |= WixRegistrySearchAttributes.WantExists;
2802 break;
2803 case Serialize.RegistrySearch.ResultType.value:
2804 attributes |= WixRegistrySearchAttributes.WantValue;
2805 break;
2806 }
2807
2808 if (expand == YesNoType.Yes)
2809 {
2810 if (0 != (attributes & WixRegistrySearchAttributes.WantExists))
2811 {
2812 this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, element.Name.LocalName,
2813 "ExpandEnvironmentVariables", expand.ToString(), "Result", result.ToString()));
2814 }
2815
2816 attributes |= WixRegistrySearchAttributes.ExpandEnvironmentVariables;
2817 }
2818
2819 if (win64 == YesNoType.Yes)
2820 {
2821 attributes |= WixRegistrySearchAttributes.Win64;
2822 }
2823
2824 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2825
2826 if (!this.Messaging.EncounteredError)
2827 {
2828 this.CreateWixSearchRow(section, sourceLineNumbers, id, variable, condition);
2829 if (after != null)
2830 {
2831 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "WixSearch", after);
2832 // TODO: We're currently defaulting to "always run after", which we will need to change...
2833 this.CreateWixSearchRelationRow(section, sourceLineNumbers, id, after, 2);
2834 }
2835
2836 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixRegistrySearch", id);
2837 row.Set(1, root);
2838 row.Set(2, key);
2839 row.Set(3, value);
2840 row.Set(4, (int)attributes);
2841 }
2842 }
2843
2844 /// <summary>
2845 /// Parses a RemoveFolderEx element.
2846 /// </summary>
2847 /// <param name="element">Element to parse.</param>
2848 /// <param name="componentId">Identifier of parent component.</param>
2849 private void ParseRemoveFolderExElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2850 {
2851 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2852 Identifier id = null;
2853 int on = (int)WixRemoveFolderExOn.Uninstall;
2854 string property = null;
2855
2856 foreach (XAttribute attrib in element.Attributes())
2857 {
2858 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2859 {
2860 switch (attrib.Name.LocalName)
2861 {
2862 case "Id":
2863 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2864 break;
2865 case "On":
2866 string onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2867 if (onValue.Length == 0)
2868 {
2869 on = CompilerConstants.IllegalInteger;
2870 }
2871 else
2872 {
2873 switch (onValue)
2874 {
2875 case "install":
2876 on = (int)WixRemoveFolderExOn.Install;
2877 break;
2878 case "uninstall":
2879 on = (int)WixRemoveFolderExOn.Uninstall;
2880 break;
2881 case "both":
2882 on = (int)WixRemoveFolderExOn.Both;
2883 break;
2884 default:
2885 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "On", onValue, "install", "uninstall", "both"));
2886 on = CompilerConstants.IllegalInteger;
2887 break;
2888 }
2889 }
2890 break;
2891 case "Property":
2892 property = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2893 break;
2894 default:
2895 this.ParseHelper.UnexpectedAttribute(element, attrib);
2896 break;
2897 }
2898 }
2899 else
2900 {
2901 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2902 }
2903 }
2904
2905 if (String.IsNullOrEmpty(property))
2906 {
2907 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Property"));
2908 }
2909
2910 if (null == id)
2911 {
2912 id = this.ParseHelper.CreateIdentifier("wrf", componentId, property, on.ToString(CultureInfo.InvariantCulture.NumberFormat));
2913 }
2914
2915 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2916
2917 if (!this.Messaging.EncounteredError)
2918 {
2919 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixRemoveFolderEx", id);
2920 row.Set(1, componentId);
2921 row.Set(2, property);
2922 row.Set(3, on);
2923
2924 this.ParseHelper.EnsureTable(section, sourceLineNumbers, "RemoveFile");
2925 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixRemoveFoldersEx");
2926 }
2927 }
2928
2929 /// <summary>
2930 /// Parses a RestartResource element.
2931 /// </summary>
2932 /// <param name="element">The element to parse.</param>
2933 /// <param name="componentId">The identity of the parent component.</param>
2934 private void ParseRestartResourceElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
2935 {
2936 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
2937 Identifier id = null;
2938 string resource = null;
2939 int attributes = CompilerConstants.IntegerNotSet;
2940
2941 foreach (XAttribute attrib in element.Attributes())
2942 {
2943 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
2944 {
2945 switch (attrib.Name.LocalName)
2946 {
2947 case "Id":
2948 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
2949 break;
2950
2951 case "Path":
2952 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2953 attributes = (int)WixRestartResourceAttributes.Filename;
2954 break;
2955
2956 case "ProcessName":
2957 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2958 attributes = (int)WixRestartResourceAttributes.ProcessName;
2959 break;
2960
2961 case "ServiceName":
2962 resource = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
2963 attributes = (int)WixRestartResourceAttributes.ServiceName;
2964 break;
2965
2966 default:
2967 this.ParseHelper.UnexpectedAttribute(element, attrib);
2968 break;
2969 }
2970 }
2971 else
2972 {
2973 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
2974 }
2975 }
2976
2977 // Validate the attribute.
2978 if (null == id)
2979 {
2980 id = this.ParseHelper.CreateIdentifier("wrr", componentId, resource, attributes.ToString());
2981 }
2982
2983 if (String.IsNullOrEmpty(resource) || CompilerConstants.IntegerNotSet == attributes)
2984 {
2985 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "Path", "ServiceName"));
2986 }
2987
2988 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
2989
2990 if (!this.Messaging.EncounteredError)
2991 {
2992 // Add a reference to the WixRegisterRestartResources custom action since nothing will happen without it.
2993 if (this.Context.Platform == Platform.ARM)
2994 {
2995 // Ensure ARM version of the CA is referenced
2996 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixRegisterRestartResources_ARM");
2997 }
2998 else
2999 {
3000 // All other supported platforms use x86
3001 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixRegisterRestartResources");
3002 }
3003
3004 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixRestartResource", id);
3005 row.Set(1, componentId);
3006 row.Set(2, resource);
3007 row.Set(3, attributes);
3008 }
3009 }
3010
3011 /// <summary>
3012 /// Parses a service configuration element.
3013 /// </summary>
3014 /// <param name="element">Element to parse.</param>
3015 /// <param name="componentId">Identifier of parent component.</param>
3016 /// <param name="parentTableName">Name of parent element.</param>
3017 /// <param name="parentTableServiceName">Optional name of service </param>
3018 private void ParseServiceConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentTableName, string parentTableServiceName)
3019 {
3020 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3021 string firstFailureActionType = null;
3022 bool newService = false;
3023 string programCommandLine = null;
3024 string rebootMessage = null;
3025 int resetPeriod = CompilerConstants.IntegerNotSet;
3026 int restartServiceDelay = CompilerConstants.IntegerNotSet;
3027 string secondFailureActionType = null;
3028 string serviceName = null;
3029 string thirdFailureActionType = null;
3030
3031 foreach (XAttribute attrib in element.Attributes())
3032 {
3033 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3034 {
3035 switch (attrib.Name.LocalName)
3036 {
3037 case "FirstFailureActionType":
3038 firstFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3039 break;
3040 case "ProgramCommandLine":
3041 programCommandLine = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3042 break;
3043 case "RebootMessage":
3044 rebootMessage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3045 break;
3046 case "ResetPeriodInDays":
3047 resetPeriod = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
3048 break;
3049 case "RestartServiceDelayInSeconds":
3050 restartServiceDelay = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
3051 break;
3052 case "SecondFailureActionType":
3053 secondFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3054 break;
3055 case "ServiceName":
3056 serviceName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3057 break;
3058 case "ThirdFailureActionType":
3059 thirdFailureActionType = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3060 break;
3061 default:
3062 this.ParseHelper.UnexpectedAttribute(element, attrib);
3063 break;
3064 }
3065 }
3066 else
3067 {
3068 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3069 }
3070 }
3071
3072 // if this element is a child of ServiceInstall then ignore the service name provided.
3073 if ("ServiceInstall" == parentTableName)
3074 {
3075 // TODO: the ServiceName attribute should not be allowed in this case (the overwriting behavior may confuse users)
3076 serviceName = parentTableServiceName;
3077 newService = true;
3078 }
3079 else
3080 {
3081 // not a child of ServiceInstall, so ServiceName must have been provided
3082 if (null == serviceName)
3083 {
3084 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ServiceName"));
3085 }
3086 }
3087
3088 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3089
3090 // Reference SchedServiceConfig since nothing will happen without it
3091 if (this.Context.Platform == Platform.ARM)
3092 {
3093 // Ensure ARM version of the CA is referenced
3094 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedServiceConfig_ARM");
3095 }
3096 else
3097 {
3098 // All other supported platforms use x86
3099 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedServiceConfig");
3100 }
3101
3102 if (!this.Messaging.EncounteredError)
3103 {
3104 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "ServiceConfig");
3105 row.Set(0, serviceName);
3106 row.Set(1, componentId);
3107 row.Set(2, (newService ? 1 : 0));
3108 row.Set(3, firstFailureActionType);
3109 row.Set(4, secondFailureActionType);
3110 row.Set(5, thirdFailureActionType);
3111 if (CompilerConstants.IntegerNotSet != resetPeriod)
3112 {
3113 row.Set(6, resetPeriod);
3114 }
3115
3116 if (CompilerConstants.IntegerNotSet != restartServiceDelay)
3117 {
3118 row.Set(7, restartServiceDelay);
3119 }
3120 row.Set(8, programCommandLine);
3121 row.Set(9, rebootMessage);
3122 }
3123 }
3124
3125 /// <summary>
3126 /// Parses a touch file element.
3127 /// </summary>
3128 /// <param name="element">Element to parse.</param>
3129 /// <param name="componentId">Identifier of parent component.</param>
3130 /// <param name="win64">Indicates whether the path is a 64-bit path.</param>
3131 private void ParseTouchFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool win64)
3132 {
3133 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3134 Identifier id = null;
3135 string path = null;
3136 YesNoType onInstall = YesNoType.NotSet;
3137 YesNoType onReinstall = YesNoType.NotSet;
3138 YesNoType onUninstall = YesNoType.NotSet;
3139 YesNoType nonvital = YesNoType.NotSet;
3140 int attributes = 0;
3141
3142 foreach (XAttribute attrib in element.Attributes())
3143 {
3144 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3145 {
3146 switch (attrib.Name.LocalName)
3147 {
3148 case "Id":
3149 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3150 break;
3151 case "Path":
3152 path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3153 break;
3154 case "OnInstall":
3155 onInstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3156 break;
3157 case "OnReinstall":
3158 onReinstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3159 break;
3160 case "OnUninstall":
3161 onUninstall = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3162 break;
3163 case "Nonvital":
3164 nonvital = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
3165 break;
3166 default:
3167 this.ParseHelper.UnexpectedAttribute(element, attrib);
3168 break;
3169 }
3170 }
3171 else
3172 {
3173 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3174 }
3175 }
3176
3177 if (null == path)
3178 {
3179 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
3180 }
3181
3182 // If none of the scheduling actions are set, default to touching on install and reinstall.
3183 if (YesNoType.NotSet == onInstall && YesNoType.NotSet == onReinstall && YesNoType.NotSet == onUninstall)
3184 {
3185 onInstall = YesNoType.Yes;
3186 onReinstall = YesNoType.Yes;
3187 }
3188
3189 attributes |= YesNoType.Yes == onInstall ? 0x1 : 0;
3190 attributes |= YesNoType.Yes == onReinstall ? 0x2 : 0;
3191 attributes |= YesNoType.Yes == onUninstall ? 0x4 : 0;
3192 attributes |= win64 ? 0x10 : 0;
3193 attributes |= YesNoType.Yes == nonvital ? 0 : 0x20;
3194
3195 if (null == id)
3196 {
3197 id = this.ParseHelper.CreateIdentifier("tf", path, attributes.ToString());
3198 }
3199
3200 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3201
3202 if (!this.Messaging.EncounteredError)
3203 {
3204 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "WixTouchFile", id);
3205 row.Set(1, componentId);
3206 row.Set(2, path);
3207 row.Set(3, attributes);
3208
3209 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "WixTouchFileDuringInstall");
3210 }
3211 }
3212
3213 /// <summary>
3214 /// Parses an user element.
3215 /// </summary>
3216 /// <param name="element">Element to parse.</param>
3217 /// <param name="componentId">Optional identifier of parent component.</param>
3218 private void ParseUserElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
3219 {
3220 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3221 Identifier id = null;
3222 int attributes = 0;
3223 string domain = null;
3224 string name = null;
3225 string password = null;
3226
3227 foreach (XAttribute attrib in element.Attributes())
3228 {
3229 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3230 {
3231 switch (attrib.Name.LocalName)
3232 {
3233 case "Id":
3234 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
3235 break;
3236 case "CanNotChangePassword":
3237 if (null == componentId)
3238 {
3239 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3240 }
3241
3242 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3243 {
3244 attributes |= UserPasswdCantChange;
3245 }
3246 break;
3247 case "CreateUser":
3248 if (null == componentId)
3249 {
3250 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3251 }
3252
3253 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3254 {
3255 attributes |= UserDontCreateUser;
3256 }
3257 break;
3258 case "Disabled":
3259 if (null == componentId)
3260 {
3261 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3262 }
3263
3264 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3265 {
3266 attributes |= UserDisableAccount;
3267 }
3268 break;
3269 case "Domain":
3270 domain = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3271 break;
3272 case "FailIfExists":
3273 if (null == componentId)
3274 {
3275 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3276 }
3277
3278 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3279 {
3280 attributes |= UserFailIfExists;
3281 }
3282 break;
3283 case "LogonAsService":
3284 if (null == componentId)
3285 {
3286 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3287 }
3288 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3289 {
3290 attributes |= UserLogonAsService;
3291 }
3292 break;
3293 case "LogonAsBatchJob":
3294 if (null == componentId)
3295 {
3296 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3297 }
3298 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3299 {
3300 attributes |= UserLogonAsBatchJob;
3301 }
3302 break;
3303 case "Name":
3304 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3305 break;
3306 case "Password":
3307 password = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3308 break;
3309 case "PasswordExpired":
3310 if (null == componentId)
3311 {
3312 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3313 }
3314
3315 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3316 {
3317 attributes |= UserPasswdChangeReqdOnLogin;
3318 }
3319 break;
3320 case "PasswordNeverExpires":
3321 if (null == componentId)
3322 {
3323 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3324 }
3325
3326 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3327 {
3328 attributes |= UserDontExpirePasswrd;
3329 }
3330 break;
3331 case "RemoveOnUninstall":
3332 if (null == componentId)
3333 {
3334 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3335 }
3336
3337 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3338 {
3339 attributes |= UserDontRemoveOnUninstall;
3340 }
3341 break;
3342 case "UpdateIfExists":
3343 if (null == componentId)
3344 {
3345 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3346 }
3347
3348 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3349 {
3350 attributes |= UserUpdateIfExists;
3351 }
3352 break;
3353 case "Vital":
3354 if (null == componentId)
3355 {
3356 this.Messaging.Write(UtilErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
3357 }
3358
3359 if (YesNoType.No == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3360 {
3361 attributes |= UserNonVital;
3362 }
3363 break;
3364 default:
3365 this.ParseHelper.UnexpectedAttribute(element, attrib);
3366 break;
3367 }
3368 }
3369 else
3370 {
3371 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3372 }
3373 }
3374
3375 if (null == id)
3376 {
3377 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
3378 }
3379
3380 if (null == name)
3381 {
3382 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
3383 }
3384
3385 foreach (XElement child in element.Elements())
3386 {
3387 if (this.Namespace == child.Name.Namespace)
3388 {
3389 switch (child.Name.LocalName)
3390 {
3391 case "GroupRef":
3392 if (null == componentId)
3393 {
3394 SourceLineNumber childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
3395 this.Messaging.Write(UtilErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
3396 }
3397
3398 this.ParseGroupRefElement(intermediate, section, child, id.Id);
3399 break;
3400 default:
3401 this.ParseHelper.UnexpectedElement(element, child);
3402 break;
3403 }
3404 }
3405 else
3406 {
3407 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
3408 }
3409 }
3410
3411 if (null != componentId)
3412 {
3413 // Reference ConfigureIIs since nothing will happen without it
3414 if (this.Context.Platform == Platform.ARM)
3415 {
3416 // Ensure ARM version of the CA is referenced
3417 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureUsers_ARM");
3418 }
3419 else
3420 {
3421 // All other supported platforms use x86
3422 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "ConfigureUsers");
3423 }
3424 }
3425
3426 if (!this.Messaging.EncounteredError)
3427 {
3428 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "User", id);
3429 row.Set(1, componentId);
3430 row.Set(2, name);
3431 row.Set(3, domain);
3432 row.Set(4, password);
3433 row.Set(5, attributes);
3434 }
3435 }
3436
3437 /// <summary>
3438 /// Parses a XmlFile element.
3439 /// </summary>
3440 /// <param name="element">Element to parse.</param>
3441 /// <param name="componentId">Identifier of parent component.</param>
3442 private void ParseXmlFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
3443 {
3444 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3445 string id = null;
3446 string file = null;
3447 string elementPath = null;
3448 string name = null;
3449 string value = null;
3450 int sequence = -1;
3451 int flags = 0;
3452
3453 foreach (XAttribute attrib in element.Attributes())
3454 {
3455 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3456 {
3457 switch (attrib.Name.LocalName)
3458 {
3459 case "Action":
3460 string actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3461 switch (actionValue)
3462 {
3463 case "createElement":
3464 flags |= 0x00000001; // XMLFILE_CREATE_ELEMENT
3465 break;
3466 case "deleteValue":
3467 flags |= 0x00000002; // XMLFILE_DELETE_VALUE
3468 break;
3469 case "bulkSetValue":
3470 flags |= 0x00000004; // XMLFILE_BULKWRITE_VALUE
3471 break;
3472 case "setValue":
3473 // no flag for set value since it's the default
3474 break;
3475 default:
3476 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Action", actionValue, "createElement", "deleteValue", "setValue", "bulkSetValue"));
3477 break;
3478 }
3479 break;
3480 case "SelectionLanguage":
3481 string selectionLanguage = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3482 switch (selectionLanguage)
3483 {
3484 case "XPath":
3485 flags |= 0x00000100; // XMLFILE_USE_XPATH
3486 break;
3487 case "XSLPattern":
3488 // no flag for since it's the default
3489 break;
3490 default:
3491 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "SelectionLanguage", selectionLanguage, "XPath", "XSLPattern"));
3492 break;
3493 }
3494 break;
3495 case "Id":
3496 id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
3497 break;
3498 case "File":
3499 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3500 break;
3501 case "ElementPath":
3502 elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3503 break;
3504 case "Name":
3505 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3506 break;
3507 case "Permanent":
3508 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3509 {
3510 flags |= 0x00010000; // XMLFILE_DONT_UNINSTALL
3511 }
3512 break;
3513 case "Sequence":
3514 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
3515 break;
3516 case "Value":
3517 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3518 break;
3519 case "PreserveModifiedDate":
3520 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3521 {
3522 flags |= 0x00001000; // XMLFILE_PRESERVE_MODIFIED
3523 }
3524 break;
3525 default:
3526 this.ParseHelper.UnexpectedAttribute(element, attrib);
3527 break;
3528 }
3529 }
3530 else
3531 {
3532 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3533 }
3534 }
3535
3536 if (null == id)
3537 {
3538 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
3539 }
3540
3541 if (null == file)
3542 {
3543 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
3544 }
3545
3546 if (null == elementPath)
3547 {
3548 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ElementPath"));
3549 }
3550
3551 if ((0x00000001 /*XMLFILE_CREATE_ELEMENT*/ & flags) != 0 && null == name)
3552 {
3553 this.Messaging.Write(ErrorMessages.IllegalAttributeWithoutOtherAttributes(sourceLineNumbers, element.Name.LocalName, "Action", "Name"));
3554 }
3555
3556 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
3557
3558 if (!this.Messaging.EncounteredError)
3559 {
3560 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "XmlFile");
3561 row.Set(0, id);
3562 row.Set(1, file);
3563 row.Set(2, elementPath);
3564 row.Set(3, name);
3565 row.Set(4, value);
3566 row.Set(5, flags);
3567 row.Set(6, componentId);
3568 if (-1 != sequence)
3569 {
3570 row.Set(7, sequence);
3571 }
3572 }
3573
3574 // Reference SchedXmlFile since nothing will happen without it
3575 if (this.Context.Platform == Platform.ARM)
3576 {
3577 // Ensure ARM version of the CA is referenced
3578 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedXmlFile_ARM");
3579 }
3580 else
3581 {
3582 // All other supported platforms use x86
3583 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedXmlFile");
3584 }
3585 }
3586
3587 /// <summary>
3588 /// Parses a XmlConfig element.
3589 /// </summary>
3590 /// <param name="element">Element to parse.</param>
3591 /// <param name="componentId">Identifier of parent component.</param>
3592 /// <param name="nested">Whether or not the element is nested.</param>
3593 private void ParseXmlConfigElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, bool nested)
3594 {
3595 SourceLineNumber sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
3596 string id = null;
3597 string elementId = null;
3598 string elementPath = null;
3599 int flags = 0;
3600 string file = null;
3601 string name = null;
3602 int sequence = CompilerConstants.IntegerNotSet;
3603 string value = null;
3604 string verifyPath = null;
3605
3606 foreach (XAttribute attrib in element.Attributes())
3607 {
3608 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
3609 {
3610 switch (attrib.Name.LocalName)
3611 {
3612 case "Id":
3613 id = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
3614 break;
3615 case "Action":
3616 if (nested)
3617 {
3618 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3619 }
3620 else
3621 {
3622 string actionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3623 switch (actionValue)
3624 {
3625 case "create":
3626 flags |= 0x10; // XMLCONFIG_CREATE
3627 break;
3628 case "delete":
3629 flags |= 0x20; // XMLCONFIG_DELETE
3630 break;
3631 default:
3632 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, actionValue, "create", "delete"));
3633 break;
3634 }
3635 }
3636 break;
3637 case "ElementId":
3638 elementId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3639 break;
3640 case "ElementPath":
3641 elementPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3642 break;
3643 case "File":
3644 file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3645 break;
3646 case "Name":
3647 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3648 break;
3649 case "Node":
3650 if (nested)
3651 {
3652 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3653 }
3654 else
3655 {
3656 string nodeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3657 switch (nodeValue)
3658 {
3659 case "element":
3660 flags |= 0x1; // XMLCONFIG_ELEMENT
3661 break;
3662 case "value":
3663 flags |= 0x2; // XMLCONFIG_VALUE
3664 break;
3665 case "document":
3666 flags |= 0x4; // XMLCONFIG_DOCUMENT
3667 break;
3668 default:
3669 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, nodeValue, "element", "value", "document"));
3670 break;
3671 }
3672 }
3673 break;
3674 case "On":
3675 if (nested)
3676 {
3677 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, element.Parent.Name.LocalName));
3678 }
3679 else
3680 {
3681 string onValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3682 switch (onValue)
3683 {
3684 case "install":
3685 flags |= 0x100; // XMLCONFIG_INSTALL
3686 break;
3687 case "uninstall":
3688 flags |= 0x200; // XMLCONFIG_UNINSTALL
3689 break;
3690 default:
3691 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, onValue, "install", "uninstall"));
3692 break;
3693 }
3694 }
3695 break;
3696 case "PreserveModifiedDate":
3697 if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
3698 {
3699 flags |= 0x00001000; // XMLCONFIG_PRESERVE_MODIFIED
3700 }
3701 break;
3702 case "Sequence":
3703 sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
3704 break;
3705 case "Value":
3706 value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3707 break;
3708 case "VerifyPath":
3709 verifyPath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
3710 break;
3711 default:
3712 this.ParseHelper.UnexpectedAttribute(element, attrib);
3713 break;
3714 }
3715 }
3716 else
3717 {
3718 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
3719 }
3720 }
3721
3722 if (null == id)
3723 {
3724 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
3725 }
3726
3727 if (null == file)
3728 {
3729 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
3730 }
3731
3732 if (null == elementId && null == elementPath)
3733 {
3734 this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
3735 }
3736 else if (null != elementId)
3737 {
3738 if (null != elementPath)
3739 {
3740 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "ElementId", "ElementPath"));
3741 }
3742
3743 if (0 != flags)
3744 {
3745 this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, element.Name.LocalName, "ElementId", "Action", "Node", "On"));
3746 }
3747
3748 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "XmlConfig", elementId);
3749 }
3750
3751 string innerText = this.ParseHelper.GetTrimmedInnerText(element);
3752 if (null != value)
3753 {
3754 // cannot specify both the value attribute and inner text
3755 if (!String.IsNullOrEmpty(innerText))
3756 {
3757 this.Messaging.Write(ErrorMessages.IllegalAttributeWithInnerText(sourceLineNumbers, element.Name.LocalName, "Value"));
3758 }
3759 }
3760 else // value attribute not specified
3761 {
3762 if (!String.IsNullOrEmpty(innerText))
3763 {
3764 value = innerText;
3765 }
3766 }
3767
3768 // find unexpected child elements
3769 foreach (XElement child in element.Elements())
3770 {
3771 if (this.Namespace == child.Name.Namespace)
3772 {
3773 switch (child.Name.LocalName)
3774 {
3775 case "XmlConfig":
3776 if (nested)
3777 {
3778 this.Messaging.Write(ErrorMessages.UnexpectedElement(sourceLineNumbers, element.Name.LocalName, child.Name.LocalName));
3779 }
3780 else
3781 {
3782 this.ParseXmlConfigElement(intermediate, section, child, componentId, true);
3783 }
3784 break;
3785 default:
3786 this.ParseHelper.UnexpectedElement(element, child);
3787 break;
3788 }
3789 }
3790 else
3791 {
3792 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
3793 }
3794 }
3795
3796 if (!this.Messaging.EncounteredError)
3797 {
3798 var row = this.ParseHelper.CreateRow(section, sourceLineNumbers, "XmlConfig");
3799 row.Set(0, id);
3800 row.Set(1, file);
3801 row.Set(2, elementId ?? elementPath);
3802 row.Set(3, verifyPath);
3803 row.Set(4, name);
3804 row.Set(5, value);
3805 row.Set(6, flags);
3806 row.Set(7, componentId);
3807 if (CompilerConstants.IntegerNotSet != sequence)
3808 {
3809 row.Set(8, sequence);
3810 }
3811 }
3812
3813 // Reference SchedXmlConfig since nothing will happen without it
3814 if (this.Context.Platform == Platform.ARM)
3815 {
3816 // Ensure ARM version of the CA is referenced
3817 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedXmlConfig_ARM");
3818 }
3819 else
3820 {
3821 // All other supported platforms use x86
3822 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "CustomAction", "SchedXmlConfig");
3823 }
3824 }
3825
3826 /// <summary>
3827 /// Match evaluator to escape properties in a string.
3828 /// </summary>
3829 private string EscapeProperties(Match match)
3830 {
3831 string escape = null;
3832 switch (match.Value)
3833 {
3834 case "[":
3835 escape = @"[\[]";
3836 break;
3837 case "]":
3838 escape = @"[\]]";
3839 break;
3840 }
3841
3842 return escape;
3843 }
3844
3845 private int CreateIntegerFromBitArray(BitArray bits)
3846 {
3847 if (32 != bits.Length)
3848 {
3849 throw new ArgumentException(String.Format("Can only convert a bit array with 32-bits to integer. Actual number of bits in array: {0}", bits.Length), "bits");
3850 }
3851
3852 int[] intArray = new int[1];
3853 bits.CopyTo(intArray, 0);
3854
3855 return intArray[0];
3856 }
3857
3858 private bool TrySetBitFromName(string[] attributeNames, string attributeName, YesNoType attributeValue, BitArray bits, int offset)
3859 {
3860 for (int i = 0; i < attributeNames.Length; i++)
3861 {
3862 if (attributeName.Equals(attributeNames[i], StringComparison.Ordinal))
3863 {
3864 bits.Set(i + offset, YesNoType.Yes == attributeValue);
3865 return true;
3866 }
3867 }
3868
3869 return false;
3870 }
3871
3872 /// <summary>
3873 /// Private class that stores the data from a parsed PerformanceCounter element.
3874 /// </summary>
3875 private class ParsedPerformanceCounter
3876 {
3877 string name;
3878 string help;
3879 int type;
3880 string language;
3881
3882 internal ParsedPerformanceCounter(string name, string help, System.Diagnostics.PerformanceCounterType type, int language)
3883 {
3884 this.name = name;
3885 this.help = help;
3886 this.type = (int)type;
3887 this.language = language.ToString("D3", CultureInfo.InvariantCulture);
3888 }
3889
3890 internal string Name
3891 {
3892 get { return this.name; }
3893 }
3894
3895 internal string Help
3896 {
3897 get { return this.help; }
3898 }
3899
3900 internal int Type
3901 {
3902 get { return this.type; }
3903 }
3904
3905 internal string Language
3906 {
3907 get { return this.language; }
3908 }
3909 }
3910 }
3911}