From f729d16ab0dfd841a16addaefba61a182d0b0d32 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Mon, 2 Oct 2017 23:49:38 -0700 Subject: Initial code commit --- src/wixext/Data/messages.xml | 133 ++++ src/wixext/Data/tables.xml | 66 ++ src/wixext/VSCompiler.cs | 835 ++++++++++++++++++++++ src/wixext/VSDecompiler.cs | 296 ++++++++ src/wixext/VSExtensionData.cs | 55 ++ src/wixext/WixToolset.VisualStudio.wixext.csproj | 69 ++ src/wixext/WixToolset.VisualStudio.wixext.targets | 10 + src/wixext/xsd/vs.xsd | 292 ++++++++ 8 files changed, 1756 insertions(+) create mode 100644 src/wixext/Data/messages.xml create mode 100644 src/wixext/Data/tables.xml create mode 100644 src/wixext/VSCompiler.cs create mode 100644 src/wixext/VSDecompiler.cs create mode 100644 src/wixext/VSExtensionData.cs create mode 100644 src/wixext/WixToolset.VisualStudio.wixext.csproj create mode 100644 src/wixext/WixToolset.VisualStudio.wixext.targets create mode 100644 src/wixext/xsd/vs.xsd (limited to 'src/wixext') diff --git a/src/wixext/Data/messages.xml b/src/wixext/Data/messages.xml new file mode 100644 index 00000000..d1c85301 --- /dev/null +++ b/src/wixext/Data/messages.xml @@ -0,0 +1,133 @@ + + + + + + + + + Invalid project output group: {0}. + + + + + + No project output group specified. + + + + + Failed to load MSBuild assembly: {0} + + + + + + Failed to load MSBuild engine: {0} + + + + + + Failed to load project {0}: {1} + + + + + + + Failed to build project {0}: {1} + + + + + + + Build failed. + + + + + Missing project output group '{1}' in project {0}. + + + + + + + DirectoryAttributeAccessor tried to access an invalid element type for attribute '{0'}. + + + + + + Invalid generated type: {0}. Must be one of: components, container, payloadgroup, layout. + + + + + + Invalid directory ID: {0}. Check that it doesn't start with a hyphen or slash. + + + + + + Invalid project name: {0}. Check that it doesn't start with a hyphen or slash. + + + + + + Build error during harvesting: {0} + + + + + + Failed to load MSBuild wrapper assembly: {0} + + + + + + Failed to load MSBuild wrapper type: {0} + + + + + + Failed to load MSBuild wrapper object: {0} + + + + + + + + Failed to set loggers: {0} + + + + + + Failed to set project configuration and platform: {0} + + + + + + + + Found ToolsVersion {0} inside project file. + + + + + + Loading project using MSBuild version {0}. + + + + + diff --git a/src/wixext/Data/tables.xml b/src/wixext/Data/tables.xml new file mode 100644 index 00000000..e9c86097 --- /dev/null +++ b/src/wixext/Data/tables.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ +// 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. + +namespace WixToolset.Extensions +{ + using System; + using System.Collections.Generic; + using System.Xml.Linq; + using WixToolset.Data; + using WixToolset.Extensibility; + + /// + /// The compiler for the WiX Toolset Visual Studio Extension. + /// + public sealed class VSCompiler : CompilerExtension + { + internal const int MsidbCustomActionTypeExe = 0x00000002; // Target = command line args + internal const int MsidbCustomActionTypeProperty = 0x00000030; // Source = full path to executable + internal const int MsidbCustomActionTypeContinue = 0x00000040; // ignore action return status; continue running + internal const int MsidbCustomActionTypeRollback = 0x00000100; // in conjunction with InScript: queue in Rollback script + internal const int MsidbCustomActionTypeInScript = 0x00000400; // queue for execution within script + internal const int MsidbCustomActionTypeNoImpersonate = 0x00000800; // queue for not impersonating + + /// + /// Instantiate a new HelpCompiler. + /// + public VSCompiler() + { + this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/vs"; + } + + /// + /// Processes an element for the Compiler. + /// + /// Source line number for the parent element. + /// Parent element of element to process. + /// Element to process. + /// Extra information about the context in which this element is being parsed. + public override void ParseElement(XElement parentElement, XElement element, IDictionary context) + { + switch (parentElement.Name.LocalName) + { + case "Component": + switch (element.Name.LocalName) + { + case "VsixPackage": + this.ParseVsixPackageElement(element, context["ComponentId"], null); + break; + default: + this.Core.UnexpectedElement(parentElement, element); + break; + } + break; + case "File": + switch (element.Name.LocalName) + { + case "HelpCollection": + this.ParseHelpCollectionElement(element, context["FileId"]); + break; + case "HelpFile": + this.ParseHelpFileElement(element, context["FileId"]); + break; + case "VsixPackage": + this.ParseVsixPackageElement(element, context["ComponentId"], context["FileId"]); + break; + default: + this.Core.UnexpectedElement(parentElement, element); + break; + } + break; + case "Fragment": + case "Module": + case "Product": + switch (element.Name.LocalName) + { + case "HelpCollectionRef": + this.ParseHelpCollectionRefElement(element); + break; + case "HelpFilter": + this.ParseHelpFilterElement(element); + break; + default: + this.Core.UnexpectedElement(parentElement, element); + break; + } + break; + default: + this.Core.UnexpectedElement(parentElement, element); + break; + } + } + + /// + /// Parses a HelpCollectionRef element. + /// + /// Element to process. + private void ParseHelpCollectionRefElement(XElement node) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string id = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "HelpNamespace", id); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == id) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); + switch (child.Name.LocalName) + { + case "HelpFileRef": + this.ParseHelpFileRefElement(child, id); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + } + + /// + /// Parses a HelpCollection element. + /// + /// Element to process. + /// Identifier of the parent File element. + private void ParseHelpCollectionElement(XElement node, string fileId) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string id = null; + string description = null; + string name = null; + YesNoType suppressCAs = YesNoType.No; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "Description": + description = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SuppressCustomActions": + suppressCAs = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == id) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); + } + + if (null == description) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Description")); + } + + if (null == name) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); + } + + foreach (XElement child in node.Elements()) + { + if (this.Namespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "HelpFileRef": + this.ParseHelpFileRefElement(child, id); + break; + case "HelpFilterRef": + this.ParseHelpFilterRefElement(child, id); + break; + case "PlugCollectionInto": + this.ParsePlugCollectionIntoElement(child, id); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + this.Core.ParseExtensionElement(node, child); + } + } + + if (!this.Core.EncounteredError) + { + Row row = this.Core.CreateRow(sourceLineNumbers, "HelpNamespace"); + row[0] = id; + row[1] = name; + row[2] = fileId; + row[3] = description; + + if (YesNoType.No == suppressCAs) + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "CA_RegisterMicrosoftHelp.3643236F_FC70_11D3_A536_0090278A1BB8"); + } + } + } + + /// + /// Parses a HelpFile element. + /// + /// Element to process. + /// Identifier of the parent file element. + private void ParseHelpFileElement(XElement node, string fileId) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string id = null; + string name = null; + int language = CompilerConstants.IntegerNotSet; + string hxi = null; + string hxq = null; + string hxr = null; + string samples = null; + YesNoType suppressCAs = YesNoType.No; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "AttributeIndex": + hxr = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "File", hxr); + break; + case "Index": + hxi = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "File", hxi); + break; + case "Language": + language = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SampleLocation": + samples = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "File", samples); + break; + case "Search": + hxq = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "File", hxq); + break; + case "SuppressCustomActions": + suppressCAs = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == id) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); + } + + if (null == name) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); + } + + //uninstall will always fail silently, leaving file registered, if Language is not set + if (CompilerConstants.IntegerNotSet == language) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Language")); + } + + this.Core.ParseForExtensionElements(node); + + if (!this.Core.EncounteredError) + { + Row row = this.Core.CreateRow(sourceLineNumbers, "HelpFile"); + row[0] = id; + row[1] = name; + row[2] = language; + row[3] = fileId; + row[4] = hxi; + row[5] = hxq; + row[6] = hxr; + row[7] = samples; + + if (YesNoType.No == suppressCAs) + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "CA_RegisterMicrosoftHelp.3643236F_FC70_11D3_A536_0090278A1BB8"); + } + } + } + + /// + /// Parses a HelpFileRef element. + /// + /// Element to process. + /// Identifier of the parent help collection. + private void ParseHelpFileRefElement(XElement node, string collectionId) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string id = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "HelpFile", id); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == id) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); + } + + this.Core.ParseForExtensionElements(node); + + if (!this.Core.EncounteredError) + { + Row row = this.Core.CreateRow(sourceLineNumbers, "HelpFileToNamespace"); + row[0] = id; + row[1] = collectionId; + } + } + + /// + /// Parses a HelpFilter element. + /// + /// Element to process. + private void ParseHelpFilterElement(XElement node) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string id = null; + string filterDefinition = null; + string name = null; + YesNoType suppressCAs = YesNoType.No; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "FilterDefinition": + filterDefinition = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Name": + name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "SuppressCustomActions": + suppressCAs = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == id) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); + } + + if (null == name) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); + } + + this.Core.ParseForExtensionElements(node); + + if (!this.Core.EncounteredError) + { + Row row = this.Core.CreateRow(sourceLineNumbers, "HelpFilter"); + row[0] = id; + row[1] = name; + row[2] = filterDefinition; + + if (YesNoType.No == suppressCAs) + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "CA_RegisterMicrosoftHelp.3643236F_FC70_11D3_A536_0090278A1BB8"); + } + } + } + + /// + /// Parses a HelpFilterRef element. + /// + /// Element to process. + /// Identifier of the parent help collection. + private void ParseHelpFilterRefElement(XElement node, string collectionId) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string id = null; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Id": + id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + this.Core.CreateSimpleReference(sourceLineNumbers, "HelpFilter", id); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (null == id) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); + } + + this.Core.ParseForExtensionElements(node); + + if (!this.Core.EncounteredError) + { + Row row = this.Core.CreateRow(sourceLineNumbers, "HelpFilterToNamespace"); + row[0] = id; + row[1] = collectionId; + } + } + + /// + /// Parses a PlugCollectionInto element. + /// + /// Element to process. + /// Identifier of the parent help collection. + private void ParsePlugCollectionIntoElement(XElement node, string parentId) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string hxa = null; + string hxt = null; + string hxtParent = null; + string namespaceParent = null; + string feature = null; + YesNoType suppressExternalNamespaces = YesNoType.No; + bool pluginVS05 = false; + bool pluginVS08 = false; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Attributes": + hxa = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "TableOfContents": + hxt = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "TargetCollection": + namespaceParent = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "TargetTableOfContents": + hxtParent = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "TargetFeature": + feature = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + case "SuppressExternalNamespaces": + suppressExternalNamespaces = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + pluginVS05 = namespaceParent.Equals("MS_VSIPCC_v80", StringComparison.Ordinal); + pluginVS08 = namespaceParent.Equals("MS.VSIPCC.v90", StringComparison.Ordinal); + + if (null == namespaceParent) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetCollection")); + } + + if (null == feature && (pluginVS05 || pluginVS08) && YesNoType.No == suppressExternalNamespaces) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetFeature")); + } + + this.Core.ParseForExtensionElements(node); + + if (!this.Core.EncounteredError) + { + Row row = this.Core.CreateRow(sourceLineNumbers, "HelpPlugin"); + row[0] = parentId; + row[1] = namespaceParent; + row[2] = hxt; + row[3] = hxa; + row[4] = hxtParent; + + if (pluginVS05) + { + if (YesNoType.No == suppressExternalNamespaces) + { + // Bring in the help 2 base namespace components for VS 2005 + this.Core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Feature, feature, String.Empty, + ComplexReferenceChildType.ComponentGroup, "Help2_VS2005_Namespace_Components", false); + // Reference CustomAction since nothing will happen without it + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", + "CA_HxMerge_VSIPCC_VSCC"); + } + } + else if (pluginVS08) + { + if (YesNoType.No == suppressExternalNamespaces) + { + // Bring in the help 2 base namespace components for VS 2008 + this.Core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Feature, feature, String.Empty, + ComplexReferenceChildType.ComponentGroup, "Help2_VS2008_Namespace_Components", false); + // Reference CustomAction since nothing will happen without it + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", + "CA_ScheduleExtHelpPlugin_VSCC_VSIPCC"); + } + } + else + { + // Reference the parent namespace to enforce the foreign key relationship + this.Core.CreateSimpleReference(sourceLineNumbers, "HelpNamespace", + namespaceParent); + } + } + } + + /// + /// Parses a VsixPackage element. + /// + /// Element to process. + /// Identifier of the parent Component element. + /// Identifier of the parent File element. + private void ParseVsixPackageElement(XElement node, string componentId, string fileId) + { + SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + string propertyId = "VS_VSIX_INSTALLER_PATH"; + string packageId = null; + YesNoType permanent = YesNoType.NotSet; + string target = null; + string targetVersion = null; + YesNoType vital = YesNoType.NotSet; + + foreach (XAttribute attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "File": + if (String.IsNullOrEmpty(fileId)) + { + fileId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + } + else + { + this.Core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, "File", "File")); + } + break; + case "PackageId": + packageId = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + break; + case "Permanent": + permanent = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "Target": + target = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (target.ToLowerInvariant()) + { + case "integrated": + case "integratedshell": + target = "IntegratedShell"; + break; + case "professional": + target = "Pro"; + break; + case "premium": + target = "Premium"; + break; + case "ultimate": + target = "Ultimate"; + break; + case "vbexpress": + target = "VBExpress"; + break; + case "vcexpress": + target = "VCExpress"; + break; + case "vcsexpress": + target = "VCSExpress"; + break; + case "vwdexpress": + target = "VWDExpress"; + break; + } + break; + case "TargetVersion": + targetVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); + break; + case "Vital": + vital = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); + break; + case "VsixInstallerPathProperty": + propertyId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + this.Core.ParseExtensionAttribute(node, attrib); + } + } + + if (String.IsNullOrEmpty(fileId)) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "File")); + } + + if (String.IsNullOrEmpty(packageId)) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "PackageId")); + } + + if (!String.IsNullOrEmpty(target) && String.IsNullOrEmpty(targetVersion)) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "TargetVersion", "Target")); + } + else if (String.IsNullOrEmpty(target) && !String.IsNullOrEmpty(targetVersion)) + { + this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Target", "TargetVersion")); + } + + this.Core.ParseForExtensionElements(node); + + if (!this.Core.EncounteredError) + { + // Ensure there is a reference to the AppSearch Property that will find the VsixInstaller.exe. + this.Core.CreateSimpleReference(sourceLineNumbers, "Property", propertyId); + + // Ensure there is a reference to the package file (even if we are a child under it). + this.Core.CreateSimpleReference(sourceLineNumbers, "File", fileId); + + string cmdlinePrefix = "/q "; + + if (!String.IsNullOrEmpty(target)) + { + cmdlinePrefix = String.Format("{0} /skuName:{1} /skuVersion:{2}", cmdlinePrefix, target, targetVersion); + } + + string installAfter = "WriteRegistryValues"; // by default, come after the registry key registration. + int installExtraBits = VSCompiler.MsidbCustomActionTypeInScript; + + // If the package is not vital, mark the install action as continue. + if (vital == YesNoType.No) + { + installExtraBits |= VSCompiler.MsidbCustomActionTypeContinue; + } + else // the package is vital so ensure there is a rollback action scheduled. + { + Identifier rollbackNamePerUser = this.Core.CreateIdentifier("vru", componentId, fileId, "per-user", target ?? String.Empty, targetVersion ?? String.Empty); + Identifier rollbackNamePerMachine = this.Core.CreateIdentifier("vrm", componentId, fileId, "per-machine", target ?? String.Empty, targetVersion ?? String.Empty); + string rollbackCmdLinePerUser = String.Concat(cmdlinePrefix, " /u:\"", packageId, "\""); + string rollbackCmdLinePerMachine = String.Concat(rollbackCmdLinePerUser, " /admin"); + int rollbackExtraBitsPerUser = VSCompiler.MsidbCustomActionTypeContinue | VSCompiler.MsidbCustomActionTypeRollback | VSCompiler.MsidbCustomActionTypeInScript; + int rollbackExtraBitsPerMachine = rollbackExtraBitsPerUser | VSCompiler.MsidbCustomActionTypeNoImpersonate; + 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. + string rollbackConditionPerMachine = String.Format("ALLUSERS AND NOT Installed AND ${0}=2 AND ?{0}>2", componentId); // NOT Installed && Component being installed but not installed already. + + this.SchedulePropertyExeAction(sourceLineNumbers, rollbackNamePerUser, propertyId, rollbackCmdLinePerUser, rollbackExtraBitsPerUser, rollbackConditionPerUser, null, installAfter); + this.SchedulePropertyExeAction(sourceLineNumbers, rollbackNamePerMachine, propertyId, rollbackCmdLinePerMachine, rollbackExtraBitsPerMachine, rollbackConditionPerMachine, null, rollbackNamePerUser.Id); + + installAfter = rollbackNamePerMachine.Id; + } + + Identifier installNamePerUser = this.Core.CreateIdentifier("viu", componentId, fileId, "per-user", target ?? String.Empty, targetVersion ?? String.Empty); + Identifier installNamePerMachine = this.Core.CreateIdentifier("vim", componentId, fileId, "per-machine", target ?? String.Empty, targetVersion ?? String.Empty); + string installCmdLinePerUser = String.Format("{0} \"[#{1}]\"", cmdlinePrefix, fileId); + string installCmdLinePerMachine = String.Concat(installCmdLinePerUser, " /admin"); + string installConditionPerUser = String.Format("NOT ALLUSERS AND ${0}=3", componentId); // only execute if the Component being installed. + string installConditionPerMachine = String.Format("ALLUSERS AND ${0}=3", componentId); // only execute if the Component being installed. + + this.SchedulePropertyExeAction(sourceLineNumbers, installNamePerUser, propertyId, installCmdLinePerUser, installExtraBits, installConditionPerUser, null, installAfter); + this.SchedulePropertyExeAction(sourceLineNumbers, installNamePerMachine, propertyId, installCmdLinePerMachine, installExtraBits | VSCompiler.MsidbCustomActionTypeNoImpersonate, installConditionPerMachine, null, installNamePerUser.Id); + + // If not permanent, schedule the uninstall custom action. + if (permanent != YesNoType.Yes) + { + Identifier uninstallNamePerUser = this.Core.CreateIdentifier("vuu", componentId, fileId, "per-user", target ?? String.Empty, targetVersion ?? String.Empty); + Identifier uninstallNamePerMachine = this.Core.CreateIdentifier("vum", componentId, fileId, "per-machine", target ?? String.Empty, targetVersion ?? String.Empty); + string uninstallCmdLinePerUser = String.Concat(cmdlinePrefix, " /u:\"", packageId, "\""); + string uninstallCmdLinePerMachine = String.Concat(uninstallCmdLinePerUser, " /admin"); + int uninstallExtraBitsPerUser = VSCompiler.MsidbCustomActionTypeContinue | VSCompiler.MsidbCustomActionTypeInScript; + int uninstallExtraBitsPerMachine = uninstallExtraBitsPerUser | VSCompiler.MsidbCustomActionTypeNoImpersonate; + string uninstallConditionPerUser = String.Format("NOT ALLUSERS AND ${0}=2 AND ?{0}>2", componentId); // Only execute if component is being uninstalled. + string uninstallConditionPerMachine = String.Format("ALLUSERS AND ${0}=2 AND ?{0}>2", componentId); // Only execute if component is being uninstalled. + + this.SchedulePropertyExeAction(sourceLineNumbers, uninstallNamePerUser, propertyId, uninstallCmdLinePerUser, uninstallExtraBitsPerUser, uninstallConditionPerUser, "InstallFinalize", null); + this.SchedulePropertyExeAction(sourceLineNumbers, uninstallNamePerMachine, propertyId, uninstallCmdLinePerMachine, uninstallExtraBitsPerMachine, uninstallConditionPerMachine, "InstallFinalize", null); + } + } + } + + private void SchedulePropertyExeAction(SourceLineNumber sourceLineNumbers, Identifier name, string source, string cmdline, int extraBits, string condition, string beforeAction, string afterAction) + { + const string sequence = "InstallExecuteSequence"; + + Row actionRow = this.Core.CreateRow(sourceLineNumbers, "CustomAction", name); + actionRow[1] = VSCompiler.MsidbCustomActionTypeProperty | VSCompiler.MsidbCustomActionTypeExe | extraBits; + actionRow[2] = source; + actionRow[3] = cmdline; + + Row sequenceRow = this.Core.CreateRow(sourceLineNumbers, "WixAction"); + sequenceRow[0] = sequence; + sequenceRow[1] = name.Id; + sequenceRow[2] = condition; + // no explicit sequence + sequenceRow[4] = beforeAction; + sequenceRow[5] = afterAction; + sequenceRow[6] = 0; // not overridable + + if (null != beforeAction) + { + if (WindowsInstallerStandard.IsStandardAction(beforeAction)) + { + this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, beforeAction); + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", beforeAction); + } + } + + if (null != afterAction) + { + if (WindowsInstallerStandard.IsStandardAction(afterAction)) + { + this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", sequence, afterAction); + } + else + { + this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", afterAction); + } + } + } + } +} diff --git a/src/wixext/VSDecompiler.cs b/src/wixext/VSDecompiler.cs new file mode 100644 index 00000000..bfa0670c --- /dev/null +++ b/src/wixext/VSDecompiler.cs @@ -0,0 +1,296 @@ +// 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. + +namespace WixToolset.Extensions +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Globalization; + using WixToolset.Data; + using WixToolset.Extensibility; + using VS = WixToolset.Extensions.Serialize.VS; + using Wix = WixToolset.Data.Serialize; + + /// + /// The decompiler for the WiX Toolset Visual Studio Extension. + /// + public sealed class VSDecompiler : DecompilerExtension + { + /// + /// Creates a decompiler for VS Extension. + /// + public VSDecompiler() + { + this.TableDefinitions = VSExtensionData.GetExtensionTableDefinitions(); + } + + /// + /// Get the extensions library to be removed. + /// + /// Table definitions for library. + /// Library to remove from decompiled output. + public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions) + { + return VSExtensionData.GetExtensionLibrary(tableDefinitions); + } + + /// + /// Decompiles an extension table. + /// + /// The table to decompile. + public override void DecompileTable(Table table) + { + switch (table.Name) + { + case "HelpFile": + this.DecompileHelpFileTable(table); + break; + case "HelpFileToNamespace": + this.DecompileHelpFileToNamespaceTable(table); + break; + case "HelpFilter": + this.DecompileHelpFilterTable(table); + break; + case "HelpFilterToNamespace": + this.DecompileHelpFilterToNamespaceTable(table); + break; + case "HelpNamespace": + this.DecompileHelpNamespaceTable(table); + break; + case "HelpPlugin": + this.DecompileHelpPluginTable(table); + break; + default: + base.DecompileTable(table); + break; + } + } + + /// + /// Decompile the HelpFile table. + /// + /// The table to decompile. + private void DecompileHelpFileTable(Table table) + { + foreach (Row row in table.Rows) + { + VS.HelpFile helpFile = new VS.HelpFile(); + + helpFile.Id = (string)row[0]; + + helpFile.Name = (string)row[1]; + + if (null != row[2]) + { + helpFile.Language = (int)row[2]; + } + + if (null != row[4]) + { + helpFile.Index = (string)row[4]; + } + + if (null != row[5]) + { + helpFile.Search = (string)row[5]; + } + + if (null != row[6]) + { + helpFile.AttributeIndex = (string)row[6]; + } + + if (null != row[7]) + { + helpFile.SampleLocation = (string)row[7]; + } + + if (this.Core.RootElement is Wix.Module) + { + helpFile.SuppressCustomActions = VS.YesNoType.yes; + } + + Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", (string)row[3]); + if (null != file) + { + file.AddChild(helpFile); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_HxS", (string)row[3], "File")); + } + } + } + + /// + /// Decompile the HelpFileToNamespace table. + /// + /// The table to decompile. + private void DecompileHelpFileToNamespaceTable(Table table) + { + foreach (Row row in table.Rows) + { + VS.HelpFileRef helpFileRef = new VS.HelpFileRef(); + + helpFileRef.Id = (string)row[0]; + + VS.HelpCollection helpCollection = (VS.HelpCollection)this.Core.GetIndexedElement("HelpNamespace", (string)row[1]); + if (null != helpCollection) + { + helpCollection.AddChild(helpFileRef); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "HelpNamespace_", (string)row[1], "HelpNamespace")); + } + } + } + + /// + /// Decompile the HelpFilter table. + /// + /// The table to decompile. + private void DecompileHelpFilterTable(Table table) + { + foreach (Row row in table.Rows) + { + VS.HelpFilter helpFilter = new VS.HelpFilter(); + + helpFilter.Id = (string)row[0]; + + helpFilter.Name = (string)row[1]; + + if (null != row[2]) + { + helpFilter.FilterDefinition = (string)row[2]; + } + + if (this.Core.RootElement is Wix.Module) + { + helpFilter.SuppressCustomActions = VS.YesNoType.yes; + } + + this.Core.RootElement.AddChild(helpFilter); + } + } + + /// + /// Decompile the HelpFilterToNamespace table. + /// + /// The table to decompile. + private void DecompileHelpFilterToNamespaceTable(Table table) + { + foreach (Row row in table.Rows) + { + VS.HelpFilterRef helpFilterRef = new VS.HelpFilterRef(); + + helpFilterRef.Id = (string)row[0]; + + VS.HelpCollection helpCollection = (VS.HelpCollection)this.Core.GetIndexedElement("HelpNamespace", (string)row[1]); + if (null != helpCollection) + { + helpCollection.AddChild(helpFilterRef); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "HelpNamespace_", (string)row[1], "HelpNamespace")); + } + } + } + + /// + /// Decompile the HelpNamespace table. + /// + /// The table to decompile. + private void DecompileHelpNamespaceTable(Table table) + { + foreach (Row row in table.Rows) + { + VS.HelpCollection helpCollection = new VS.HelpCollection(); + + helpCollection.Id = (string)row[0]; + + helpCollection.Name = (string)row[1]; + + if (null != row[3]) + { + helpCollection.Description = (string)row[3]; + } + + if (this.Core.RootElement is Wix.Module) + { + helpCollection.SuppressCustomActions = VS.YesNoType.yes; + } + + Wix.File file = (Wix.File)this.Core.GetIndexedElement("File", (string)row[2]); + if (null != file) + { + file.AddChild(helpCollection); + } + else if (0 != String.Compare(helpCollection.Id, "MS_VSIPCC_v80", StringComparison.Ordinal) && + 0 != String.Compare(helpCollection.Id, "MS.VSIPCC.v90", StringComparison.Ordinal)) + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "File_Collection", (string)row[2], "File")); + } + this.Core.IndexElement(row, helpCollection); + } + } + + /// + /// Decompile the HelpPlugin table. + /// + /// The table to decompile. + private void DecompileHelpPluginTable(Table table) + { + foreach (Row row in table.Rows) + { + VS.PlugCollectionInto plugCollectionInto = new VS.PlugCollectionInto(); + + plugCollectionInto.TargetCollection = (string)row[1]; + + if (null != row[2]) + { + plugCollectionInto.TableOfContents = (string)row[2]; + } + + if (null != row[3]) + { + plugCollectionInto.Attributes = (string)row[3]; + } + + if (null != row[4]) + { + plugCollectionInto.TargetTableOfContents = (string)row[4]; + } + + if (this.Core.RootElement is Wix.Module) + { + plugCollectionInto.SuppressExternalNamespaces = VS.YesNoType.yes; + } + + //we cannot do this work because we cannot get the FeatureComponent table + //plugCollectionInto.TargetFeature = DecompileHelpComponents(); + + VS.HelpCollection helpCollection = (VS.HelpCollection)this.Core.GetIndexedElement("HelpNamespace", (string)row[0]); + if (null != helpCollection) + { + helpCollection.AddChild(plugCollectionInto); + } + else + { + this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "HelpNamespace_", (string)row[0], "HelpNamespace")); + } + } + } + //private string DecompileHelpComponents() + //{ + // throw new NotImplementedException(); + // //Find both known compontents from FeatureComponents table and build feature list + + // //remove components from FeatureComponents + + // //return a space delimited list of features that mapped to our help components + // return String.Empty; + //} + } +} diff --git a/src/wixext/VSExtensionData.cs b/src/wixext/VSExtensionData.cs new file mode 100644 index 00000000..edb1fd42 --- /dev/null +++ b/src/wixext/VSExtensionData.cs @@ -0,0 +1,55 @@ +// 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. + +namespace WixToolset.Extensions +{ + using System; + using System.Reflection; + using WixToolset.Data; + using WixToolset.Extensibility; + + /// + /// The WiX Toolset Visual Studio Extension. + /// + public sealed class VSExtensionData : ExtensionData + { + /// + /// Gets the optional table definitions for this extension. + /// + /// The optional table definitions for this extension. + public override TableDefinitionCollection TableDefinitions + { + get + { + return VSExtensionData.GetExtensionTableDefinitions(); + } + } + + /// + /// Gets the library associated with this extension. + /// + /// The table definitions to use while loading the library. + /// The loaded library. + public override Library GetLibrary(TableDefinitionCollection tableDefinitions) + { + return VSExtensionData.GetExtensionLibrary(tableDefinitions); + } + + /// + /// Internal mechanism to access the extension's table definitions. + /// + /// Extension's table definitions. + internal static TableDefinitionCollection GetExtensionTableDefinitions() + { + return ExtensionData.LoadTableDefinitionHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.tables.xml"); + } + + /// + /// Internal mechanism to access the extension's library. + /// + /// Extension's library. + internal static Library GetExtensionLibrary(TableDefinitionCollection tableDefinitions) + { + return ExtensionData.LoadLibraryHelper(Assembly.GetExecutingAssembly(), "WixToolset.Extensions.Data.vs.wixlib", tableDefinitions); + } + } +} diff --git a/src/wixext/WixToolset.VisualStudio.wixext.csproj b/src/wixext/WixToolset.VisualStudio.wixext.csproj new file mode 100644 index 00000000..0b092662 --- /dev/null +++ b/src/wixext/WixToolset.VisualStudio.wixext.csproj @@ -0,0 +1,69 @@ + + + + + + netstandard2.0 + WixToolset.Extensions + WiX Toolset Visual Studio Extension + WiX Toolset VS Extension + true + build + + + + NU1701 + + + + + $(RootNamespace).Data.tables.xml + + + + $(RootNamespace).Data.Messages.resources + + + + $(RootNamespace).Xsd.vs.xsd + true + tools + + + + WixToolset.Data.Serialize + WixToolset.Extensions.Serialize.VS + + + + Data\vs.wixlib + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + diff --git a/src/wixext/WixToolset.VisualStudio.wixext.targets b/src/wixext/WixToolset.VisualStudio.wixext.targets new file mode 100644 index 00000000..903455e3 --- /dev/null +++ b/src/wixext/WixToolset.VisualStudio.wixext.targets @@ -0,0 +1,10 @@ + + + + + + + $(MSBuildThisFileDirectory)..\tools\WixToolset.VS.wixext.dll + + + diff --git a/src/wixext/xsd/vs.xsd b/src/wixext/xsd/vs.xsd new file mode 100644 index 00000000..51172920 --- /dev/null +++ b/src/wixext/xsd/vs.xsd @@ -0,0 +1,292 @@ + + + + + + + + The source code schema for the WiX Toolset Visual Studio Extension. + + + + + + + Help Namespace for a help collection. The parent file is the key for the HxC (Collection) file. + + + + + + + + + + + + + Primary Key for HelpNamespace. + + + Friendly name for Namespace. + + + Internal Microsoft Help ID for this Namespace. + + + Suppress linking Help registration custom actions. Help redistributable merge modules will be required. Use this when building a merge module. + + + + + + + + Filter for Help Namespace. + + + + + + + + + + Primary Key for HelpFilter. + + + Query String for Help Filter. + + + Friendly name for Filter. + + + Suppress linking Help registration custom actions. Help redistributable merge modules will be required. Use this when building a merge module. + + + + + + + + File for Help Namespace. The parent file is the key for HxS (Title) file. + + + + + + + + Primary Key for HelpFile Table. + + + Key for HxR (Attributes) file. + + + Key for HxI (Index) file. + + + Language ID for content file. + + + Internal Microsoft Help ID for this HelpFile. + + + Key for a file that is in the "root" of the samples directory for this HelpFile. + + + Key for HxQ (Query) file. + + + Suppress linking Help registration custom actions. Help redistributable merge modules will be required. Use this when building a merge module. + + + + + + Plugin for Help Namespace. + + + Key for HxA (Attributes) file of child namespace. + + + Key for HxT file of child namespace. + + + + Foriegn Key into HelpNamespace table for the parent namespace into which the child will be inserted. + The following special keys can be used to plug into external namespaces defined outside of the installer. + MS_VSIPCC_v80 : Visual Studio 2005 + MS.VSIPCC.v90 : Visual Studio 2008 + + + + Key for HxT file of parent namespace that now includes the new child namespace. + + + Key for the feature parent of this help collection. Required only when plugging into external namespaces. + + + Suppress linking Visual Studio Help namespaces. Help redistributable merge modules will be required. Use this when building a merge module. + + + + + + Create a reference to a HelpFile element in another Fragment. + + + Primary Key for HelpFile Table. + + + + Extensibility point in the WiX XML Schema. Schema extensions can register additional + attributes at this point in the schema. + + + + + + + Create a reference to a HelpFile element in another Fragment. + + + Primary Key for HelpFilter. + + + + Extensibility point in the WiX XML Schema. Schema extensions can register additional + attributes at this point in the schema. + + + + + + + + Create a reference to a HelpCollection element in another Fragment. + + + + + + + + + + + + Primary Key for HelpNamespace Table. + + + + Extensibility point in the WiX XML Schema. Schema extensions can register additional + attributes at this point in the schema. + + + + + + + + + This element provides the metdata required to install/uninstall a file as + a VSIX Package. The VSIX package file will be installed as part of the MSI + then passed to the VSIX installer to install the VSIX package. To avoid the + duplication, simply use the MSI to install the VSIX package itself. + + + + + + + + + + + Reference to file identifer. This attribute is required when the element is not a + child of a File element and is invalid when the element is a child of the File element. + + + + + + + Identity of the VSIX package per its internal manifest. If this value is not correct + the VSIX package will not correctly uninstall. + + + + + + + Indicates whether the VSIX package is uninstalled when the parent Component is uninstalled. + The default is 'no'. + + + + + + + Specifies the SKU of Visual Studio in which to register the extension. If no target + is specified the extension is registered with all installed SKUs. If the Target + attribute is specified the TargetVersion attribute must also be specified. The + following is a list of known Visual Studio targets: integratedShell, professional, + premium, ultimate, vbExpress, vcExpress, vcsExpress, vwdExpress + + + + + + + Specifies the version of Visual Studio in which to register the extension. This attribute + is required if the Target attribute is specified. + + + + + + + Indicates whether failure to install the VSIX package causes the installation to rollback. + The default is 'yes'. + + + + + + + Optional reference to a Property element that contains the path to the VsixInstaller.exe. + By default, the latest VsixInstaller.exe on the machine will be used to install the VSIX + package. It is highly recommended that this attribute is *not* used. + + + + + + Extensibility point in the WiX XML Schema. Schema extensions can register additional + attributes at this point in the schema. + + + + + + + Values of this type will look like: "x.x.x.x" where x is an integer from 0 to 65534. + + + + + + + + Values of this type will either be "yes" or "no". + + + + + + + -- cgit v1.2.3-55-g6feb