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