summaryrefslogtreecommitdiff
path: root/src/ext/VisualStudio/wixext/VSCompiler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/VisualStudio/wixext/VSCompiler.cs')
-rw-r--r--src/ext/VisualStudio/wixext/VSCompiler.cs828
1 files changed, 828 insertions, 0 deletions
diff --git a/src/ext/VisualStudio/wixext/VSCompiler.cs b/src/ext/VisualStudio/wixext/VSCompiler.cs
new file mode 100644
index 00000000..65f0f97d
--- /dev/null
+++ b/src/ext/VisualStudio/wixext/VSCompiler.cs
@@ -0,0 +1,828 @@
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.VisualStudio
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.Xml.Linq;
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11 using WixToolset.Data.WindowsInstaller;
12 using WixToolset.Extensibility;
13 using WixToolset.VisualStudio.Symbols;
14
15 /// <summary>
16 /// The compiler for the WiX Toolset Visual Studio Extension.
17 /// </summary>
18 public sealed class VSCompiler : BaseCompilerExtension
19 {
20 internal const int MsidbCustomActionTypeExe = 0x00000002; // Target = command line args
21 internal const int MsidbCustomActionTypeProperty = 0x00000030; // Source = full path to executable
22 internal const int MsidbCustomActionTypeContinue = 0x00000040; // ignore action return status; continue running
23 internal const int MsidbCustomActionTypeRollback = 0x00000100; // in conjunction with InScript: queue in Rollback script
24 internal const int MsidbCustomActionTypeInScript = 0x00000400; // queue for execution within script
25 internal const int MsidbCustomActionTypeNoImpersonate = 0x00000800; // queue for not impersonating
26
27 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/vs";
28
29 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
30 {
31 switch (parentElement.Name.LocalName)
32 {
33 case "Component":
34 switch (element.Name.LocalName)
35 {
36 case "VsixPackage":
37 this.ParseVsixPackageElement(intermediate, section, element, context["ComponentId"], null);
38 break;
39 default:
40 this.ParseHelper.UnexpectedElement(parentElement, element);
41 break;
42 }
43 break;
44 case "File":
45 switch (element.Name.LocalName)
46 {
47 case "HelpCollection":
48 this.ParseHelpCollectionElement(intermediate, section, element, context["FileId"]);
49 break;
50 case "HelpFile":
51 this.ParseHelpFileElement(intermediate, section, element, context["FileId"]);
52 break;
53 case "VsixPackage":
54 this.ParseVsixPackageElement(intermediate, section, element, context["ComponentId"], context["FileId"]);
55 break;
56 default:
57 this.ParseHelper.UnexpectedElement(parentElement, element);
58 break;
59 }
60 break;
61 case "Fragment":
62 case "Module":
63 case "Package":
64 switch (element.Name.LocalName)
65 {
66 case "HelpCollectionRef":
67 this.ParseHelpCollectionRefElement(intermediate, section, element);
68 break;
69 case "HelpFilter":
70 this.ParseHelpFilterElement(intermediate, section, element);
71 break;
72 default:
73 this.ParseHelper.UnexpectedElement(parentElement, element);
74 break;
75 }
76 break;
77 default:
78 this.ParseHelper.UnexpectedElement(parentElement, element);
79 break;
80 }
81 }
82
83 private void ParseHelpCollectionRefElement(Intermediate intermediate, IntermediateSection section, XElement element)
84 {
85 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
86 Identifier id = null;
87
88 foreach (var attrib in element.Attributes())
89 {
90 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
91 {
92 switch (attrib.Name.LocalName)
93 {
94 case "Id":
95 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
96 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, VSSymbolDefinitions.HelpNamespace, id.Id);
97 break;
98 default:
99 this.ParseHelper.UnexpectedAttribute(element, attrib);
100 break;
101 }
102 }
103 else
104 {
105 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
106 }
107 }
108
109 if (null == id)
110 {
111 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
112 }
113
114 foreach (var child in element.Elements())
115 {
116 if (this.Namespace == child.Name.Namespace)
117 {
118 switch (child.Name.LocalName)
119 {
120 case "HelpFileRef":
121 this.ParseHelpFileRefElement(intermediate, section, child, id);
122 break;
123 default:
124 this.ParseHelper.UnexpectedElement(element, child);
125 break;
126 }
127 }
128 else
129 {
130 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
131 }
132 }
133 }
134
135 private void ParseHelpCollectionElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId)
136 {
137 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
138 Identifier id = null;
139 string description = null;
140 string name = null;
141 var suppressCAs = YesNoType.No;
142
143 foreach (var attrib in element.Attributes())
144 {
145 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
146 {
147 switch (attrib.Name.LocalName)
148 {
149 case "Id":
150 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
151 break;
152 case "Description":
153 description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
154 break;
155 case "Name":
156 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
157 break;
158 case "SuppressCustomActions":
159 suppressCAs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
160 break;
161 default:
162 this.ParseHelper.UnexpectedAttribute(element, attrib);
163 break;
164 }
165 }
166 else
167 {
168 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
169 }
170 }
171
172 if (null == id)
173 {
174 id = this.ParseHelper.CreateIdentifier("vshc", fileId, description, name);
175 }
176
177 if (null == description)
178 {
179 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Description"));
180 }
181
182 if (null == name)
183 {
184 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
185 }
186
187 foreach (var child in element.Elements())
188 {
189 if (this.Namespace == child.Name.Namespace)
190 {
191 switch (child.Name.LocalName)
192 {
193 case "HelpFileRef":
194 this.ParseHelpFileRefElement(intermediate, section, child, id);
195 break;
196 case "HelpFilterRef":
197 this.ParseHelpFilterRefElement(intermediate, section, child, id);
198 break;
199 case "PlugCollectionInto":
200 this.ParsePlugCollectionIntoElement(intermediate, section, child, id);
201 break;
202 default:
203 this.ParseHelper.UnexpectedElement(element, child);
204 break;
205 }
206 }
207 else
208 {
209 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
210 }
211 }
212
213 if (!this.Messaging.EncounteredError)
214 {
215 section.AddSymbol(new HelpNamespaceSymbol(sourceLineNumbers, id)
216 {
217 NamespaceName = name,
218 CollectionFileRef = fileId,
219 Description = description,
220 });
221
222 if (YesNoType.No == suppressCAs)
223 {
224 this.AddReferenceToRegisterMicrosoftHelp(section, sourceLineNumbers);
225 }
226 }
227 }
228
229 private void ParseHelpFileElement(Intermediate intermediate, IntermediateSection section, XElement element, string fileId)
230 {
231 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
232 Identifier id = null;
233 string name = null;
234 var language = CompilerConstants.IntegerNotSet;
235 string hxi = null;
236 string hxq = null;
237 string hxr = null;
238 string samples = null;
239 var suppressCAs = YesNoType.No;
240
241 foreach (var attrib in element.Attributes())
242 {
243 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
244 {
245 switch (attrib.Name.LocalName)
246 {
247 case "Id":
248 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
249 break;
250 case "AttributeIndex":
251 hxr = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
252 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.File, hxr);
253 break;
254 case "Index":
255 hxi = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
256 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.File, hxi);
257 break;
258 case "Language":
259 language = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
260 break;
261 case "Name":
262 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
263 break;
264 case "SampleLocation":
265 samples = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
266 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.File, samples);
267 break;
268 case "Search":
269 hxq = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
270 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.File, hxq);
271 break;
272 case "SuppressCustomActions":
273 suppressCAs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
274 break;
275 default:
276 this.ParseHelper.UnexpectedAttribute(element, attrib);
277 break;
278 }
279 }
280 else
281 {
282 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
283 }
284 }
285
286 if (null == id)
287 {
288 id = this.ParseHelper.CreateIdentifier("vshf", fileId, name, language.ToString(CultureInfo.InvariantCulture.NumberFormat));
289 }
290
291 if (null == name)
292 {
293 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
294 }
295
296 // Uninstall will always fail silently, leaving file registered, if Language is not set
297 if (CompilerConstants.IntegerNotSet == language)
298 {
299 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Language"));
300 }
301
302 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
303
304 if (!this.Messaging.EncounteredError)
305 {
306 section.AddSymbol(new HelpFileSymbol(sourceLineNumbers, id)
307 {
308 HelpFileName = name,
309 LangID = language,
310 HxSFileRef = fileId,
311 HxIFileRef = hxi,
312 HxQFileRef = hxq,
313 HxRFileRef = hxr,
314 SamplesFileRef = samples,
315 });
316
317 if (YesNoType.No == suppressCAs)
318 {
319 this.AddReferenceToRegisterMicrosoftHelp(section, sourceLineNumbers);
320 }
321 }
322 }
323
324 private void ParseHelpFileRefElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier collectionId)
325 {
326 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
327 Identifier id = null;
328
329 foreach (var attrib in element.Attributes())
330 {
331 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
332 {
333 switch (attrib.Name.LocalName)
334 {
335 case "Id":
336 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
337 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, VSSymbolDefinitions.HelpFile, id.Id);
338 break;
339 default:
340 this.ParseHelper.UnexpectedAttribute(element, attrib);
341 break;
342 }
343 }
344 else
345 {
346 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
347 }
348 }
349
350 if (null == id)
351 {
352 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
353 }
354
355 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
356
357 if (!this.Messaging.EncounteredError)
358 {
359 section.AddSymbol(new HelpFileToNamespaceSymbol(sourceLineNumbers, id)
360 {
361 HelpFileRef = id.Id,
362 HelpNamespaceRef = collectionId.Id,
363 });
364 }
365 }
366
367 private void ParseHelpFilterElement(Intermediate intermediate, IntermediateSection section, XElement element)
368 {
369 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
370 Identifier id = null;
371 string filterDefinition = null;
372 string name = null;
373 var suppressCAs = YesNoType.No;
374
375 foreach (var attrib in element.Attributes())
376 {
377 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
378 {
379 switch (attrib.Name.LocalName)
380 {
381 case "Id":
382 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
383 break;
384 case "FilterDefinition":
385 filterDefinition = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
386 break;
387 case "Name":
388 name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
389 break;
390 case "SuppressCustomActions":
391 suppressCAs = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
392 break;
393 default:
394 this.ParseHelper.UnexpectedAttribute(element, attrib);
395 break;
396 }
397 }
398 else
399 {
400 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
401 }
402 }
403
404 if (null == id)
405 {
406 id = this.ParseHelper.CreateIdentifier("hfl", name, filterDefinition);
407 }
408
409 if (null == name)
410 {
411 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
412 }
413
414 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
415
416 if (!this.Messaging.EncounteredError)
417 {
418 section.AddSymbol(new HelpFilterSymbol(sourceLineNumbers, id)
419 {
420 Description = name,
421 QueryString = filterDefinition,
422 });
423
424 if (YesNoType.No == suppressCAs)
425 {
426 this.AddReferenceToRegisterMicrosoftHelp(section, sourceLineNumbers);
427 }
428 }
429 }
430
431 private void ParseHelpFilterRefElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier collectionId)
432 {
433 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
434 Identifier id = null;
435
436 foreach (var attrib in element.Attributes())
437 {
438 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
439 {
440 switch (attrib.Name.LocalName)
441 {
442 case "Id":
443 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
444 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, VSSymbolDefinitions.HelpFilter, id.Id);
445 break;
446 default:
447 this.ParseHelper.UnexpectedAttribute(element, attrib);
448 break;
449 }
450 }
451 else
452 {
453 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
454 }
455 }
456
457 if (null == id)
458 {
459 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
460 }
461
462 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
463
464 if (!this.Messaging.EncounteredError)
465 {
466 section.AddSymbol(new HelpFilterToNamespaceSymbol(sourceLineNumbers, id)
467 {
468 HelpFilterRef = id.Id,
469 HelpNamespaceRef = collectionId.Id,
470 });
471 }
472 }
473
474 private void ParsePlugCollectionIntoElement(Intermediate intermediate, IntermediateSection section, XElement element, Identifier parentId)
475 {
476 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
477 string hxa = null;
478 string hxt = null;
479 string hxtParent = null;
480 string namespaceParent = null;
481 string feature = null;
482 var suppressExternalNamespaces = YesNoType.No;
483
484 foreach (var attrib in element.Attributes())
485 {
486 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
487 {
488 switch (attrib.Name.LocalName)
489 {
490 case "Attributes":
491 hxa = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
492 break;
493 case "TableOfContents":
494 hxt = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
495 break;
496 case "TargetCollection":
497 namespaceParent = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
498 break;
499 case "TargetTableOfContents":
500 hxtParent = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
501 break;
502 case "TargetFeature":
503 feature = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
504 break;
505 case "SuppressExternalNamespaces":
506 suppressExternalNamespaces = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
507 break;
508 default:
509 this.ParseHelper.UnexpectedAttribute(element, attrib);
510 break;
511 }
512 }
513 else
514 {
515 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
516 }
517 }
518
519 var pluginVS05 = namespaceParent.Equals("MS_VSIPCC_v80", StringComparison.Ordinal);
520 var pluginVS08 = namespaceParent.Equals("MS.VSIPCC.v90", StringComparison.Ordinal);
521
522 if (null == namespaceParent)
523 {
524 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "TargetCollection"));
525 }
526
527 if (null == feature && (pluginVS05 || pluginVS08) && YesNoType.No == suppressExternalNamespaces)
528 {
529 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "TargetFeature"));
530 }
531
532 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
533
534 if (!this.Messaging.EncounteredError)
535 {
536 section.AddSymbol(new HelpPluginSymbol(sourceLineNumbers, parentId)
537 {
538 HelpNamespaceRef = parentId.Id,
539 ParentHelpNamespaceRef = namespaceParent,
540 HxTFileRef = hxt,
541 HxAFileRef = hxa,
542 ParentHxTFileRef = hxtParent,
543 });
544
545 if (pluginVS05)
546 {
547 if (YesNoType.No == suppressExternalNamespaces)
548 {
549 // Bring in the help 2 base namespace components for VS 2005
550 this.ParseHelper.CreateComplexReference(section, sourceLineNumbers, ComplexReferenceParentType.Feature, feature, String.Empty,
551 ComplexReferenceChildType.ComponentGroup, "Help2_VS2005_Namespace_Components", false);
552 // Reference CustomAction since nothing will happen without it
553 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, "CA_HxMerge_VSIPCC_VSCC");
554 }
555 }
556 else if (pluginVS08)
557 {
558 if (YesNoType.No == suppressExternalNamespaces)
559 {
560 // Bring in the help 2 base namespace components for VS 2008
561 this.ParseHelper.CreateComplexReference(section, sourceLineNumbers, ComplexReferenceParentType.Feature, feature, String.Empty,
562 ComplexReferenceChildType.ComponentGroup, "Help2_VS2008_Namespace_Components", false);
563 // Reference CustomAction since nothing will happen without it
564 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, "CA_ScheduleExtHelpPlugin_VSCC_VSIPCC");
565 }
566 }
567 else
568 {
569 // Reference the parent namespace to enforce the foreign key relationship
570 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, VSSymbolDefinitions.HelpNamespace, namespaceParent);
571 }
572 }
573 }
574
575 private void ParseVsixPackageElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string fileId)
576 {
577 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
578 var propertyId = "VS_VSIX_INSTALLER_PATH";
579 string packageId = null;
580 var permanent = YesNoType.NotSet;
581 string target = null;
582 string targetVersion = null;
583 var vital = YesNoType.NotSet;
584
585 foreach (var attrib in element.Attributes())
586 {
587 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
588 {
589 switch (attrib.Name.LocalName)
590 {
591 case "File":
592 if (String.IsNullOrEmpty(fileId))
593 {
594 fileId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
595 }
596 else
597 {
598 this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, element.Name.LocalName, "File", "File"));
599 }
600 break;
601 case "PackageId":
602 packageId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
603 break;
604 case "Permanent":
605 permanent = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
606 break;
607 case "Target":
608 target = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
609 switch (target.ToLowerInvariant())
610 {
611 case "integrated":
612 case "integratedshell":
613 target = "IntegratedShell";
614 break;
615 case "professional":
616 target = "Pro";
617 break;
618 case "premium":
619 target = "Premium";
620 break;
621 case "ultimate":
622 target = "Ultimate";
623 break;
624 case "vbexpress":
625 target = "VBExpress";
626 break;
627 case "vcexpress":
628 target = "VCExpress";
629 break;
630 case "vcsexpress":
631 target = "VCSExpress";
632 break;
633 case "vwdexpress":
634 target = "VWDExpress";
635 break;
636 }
637 break;
638 case "TargetVersion":
639 targetVersion = this.ParseHelper.GetAttributeVersionValue(sourceLineNumbers, attrib);
640 break;
641 case "Vital":
642 vital = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
643 break;
644 case "VsixInstallerPathProperty":
645 propertyId = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
646 break;
647 default:
648 this.ParseHelper.UnexpectedAttribute(element, attrib);
649 break;
650 }
651 }
652 else
653 {
654 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
655 }
656 }
657
658 if (String.IsNullOrEmpty(fileId))
659 {
660 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
661 }
662
663 if (String.IsNullOrEmpty(packageId))
664 {
665 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "PackageId"));
666 }
667
668 if (!String.IsNullOrEmpty(target) && String.IsNullOrEmpty(targetVersion))
669 {
670 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "TargetVersion", "Target"));
671 }
672 else if (String.IsNullOrEmpty(target) && !String.IsNullOrEmpty(targetVersion))
673 {
674 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Target", "TargetVersion"));
675 }
676
677 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
678
679 if (!this.Messaging.EncounteredError)
680 {
681 // Ensure there is a reference to the AppSearch Property that will find the VsixInstaller.exe.
682 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Property, propertyId);
683
684 // Ensure there is a reference to the package file (even if we are a child under it).
685 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.File, fileId);
686
687 var cmdlinePrefix = "/q ";
688
689 if (!String.IsNullOrEmpty(target))
690 {
691 cmdlinePrefix = String.Format("{0} /skuName:{1} /skuVersion:{2}", cmdlinePrefix, target, targetVersion);
692 }
693
694 var installAfter = "WriteRegistryValues"; // by default, come after the registry key registration.
695
696 var installNamePerUser = this.ParseHelper.CreateIdentifier("viu", componentId, fileId, "per-user", target, targetVersion);
697 var installNamePerMachine = this.ParseHelper.CreateIdentifier("vim", componentId, fileId, "per-machine", target, targetVersion);
698 var installCmdLinePerUser = String.Format("{0} \"[#{1}]\"", cmdlinePrefix, fileId);
699 var installCmdLinePerMachine = String.Concat(installCmdLinePerUser, " /admin");
700 var installConditionPerUser = String.Format("NOT ALLUSERS AND ${0}=3", componentId); // only execute if the Component being installed.
701 var installConditionPerMachine = String.Format("ALLUSERS AND ${0}=3", componentId); // only execute if the Component being installed.
702 var installPerUserCA = new CustomActionSymbol(sourceLineNumbers, installNamePerUser)
703 {
704 ExecutionType = CustomActionExecutionType.Deferred,
705 Impersonate = true,
706 };
707 var installPerMachineCA = new CustomActionSymbol(sourceLineNumbers, installNamePerMachine)
708 {
709 ExecutionType = CustomActionExecutionType.Deferred,
710 Impersonate = false,
711 };
712
713 // If the package is not vital, mark the install action as continue.
714 if (vital == YesNoType.No)
715 {
716 installPerUserCA.IgnoreResult = true;
717 installPerMachineCA.IgnoreResult = true;
718 }
719 else // the package is vital so ensure there is a rollback action scheduled.
720 {
721 var rollbackNamePerUser = this.ParseHelper.CreateIdentifier("vru", componentId, fileId, "per-user", target, targetVersion);
722 var rollbackNamePerMachine = this.ParseHelper.CreateIdentifier("vrm", componentId, fileId, "per-machine", target, targetVersion);
723 var rollbackCmdLinePerUser = String.Concat(cmdlinePrefix, " /u:\"", packageId, "\"");
724 var rollbackCmdLinePerMachine = String.Concat(rollbackCmdLinePerUser, " /admin");
725 var rollbackConditionPerUser = String.Format("NOT ALLUSERS AND NOT Installed AND ${0}=2 AND ?{0}>2", componentId); // NOT Installed && Component being installed but not installed already.
726 var rollbackConditionPerMachine = String.Format("ALLUSERS AND NOT Installed AND ${0}=2 AND ?{0}>2", componentId); // NOT Installed && Component being installed but not installed already.
727 var rollbackPerUserCA = new CustomActionSymbol(sourceLineNumbers, rollbackNamePerUser)
728 {
729 ExecutionType = CustomActionExecutionType.Rollback,
730 IgnoreResult = true,
731 Impersonate = true,
732 };
733 var rollbackPerMachineCA = new CustomActionSymbol(sourceLineNumbers, rollbackNamePerMachine)
734 {
735 ExecutionType = CustomActionExecutionType.Rollback,
736 IgnoreResult = true,
737 Impersonate = false,
738 };
739
740 this.SchedulePropertyExeAction(section, sourceLineNumbers, rollbackNamePerUser, propertyId, rollbackCmdLinePerUser, rollbackPerUserCA, rollbackConditionPerUser, null, installAfter);
741 this.SchedulePropertyExeAction(section, sourceLineNumbers, rollbackNamePerMachine, propertyId, rollbackCmdLinePerMachine, rollbackPerMachineCA, rollbackConditionPerMachine, null, rollbackNamePerUser.Id);
742
743 installAfter = rollbackNamePerMachine.Id;
744 }
745
746 this.SchedulePropertyExeAction(section, sourceLineNumbers, installNamePerUser, propertyId, installCmdLinePerUser, installPerUserCA, installConditionPerUser, null, installAfter);
747 this.SchedulePropertyExeAction(section, sourceLineNumbers, installNamePerMachine, propertyId, installCmdLinePerMachine, installPerMachineCA, installConditionPerMachine, null, installNamePerUser.Id);
748
749 // If not permanent, schedule the uninstall custom action.
750 if (permanent != YesNoType.Yes)
751 {
752 var uninstallNamePerUser = this.ParseHelper.CreateIdentifier("vuu", componentId, fileId, "per-user", target ?? String.Empty, targetVersion ?? String.Empty);
753 var uninstallNamePerMachine = this.ParseHelper.CreateIdentifier("vum", componentId, fileId, "per-machine", target ?? String.Empty, targetVersion ?? String.Empty);
754 var uninstallCmdLinePerUser = String.Concat(cmdlinePrefix, " /u:\"", packageId, "\"");
755 var uninstallCmdLinePerMachine = String.Concat(uninstallCmdLinePerUser, " /admin");
756 var uninstallConditionPerUser = String.Format("NOT ALLUSERS AND ${0}=2 AND ?{0}>2", componentId); // Only execute if component is being uninstalled.
757 var uninstallConditionPerMachine = String.Format("ALLUSERS AND ${0}=2 AND ?{0}>2", componentId); // Only execute if component is being uninstalled.
758 var uninstallPerUserCA = new CustomActionSymbol(sourceLineNumbers, uninstallNamePerUser)
759 {
760 ExecutionType = CustomActionExecutionType.Deferred,
761 IgnoreResult = true,
762 Impersonate = true,
763 };
764 var uninstallPerMachineCA = new CustomActionSymbol(sourceLineNumbers, uninstallNamePerMachine)
765 {
766 ExecutionType = CustomActionExecutionType.Deferred,
767 IgnoreResult = true,
768 Impersonate = false,
769 };
770
771 this.SchedulePropertyExeAction(section, sourceLineNumbers, uninstallNamePerUser, propertyId, uninstallCmdLinePerUser, uninstallPerUserCA, uninstallConditionPerUser, "InstallFinalize", null);
772 this.SchedulePropertyExeAction(section, sourceLineNumbers, uninstallNamePerMachine, propertyId, uninstallCmdLinePerMachine, uninstallPerMachineCA, uninstallConditionPerMachine, "InstallFinalize", null);
773 }
774 }
775 }
776
777 private void SchedulePropertyExeAction(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier name, string source, string cmdline, CustomActionSymbol caTemplate, string condition, string beforeAction, string afterAction)
778 {
779 const SequenceTable sequence = SequenceTable.InstallExecuteSequence;
780
781 caTemplate.SourceType = CustomActionSourceType.Property;
782 caTemplate.Source = source;
783 caTemplate.TargetType = CustomActionTargetType.Exe;
784 caTemplate.Target = cmdline;
785 section.AddSymbol(caTemplate);
786
787 section.AddSymbol(new WixActionSymbol(sourceLineNumbers, new Identifier(name.Access, sequence, name.Id))
788 {
789 SequenceTable = SequenceTable.InstallExecuteSequence,
790 Action = name.Id,
791 Condition = condition,
792 // no explicit sequence
793 Before = beforeAction,
794 After = afterAction,
795 Overridable = false,
796 });
797
798 if (null != beforeAction)
799 {
800 if (WindowsInstallerStandard.IsStandardAction(beforeAction))
801 {
802 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixAction, sequence.ToString(), beforeAction);
803 }
804 else
805 {
806 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, beforeAction);
807 }
808 }
809
810 if (null != afterAction)
811 {
812 if (WindowsInstallerStandard.IsStandardAction(afterAction))
813 {
814 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.WixAction, sequence.ToString(), afterAction);
815 }
816 else
817 {
818 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, afterAction);
819 }
820 }
821 }
822
823 private void AddReferenceToRegisterMicrosoftHelp(IntermediateSection section, SourceLineNumber sourceLineNumbers)
824 {
825 this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.CustomAction, "CA_RegisterMicrosoftHelp.3643236F_FC70_11D3_A536_0090278A1BB8");
826 }
827 }
828}