/// <summary> /// Parse a localization file from an XML format. /// </summary> /// <param name="reader">XmlReader where the localization file is persisted.</param> /// <param name="tableDefinitions">Collection containing TableDefinitions to use when parsing the localization file.</param> /// <returns>The parsed localization.</returns> internal static Localization Parse(XmlReader reader, TableDefinitionCollection tableDefinitions) { Debug.Assert("WixLocalization" == reader.LocalName); bool empty = reader.IsEmptyElement; int codepage = -1; string culture = null; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "Codepage": try { codepage = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture.NumberFormat); } catch (FormatException) { throw new WixException(WixErrors.IllegalIntegerValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "WixLocalization", reader.Name, reader.Value)); } catch (OverflowException) { throw new WixException(WixErrors.IllegalIntegerValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "WixLocalization", reader.Name, reader.Value)); } break; case "Culture": culture = reader.Value; break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/")) { throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "WixLocalization", reader.Name)); } break; } } if (null == culture) { throw new WixException(WixErrors.ExpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "WixLocalization", "Culture")); } Localization localization = new Localization(codepage, culture); if (!empty) { bool done = false; while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "String": ParseString(reader, tableDefinitions, localization); break; default: throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "WixLocalization", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "WixLocalization")); } } return(localization); }
/// <summary> /// Parses a PlugCollectionInto element. /// </summary> /// <param name="node">Element to process.</param> /// <param name="parentId">Identifier of the parent help collection.</param> 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); } } }
/// <summary> /// Parses a Condition element for Bundles. /// </summary> /// <param name="node">The element to parse.</param> private void ParseConditionElement(XmlNode node) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string condition = CompilerCore.GetConditionInnerText(node); // condition is the inner text of the element. string message = null; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Message": message = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false); break; default: this.Core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.Core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { this.Core.UnexpectedElement(node, child); } else { this.Core.UnsupportedExtensionElement(node, child); } } } // Error check the values. if (String.IsNullOrEmpty(condition)) { this.Core.OnMessage(WixErrors.ConditionExpected(sourceLineNumbers, node.Name)); } if (null == message) { this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Message")); } if (!this.Core.EncounteredError) { Row row = this.Core.CreateRow(sourceLineNumbers, "WixBalCondition"); row[0] = condition; row[1] = message; if (null == this.addedConditionLineNumber) { this.addedConditionLineNumber = sourceLineNumbers; } } }
/// <summary> /// Include transforms in a patch. /// </summary> /// <param name="transforms">List of transforms to attach.</param> public void AttachTransforms(ArrayList transforms) { int emptyTransform = 0; if (transforms == null || transforms.Count == 0) { throw new WixException(WixErrors.PatchWithoutTransforms()); } // Get the patch id from the WixPatchId table. string patchId = null; Table wixPatchIdTable = this.patch.Tables["WixPatchId"]; if (null != wixPatchIdTable && 0 < wixPatchIdTable.Rows.Count) { Row patchIdRow = wixPatchIdTable.Rows[0]; if (null != patchIdRow) { patchId = patchIdRow[0].ToString(); } } // enumerate patch.Media to map diskId to Media row Hashtable mediaRows = new Hashtable(); Table patchMediaTable = patch.Tables["Media"]; if (patchMediaTable != null) { foreach (MediaRow row in patchMediaTable.Rows) { int media = row.DiskId; mediaRows[media] = row; } } // enumerate patch.WixPatchBaseline to map baseline to diskId Hashtable baselineMedia = new Hashtable(); Table patchBaselineTable = patch.Tables["WixPatchBaseline"]; if (patchBaselineTable != null) { foreach (Row row in patchBaselineTable.Rows) { string baseline = (string)row[0]; int media = (int)row[1]; if (baselineMedia.Contains(baseline)) { throw new InvalidOperationException(String.Format("PatchBaseline '{0}' authored into multiple Media.", baseline)); } baselineMedia[baseline] = media; } } // enumerate transforms ArrayList productCodes = new ArrayList(); ArrayList transformNames = new ArrayList(); int transformCount = 0; foreach (PatchTransform mainTransform in transforms) { string baseline = null; int media = -1; if (baselineMedia.Contains(mainTransform.Baseline)) { int newMedia = (int)baselineMedia[mainTransform.Baseline]; if (media != -1 && media != newMedia) { throw new InvalidOperationException(String.Format("Transform authored into multiple Media '{0}' and '{1}'.", media, newMedia)); } baseline = mainTransform.Baseline; media = newMedia; } if (media == -1) { // transform's baseline not attached to any Media continue; } Table patchRefTable = patch.Tables["WixPatchRef"]; if (patchRefTable != null && patchRefTable.Rows.Count > 0) { if (!this.ReduceTransform(mainTransform.Transform, patchRefTable)) { // transform has none of the content authored into this patch emptyTransform++; continue; } } // ensure consistent File.Sequence within each Media MediaRow mediaRow = (MediaRow)mediaRows[media]; // TODO: should this be authored rather than inferring it from DiskId? mediaRow.LastSequence = mediaRow.DiskId; // ignore media table from transform. mainTransform.Transform.Tables.Remove("Media"); mainTransform.Transform.Tables.Remove("WixMedia"); mainTransform.Transform.Tables.Remove("MsiDigitalSignature"); string productCode = null; Output pairedTransform = this.BuildPairedTransform(patchId, mainTransform.Transform, mediaRow, ref productCode); productCodes.Add(productCode); // attach these transforms to the patch object // TODO: is this an acceptable way to auto-generate transform stream names? string transformName = baseline + "." + (++transformCount).ToString(); patch.SubStorages.Add(new SubStorage(transformName, mainTransform.Transform)); patch.SubStorages.Add(new SubStorage("#" + transformName, pairedTransform)); transformNames.Add(":" + transformName); transformNames.Add(":#" + transformName); } if (emptyTransform == transforms.Count) { throw new WixException(WixErrors.PatchWithoutValidTransforms()); } // populate MSP summary information Table patchSummaryInfo = patch.EnsureTable(this.tableDefinitions["_SummaryInformation"]); // remove any existing data for these fields for (int i = patchSummaryInfo.Rows.Count - 1; i >= 0; i--) { Row row = patchSummaryInfo.Rows[i]; switch ((SummaryInformation.Patch)row[0]) { case SummaryInformation.Patch.ProductCodes: case SummaryInformation.Patch.TransformNames: case SummaryInformation.Patch.PatchCode: case SummaryInformation.Patch.InstallerRequirement: patchSummaryInfo.Rows.RemoveAt(i); break; } } // Semicolon delimited list of the product codes that can accept the patch. Row templateRow = patchSummaryInfo.CreateRow(null); templateRow[0] = (int)SummaryInformation.Patch.ProductCodes; templateRow[1] = String.Join(";", (string[])productCodes.ToArray(typeof(string))); // Semicolon delimited list of transform substorage names in the order they are applied. Row savedbyRow = patchSummaryInfo.CreateRow(null); savedbyRow[0] = (int)SummaryInformation.Patch.TransformNames; savedbyRow[1] = String.Join(";", (string[])transformNames.ToArray(typeof(string))); // GUID patch code for the patch. Row revisionRow = patchSummaryInfo.CreateRow(null); revisionRow[0] = (int)SummaryInformation.Patch.PatchCode; revisionRow[1] = patchId; // Indicates the minimum Windows Installer version that is required to install the patch. Row wordsRow = patchSummaryInfo.CreateRow(null); wordsRow[0] = (int)SummaryInformation.Patch.InstallerRequirement; wordsRow[1] = ((int)SummaryInformation.InstallerRequirement.Version31).ToString(); Row security = patchSummaryInfo.CreateRow(null); security[0] = 19; //PID_SECURITY security[1] = "4"; Table msiPatchMetadataTable = patch.Tables["MsiPatchMetadata"]; if (null != msiPatchMetadataTable) { Hashtable metadataTable = new Hashtable(); foreach (Row row in msiPatchMetadataTable.Rows) { metadataTable.Add(row.Fields[1].Data.ToString(), row.Fields[2].Data.ToString()); } if (metadataTable.Contains("DisplayName")) { string comment = String.Concat("This patch contains the logic and data required to install ", metadataTable["DisplayName"]); Row title = patchSummaryInfo.CreateRow(null); title[0] = 2; //PID_TITLE title[1] = metadataTable["DisplayName"]; Row comments = patchSummaryInfo.CreateRow(null); comments[0] = 6; //PID_COMMENTS comments[1] = comment; } if (metadataTable.Contains("CodePage")) { Row codePage = patchSummaryInfo.CreateRow(null); codePage[0] = 1; //PID_CODEPAGE codePage[1] = metadataTable["CodePage"]; } if (metadataTable.Contains("Description")) { Row subject = patchSummaryInfo.CreateRow(null); subject[0] = 3; //PID_SUBJECT subject[1] = metadataTable["Description"]; } if (metadataTable.Contains("ManufacturerName")) { Row author = patchSummaryInfo.CreateRow(null); author[0] = 4; //PID_AUTHOR author[1] = metadataTable["ManufacturerName"]; } } }
/// <summary> /// Parses a HelpFile element. /// </summary> /// <param name="node">Element to process.</param> /// <param name="fileId">Identifier of the parent file element.</param> 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"); } } }
/// <summary> /// Loads a HeatExtension from a type description string. /// </summary> /// <param name="extension">The extension type description string.</param> /// <returns>The loaded HeatExtension.</returns> /// <remarks> /// <paramref name="extension"/> can be in several different forms: /// <list type="number"> /// <item><term>AssemblyQualifiedName (TopNamespace.SubNameSpace.ContainingClass+NestedClass, MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089)</term></item> /// <item><term>AssemblyName (MyAssembly, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b17a5c561934e089)</term></item> /// <item><term>Absolute path to an assembly (C:\MyExtensions\ExtensionAssembly.dll)</term></item> /// <item><term>Filename of an assembly in the application directory (ExtensionAssembly.dll)</term></item> /// <item><term>Relative path to an assembly (..\..\MyExtensions\ExtensionAssembly.dll)</term></item> /// </list> /// To specify a particular class to use, prefix the fully qualified class name to the assembly and separate them with a comma. /// For example: "TopNamespace.SubNameSpace.ContainingClass+NestedClass, C:\MyExtensions\ExtensionAssembly.dll" /// </remarks> public static HeatExtension Load(string extension) { Type extensionType = null; int commaIndex = extension.IndexOf(','); string className = String.Empty; string assemblyName = extension; if (0 <= commaIndex) { className = extension.Substring(0, commaIndex); assemblyName = (extension.Length <= commaIndex + 1 ? String.Empty : extension.Substring(commaIndex + 1)); } className = className.Trim(); assemblyName = assemblyName.Trim(); if (null == extensionType && 0 < assemblyName.Length) { Assembly extensionAssembly; // case 3: Absolute path to an assembly if (Path.IsPathRooted(assemblyName)) { extensionAssembly = ExtensionLoadFrom(assemblyName); } else { try { // case 2: AssemblyName extensionAssembly = Assembly.Load(assemblyName); } catch (IOException e) { if (e is FileLoadException || e is FileNotFoundException) { try { // case 4: Filename of an assembly in the application directory extensionAssembly = Assembly.Load(Path.GetFileNameWithoutExtension(assemblyName)); } catch (IOException innerE) { if (innerE is FileLoadException || innerE is FileNotFoundException) { // case 5: Relative path to an assembly // we want to use Assembly.Load when we can because it has some benefits over Assembly.LoadFrom // (see the documentation for Assembly.LoadFrom). However, it may fail when the path is a relative // path, so we should try Assembly.LoadFrom one last time. We could have detected a directory // separator character and used Assembly.LoadFrom directly, but dealing with path canonicalization // issues is something we don't want to deal with if we don't have to. extensionAssembly = ExtensionLoadFrom(assemblyName); } else { throw new WixException(WixErrors.InvalidExtension(assemblyName, innerE.Message)); } } } else { throw new WixException(WixErrors.InvalidExtension(assemblyName, e.Message)); } } } if (0 < className.Length) { try { // case 1: AssemblyQualifiedName extensionType = extensionAssembly.GetType(className, true /* throwOnError */, true /* ignoreCase */); } catch (Exception e) { throw new WixException(WixErrors.InvalidExtensionType(assemblyName, className, e.GetType().ToString(), e.Message)); } } else { // if no class name was specified, then let's hope the assembly defined a default WixExtension AssemblyDefaultHeatExtensionAttribute extensionAttribute = (AssemblyDefaultHeatExtensionAttribute)Attribute.GetCustomAttribute(extensionAssembly, typeof(AssemblyDefaultHeatExtensionAttribute)); if (null != extensionAttribute) { extensionType = extensionAttribute.ExtensionType; } else { throw new WixException(WixErrors.InvalidExtensionType(assemblyName, typeof(AssemblyDefaultHeatExtensionAttribute).ToString())); } } } if (extensionType.IsSubclassOf(typeof(HeatExtension))) { return(Activator.CreateInstance(extensionType) as HeatExtension); } else { throw new WixException(WixErrors.InvalidExtensionType(extension, extensionType.ToString(), typeof(HeatExtension).ToString())); } }
/// <summary> /// Processes the Requires element. /// </summary> /// <param name="node">The XML node for the Requires element.</param> /// <param name="providerId">The parent provider identifier.</param> /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param> private void ParseRequiresElement(XElement node, string providerId, bool requiresAction) { SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; string providerKey = null; string minVersion = null; string maxVersion = null; int attributes = 0; int illegalChar = -1; 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.GetAttributeIdentifier(sourceLineNumbers, attrib); break; case "ProviderKey": providerKey = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Minimum": minVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); break; case "Maximum": maxVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); break; case "IncludeMinimum": if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= DependencyCommon.RequiresAttributesMinVersionInclusive; } break; case "IncludeMaximum": if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= DependencyCommon.RequiresAttributesMaxVersionInclusive; } break; default: this.Core.UnexpectedAttribute(node, attrib); break; } } else { this.Core.ParseExtensionAttribute(node, attrib); } } this.Core.ParseForExtensionElements(node); if (null == id) { // Generate an ID only if this element is authored under a Provides element; otherwise, a RequiresRef // element will be necessary and the Id attribute will be required. if (!String.IsNullOrEmpty(providerId)) { id = this.Core.CreateIdentifier("dep", node.Name.LocalName, providerKey); } else { this.Core.OnMessage(WixErrors.ExpectedAttributeWhenElementNotUnderElement(sourceLineNumbers, node.Name.LocalName, "Id", "Provides")); id = Identifier.Invalid; } } if (String.IsNullOrEmpty(providerKey)) { this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "ProviderKey")); } // Make sure the key does not contain any illegal characters. else if (0 <= (illegalChar = providerKey.IndexOfAny(DependencyCommon.InvalidCharacters))) { StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); Array.ForEach <char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "ProviderKey", providerKey[illegalChar], sb.ToString())); } if (!this.Core.EncounteredError) { // Reference the Require custom action if required. if (requiresAction) { if (Platform.ARM == this.Core.CurrentPlatform) { // Ensure the ARM version of the CA is referenced. this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire_ARM"); } else { // All other supported platforms use x86. this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyRequire"); } } Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependency", id); row[1] = providerKey; row[2] = minVersion; row[3] = maxVersion; if (0 != attributes) { row[4] = attributes; } // Create the relationship between this WixDependency row and the WixDependencyProvider row. if (!String.IsNullOrEmpty(providerId)) { // Create the relationship between the WixDependency row and the parent WixDependencyProvider row. row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyRef"); row[0] = providerId; row[1] = id.Id; } } }
/// <summary> /// Creates a Row from the XmlReader. /// </summary> /// <param name="reader">Reader to get data from.</param> /// <param name="table">Table for this row.</param> /// <returns>New row object.</returns> internal static Row Parse(XmlReader reader, Table table) { Debug.Assert("row" == reader.LocalName); bool empty = reader.IsEmptyElement; RowOperation operation = RowOperation.None; string sectionId = null; SourceLineNumber sourceLineNumbers = null; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "op": switch (reader.Value) { case "add": operation = RowOperation.Add; break; case "delete": operation = RowOperation.Delete; break; case "modify": operation = RowOperation.Modify; break; default: throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumber.CreateFromUri(reader.BaseURI), "row", reader.Name, reader.Value, "Add", "Delete", "Modify")); } break; case "sectionId": sectionId = reader.Value; break; case "sourceLineNumber": sourceLineNumbers = new SourceLineNumber(reader.Value); break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal)) { throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumber.CreateFromUri(reader.BaseURI), "row", reader.Name)); } break; } } Row row = table.CreateRow(sourceLineNumbers); row.Operation = operation; row.SectionId = sectionId; // loop through all the fields in a row if (!empty) { bool done = false; int field = 0; // loop through all the fields in a row while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "field": if (row.Fields.Length <= field) { if (!reader.IsEmptyElement) { throw new WixException(WixErrors.UnexpectedColumnCount(SourceLineNumber.CreateFromUri(reader.BaseURI), table.Name)); } } else { row.fields[field].Parse(reader); } ++field; break; default: throw new WixException(WixErrors.UnexpectedElement(SourceLineNumber.CreateFromUri(reader.BaseURI), "row", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumber.CreateFromUri(reader.BaseURI), "row")); } } return(row); }
/// <summary> /// Assign files to cabinets based on MediaTemplate authoring. /// </summary> /// <param name="fileRows">FileRowCollection</param> private void AutoAssignFiles(Table mediaTable, FileRowCollection fileRows) { const int MaxCabIndex = 999; ulong currentPreCabSize = 0; ulong maxPreCabSizeInBytes; int maxPreCabSizeInMB = 0; int currentCabIndex = 0; MediaRow currentMediaRow = null; Table mediaTemplateTable = this.output.Tables["WixMediaTemplate"]; // Auto assign files to cabinets based on maximum uncompressed media size mediaTable.Rows.Clear(); WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0]; if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate)) { this.cabinetNameTemplate = mediaTemplateRow.CabinetTemplate; } string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS"); try { // Override authored mums value if environment variable is authored. if (!String.IsNullOrEmpty(mumsString)) { maxPreCabSizeInMB = Int32.Parse(mumsString); } else { maxPreCabSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize; } maxPreCabSizeInBytes = (ulong)maxPreCabSizeInMB * 1024 * 1024; } catch (FormatException) { throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString)); } catch (OverflowException) { throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB)); } foreach (FileRow fileRow in fileRows) { // When building a product, if the current file is not to be compressed or if // the package set not to be compressed, don't cab it. if (OutputType.Product == output.Type && (YesNoType.No == fileRow.Compressed || (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed))) { uncompressedFileRows.Add(fileRow); continue; } FileInfo fileInfo = null; // Get the file size try { fileInfo = new FileInfo(fileRow.Source); } catch (ArgumentException) { this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source)); } catch (PathTooLongException) { this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source)); } catch (NotSupportedException) { this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source)); } if (fileInfo.Exists) { if (fileInfo.Length > Int32.MaxValue) { throw new WixException(WixErrors.FileTooLarge(fileRow.SourceLineNumbers, fileRow.Source)); } fileRow.FileSize = Convert.ToInt32(fileInfo.Length, CultureInfo.InvariantCulture); } if (currentCabIndex == MaxCabIndex) { // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore. FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow]; fileRow.DiskId = currentCabIndex; cabinetFileRow.Add(fileRow); continue; } // Update current cab size. currentPreCabSize += (ulong)fileRow.FileSize; if (currentPreCabSize > maxPreCabSizeInBytes) { // Overflow due to current file currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel); FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow]; fileRow.DiskId = currentCabIndex; cabinetFileRow.Add(fileRow); // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize currentPreCabSize = (ulong)fileRow.FileSize; } else { // File fits in the current cab. if (currentMediaRow == null) { // Create new cab and MediaRow currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel); } // Associate current file with current cab. FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow]; fileRow.DiskId = currentCabIndex; cabinetFileRow.Add(fileRow); } } // If there are uncompressed files and no MediaRow, create a default one. if (uncompressedFileRows.Count > 0 && mediaTable.Rows.Count == 0) { MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null); defaultMediaRow.DiskId = 1; mediaRows.Add(defaultMediaRow); } }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { try { // parse the command line this.ParseCommandLine(args); // exit if there was an error parsing the command line (otherwise the logo appears after error messages) if (Messaging.Instance.EncounteredError) { return(Messaging.Instance.LastErrorNumber); } if (this.showLogo) { AppCommon.DisplayToolHeader(); } if (this.showHelp) { Console.WriteLine(LuxStrings.HelpMessage); AppCommon.DisplayToolFooter(); return(Messaging.Instance.LastErrorNumber); } foreach (string parameter in this.invalidArgs) { Messaging.Instance.OnMessage(WixWarnings.UnsupportedCommandLineArgument(parameter)); } this.invalidArgs = null; // gotta have something to do if (0 == this.inputFiles.Count || String.IsNullOrEmpty(this.outputFile)) { Console.WriteLine(LuxStrings.HelpMessage); Messaging.Instance.OnMessage(LuxBuildErrors.MalfunctionNeedInput()); return(Messaging.Instance.LastErrorNumber); } if (String.IsNullOrEmpty(Path.GetExtension(this.outputFile))) { this.outputFile = Path.ChangeExtension(this.outputFile, ".wxs"); } // get extensions from lux.exe.config AppCommon.ReadConfiguration(this.extensionList); Generator.Generate(this.extensionList, this.inputFiles, this.outputFile); } catch (WixException we) { Messaging.Instance.OnMessage(we.Error); } catch (Exception e) { Messaging.Instance.OnMessage(WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } return(Messaging.Instance.LastErrorNumber); }
/// <summary> /// Replaces parameters in the source text. /// </summary> /// <param name="sourceLineNumbers">The source line information for the function.</param> /// <param name="value">Text that may contain parameters to replace.</param> /// <returns>Text after parameters have been replaced.</returns> public string PreprocessString(SourceLineNumberCollection sourceLineNumbers, string value) { StringBuilder sb = new StringBuilder(); int currentPosition = 0; int end = 0; while (-1 != (currentPosition = value.IndexOf('$', end))) { if (end < currentPosition) { sb.Append(value, end, currentPosition - end); } end = currentPosition + 1; string remainder = value.Substring(end); if (remainder.StartsWith("$")) { sb.Append("$"); end++; } else if (remainder.StartsWith("(loc.")) { currentPosition = remainder.IndexOf(')'); if (-1 == currentPosition) { throw new WixException(WixErrors.InvalidPreprocessorVariable(sourceLineNumbers, remainder)); } sb.Append("$"); // just put the resource reference back as was sb.Append(remainder, 0, currentPosition + 1); end += currentPosition + 1; } else if (remainder.StartsWith("(")) { int openParenCount = 1; int closingParenCount = 0; bool isFunction = false; bool foundClosingParen = false; // find the closing paren int closingParenPosition; for (closingParenPosition = 1; closingParenPosition < remainder.Length; closingParenPosition++) { switch (remainder[closingParenPosition]) { case '(': openParenCount++; isFunction = true; break; case ')': closingParenCount++; break; } if (openParenCount == closingParenCount) { foundClosingParen = true; break; } } // move the currentPosition to the closing paren currentPosition += closingParenPosition; if (!foundClosingParen) { if (isFunction) { throw new WixException(WixErrors.InvalidPreprocessorFunction(sourceLineNumbers, remainder)); } else { throw new WixException(WixErrors.InvalidPreprocessorVariable(sourceLineNumbers, remainder)); } } string subString = remainder.Substring(1, closingParenPosition - 1); string result = null; if (isFunction) { result = this.EvaluateFunction(sourceLineNumbers, subString); } else { result = this.GetVariableValue(sourceLineNumbers, subString, false); } if (null == result) { if (isFunction) { throw new WixException(WixErrors.UndefinedPreprocessorFunction(sourceLineNumbers, subString)); } else { throw new WixException(WixErrors.UndefinedPreprocessorVariable(sourceLineNumbers, subString)); } } sb.Append(result); end += closingParenPosition + 1; } else // just a floating "$" so put it in the final string (i.e. leave it alone) and keep processing { sb.Append('$'); } } if (end < value.Length) { sb.Append(value.Substring(end)); } return(sb.ToString()); }
/// <summary> /// Parse the commandline arguments. /// </summary> /// <param name="args">Commandline arguments.</param> private void ParseCommandLine(string[] args) { for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (null == arg || 0 == arg.Length) { // skip blank arguments continue; } if (1 == arg.Length) { // treat '-' and '@' as filenames when by themselves. this.inputFiles.AddRange(CommandLine.GetFiles(arg, "Source")); continue; } if ('-' == arg[0] || '/' == arg[0]) { string parameter = arg.Substring(1); if ("ext" == parameter) { if (!CommandLine.IsValidArg(args, ++i)) { Messaging.Instance.OnMessage(WixErrors.TypeSpecificationForExtensionRequired("-ext")); return; } this.extensionList.Add(args[i]); } else if ("nologo" == parameter) { this.showLogo = false; } else if ("o" == parameter || "out" == parameter) { string path = CommandLine.GetFileOrDirectory(parameter, args, ++i); if (String.IsNullOrEmpty(path)) { return; } else { this.outputFile = path; } } else if ("v" == parameter) { Messaging.Instance.ShowVerboseMessages = true; } else if ("?" == parameter || "help" == parameter) { this.showHelp = true; return; } else { this.invalidArgs.Add(parameter); } } else if ('@' == arg[0]) { this.ParseCommandLine(CommandLineResponseFile.Parse(arg.Substring(1))); } else { this.inputFiles.AddRange(CommandLine.GetFiles(arg, "Source")); } } return; }
/// <summary> /// Parses a Driver element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="componentId">Identifier for parent component.</param> private void ParseDriverElement(XmlNode node, string componentId) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); int attributes = 0; int sequence = CompilerCore.IntegerNotSet; // check the number of times a Driver element has been nested under this Component element if (null != componentId) { if (this.components.Contains(componentId)) { this.Core.OnMessage(WixErrors.TooManyElements(sourceLineNumbers, "Component", node.Name, 1)); } else { this.components.Add(componentId, null); } } foreach (XmlAttribute attrib in node.Attributes) { switch (attrib.LocalName) { case "AddRemovePrograms": if (YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= 0x4; } break; case "DeleteFiles": if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= 0x10; } break; case "ForceInstall": if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= 0x1; } break; case "Legacy": if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= 0x8; } break; case "PlugAndPlayPrompt": if (YesNoType.No == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= 0x2; } break; case "Sequence": sequence = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); break; default: this.Core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } if (!this.Core.EncounteredError) { Row row = this.Core.CreateRow(sourceLineNumbers, "MsiDriverPackages"); row[0] = componentId; row[1] = attributes; if (CompilerCore.IntegerNotSet != sequence) { row[2] = sequence; } this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "MsiProcessDrivers"); } }
/// <summary> /// Parse a localization string. /// </summary> /// <param name="reader">XmlReader where the localization file is persisted.</param> /// <param name="tableDefinitions">Collection containing TableDefinitions to use when loading the localization file.</param> /// <param name="localization">The localization being parsed.</param> private static void ParseString(XmlReader reader, TableDefinitionCollection tableDefinitions, Localization localization) { Debug.Assert("String" == reader.LocalName); bool empty = reader.IsEmptyElement; SourceLineNumberCollection sourceLineNumbers = SourceLineNumberCollection.FromUri(reader.BaseURI); string id = null; bool overridable = false; string value = String.Empty; // default this value to the empty string while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "Id": id = reader.Value; break; case "Overridable": overridable = Common.IsYes(sourceLineNumbers, "String", reader.Name, reader.Value); break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/")) { throw new WixException(WixErrors.UnexpectedAttribute(sourceLineNumbers, "String", reader.Name)); } break; } } if (!empty) { bool done = false; while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: throw new WixException(WixErrors.UnexpectedElement(sourceLineNumbers, "String", reader.Name)); case XmlNodeType.CDATA: case XmlNodeType.Text: if (0 < reader.Value.Length) { value = reader.Value; } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixException(WixErrors.ExpectedEndElement(sourceLineNumbers, "String")); } } if (null == id) { throw new WixException(WixErrors.ExpectedAttribute(sourceLineNumbers, "String", "Id")); } WixVariableRow wixVariableRow = new WixVariableRow(sourceLineNumbers, tableDefinitions["WixVariable"]); wixVariableRow.Id = id; wixVariableRow.Overridable = overridable; wixVariableRow.Value = value; WixVariableRow existingWixVariableRow = (WixVariableRow)localization.variables[id]; if (null == existingWixVariableRow || (existingWixVariableRow.Overridable && !overridable)) { localization.variables.Add(id, wixVariableRow); } else if (!overridable) { throw new WixException(WixErrors.DuplicateLocalizationIdentifier(sourceLineNumbers, id)); } }
/// <summary> /// Instantiate a new WixInvalidIdtException. /// </summary> /// <param name="idtFile">The invalid idt file.</param> /// <param name="tableName">The table name of the invalid idt file.</param> public WixInvalidIdtException(string idtFile, string tableName) : base(WixErrors.InvalidIdt(new SourceLineNumber(idtFile), idtFile, tableName)) { }
/// <summary> /// Assign files to cabinets based on Media authoring. /// </summary> /// <param name="mediaTable"></param> /// <param name="mergeModuleMediaRow"></param> /// <param name="fileRows"></param> private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, FileRowCollection fileRows) { if (OutputType.Module != this.output.Type) { if (null != mediaTable) { Dictionary <string, MediaRow> cabinetMediaRows = new Dictionary <string, MediaRow>(StringComparer.InvariantCultureIgnoreCase); foreach (MediaRow mediaRow in mediaTable.Rows) { // If the Media row has a cabinet, make sure it is unique across all Media rows. if (!String.IsNullOrEmpty(mediaRow.Cabinet)) { MediaRow existingRow; if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow)) { this.core.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet)); this.core.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet)); } else { cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow); } } this.mediaRows.Add(mediaRow); } } foreach (MediaRow mediaRow in this.mediaRows) { if (null != mediaRow.Cabinet) { this.cabinets.Add(mediaRow, new FileRowCollection()); } } } foreach (FileRow fileRow in fileRows) { if (OutputType.Module == output.Type) { ((FileRowCollection)this.cabinets[mergeModuleMediaRow]).Add(fileRow); } else { MediaRow mediaRow = this.mediaRows[fileRow.DiskId]; if (null == mediaRow) { this.core.OnMessage(WixErrors.MissingMedia(fileRow.SourceLineNumbers, fileRow.DiskId)); continue; } // When building a product, if the current file is not to be compressed or if // the package set not to be compressed, don't cab it. if (OutputType.Product == output.Type && (YesNoType.No == fileRow.Compressed || (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed))) { uncompressedFileRows.Add(fileRow); } else // file in a Module or marked compressed { FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[mediaRow]; if (null != cabinetFileRow) { cabinetFileRow.Add(fileRow); } else { this.core.OnMessage(WixErrors.ExpectedMediaCabinet(fileRow.SourceLineNumbers, fileRow.File, fileRow.DiskId)); } } } } }
/// <summary> /// Parse a table from the xml. /// </summary> /// <param name="reader">XmlReader where the intermediate is persisted.</param> /// <param name="section">Section to populate with persisted data.</param> /// <param name="tableDefinitions">TableDefinitions to use in the intermediate.</param> /// <returns>The parsed table.</returns> internal static Table Parse(XmlReader reader, Section section, TableDefinitionCollection tableDefinitions) { Debug.Assert("table" == reader.LocalName); bool empty = reader.IsEmptyElement; TableOperation operation = TableOperation.None; string name = null; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "name": name = reader.Value; break; case "op": switch (reader.Value) { case "add": operation = TableOperation.Add; break; case "drop": operation = TableOperation.Drop; break; default: throw new WixException(WixErrors.IllegalAttributeValue(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", reader.Name, reader.Value, "Add", "Drop")); } break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal)) { throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", reader.Name)); } break; } } if (null == name) { throw new WixException(WixErrors.ExpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", "name")); } TableDefinition tableDefinition = tableDefinitions[name]; Table table = new Table(section, tableDefinition); table.Operation = operation; if (!empty) { bool done = false; // loop through all the rows in a table while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: switch (reader.LocalName) { case "row": Row.Parse(reader, table); break; default: throw new WixException(WixErrors.UnexpectedElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "table", reader.Name)); } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumberCollection.FromUri(reader.BaseURI), "table")); } } return(table); }
/// <summary> /// Parses ActionRows from the Xml reader. /// </summary> /// <param name="reader">Xml reader that contains serialized ActionRows.</param> /// <returns>The parsed ActionRows.</returns> internal static WixActionRow[] Parse(XmlReader reader) { Debug.Assert("action" == reader.LocalName); string id = null; string condition = null; bool empty = reader.IsEmptyElement; int sequence = int.MinValue; int sequenceCount = 0; SequenceTable[] sequenceTables = new SequenceTable[Enum.GetValues(typeof(SequenceTable)).Length]; while (reader.MoveToNextAttribute()) { switch (reader.Name) { case "name": id = reader.Value; break; case "AdminExecuteSequence": if (Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", reader.Name, reader.Value)) { sequenceTables[sequenceCount] = SequenceTable.AdminExecuteSequence; ++sequenceCount; } break; case "AdminUISequence": if (Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", reader.Name, reader.Value)) { sequenceTables[sequenceCount] = SequenceTable.AdminUISequence; ++sequenceCount; } break; case "AdvtExecuteSequence": if (Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", reader.Name, reader.Value)) { sequenceTables[sequenceCount] = SequenceTable.AdvtExecuteSequence; ++sequenceCount; } break; case "condition": condition = reader.Value; break; case "InstallExecuteSequence": if (Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", reader.Name, reader.Value)) { sequenceTables[sequenceCount] = SequenceTable.InstallExecuteSequence; ++sequenceCount; } break; case "InstallUISequence": if (Common.IsYes(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", reader.Name, reader.Value)) { sequenceTables[sequenceCount] = SequenceTable.InstallUISequence; ++sequenceCount; } break; case "sequence": sequence = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture); break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal)) { throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", reader.Name)); } break; } } if (null == id) { throw new WixException(WixErrors.ExpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", "name")); } if (int.MinValue == sequence) { throw new WixException(WixErrors.ExpectedAttribute(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", "sequence")); } else if (1 > sequence) { throw new WixException(WixErrors.IntegralValueOutOfRange(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", "sequence", sequence, 1, int.MaxValue)); } if (0 == sequenceCount) { throw new WixException(WixErrors.ExpectedAttributes(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", "AdminExecuteSequence", "AdminUISequence", "AdvtExecuteSequence", "InstallExecuteSequence", "InstallUISequence")); } if (!empty && reader.Read() && XmlNodeType.EndElement != reader.MoveToContent()) { throw new WixException(WixErrors.UnexpectedContentNode(SourceLineNumberCollection.FromUri(reader.BaseURI), "action", reader.NodeType.ToString())); } // create the actions WixActionRow[] actionRows = new WixActionRow[sequenceCount]; for (int i = 0; i < sequenceCount; i++) { WixActionRow actionRow = new WixActionRow(sequenceTables[i], id, condition, sequence); actionRows[i] = actionRow; } return(actionRows); }
/// <summary> /// Processes the Provides element. /// </summary> /// <param name="node">The XML node for the Provides element.</param> /// <param name="packageType">The type of the package being chained into a bundle, or "None" if building an MSI package.</param> /// <param name="keyPath">Explicit key path.</param> /// <param name="parentId">The identifier of the parent component or package.</param> /// <returns>The type of key path if set.</returns> private ComponentKeyPath ParseProvidesElement(XElement node, PackageType packageType, string parentId) { SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); ComponentKeyPath keyPath = null; Identifier id = null; string key = null; string version = null; string displayName = null; int attributes = 0; int illegalChar = -1; 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.GetAttributeIdentifier(sourceLineNumbers, attrib); break; case "Key": key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Version": version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); break; case "DisplayName": displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.Core.UnexpectedAttribute(node, attrib); break; } } else { this.Core.ParseExtensionAttribute(node, attrib); } } // Make sure the key is valid. The key will default to the ProductCode for MSI packages // and the package code for MSP packages in the binder if not specified. if (!String.IsNullOrEmpty(key)) { // Make sure the key does not contain any illegal characters or values. if (0 <= (illegalChar = key.IndexOfAny(DependencyCommon.InvalidCharacters))) { StringBuilder sb = new StringBuilder(DependencyCommon.InvalidCharacters.Length * 2); Array.ForEach <char>(DependencyCommon.InvalidCharacters, c => sb.Append(c).Append(" ")); this.Core.OnMessage(DependencyErrors.IllegalCharactersInProvider(sourceLineNumbers, "Key", key[illegalChar], sb.ToString())); } else if ("ALL" == key) { this.Core.OnMessage(DependencyErrors.ReservedValue(sourceLineNumbers, node.Name.LocalName, "Key", key)); } } else if (PackageType.ExePackage == packageType || PackageType.MsuPackage == packageType) { // Must specify the provider key when authored for a package. this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Key")); } else if (PackageType.None == packageType) { // Make sure the ProductCode is authored and set the key. this.Core.CreateSimpleReference(sourceLineNumbers, "Property", "ProductCode"); key = "!(bind.property.ProductCode)"; } // The Version attribute should not be authored in or for an MSI package. if (!String.IsNullOrEmpty(version)) { switch (packageType) { case PackageType.None: this.Core.OnMessage(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers)); break; case PackageType.MsiPackage: this.Core.OnMessage(DependencyWarnings.DiscouragedVersionAttribute(sourceLineNumbers, parentId)); break; } } else if (PackageType.MspPackage == packageType || PackageType.MsuPackage == packageType) { // Must specify the Version when authored for packages that do not contain a version. this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); } // Need the element ID for child element processing, so generate now if not authored. if (null == id) { id = this.Core.CreateIdentifier("dep", node.Name.LocalName, parentId, key); } foreach (XElement child in node.Elements()) { if (this.Namespace == child.Name.Namespace) { switch (child.Name.LocalName) { case "Requires": this.ParseRequiresElement(child, id.Id, PackageType.None == packageType); break; case "RequiresRef": this.ParseRequiresRefElement(child, id.Id, PackageType.None == packageType); break; default: this.Core.UnexpectedElement(node, child); break; } } else { this.Core.ParseExtensionElement(node, child); } } if (!this.Core.EncounteredError) { // Create the row in the provider table. Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyProvider", id); row[1] = parentId; row[2] = key; if (!String.IsNullOrEmpty(version)) { row[3] = version; } if (!String.IsNullOrEmpty(displayName)) { row[4] = displayName; } if (0 != attributes) { row[5] = attributes; } if (PackageType.None == packageType) { // Reference the Check custom action to check for dependencies on the current provider. if (Platform.ARM == this.Core.CurrentPlatform) { // Ensure the ARM version of the CA is referenced. this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyCheck_ARM"); } else { // All other supported platforms use x86. this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixDependencyCheck"); } // Generate registry rows for the provider using binder properties. string keyProvides = String.Concat(DependencyCommon.RegistryRoot, key); row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "(Default)")); row[1] = -1; row[2] = keyProvides; row[3] = null; row[4] = "[ProductCode]"; row[5] = parentId; // Use the Version registry value and use that as a potential key path. Identifier idVersion = this.Core.CreateIdentifier("reg", id.Id, "Version"); keyPath = new ComponentKeyPath() { Id = idVersion.Id, Explicit = false, Type = ComponentKeyPathType.Registry }; row = this.Core.CreateRow(sourceLineNumbers, "Registry", idVersion); row[1] = -1; row[2] = keyProvides; row[3] = "Version"; row[4] = !String.IsNullOrEmpty(version) ? version : "[ProductVersion]"; row[5] = parentId; row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "DisplayName")); row[1] = -1; row[2] = keyProvides; row[3] = "DisplayName"; row[4] = !String.IsNullOrEmpty(displayName) ? displayName : "[ProductName]"; row[5] = parentId; if (0 != attributes) { row = this.Core.CreateRow(sourceLineNumbers, "Registry", this.Core.CreateIdentifier("reg", id.Id, "Attributes")); row[1] = -1; row[2] = keyProvides; row[3] = "Attributes"; row[4] = String.Concat("#", attributes.ToString(CultureInfo.InvariantCulture.NumberFormat)); row[5] = parentId; } } } return(keyPath); }
/// <summary> /// Parse a field from the xml. /// </summary> /// <param name="reader">XmlReader where the intermediate is persisted.</param> internal override void Parse(XmlReader reader) { Debug.Assert("field" == reader.LocalName); bool empty = reader.IsEmptyElement; this.baseUri = reader.BaseURI; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "cabinetFileId": this.cabinetFileId = reader.Value; break; case "modified": this.Modified = Common.IsYes(SourceLineNumber.CreateFromUri(reader.BaseURI), "field", reader.Name, reader.Value); break; case "previousData": this.PreviousData = reader.Value; break; case "unresolvedPreviousData": this.unresolvedPreviousData = reader.Value; break; case "unresolvedData": this.unresolvedData = reader.Value; break; case "previousCabinetFileId": this.previousCabinetFileId = reader.Value; break; default: if (!reader.NamespaceURI.StartsWith("http://www.w3.org/", StringComparison.Ordinal)) { throw new WixException(WixErrors.UnexpectedAttribute(SourceLineNumber.CreateFromUri(reader.BaseURI), "field", reader.Name)); } break; } } if (!empty) { bool done = false; while (!done && reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: throw new WixException(WixErrors.UnexpectedElement(SourceLineNumber.CreateFromUri(reader.BaseURI), "field", reader.Name)); case XmlNodeType.CDATA: case XmlNodeType.Text: if (0 < reader.Value.Length) { this.Data = reader.Value; } break; case XmlNodeType.EndElement: done = true; break; } } if (!done) { throw new WixException(WixErrors.ExpectedEndElement(SourceLineNumber.CreateFromUri(reader.BaseURI), "field")); } } }
/// <summary> /// Indicates the decompiler encountered and unexpected table to decompile. /// </summary> /// <param name="table">Unknown decompiled table.</param> public void UnexpectedTable(Table table) { this.OnMessage(WixErrors.TableDecompilationUnimplemented(table.Name)); }
/// <summary> /// Parses a UrlAce element. /// </summary> /// <param name="node">The element to parse.</param> /// <param name="urlReservationId">The URL reservation ID.</param> /// <param name="defaultSecurityPrincipal">The default security principal.</param> private void ParseUrlAceElement(XmlNode node, string urlReservationId, string defaultSecurityPrincipal) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; string securityPrincipal = defaultSecurityPrincipal; int rights = HttpConstants.GENERIC_ALL; string rightsValue = null; foreach (XmlAttribute attrib in node.Attributes) { if (String.IsNullOrEmpty(attrib.NamespaceURI) || this.schema.TargetNamespace == attrib.NamespaceURI) { switch (attrib.LocalName) { case "Id": id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "SecurityPrincipal": securityPrincipal = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Rights": rightsValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); switch (rightsValue) { case "all": rights = HttpConstants.GENERIC_ALL; break; case "delegate": rights = HttpConstants.GENERIC_WRITE; break; case "register": rights = HttpConstants.GENERIC_EXECUTE; break; default: this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.LocalName, "Rights", rightsValue, "all", "delegate", "register")); break; } break; default: this.Core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.Core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } // Generate Id now if not authored. if (null == id) { id = this.Core.GenerateIdentifier("ace", urlReservationId, securityPrincipal, rightsValue); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (this.Schema.TargetNamespace == child.NamespaceURI) { this.Core.UnexpectedElement(node, child); } else { this.Core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child); } } } // SecurityPrincipal is required. if (null == securityPrincipal) { this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.LocalName, "SecurityPrincipal")); } if (!this.Core.EncounteredError) { Row row = this.Core.CreateRow(sourceLineNumbers, "WixHttpUrlAce"); row[0] = id; row[1] = urlReservationId; row[2] = securityPrincipal; row[3] = rights; } }
/// <summary> /// Run a Light unit test. /// </summary> /// <param name="element">The unit test element.</param> /// <param name="previousUnitResults">The previous unit test results.</param> /// <param name="update">Indicates whether to give the user the option to fix a failing test.</param> /// <param name="args">The command arguments passed to WixUnit.</param> public static void RunUnitTest(XmlElement element, UnitResults previousUnitResults, bool update, ICommandArgs args) { string arguments = element.GetAttribute("Arguments"); string expectedErrors = element.GetAttribute("ExpectedErrors"); string expectedResult = element.GetAttribute("ExpectedResult"); string expectedWarnings = element.GetAttribute("ExpectedWarnings"); string extensions = element.GetAttribute("Extensions"); string outputFile = element.GetAttribute("OutputFile"); string intermediateOutputType = element.GetAttribute("IntermediateOutputType"); string suppressExtensions = element.GetAttribute("SuppressExtensions"); string tempDirectory = element.GetAttribute("TempDirectory"); string testName = element.ParentNode.Attributes["Name"].Value; string toolsDirectory = element.GetAttribute("ToolsDirectory"); bool usePreviousOutput = ("true" == element.GetAttribute("UsePreviousOutput")); if (expectedErrors.Length == 0 && expectedResult.Length == 0 && intermediateOutputType.Length == 0 && outputFile.Length == 0) { throw new WixException(WixErrors.ExpectedAttributes(null, element.Name, "ExpectedErrors", "ExpectedResult", "IntermediateOutputType", "OutputFile", null)); } if (expectedErrors.Length > 0 && (expectedResult.Length > 0 || intermediateOutputType.Length > 0 || outputFile.Length > 0)) { throw new WixException(WixErrors.IllegalAttributeWithOtherAttributes(null, element.Name, "ExpectedErrors", "ExpectedResult", "IntermediateOutputType", "OutputFile", null)); } else if (expectedResult.Length > 0 && (intermediateOutputType.Length > 0 || outputFile.Length > 0)) { throw new WixException(WixErrors.IllegalAttributeWithOtherAttributes(null, element.Name, "ExpectedResult", "IntermediateOutputType", "OutputFile")); } else if (intermediateOutputType.Length > 0 && outputFile.Length > 0) { throw new WixException(WixErrors.IllegalAttributeWithOtherAttributes(null, element.Name, "IntermediateOutputType", "OutputFile", null)); } string toolFile = Path.Combine(toolsDirectory, "light.exe"); StringBuilder commandLine = new StringBuilder(arguments); commandLine.Append(" -b \"%WIX%\\examples\\data\""); // handle wixunit arguments if (args.NoTidy) { commandLine.Append(" -notidy"); } // handle extensions if (!String.IsNullOrEmpty(extensions)) { string[] suppressedExtensionArray = suppressExtensions.Split(';'); foreach (string extension in extensions.Split(';')) { if (0 > Array.BinarySearch(suppressedExtensionArray, extension)) { commandLine.AppendFormat(" -ext \"{0}\"", extension); } } } // handle any previous outputs if (usePreviousOutput) { foreach (string inputFile in previousUnitResults.OutputFiles) { commandLine.AppendFormat(" \"{0}\"", inputFile); } } previousUnitResults.OutputFiles.Clear(); // handle child elements foreach (XmlNode node in element.ChildNodes) { if (node.NodeType == XmlNodeType.Element) { switch (node.LocalName) { case "LibraryFile": string libraryFile = node.InnerText.Trim(); commandLine.AppendFormat(" \"{0}\"", libraryFile); break; case "LocalizationFile": string localizationFile = node.InnerText.Trim(); commandLine.AppendFormat(" -loc \"{0}\"", localizationFile); break; } } } if (outputFile.Length > 0) { // outputFile has been explicitly set } else if (expectedResult.Length > 0) { outputFile = Path.Combine(tempDirectory, Path.GetFileName(expectedResult)); } else if (intermediateOutputType.Length > 0) { string intermediateFile = String.Concat("intermediate.", intermediateOutputType); outputFile = Path.Combine(tempDirectory, intermediateFile); } else { outputFile = Path.Combine(tempDirectory, "ShouldNotBeCreated.msi"); } commandLine.AppendFormat("{0} -out \"{1}\"", (Path.GetExtension(outputFile) == ".wixout" ? " -xo" : String.Empty), outputFile); previousUnitResults.OutputFiles.Add(outputFile); // run the tool ArrayList output = ToolUtility.RunTool(toolFile, commandLine.ToString()); previousUnitResults.Errors.AddRange(ToolUtility.GetErrors(output, expectedErrors, expectedWarnings)); previousUnitResults.Output.AddRange(output); // check the output file if (previousUnitResults.Errors.Count == 0) { if (expectedResult.Length > 0) { ArrayList differences = CompareUnit.CompareResults(expectedResult, outputFile, testName, update); previousUnitResults.Errors.AddRange(differences); previousUnitResults.Output.AddRange(differences); } else if (expectedErrors.Length > 0 && File.Exists(outputFile)) // ensure the output doesn't exist { string error = String.Format(CultureInfo.InvariantCulture, "Expected failure, but the unit test created output file \"{0}\".", outputFile); previousUnitResults.Errors.Add(error); previousUnitResults.Output.Add(error); } } }
/// <summary> /// Parses a UrlReservation element. /// </summary> /// <param name="node">The element to parse.</param> /// <param name="componentId">Identifier of the component that owns this URL reservation.</param> /// <param name="securityPrincipal">The security principal of the parent element (null if nested under Component).</param> private void ParseUrlReservationElement(XmlNode node, string componentId, string securityPrincipal) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; int handleExisting = HttpConstants.heReplace; string handleExistingValue = null; string sddl = null; string url = null; bool foundACE = false; foreach (XmlAttribute attrib in node.Attributes) { if (String.IsNullOrEmpty(attrib.NamespaceURI) || this.schema.TargetNamespace == attrib.NamespaceURI) { switch (attrib.LocalName) { case "Id": id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "HandleExisting": handleExistingValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); switch (handleExistingValue) { case "replace": handleExisting = HttpConstants.heReplace; break; case "ignore": handleExisting = HttpConstants.heIgnore; break; case "fail": handleExisting = HttpConstants.heFail; break; default: this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.LocalName, "HandleExisting", handleExistingValue, "replace", "ignore", "fail")); break; } break; case "Sddl": sddl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Url": url = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.Core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.Core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } // Need the element ID for child element processing, so generate now if not authored. if (null == id) { id = this.Core.GenerateIdentifier("url", componentId, securityPrincipal, url); } // Parse UrlAce children. foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (this.Schema.TargetNamespace == child.NamespaceURI) { switch (child.LocalName) { case "UrlAce": if (null != sddl) { this.Core.OnMessage(WixErrors.IllegalParentAttributeWhenNested(sourceLineNumbers, "UrlReservation", "Sddl", "UrlAce")); } else { foundACE = true; this.ParseUrlAceElement(child, id, securityPrincipal); } break; default: this.Core.UnexpectedElement(node, child); break; } } else { this.Core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child); } } } // Url is required. if (null == url) { this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.LocalName, "Url")); } // Security is required. if (null == sddl && !foundACE) { this.Core.OnMessage(HttpErrors.NoSecuritySpecified(sourceLineNumbers)); } if (!this.Core.EncounteredError) { Row row = this.Core.CreateRow(sourceLineNumbers, "WixHttpUrlReservation"); row[0] = id; row[1] = handleExisting; row[2] = sddl; row[3] = url; row[4] = componentId; if (this.Core.CurrentPlatform == Platform.ARM) { // Ensure ARM version of the CA is referenced. this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsInstall_ARM"); this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsUninstall_ARM"); } else { // All other supported platforms use x86. this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsInstall"); this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsUninstall"); } } }
/// <summary> /// Parses a HelpFilter element. /// </summary> /// <param name="node">Element to process.</param> 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"); } } }
/// <summary> /// Run a Wixproj unit test. /// </summary> /// <param name="element">The unit test element.</param> /// <param name="previousUnitResults">The previous unit test results.</param> /// <param name="verbose">The level of verbosity for the MSBuild logging.</param> /// <param name="skipValidation">Tells light to skip validation.</param> /// <param name="update">Indicates whether to give the user the option to fix a failing test.</param> /// <param name="args">The command arguments passed to WixUnit.</param> public static void RunUnitTest(XmlElement element, UnitResults previousUnitResults, bool verbose, bool skipValidation, bool update, ICommandArgs args) { string arguments = element.GetAttribute("Arguments"); string expectedErrors = element.GetAttribute("ExpectedErrors"); string expectedResult = element.GetAttribute("ExpectedResult"); string expectedWarnings = element.GetAttribute("ExpectedWarnings"); string extensions = element.GetAttribute("Extensions"); bool noOutputName = XmlConvert.ToBoolean(element.GetAttribute("NoOutputName")); bool noOutputPath = XmlConvert.ToBoolean(element.GetAttribute("NoOutputPath")); bool defineSolutionProperties = XmlConvert.ToBoolean(element.GetAttribute("DefineSolutionProperties")); string suppressExtensions = element.GetAttribute("SuppressExtensions"); string tempDirectory = element.GetAttribute("TempDirectory"); string testName = element.ParentNode.Attributes["Name"].Value; string toolsDirectory = element.GetAttribute("ToolsDirectory"); string msBuildDirectory = Environment.GetEnvironmentVariable("WixTestMSBuildDirectory"); string msBuildToolsVersion = Environment.GetEnvironmentVariable("WixTestMSBuildToolsVersion"); // check the combinations of attributes if (expectedErrors.Length > 0 && expectedResult.Length > 0) { throw new WixException(WixErrors.IllegalAttributeWithOtherAttribute(null, element.Name, "ExpectedErrors", "ExpectedResult")); } // we'll run MSBuild on the .wixproj to generate the output if (null == msBuildDirectory) { msBuildDirectory = Path.Combine(Environment.GetEnvironmentVariable("SystemRoot"), @"Microsoft.NET\Framework\v3.5"); } string toolFile = Path.Combine(msBuildDirectory, "MSBuild.exe"); StringBuilder commandLine = new StringBuilder(arguments); // rebuild by default commandLine.AppendFormat(" /target:Rebuild /verbosity:{0}", verbose ? "detailed" : "normal"); if (skipValidation) { commandLine.Append(" /property:SuppressValidation=true"); } // add DefineSolutionProperties commandLine.AppendFormat(" /property:DefineSolutionProperties={0}", defineSolutionProperties); // make sure the tools directory ends in a single backslash if (toolsDirectory[toolsDirectory.Length - 1] != Path.DirectorySeparatorChar) { toolsDirectory = String.Concat(toolsDirectory, Path.DirectorySeparatorChar); } // handle the wix-specific directories and files commandLine.AppendFormat(" /property:WixToolPath=\"{0}\\\"", toolsDirectory); commandLine.AppendFormat(" /property:WixExtDir=\"{0}\\\"", toolsDirectory); commandLine.AppendFormat(" /property:WixTargetsPath=\"{0}\"", Path.Combine(toolsDirectory, "wix.targets")); commandLine.AppendFormat(" /property:WixTasksPath=\"{0}\"", Path.Combine(toolsDirectory, "WixTasks.dll")); commandLine.AppendFormat(" /property:BaseIntermediateOutputPath=\"{0}\\\\\"", Path.Combine(tempDirectory, "obj")); // handle extensions string[] suppressedExtensionArray = suppressExtensions.Split(';'); StringBuilder extensionsToUse = new StringBuilder(); foreach (string extension in extensions.Split(';')) { if (0 > Array.BinarySearch(suppressedExtensionArray, extension)) { if (extensionsToUse.Length > 0) { extensionsToUse.Append(";"); } extensionsToUse.Append(extension); } } commandLine.AppendFormat(" /property:WixExtension=\"{0}\"", extensionsToUse.ToString()); previousUnitResults.OutputFiles.Clear(); // handle the source file string sourceFile = element.GetAttribute("SourceFile").Trim(); // handle the expected result output file string outputFile; if (expectedResult.Length > 0) { outputFile = Path.Combine(tempDirectory, Path.GetFileName(expectedResult)); } else { outputFile = Path.Combine(tempDirectory, "ShouldNotBeCreated.msi"); } if (!noOutputName) { commandLine.AppendFormat(" /property:OutputName=\"{0}\"", Path.GetFileNameWithoutExtension(outputFile)); } if (!noOutputPath) { commandLine.AppendFormat(" /property:OutputPath=\"{0}\\\\\"", Path.GetDirectoryName(outputFile)); } previousUnitResults.OutputFiles.Add(outputFile); if (!String.IsNullOrEmpty(msBuildToolsVersion)) { commandLine.AppendFormat(" /tv:{0}", msBuildToolsVersion); } // add the source file as the last parameter commandLine.AppendFormat(" \"{0}\"", sourceFile); // run one msbuild process at a time due to multiproc issues ArrayList output = null; try { mutex.WaitOne(); output = ToolUtility.RunTool(toolFile, commandLine.ToString()); } finally { mutex.ReleaseMutex(); } previousUnitResults.Errors.AddRange(ToolUtility.GetErrors(output, expectedErrors, expectedWarnings)); previousUnitResults.Output.AddRange(output); // check the output file if (previousUnitResults.Errors.Count == 0) { if (expectedResult.Length > 0) { ArrayList differences = CompareUnit.CompareResults(expectedResult, outputFile, testName, update); previousUnitResults.Errors.AddRange(differences); previousUnitResults.Output.AddRange(differences); } else if (expectedErrors.Length > 0 && File.Exists(outputFile)) // ensure the output doesn't exist { string error = String.Format(CultureInfo.InvariantCulture, "Expected failure, but the unit test created output file \"{0}\".", outputFile); previousUnitResults.Errors.Add(error); previousUnitResults.Output.Add(error); } } }
/// <summary> /// Parses a VsixPackage element. /// </summary> /// <param name="node">Element to process.</param> /// <param name="componentId">Identifier of the parent Component element.</param> /// <param name="fileId">Identifier of the parent File element.</param> 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); } } }
/// <summary> /// Processes the RequiresRef element. /// </summary> /// <param name="node">The XML node for the RequiresRef element.</param> /// <param name="providerId">The parent provider identifier.</param> /// <param name="requiresAction">Whether the Requires custom action should be referenced.</param> private void ParseRequiresRefElement(XmlNode node, string providerId, bool requiresAction) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; default: this.Core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.Core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { this.Core.UnexpectedElement(node, child); } else { this.Core.UnsupportedExtensionElement(node, child); } } } if (String.IsNullOrEmpty(id)) { this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.LocalName, "Id")); } if (!this.Core.EncounteredError) { // Reference the Require custom action if required. if (requiresAction) { if (Platform.ARM == this.Core.CurrentPlatform) { // Ensure the ARM version of the CA is referenced. this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "WixDependencyRequire_ARM"); } else { // All other supported platforms use x86. this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "WixDependencyRequire"); } } // Create a link dependency on the row that contains information we'll need during bind. this.Core.CreateWixSimpleReferenceRow(sourceLineNumbers, "WixDependency", id); // Create the relationship between the WixDependency row and the parent WixDependencyProvider row. Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyRef"); row[0] = providerId; row[1] = id; } }
/// <summary> /// Parses a WixStandardBootstrapperApplication element for Bundles. /// </summary> /// <param name="node">The element to parse.</param> private void ParseWixStandardBootstrapperApplicationElement(XmlNode node) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string licenseFile = null; string licenseUrl = null; string logoFile = null; string themeFile = null; string localizationFile = null; YesNoType suppressOptionsUI = YesNoType.NotSet; YesNoType suppressDowngradeFailure = YesNoType.NotSet; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "LicenseFile": licenseFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false); break; case "LicenseUrl": licenseUrl = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false); break; case "LogoFile": logoFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false); break; case "ThemeFile": themeFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false); break; case "LocalizationFile": localizationFile = this.Core.GetAttributeValue(sourceLineNumbers, attrib, false); break; case "SuppressOptionsUI": suppressOptionsUI = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "SuppressDowngradeFailure": suppressDowngradeFailure = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; default: this.Core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.Core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { this.Core.UnexpectedElement(node, child); } else { this.Core.UnsupportedExtensionElement(node, child); } } } if (String.IsNullOrEmpty(licenseFile) == String.IsNullOrEmpty(licenseUrl)) { this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "LicenseFile", "LicenseUrl", true)); } if (!this.Core.EncounteredError) { if (!String.IsNullOrEmpty(licenseFile)) { this.Core.CreateWixVariableRow(sourceLineNumbers, "WixStdbaLicenseRtf", licenseFile, false); } if (!String.IsNullOrEmpty(licenseUrl)) { this.Core.CreateWixVariableRow(sourceLineNumbers, "WixStdbaLicenseUrl", licenseUrl, false); } if (!String.IsNullOrEmpty(logoFile)) { this.Core.CreateWixVariableRow(sourceLineNumbers, "WixStdbaLogo", logoFile, false); } if (!String.IsNullOrEmpty(themeFile)) { this.Core.CreateWixVariableRow(sourceLineNumbers, "WixStdbaThemeXml", themeFile, false); } if (!String.IsNullOrEmpty(localizationFile)) { this.Core.CreateWixVariableRow(sourceLineNumbers, "WixStdbaThemeWxl", localizationFile, false); } if (YesNoType.Yes == suppressOptionsUI || YesNoType.Yes == suppressDowngradeFailure) { Row row = this.Core.CreateRow(sourceLineNumbers, "WixStdbaOptions"); if (YesNoType.Yes == suppressOptionsUI) { row[0] = 1; } if (YesNoType.Yes == suppressDowngradeFailure) { row[1] = 1; } } } }
private void ParseFileElement(XmlNode node) { SourceLineNumberCollection sourceLineNumber = Preprocessor.GetSourceLineNumbers(node); string superElementId = null; string file = null; string arguments = null; var elevated = YesNoType.No; YesNoType ignoreErrors = YesNoType.No; int order = 1000000000 + sourceLineNumber[0].LineNumber; foreach (XmlAttribute attribute in node.Attributes) { if (attribute.NamespaceURI.Length == 0 || attribute.NamespaceURI == _schema.TargetNamespace) { switch (attribute.LocalName) { case "Id": superElementId = Core.GetAttributeIdentifierValue(sourceLineNumber, attribute); break; case "File": file = Core.GetAttributeValue(sourceLineNumber, attribute, false); break; case "Arguments": arguments = Core.GetAttributeValue(sourceLineNumber, attribute); break; case "Elevated": elevated = Core.GetAttributeYesNoValue(sourceLineNumber, attribute); break; case "IgnoreErrors": ignoreErrors = Core.GetAttributeYesNoValue(sourceLineNumber, attribute); break; case "Order": order = Core.GetAttributeIntegerValue(sourceLineNumber, attribute, 0, 1000000000); break; default: Core.UnexpectedAttribute(sourceLineNumber, attribute); break; } } else { Core.UnsupportedExtensionAttribute(sourceLineNumber, attribute); } } if (string.IsNullOrEmpty(superElementId)) { Core.OnMessage( WixErrors.ExpectedAttribute(sourceLineNumber, node.Name, "Id")); } if (string.IsNullOrEmpty(file)) { Core.OnMessage( WixErrors.ExpectedElement(sourceLineNumber, node.Name, "File")); } if (!Core.EncounteredError) { Row superElementRow = Core.CreateRow(sourceLineNumber, "PowerShellFiles"); superElementRow[0] = superElementId; superElementRow[1] = file; superElementRow[2] = arguments; superElementRow[3] = elevated == YesNoType.Yes ? 1 : 0; superElementRow[4] = (ignoreErrors == YesNoType.Yes) ? 1 : 0; superElementRow[5] = order; } Core.CreateWixSimpleReferenceRow(sourceLineNumber, "CustomAction", "PowerShellFilesImmediate"); }