/// <summary> /// Finds all items under a parent group type and creates new WixGroup data for them. /// </summary> /// <param name="parentType">The type of the parent group to flatten.</param> /// <param name="removeUsedRows">Whether to remove used group rows before returning.</param> public void FlattenAndRewriteGroups(ComplexReferenceParentType parentType, bool removeUsedRows) { var parentTypeString = parentType.ToString(); Debug.Assert(this.groupTypes.Contains(parentTypeString)); this.LoadFlattenOrderGroups(); if (this.Messaging.EncounteredError) { return; } foreach (Item item in this.items) { if (parentTypeString == item.Type) { this.CreateOrderedList(item.Type, item.Id, out var orderedItems); this.CreateNewGroupRows(item.Type, item.Id, orderedItems); } } if (removeUsedRows) { this.RemoveUsedGroupRows(); } }
/// <summary> /// Creates a new complex reference. /// </summary> /// <param name="parentType">Parent type of complex reference.</param> /// <param name="parentId">Identifier for parent of complex reference.</param> /// <param name="parentLanguage">Language for parent of complex reference (only valid when parent is Module).</param> /// <param name="childType">Child type of complex reference.</param> /// <param name="childId">Identifier for child of complex reference.</param> /// <param name="primary">Flag if complex reference is the primary for advertised goop.</param> public ComplexReference(ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool primary) { if (ComplexReferenceParentType.Module != this.parentType && null != this.parentLanguage) { throw new ArgumentException("ParentLanguage cannot be specified unless the parent is a Module."); } this.parentType = parentType; this.parentId = parentId; this.parentLanguage = parentLanguage; this.childType = childType; this.childId = childId; this.primary = primary; this.section = null; }
public WixBundlePayloadSymbol CreatePayloadSymbol(ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown, string previousId = null) { WixBundlePayloadSymbol symbol = null; if (parentType == ComplexReferenceParentType.Container && parentId == BurnConstants.BurnUXContainerName) { if (this.Compressed == YesNoDefaultType.No) { this.Core.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(this.SourceLineNumbers, this.SourceFile)); } if (!String.IsNullOrEmpty(this.DownloadUrl)) { this.Core.Write(WarningMessages.DownloadUrlNotSupportedForBAPayloads(this.SourceLineNumbers, this.Id.Id)); } this.Compressed = YesNoDefaultType.Yes; this.DownloadUrl = null; } if (!this.Core.EncounteredError) { symbol = this.Core.AddSymbol(new WixBundlePayloadSymbol(this.SourceLineNumbers, this.Id) { Name = String.IsNullOrEmpty(this.Name) ? Path.GetFileName(this.SourceFile) : this.Name, SourceFile = new IntermediateFieldPathValue { Path = this.SourceFile }, DownloadUrl = this.DownloadUrl, Compressed = (this.Compressed == YesNoDefaultType.Yes) ? true : (this.Compressed == YesNoDefaultType.No) ? (bool?)false : null, UnresolvedSourceFile = this.SourceFile, // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. DisplayName = this.ProductName, Description = this.Description, Hash = this.Hash, FileSize = this.Size, Version = this.Version, }); this.Core.CreateGroupAndOrderingRows(this.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, symbol.Id.Id, previousType, previousId); } return(symbol); }
/// <summary> /// Finds all nested items under a parent group and creates new WixGroup data for them. /// </summary> /// <param name="parentType">The group type for the parent group to flatten.</param> /// <param name="parentId">The identifier of the parent group to flatten.</param> /// <param name="removeUsedRows">Whether to remove used group rows before returning.</param> public void FlattenAndRewriteRows(ComplexReferenceParentType parentType, string parentId, bool removeUsedRows) { var parentTypeString = parentType.ToString(); Debug.Assert(this.groupTypes.Contains(parentTypeString)); this.CreateOrderedList(parentTypeString, parentId, out var orderedItems); if (this.Messaging.EncounteredError) { return; } this.CreateNewGroupRows(parentTypeString, parentId, orderedItems); if (removeUsedRows) { this.RemoveUsedGroupRows(); } }
/// <summary> /// Parses a PatchFamilyGroup reference element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">The type of parent.</param> /// <param name="parentId">Identifier of parent element.</param> private void ParsePatchFamilyGroupRefElement(XElement node, ComplexReferenceParentType parentType, string parentId) { Debug.Assert(ComplexReferenceParentType.PatchFamilyGroup == parentType || ComplexReferenceParentType.Patch == parentType); var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; foreach (var attrib in node.Attributes()) { if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) { switch (attrib.Name.LocalName) { case "Id": id = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.WixPatchFamilyGroup, id); break; default: this.Core.UnexpectedAttribute(node, attrib); break; } } else { this.Core.ParseExtensionAttribute(node, attrib); } } if (null == id) { this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); } this.Core.ParseForExtensionElements(node); if (!this.Core.EncounteredError) { this.Core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamilyGroup, id, true); } }
/// <summary> /// Parses a merge reference element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">Parents complex reference type.</param> /// <param name="parentId">Identifier for parent feature or feature group.</param> private void ParseMergeRefElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; YesNoType primary = YesNoType.NotSet; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "WixMerge", id); break; case "Primary": primary = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } 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); } } } this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Module, id, (YesNoType.Yes == primary)); }
private void ParseFeatureElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ref int lastDisplay) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; string allowAdvertise = null; int bits = 0; string configurableDirectory = null; string description = null; string display = "collapse"; YesNoType followParent = YesNoType.NotSet; string installDefault = null; int level = 1; string title = null; string typicalDefault = 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; case "Absent": string absent = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (0 < absent.Length) { Wix.Feature.AbsentType absentType = Wix.Feature.ParseAbsentType(absent); switch (absentType) { case Wix.Feature.AbsentType.allow: // this is the default break; case Wix.Feature.AbsentType.disallow: bits = bits | MsiInterop.MsidbFeatureAttributesUIDisallowAbsent; break; default: this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, attrib.Name, absent, "allow", "disallow")); break; } } break; case "AllowAdvertise": allowAdvertise = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (0 < allowAdvertise.Length) { Wix.Feature.AllowAdvertiseType allowAdvertiseType = Wix.Feature.ParseAllowAdvertiseType(allowAdvertise); switch (allowAdvertiseType) { case Wix.Feature.AllowAdvertiseType.no: bits |= MsiInterop.MsidbFeatureAttributesDisallowAdvertise; break; case Wix.Feature.AllowAdvertiseType.system: bits |= MsiInterop.MsidbFeatureAttributesNoUnsupportedAdvertise; break; case Wix.Feature.AllowAdvertiseType.yes: // this is the default break; default: this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, attrib.Name, allowAdvertise, "no", "system", "yes")); break; } } break; case "ConfigurableDirectory": configurableDirectory = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "Directory", configurableDirectory); break; case "Description": description = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Display": display = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "InstallDefault": installDefault = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (0 < installDefault.Length) { Wix.Feature.InstallDefaultType installDefaultType = Wix.Feature.ParseInstallDefaultType(installDefault); switch (installDefaultType) { case Wix.Feature.InstallDefaultType.followParent: if (ComplexReferenceParentType.Product == parentType) { this.core.OnMessage(WixErrors.RootFeatureCannotFollowParent(sourceLineNumbers)); } bits = bits | MsiInterop.MsidbFeatureAttributesFollowParent; break; case Wix.Feature.InstallDefaultType.local: // this is the default break; case Wix.Feature.InstallDefaultType.source: bits = bits | MsiInterop.MsidbFeatureAttributesFavorSource; break; default: this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, attrib.Name, installDefault, "followParent", "local", "source")); break; } } break; case "Level": level = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); break; case "Title": title = this.core.GetAttributeValue(sourceLineNumbers, attrib); if ("PUT-FEATURE-TITLE-HERE" == title) { this.core.OnMessage(WixWarnings.PlaceholderValue(sourceLineNumbers, node.Name, attrib.Name, title)); } break; case "TypicalDefault": typicalDefault = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (0 < typicalDefault.Length) { Wix.Feature.TypicalDefaultType typicalDefaultType = Wix.Feature.ParseTypicalDefaultType(typicalDefault); switch (typicalDefaultType) { case Wix.Feature.TypicalDefaultType.advertise: bits = bits | MsiInterop.MsidbFeatureAttributesFavorAdvertise; break; case Wix.Feature.TypicalDefaultType.install: // this is the default break; default: this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, attrib.Name, typicalDefault, "advertise", "install")); break; } } break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } else if (38 < id.Length) { this.core.OnMessage(WixErrors.FeatureNameTooLong(sourceLineNumbers, node.Name, "Id", id)); } if (null != configurableDirectory && configurableDirectory.ToUpper(CultureInfo.InvariantCulture) != configurableDirectory) { this.core.OnMessage(WixErrors.FeatureConfigurableDirectoryNotUppercase(sourceLineNumbers, node.Name, "ConfigurableDirectory", configurableDirectory)); } if ("advertise" == typicalDefault && "no" == allowAdvertise) { this.core.OnMessage(WixErrors.FeatureCannotFavorAndDisallowAdvertise(sourceLineNumbers, node.Name, "TypicalDefault", typicalDefault, "AllowAdvertise", allowAdvertise)); } if (YesNoType.Yes == followParent && ("local" == installDefault || "source" == installDefault)) { this.core.OnMessage(WixErrors.FeatureCannotFollowParentAndFavorLocalOrSource(sourceLineNumbers, node.Name, "InstallDefault", "FollowParent", "yes")); } int childDisplay = 0; foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "ComponentGroupRef": this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.Feature, id, null); break; case "ComponentRef": this.ParseComponentRefElement(child, ComplexReferenceParentType.Feature, id, null); break; case "Component": this.ParseComponentElement(child, ComplexReferenceParentType.Feature, id, null, CompilerCore.IntegerNotSet, null, null); break; case "Condition": this.ParseConditionElement(child, node.LocalName, id, null); break; case "Feature": this.ParseFeatureElement(child, ComplexReferenceParentType.Feature, id, ref childDisplay); break; case "FeatureGroupRef": this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Feature, id); break; case "FeatureRef": this.ParseFeatureRefElement(child, ComplexReferenceParentType.Feature, id); break; case "MergeRef": this.ParseMergeRefElement(child, ComplexReferenceParentType.Feature, id); break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "Feature"); row[0] = id; row[1] = null; // this column is set in the linker row[2] = title; row[3] = description; if (0 < display.Length) { switch (display) { case "collapse": lastDisplay = (lastDisplay | 1) + 1; row[4] = lastDisplay; break; case "expand": lastDisplay = (lastDisplay + 1) | 1; row[4] = lastDisplay; break; case "hidden": row[4] = 0; break; default: int value; if (!Int32.TryParse(display, NumberStyles.Integer, CultureInfo.InvariantCulture, out value)) { this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, "Display", display, "collapse", "expand", "hidden")); } else { row[4] = value; // save the display value of this row (if its not hidden) for subsequent rows if (0 != (int)row[4]) { lastDisplay = (int)row[4]; } } break; } } row[5] = level; row[6] = configurableDirectory; row[7] = bits; if (ComplexReferenceParentType.Unknown != parentType) { this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Feature, id, false); } } }
/// <summary> /// Parses a PatchFamilyRef element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">The parent type.</param> /// <param name="parentId">The ID of the parent.</param> /// <returns>Id of the referenced element.</returns> private void ParsePatchFamilyRefElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string[] primaryKeys = new string[2]; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": primaryKeys[0] = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "ProductCode": primaryKeys[1] = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (null == primaryKeys[0]) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "MsiPatchSequence", primaryKeys); 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 (!this.core.EncounteredError) { this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamily, primaryKeys[0], true); } }
/// <summary> /// Creates a WiX complex reference in the active section. /// </summary> /// <param name="sourceLineNumbers">Source line information.</param> /// <param name="parentType">The parent type.</param> /// <param name="parentId">The parent id.</param> /// <param name="parentLanguage">The parent language.</param> /// <param name="childType">The child type.</param> /// <param name="childId">The child id.</param> /// <param name="isPrimary">Whether the child is primary.</param> internal void CreateWixComplexReferenceRow(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { if (!this.EncounteredError) { WixComplexReferenceRow wixComplexReferenceRow = (WixComplexReferenceRow)this.CreateRow(sourceLineNumbers, "WixComplexReference"); wixComplexReferenceRow.ParentId = parentId; wixComplexReferenceRow.ParentType = parentType; wixComplexReferenceRow.ParentLanguage = parentLanguage; wixComplexReferenceRow.ChildId = childId; wixComplexReferenceRow.ChildType = childType; wixComplexReferenceRow.IsPrimary = isPrimary; } }
/// <summary> /// Parses a package group reference element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> /// <param name="parentId">Identifier of parent element.</param> /// <returns>Identifier for package group element.</rereturns> private string ParsePackageGroupRefElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { return ParsePackageGroupRefElement(node, parentType, parentId, ComplexReferenceChildType.PackageGroup, null); }
/// <summary> /// Parse RollbackBoundary element /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <returns>Identifier for package element.</returns> private string ParseRollbackBoundaryElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; YesNoType vital = YesNoType.Yes; // This crazy list lets us evaluate extension attributes *after* all core attributes // have been parsed and dealt with, regardless of authoring order. List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>> extensionAttributes = new List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>>(); foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { bool allowed = true; switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "Vital": vital = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; default: allowed = false; break; } if (!allowed) { this.core.UnexpectedAttribute(sourceLineNumbers, attrib); } } else { // Save the extension attributes for later... extensionAttributes.Add(new KeyValuePair<SourceLineNumberCollection, XmlAttribute>(sourceLineNumbers, attrib)); } } if (String.IsNullOrEmpty(id)) { if (!String.IsNullOrEmpty(previousId)) { id = this.core.GenerateIdentifier("rba", previousId); } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } else if (!CompilerCore.IsIdentifier(id)) { this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name, "Id", id)); } } // Now that the package ID is known, we can parse the extension attributes... Dictionary<string, string> contextValues = new Dictionary<string, string>(); contextValues["RollbackBoundaryId"] = id; foreach (KeyValuePair<SourceLineNumberCollection, XmlAttribute> pair in extensionAttributes) { this.core.ParseExtensionAttribute(pair.Key, (XmlElement)node, pair.Value, contextValues); } 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.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child, id); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "ChainPackage"); row[0] = id; row[1] = ChainPackageType.RollbackBoundary.ToString(); if (YesNoType.NotSet != vital) { row[10] = (YesNoType.Yes == vital) ? 1 : 0; } this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id, previousType, previousId, null); } return id; }
/// <summary> /// Creates group and ordering information. /// </summary> /// <param name="sourceLineNumbers">Source line numbers.</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="type">Type of this item.</param> /// <param name="id">Identifier for this item.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> private void CreateGroupAndOrderingRows(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType type, string id, ComplexReferenceChildType previousType, string previousId) { if (ComplexReferenceParentType.Unknown != parentType && null != parentId) { this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, type, id); } if (ComplexReferenceChildType.Unknown != previousType && null != previousId) { this.CreateWixOrderingRow(sourceLineNumbers, type, id, previousType, previousId); } }
/// <summary> /// Creates the row for a Payload. /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">ComplexReferenceParentType of parent element</param> /// <param name="parentId">Identifier of parent element.</param> private void CreatePayloadRow(SourceLineNumberCollection sourceLineNumbers, string id, string name, string sourceFile, string downloadUrl, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId, YesNoDefaultType compressed, YesNoType suppressSignatureVerification, string displayName, string description) { if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "Payload"); row[0] = id; row[1] = String.IsNullOrEmpty(name) ? Path.GetFileName(sourceFile) : name; row[2] = sourceFile; row[3] = downloadUrl; if (YesNoDefaultType.Default != compressed) { row[4] = (YesNoDefaultType.Yes == compressed) ? 1 : 0; } row[5] = sourceFile; // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. row[6] = (YesNoType.Yes == suppressSignatureVerification) ? 1 : 0; if (!String.IsNullOrEmpty(description) || !String.IsNullOrEmpty(displayName)) { Row rowDisplay = this.core.CreateRow(sourceLineNumbers, "PayloadDisplayInformation"); rowDisplay[0] = id; rowDisplay[1] = displayName; rowDisplay[2] = description; } this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Payload, id, previousType, previousId); } }
/// <summary> /// Parses a PatchFamilyGroup element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType"></param> /// <param name="parentId"></param> private void ParsePatchFamilyGroupElement(XElement node, ComplexReferenceParentType parentType, string parentId) { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; foreach (var attrib in node.Attributes()) { if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) { switch (attrib.Name.LocalName) { case "Id": id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); break; default: this.Core.UnexpectedAttribute(node, attrib); break; } } else { this.Core.ParseExtensionAttribute(node, attrib); } } if (null == id) { this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); id = Identifier.Invalid; } foreach (var child in node.Elements()) { if (CompilerCore.WixNamespace == child.Name.Namespace) { switch (child.Name.LocalName) { case "PatchFamily": this.ParsePatchFamilyElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); break; case "PatchFamilyRef": this.ParsePatchFamilyRefElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); break; case "PatchFamilyGroupRef": this.ParsePatchFamilyGroupRefElement(child, ComplexReferenceParentType.PatchFamilyGroup, id.Id); break; default: this.Core.UnexpectedElement(node, child); break; } } else { this.Core.ParseExtensionElement(node, child); } } if (!this.Core.EncounteredError) { this.Core.AddSymbol(new WixPatchFamilyGroupSymbol(sourceLineNumbers, id)); //Add this PatchFamilyGroup and its parent in WixGroup. this.Core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PatchFamilyGroup, id.Id); } }
/// <summary> /// Parses a PatchFamily element. /// </summary> /// <param name="node">The element to parse.</param> /// <param name="parentType"></param> /// <param name="parentId"></param> private void ParsePatchFamilyElement(XElement node, ComplexReferenceParentType parentType, string parentId) { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); Identifier id = null; string productCode = null; string version = null; var attributes = 0; foreach (var attrib in node.Attributes()) { if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) { switch (attrib.Name.LocalName) { case "Id": id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); break; case "ProductCode": productCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); break; case "Version": version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); break; case "Supersede": if (YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= 0x1; } break; default: this.Core.UnexpectedAttribute(node, attrib); break; } } else { this.Core.ParseExtensionAttribute(node, attrib); } } if (null == id) { this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); id = Identifier.Invalid; } if (String.IsNullOrEmpty(version)) { this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version")); } else if (!CompilerCore.IsValidProductVersion(version)) { this.Core.Write(ErrorMessages.InvalidProductVersion(sourceLineNumbers, version)); } // find unexpected child elements foreach (var child in node.Elements()) { if (CompilerCore.WixNamespace == child.Name.Namespace) { switch (child.Name.LocalName) { case "All": this.ParseAllElement(child); break; case "BinaryRef": this.ParsePatchChildRefElement(child, "Binary"); break; case "ComponentRef": this.ParsePatchChildRefElement(child, "Component"); break; case "CustomActionRef": this.ParsePatchChildRefElement(child, "CustomAction"); break; case "DirectoryRef": this.ParsePatchChildRefElement(child, "Directory"); break; case "DigitalCertificateRef": this.ParsePatchChildRefElement(child, "MsiDigitalCertificate"); break; case "FeatureRef": this.ParsePatchChildRefElement(child, "Feature"); break; case "IconRef": this.ParsePatchChildRefElement(child, "Icon"); break; case "PropertyRef": this.ParsePatchChildRefElement(child, "Property"); break; case "SoftwareTagRef": this.ParseTagRefElement(child); break; case "UIRef": this.ParsePatchChildRefElement(child, "WixUI"); break; default: this.Core.UnexpectedElement(node, child); break; } } else { this.Core.ParseExtensionElement(node, child); } } if (!this.Core.EncounteredError) { this.Core.AddSymbol(new MsiPatchSequenceSymbol(sourceLineNumbers) { PatchFamily = id.Id, ProductCode = productCode, Sequence = version, Attributes = attributes }); if (ComplexReferenceParentType.Unknown != parentType) { this.Core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamily, id.Id, ComplexReferenceParentType.Patch == parentType); } } }
/// <summary> /// Changes all of the parent references to point to the passed in parent reference. /// </summary> /// <param name="parent">New parent complex reference.</param> internal void Reparent(WixComplexReferenceRow parent) { this.ParentId = parent.ParentId; this.ParentLanguage = parent.ParentLanguage; this.ParentType = parent.ParentType; if (!this.IsPrimary) { this.IsPrimary = parent.IsPrimary; } }
/// <summary> /// A row in the WixGroup table is added for this child node and its parent node. /// </summary> /// <param name="sourceLineNumbers">Source line information for the row.</param> /// <param name="parentType">Type of child's complex reference parent.</param> /// <param name="parentId">Id of the parenet node.</param> /// <param name="childType">Complex reference type of child</param> /// <param name="childId">Id of the Child Node.</param> public void CreateWixGroupRow(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { if (!this.EncounteredError) { if (null == parentId || ComplexReferenceParentType.Unknown == parentType) { return; } if (null == childId) { throw new ArgumentNullException("childId"); } Row WixGroupRow = this.CreateRow(sourceLineNumbers, "WixGroup"); WixGroupRow[0] = parentId; WixGroupRow[1] = Enum.GetName(typeof(ComplexReferenceParentType), parentType); WixGroupRow[2] = childId; WixGroupRow[3] = Enum.GetName(typeof(ComplexReferenceChildType), childType); } }
/// <summary> /// Creates WixComplexReference and WixGroup rows in the active section. /// </summary> /// <param name="sourceLineNumbers">Source line information.</param> /// <param name="parentType">The parent type.</param> /// <param name="parentId">The parent id.</param> /// <param name="parentLanguage">The parent language.</param> /// <param name="childType">The child type.</param> /// <param name="childId">The child id.</param> /// <param name="isPrimary">Whether the child is primary.</param> public void CreateComplexReference(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { this.CreateWixComplexReferenceRow(sourceLineNumbers, parentType, parentId, parentLanguage, childType, childId, isPrimary); this.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, childType, childId); }
/// <summary> /// Parse the attributes of the Payload element. /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">ComplexReferenceParentType of parent element.</param> /// <param name="parentId">Identifier of parent element.</param> private string ParsePayloadElementContent(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId, bool required) { Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); YesNoDefaultType compressed = YesNoDefaultType.Default; YesNoType suppressSignatureVerification = YesNoType.NotSet; string id = null; string name = null; string sourceFile = null; string downloadUrl = null; PayloadInfoRow remotePayload = 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.GetAttributeValue(sourceLineNumbers, attrib); break; case "Compressed": compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); break; case "Name": name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); break; case "SourceFile": sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DownloadUrl": downloadUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "SuppressSignatureVerification": suppressSignatureVerification = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (!required && null == sourceFile) { // Nothing left to do! return null; } foreach (XmlNode child in node.ChildNodes) { // We only handle the elements we care about. Let caller handle other children. if ((XmlNodeType.Element == child.NodeType) && (child.NamespaceURI == this.schema.TargetNamespace) && (child.LocalName == "RemotePayload")) { SourceLineNumberCollection childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); if (node.NamespaceURI == this.schema.TargetNamespace && node.LocalName != "ExePackage") { this.core.OnMessage(WixErrors.RemotePayloadUnsupported(childSourceLineNumbers)); continue; } if (null != remotePayload) { this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name, child.LocalName)); } remotePayload = this.ParseRemotePayloadElement(child, id); } } if (null != sourceFile && null != remotePayload) { this.core.OnMessage(WixErrors.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name, "RemotePayload", "SourceFile")); } else if (null == sourceFile && null == remotePayload) { this.core.OnMessage(WixErrors.ExpectedAttributeOrElement(sourceLineNumbers, node.Name, "SourceFile", "RemotePayload")); } else if (null == sourceFile) { sourceFile = String.Empty; } if (null == downloadUrl && null != remotePayload) { this.core.OnMessage(WixErrors.ExpectedAttributeWithElement(sourceLineNumbers, node.Name, "DownloadUrl", "RemotePayload")); } if (Compiler.BurnUXContainerId == parentId) { if (compressed == YesNoDefaultType.No) { core.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(sourceLineNumbers, sourceFile)); } compressed = YesNoDefaultType.Yes; } if (String.IsNullOrEmpty(id)) { id = this.core.GenerateIdentifier("pay", (null != sourceFile) ? sourceFile.ToUpperInvariant() : String.Empty); } if (null != remotePayload) { remotePayload.Id = id; } this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, parentType, parentId, previousType, previousId, compressed, suppressSignatureVerification, null, null); return id; }
private string CombineTypeAndId(ComplexReferenceParentType type, string id) { return String.Format("{0}:{1}", type.ToString(), id); }
/// <summary> /// Parse PayloadGroup element. /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">Optional ComplexReferenceParentType of parent element. (typically another PayloadGroup)</param> /// <param name="parentId">Identifier of parent element.</param> private void ParsePayloadGroupElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.Layout == parentType || ComplexReferenceParentType.PayloadGroup == parentType); 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); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } ComplexReferenceChildType previousType = ComplexReferenceChildType.Unknown; string previousId = null; foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "Payload": previousId = this.ParsePayloadElement(child, ComplexReferenceParentType.PayloadGroup, id, previousType, previousId); previousType = ComplexReferenceChildType.Payload; break; case "PayloadGroupRef": previousId = this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.PayloadGroup, id, previousType, previousId); previousType = ComplexReferenceChildType.PayloadGroup; break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.UnsupportedExtensionElement(node, child); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "PayloadGroup"); row[0] = id; this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PayloadGroup, id, ComplexReferenceChildType.Unknown, null); } }
public void CreateWixGroupRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { if (null == parentId || ComplexReferenceParentType.Unknown == parentType) { return; } if (null == childId) { throw new ArgumentNullException("childId"); } var row = (WixGroupTuple)this.CreateRow(section, sourceLineNumbers, TupleDefinitionType.WixGroup); row.ParentId = parentId; row.ParentType = parentType; row.ChildId = childId; row.ChildType = childType; }
/// <summary> /// Parse ExePackage element /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <returns>Identifier for package element.</returns> private string ParseExePackageElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { return ParseChainPackage(node, ChainPackageType.Exe, parentType, parentId, previousType, previousId); }
public void CreateComplexReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { var wixComplexReferenceRow = (WixComplexReferenceTuple)this.CreateRow(section, sourceLineNumbers, TupleDefinitionType.WixComplexReference); wixComplexReferenceRow.Parent = parentId; wixComplexReferenceRow.ParentType = parentType; wixComplexReferenceRow.ParentLanguage = parentLanguage; wixComplexReferenceRow.Child = childId; wixComplexReferenceRow.ChildType = childType; wixComplexReferenceRow.IsPrimary = isPrimary; this.CreateWixGroupRow(section, sourceLineNumbers, parentType, parentId, childType, childId); }
/// <summary> /// Parses one of the ChainPackage elements /// </summary> /// <param name="node">Element to parse</param> /// <param name="packageType">Type of package to parse</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <returns>Identifier for package element.</returns> /// <remarks>This method contains the shared logic for parsing all of the ChainPackage /// types, as there is more in common between them than different.</remarks> private string ParseChainPackage(XmlNode node, ChainPackageType packageType, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.PackageGroup == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string name = null; string sourceFile = null; string downloadUrl = null; string id = null; string after = null; string installCondition = null; YesNoType cache = YesNoType.NotSet; string cacheId = null; string description = null; string displayName = null; string logPathVariable = (packageType == ChainPackageType.Msu) ? String.Empty : null; string rollbackPathVariable = (packageType == ChainPackageType.Msu) ? String.Empty : null; YesNoType permanent = YesNoType.NotSet; YesNoType visible = YesNoType.NotSet; YesNoType vital = YesNoType.Yes; string installCommand = null; string repairCommand = null; YesNoType repairable = YesNoType.NotSet; string uninstallCommand = null; YesNoDefaultType perMachine = YesNoDefaultType.NotSet; string detectCondition = null; string protocol = null; int installSize = CompilerCore.IntegerNotSet; string msuKB = null; YesNoType suppressLooseFilePayloadGeneration = YesNoType.NotSet; YesNoType suppressSignatureVerification = YesNoType.NotSet; YesNoDefaultType compressed = YesNoDefaultType.Default; YesNoType displayInternalUI = YesNoType.NotSet; YesNoType enableFeatureSelection = YesNoType.NotSet; YesNoType forcePerMachine = YesNoType.NotSet; BundlePackageAttributes attributes = BundlePackageAttributes.None; PayloadInfoRow remotePayload = null; YesNoType slipstream = YesNoType.NotSet; string[] expectedNetFx4Args = new string[] { "/q", "/norestart", "/chainingpackage" }; // This crazy list lets us evaluate extension attributes *after* all core attributes // have been parsed and dealt with, regardless of authoring order. List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>> extensionAttributes = new List<KeyValuePair<SourceLineNumberCollection, XmlAttribute>>(); foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { bool allowed = true; switch (attrib.LocalName) { case "Name": name = this.core.GetAttributeLongFilename(sourceLineNumbers, attrib, false, true); if (!CompilerCore.IsValidLongFilename(name, false, true)) { this.core.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, node.Name, "Name", name)); } break; case "SourceFile": sourceFile = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DownloadUrl": downloadUrl = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Id": id = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "After": after = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "InstallCondition": installCondition = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Cache": cache = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "CacheId": cacheId = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Description": description = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DisplayName": displayName = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; case "DisplayInternalUI": displayInternalUI = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi || packageType == ChainPackageType.Msp); break; case "EnableFeatureSelection": enableFeatureSelection = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "ForcePerMachine": forcePerMachine = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "LogPathVariable": logPathVariable = this.core.GetAttributeValue(sourceLineNumbers, attrib, true); break; case "RollbackLogPathVariable": rollbackPathVariable = this.core.GetAttributeValue(sourceLineNumbers, attrib, true); break; case "Permanent": permanent = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "Visible": visible = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "Vital": vital = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "InstallCommand": installCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe); break; case "RepairCommand": repairCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib, true); repairable = YesNoType.Yes; allowed = (packageType == ChainPackageType.Exe); break; case "UninstallCommand": uninstallCommand = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe); break; case "PerMachine": perMachine = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe || packageType == ChainPackageType.Msp); break; case "DetectCondition": detectCondition = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe || packageType == ChainPackageType.Msu); break; case "Protocol": protocol = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Exe); break; case "InstallSize": installSize = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue); break; case "KB": msuKB = this.core.GetAttributeValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msu); break; case "Compressed": compressed = this.core.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib); break; case "SuppressLooseFilePayloadGeneration": this.core.OnMessage(WixWarnings.DeprecatedAttribute(sourceLineNumbers, node.Name, attrib.Name)); suppressLooseFilePayloadGeneration = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msi); break; case "SuppressSignatureVerification": suppressSignatureVerification = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "Slipstream": slipstream = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); allowed = (packageType == ChainPackageType.Msp); break; default: allowed = false; break; } if (!allowed) { this.core.UnexpectedAttribute(sourceLineNumbers, attrib); } } else { // Save the extension attributes for later... extensionAttributes.Add(new KeyValuePair<SourceLineNumberCollection, XmlAttribute>(sourceLineNumbers, attrib)); } } foreach (XmlNode child in node.ChildNodes) { // We need to handle RemotePayload up front because it effects value of sourceFile which is used in Id generation. Id is needed by other child elements. if ((XmlNodeType.Element == child.NodeType) && (child.NamespaceURI == this.schema.TargetNamespace) && (child.LocalName == "RemotePayload")) { SourceLineNumberCollection childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child); if (node.NamespaceURI == this.schema.TargetNamespace && node.LocalName != "ExePackage") { this.core.OnMessage(WixErrors.RemotePayloadUnsupported(childSourceLineNumbers)); continue; } if (null != remotePayload) { this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name, child.LocalName)); } remotePayload = this.ParseRemotePayloadElement(child, id); } } if (String.IsNullOrEmpty(sourceFile)) { if (String.IsNullOrEmpty(name)) { this.core.OnMessage(WixErrors.ExpectedAttributesWithOtherAttribute(sourceLineNumbers, node.Name, "Name", "SourceFile")); } else if (null == remotePayload) { sourceFile = Path.Combine("SourceDir", name); } else { sourceFile = String.Empty; // SourceFile is required it cannot be null. } } else if (null != remotePayload) { this.core.OnMessage(WixErrors.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name, "RemotePayload", "SourceFile")); } else if (sourceFile.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) { if (String.IsNullOrEmpty(name)) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Name", "SourceFile", sourceFile)); } else { sourceFile = Path.Combine(sourceFile, Path.GetFileName(name)); } } if (null == downloadUrl && null != remotePayload) { this.core.OnMessage(WixErrors.ExpectedAttributeWithElement(sourceLineNumbers, node.Name, "DownloadUrl", "RemotePayload")); } if (String.IsNullOrEmpty(id)) { if (!String.IsNullOrEmpty(name)) { id = CompilerCore.GetIdentifierFromName(Path.GetFileName(name)); } else if (!String.IsNullOrEmpty(sourceFile)) { id = CompilerCore.GetIdentifierFromName(Path.GetFileName(sourceFile)); } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } else if (!CompilerCore.IsIdentifier(id)) { this.core.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, node.Name, "Id", id)); } } if (null != remotePayload) { remotePayload.Id = id; } if (null == logPathVariable) { logPathVariable = String.Concat("WixBundleLog_", id); } if (null == rollbackPathVariable) { rollbackPathVariable = String.Concat("WixBundleRollbackLog_", id); } if (!String.IsNullOrEmpty(protocol) && !protocol.Equals("burn", StringComparison.Ordinal) && !protocol.Equals("netfx4", StringComparison.Ordinal) && !protocol.Equals("none", StringComparison.Ordinal)) { this.core.OnMessage(WixErrors.IllegalAttributeValueWithLegalList(sourceLineNumbers, node.Name, "Protocol", protocol, "none, burn, netfx4")); } if (!String.IsNullOrEmpty(protocol) && protocol.Equals("netfx4", StringComparison.Ordinal)) { foreach (string expectedArgument in expectedNetFx4Args) { if (null == installCommand || -1 == installCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) { this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name, "InstallCommand", installCommand, expectedArgument, "Protocol", "netfx4")); } if (null == repairCommand || -1 == repairCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) { this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name, "RepairCommand", repairCommand, expectedArgument, "Protocol", "netfx4")); } if (null == uninstallCommand || -1 == uninstallCommand.IndexOf(expectedArgument, StringComparison.OrdinalIgnoreCase)) { this.core.OnMessage(WixWarnings.AttributeShouldContain(sourceLineNumbers, node.Name, "UninstallCommand", uninstallCommand, expectedArgument, "Protocol", "netfx4")); } } } // Only set default scope for EXEs and MSPs if not already set. if ((ChainPackageType.Exe == packageType || ChainPackageType.Msp == packageType) && YesNoDefaultType.NotSet == perMachine) { perMachine = YesNoDefaultType.Default; } // Now that the package ID is known, we can parse the extension attributes... Dictionary<string, string> contextValues = new Dictionary<string, string>(); contextValues["PackageId"] = id; foreach (KeyValuePair<SourceLineNumberCollection, XmlAttribute> pair in extensionAttributes) { this.core.ParseExtensionAttribute(pair.Key, (XmlElement)node, pair.Value, contextValues); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { bool allowed = true; switch (child.LocalName) { case "SlipstreamMsp": allowed = (packageType == ChainPackageType.Msi); if (allowed) { this.ParseSlipstreamMspElement(child, id); } break; case "MsiProperty": allowed = (packageType == ChainPackageType.Msi || packageType == ChainPackageType.Msp); if (allowed) { this.ParseMsiPropertyElement(child, id); } break; case "Payload": this.ParsePayloadElement(child, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null); break; case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null); break; case "ExitCode": allowed = (packageType == ChainPackageType.Exe); if (allowed) { this.ParseExitCodeElement(child, id); } break; case "RemotePayload": // Handled previously break; default: allowed = false; break; } if (!allowed) { this.core.UnexpectedElement(node, child); } } else { this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child, id); } } } if (!this.core.EncounteredError) { if (YesNoType.Yes == permanent) { attributes |= BundlePackageAttributes.Permanent; } if (YesNoType.Yes == visible) { attributes |= BundlePackageAttributes.Visible; } if (YesNoType.Yes == slipstream) { attributes |= BundlePackageAttributes.Slipstream; } // We create the package contents as a payload with this package as the parent this.CreatePayloadRow(sourceLineNumbers, id, name, sourceFile, downloadUrl, ComplexReferenceParentType.Package, id, ComplexReferenceChildType.Unknown, null, compressed, suppressSignatureVerification, displayName, description); Row row = this.core.CreateRow(sourceLineNumbers, "ChainPackage"); row[0] = id; row[1] = packageType.ToString(); row[2] = id; row[3] = installCondition; row[4] = installCommand; row[5] = repairCommand; row[6] = uninstallCommand; if (YesNoType.NotSet != cache) { row[7] = (YesNoType.Yes == cache) ? 1 : 0; } row[8] = cacheId; row[9] = (int)attributes; if (YesNoType.NotSet != vital) { row[10] = (YesNoType.Yes == vital) ? 1 : 0; } switch (perMachine) { case YesNoDefaultType.No: row[11] = 0; break; case YesNoDefaultType.Yes: row[11] = 1; break; case YesNoDefaultType.Default: row[11] = 2; break; } row[12] = detectCondition; row[13] = msuKB; if (YesNoType.NotSet != repairable) { row[14] = (YesNoType.Yes == repairable) ? 1 : 0; } row[15] = logPathVariable; row[16] = rollbackPathVariable; row[17] = protocol; row[18] = installSize; if (YesNoType.NotSet != suppressLooseFilePayloadGeneration) { row[19] = (YesNoType.Yes == suppressLooseFilePayloadGeneration) ? 1 : 0; } if (YesNoType.NotSet != enableFeatureSelection) { row[20] = (YesNoType.Yes == enableFeatureSelection) ? 1 : 0; } if (YesNoType.NotSet != forcePerMachine) { row[21] = (YesNoType.Yes == forcePerMachine) ? 1 : 0; } if (YesNoType.NotSet != displayInternalUI) { row[22] = (YesNoType.Yes == displayInternalUI) ? 1 : 0; } this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id, previousType, previousId, after); } return id; }
/// <summary> /// Creates group and ordering information for packages /// </summary> /// <param name="sourceLineNumbers">Source line numbers.</param> /// <param name="parentType">Type of parent group, if known.</param> /// <param name="parentId">Identifier of parent group, if known.</param> /// <param name="type">Type of this item.</param> /// <param name="id">Identifier for this item.</param> /// <param name="previousType">Type of previous item, if known.</param> /// <param name="previousId">Identifier of previous item, if known</param> /// <param name="afterId">Identifier of explicit 'After' attribute, if given.</param> private void CreateChainPackageMetaRows(SourceLineNumberCollection sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType type, string id, ComplexReferenceChildType previousType, string previousId, string afterId) { // If there's an explicit 'After' attribute, it overrides the inferred previous item. if (null != afterId) { previousType = ComplexReferenceChildType.Package; previousId = afterId; } this.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId, type, id, previousType, previousId); }
/// <summary> /// Parses a package group reference element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">ComplexReferenceParentType of parent element (Unknown or PackageGroup).</param> /// <param name="parentId">Identifier of parent element.</param> /// <param name="parentType">ComplexReferenceParentType of previous element (Unknown, Package, or PackageGroup).</param> /// <param name="parentId">Identifier of parent element.</param> /// <returns>Identifier for package group element.</rereturns> private string ParsePackageGroupRefElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.Unknown == parentType || ComplexReferenceParentType.PackageGroup == parentType || ComplexReferenceParentType.Container == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PackageGroup == previousType || ComplexReferenceChildType.Package == previousType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; string after = 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); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "ChainPackageGroup", id); break; case "After": after = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } if (null != after && ComplexReferenceParentType.Container == parentType) { this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name, "After", parentId)); } 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 (ComplexReferenceParentType.Container == parentType) { this.core.CreateWixGroupRow(sourceLineNumbers, ComplexReferenceParentType.Container, parentId, ComplexReferenceChildType.PackageGroup, id); } else { this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PackageGroup, id, previousType, previousId, after); } return id; }
private void ParseComponentGroupElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; string directoryId = null; string source = 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.GetAttributeValue(sourceLineNumbers, attrib); if (!CompilerCore.IsIdentifier(id)) { this.core.OnMessage(WixWarnings.DeprecatedComponentGroupId(sourceLineNumbers, node.LocalName)); } break; case "Directory": directoryId = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "Directory", directoryId); break; case "Source": source = this.core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } if (!String.IsNullOrEmpty(source) && !source.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) { source = String.Concat(source, Path.DirectorySeparatorChar); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "ComponentGroupRef": this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.ComponentGroup, id, null); break; case "ComponentRef": this.ParseComponentRefElement(child, ComplexReferenceParentType.ComponentGroup, id, null); break; case "Component": this.ParseComponentElement(child, ComplexReferenceParentType.ComponentGroup, id, null, CompilerCore.IntegerNotSet, directoryId, source); break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "WixComponentGroup"); row[0] = id; //Add this componentGroup and its parent in WixGroup. this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.ComponentGroup, id); } }
private string ParseComponentElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, string parentLanguage, int diskId, string directoryId, string srcPath) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); int bits = 0; int comPlusBits = CompilerCore.IntegerNotSet; string condition = null; bool encounteredODBCDataSource = false; bool explicitWin64 = false; int files = 0; string guid = "*"; string autoId = Compiler.DefaultComponentIdPlaceholder; // placeholder id for defaulting Component/@Id to keypath id. string id = Compiler.DefaultComponentIdPlaceholderWixVariable; int keyBits = 0; bool keyFound = false; string keyPath = null; bool shouldAddCreateFolder = false; bool win64 = false; bool multiInstance = false; string symbols = null; string feature = 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; case "ComPlusFlags": comPlusBits = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue); break; case "DisableRegistryReflection": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesDisableRegistryReflection; } break; case "Directory": if (null != directoryId) { this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name, attrib.Name, "Directory")); } directoryId = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "Directory", directoryId); break; case "DiskId": diskId = this.core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue); break; case "Feature": feature = this.core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); break; case "Guid": guid = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, true, true); break; case "KeyPath": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { keyFound = true; keyPath = null; keyBits = 0; shouldAddCreateFolder = true; } break; case "Location": string location = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (0 < location.Length) { Wix.Component.LocationType locationType = Wix.Component.ParseLocationType(location); switch (locationType) { case Wix.Component.LocationType.either: bits |= MsiInterop.MsidbComponentAttributesOptional; break; case Wix.Component.LocationType.local: // this is the default break; case Wix.Component.LocationType.source: bits |= MsiInterop.MsidbComponentAttributesSourceOnly; break; default: this.core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name, attrib.Name, "either", "local", "source")); break; } } break; case "MultiInstance": multiInstance = YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; case "NeverOverwrite": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesNeverOverwrite; } break; case "Permanent": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesPermanent; } break; case "Shared": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesShared; } break; case "SharedDllRefCount": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesSharedDllRefCount; } break; case "Transitive": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesTransitive; } break; case "UninstallWhenSuperseded": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributesUninstallOnSupersedence; } break; case "Win64": explicitWin64 = true; if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { bits |= MsiInterop.MsidbComponentAttributes64bit; win64 = true; } break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (!explicitWin64 && (Platform.IA64 == CurrentPlatform || Platform.X64 == CurrentPlatform)) { bits |= MsiInterop.MsidbComponentAttributes64bit; win64 = true; } if (null == directoryId) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Directory")); } if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesShared == (bits & MsiInterop.MsidbComponentAttributesShared)) { this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name, "Shared", "yes", "Guid", "")); } if (String.IsNullOrEmpty(guid) && MsiInterop.MsidbComponentAttributesPermanent == (bits & MsiInterop.MsidbComponentAttributesPermanent)) { this.core.OnMessage(WixErrors.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name, "Permanent", "yes", "Guid", "")); } if (null != feature) { if (this.compilingModule) { this.core.OnMessage(WixErrors.IllegalAttributeInMergeModule(sourceLineNumbers, node.Name, "Feature")); } else { if (ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.FeatureGroup == parentType) { this.core.OnMessage(WixErrors.IllegalAttributeWhenNested(sourceLineNumbers, node.Name, "Feature", node.ParentNode.LocalName)); } else { this.core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Feature, feature, null, ComplexReferenceChildType.Component, id, true); } } } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { YesNoType keyPathSet = YesNoType.NotSet; string keyPossible = null; int keyBit = 0; if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "AppId": this.ParseAppIdElement(child, id, YesNoType.NotSet, null, null, null); break; case "Category": this.ParseCategoryElement(child, id); break; case "Class": this.ParseClassElement(child, id, YesNoType.NotSet, null, null, null, null); break; case "Condition": if (null != condition) { SourceLineNumberCollection childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); this.core.OnMessage(WixErrors.TooManyChildren(childSourceLineNumbers, node.Name, child.Name)); } condition = this.ParseConditionElement(child, node.LocalName, null, null); break; case "CopyFile": this.ParseCopyFileElement(child, id, null); break; case "CreateFolder": string createdFolder = this.ParseCreateFolderElement(child, id, directoryId, win64); if (directoryId == createdFolder) { shouldAddCreateFolder = false; } break; case "Environment": this.ParseEnvironmentElement(child, id); break; case "Extension": this.ParseExtensionElement(child, id, YesNoType.NotSet, null); break; case "File": keyPathSet = this.ParseFileElement(child, id, directoryId, diskId, srcPath, out keyPossible, win64, guid); if (null != keyPossible) { keyBit = 0; } files++; break; case "IniFile": this.ParseIniFileElement(child, id); break; case "Interface": this.ParseInterfaceElement(child, id, null, null, null, null); break; case "IsolateComponent": this.ParseIsolateComponentElement(child, id); break; case "ODBCDataSource": keyPathSet = this.ParseODBCDataSource(child, id, null, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesODBCDataSource; encounteredODBCDataSource = true; break; case "ODBCDriver": this.ParseODBCDriverOrTranslator(child, id, null, this.tableDefinitions["ODBCDriver"]); break; case "ODBCTranslator": this.ParseODBCDriverOrTranslator(child, id, null, this.tableDefinitions["ODBCTranslator"]); break; case "ProgId": bool foundExtension = false; this.ParseProgIdElement(child, id, YesNoType.NotSet, null, null, null, ref foundExtension, YesNoType.NotSet); break; case "Registry": keyPathSet = this.ParseRegistryElement(child, id, CompilerCore.IntegerNotSet, null, win64, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; break; case "RegistryKey": keyPathSet = this.ParseRegistryKeyElement(child, id, CompilerCore.IntegerNotSet, null, win64, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; break; case "RegistryValue": keyPathSet = this.ParseRegistryValueElement(child, id, CompilerCore.IntegerNotSet, null, win64, out keyPossible); keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; break; case "RemoveFile": this.ParseRemoveFileElement(child, id, directoryId); break; case "RemoveFolder": this.ParseRemoveFolderElement(child, id, directoryId); break; case "RemoveRegistryKey": this.ParseRemoveRegistryKeyElement(child, id); break; case "RemoveRegistryValue": this.ParseRemoveRegistryValueElement(child, id); break; case "ReserveCost": this.ParseReserveCostElement(child, id, directoryId); break; case "ServiceConfig": this.ParseServiceConfigElement(child, id, null); break; case "ServiceConfigFailureActions": this.ParseServiceConfigFailureActionsElement(child, id, null); break; case "ServiceControl": this.ParseServiceControlElement(child, id); break; case "ServiceInstall": this.ParseServiceInstallElement(child, id, win64); break; case "Shortcut": this.ParseShortcutElement(child, id, node.LocalName, directoryId, YesNoType.No); break; case "SymbolPath": if (null != symbols) { symbols += ";" + this.ParseSymbolPathElement(child); } else { symbols = this.ParseSymbolPathElement(child); } break; case "TypeLib": this.ParseTypeLibElement(child, id, null, win64); break; default: this.core.UnexpectedElement(node, child); break; } } else { CompilerExtension.ComponentKeypathType keyType = this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child, ref keyPossible, id, directoryId, win64.ToString()); // CompilerExtension must return a key path type, so the component key path is either set or not (no automatic selection). keyPathSet = CompilerExtension.ComponentKeypathType.None != keyType ? YesNoType.Yes : YesNoType.No; if (CompilerExtension.ComponentKeypathType.Registry == keyType || CompilerExtension.ComponentKeypathType.RegistryFormatted == keyType) { keyBit = MsiInterop.MsidbComponentAttributesRegistryKeyPath; } } // Verify that either the key path is not set, or it is set along with a key path ID. Debug.Assert(YesNoType.Yes != keyPathSet || (YesNoType.Yes == keyPathSet && null != keyPossible)); if (keyFound && YesNoType.Yes == keyPathSet) { this.core.OnMessage(WixErrors.ComponentMultipleKeyPaths(sourceLineNumbers, node.Name, "KeyPath", "yes", "File", "RegistryValue", "ODBCDataSource")); } // if a possible KeyPath has been found and that value was explicitly set as // the KeyPath of the component, set it now. Alternatively, if a possible // KeyPath has been found and no KeyPath has been previously set, use this // value as the default KeyPath of the component if (null != keyPossible && (YesNoType.Yes == keyPathSet || (YesNoType.NotSet == keyPathSet && null == keyPath && !keyFound))) { keyFound = YesNoType.Yes == keyPathSet; keyPath = keyPossible; keyBits = keyBit; } } } if (shouldAddCreateFolder) { Row row = this.core.CreateRow(sourceLineNumbers, "CreateFolder"); row[0] = directoryId; row[1] = id; } // check for conditions that exclude this component from using generated guids bool isGeneratableGuidOk = "*" == guid; if (isGeneratableGuidOk) { if (encounteredODBCDataSource) { this.core.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers)); isGeneratableGuidOk = false; } if (0 != files && MsiInterop.MsidbComponentAttributesRegistryKeyPath == keyBits) { this.core.OnMessage(WixErrors.IllegalComponentWithAutoGeneratedGuid(sourceLineNumbers, true)); isGeneratableGuidOk = false; } } // check for implicit KeyPath which can easily be accidentally changed if (this.showPedanticMessages && !keyFound && !isGeneratableGuidOk) { this.core.OnMessage(WixErrors.ImplicitComponentKeyPath(sourceLineNumbers, id)); } // if there isn't an @Id attribute value, replace the placeholder with the id of the keypath. // either an explicit KeyPath="yes" attribute must be specified or requirements for // generatable guid must be met. if (Compiler.DefaultComponentIdPlaceholderWixVariable == id) { if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) { id = keyPath; WixVariableResolver resolver = new WixVariableResolver(); resolver.AddVariable(autoId, keyPath); foreach (Table table in this.core.ActiveSection.Tables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { if (field.Data is string) { bool isDefault = false; bool delayedResolve = false; field.Data = resolver.ResolveVariables(row.SourceLineNumbers, (string)field.Data, false, false, ref isDefault, ref delayedResolve); } } } } } else { this.core.OnMessage(WixErrors.CannotDefaultComponentId(sourceLineNumbers)); } } // If an id was not determined by now, we have to error. if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } // finally add the Component table row if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "Component"); row[0] = id; row[1] = guid; row[2] = directoryId; row[3] = bits | keyBits; row[4] = condition; row[5] = keyPath; if (multiInstance) { Row instanceComponentRow = this.core.CreateRow(sourceLineNumbers, "WixInstanceComponent"); instanceComponentRow[0] = id; } if (null != symbols) { Row symbolRow = this.core.CreateRow(sourceLineNumbers, "WixPatchSymbolPaths"); symbolRow[0] = "Component"; symbolRow[1] = id; symbolRow[2] = symbols; } // Complus if (CompilerCore.IntegerNotSet != comPlusBits) { row = this.core.CreateRow(sourceLineNumbers, "Complus"); row[0] = id; row[1] = comPlusBits; } // if this is a module, automatically add this component to the references to ensure it gets in the ModuleComponents table if (this.compilingModule) { this.core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Module, this.activeName, this.activeLanguage, ComplexReferenceChildType.Component, id, false); } else if (ComplexReferenceParentType.Unknown != parentType && null != parentId) // if parent was provided, add a complex reference to that. { // If the Component is defined directly under a feature, then mark the complex reference primary. this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, parentLanguage, ComplexReferenceChildType.Component, id, ComplexReferenceParentType.Feature == parentType); } } return id; }
/// <summary> /// Parse a complex reference from the xml. /// </summary> /// <param name="intermediate">Intermediate to populate with persisted data.</param> /// <param name="reader">XmlReader where the intermediate is persisted.</param> /// <param name="section">Section to populate with persisted data.</param> private static void ParseComplexReference(Intermediate intermediate, XmlReader reader, Section section) { bool empty = reader.IsEmptyElement; ComplexReferenceParentType parentType = ComplexReferenceParentType.Unknown; string parentId = null; string parentLanguage = null; ComplexReferenceChildType childType = ComplexReferenceChildType.Unknown; string childId = null; bool primary = false; while (reader.MoveToNextAttribute()) { switch (reader.LocalName) { case "parent": parentId = reader.Value; break; case "parentLanguage": parentLanguage = reader.Value; break; case "parentType": switch (reader.Value) { case "componentGroup": parentType = ComplexReferenceParentType.ComponentGroup; break; case "feature": parentType = ComplexReferenceParentType.Feature; break; case "module": parentType = ComplexReferenceParentType.Module; break; } break; case "child": childId = reader.Value; break; case "childType": switch (reader.Value) { case "component": childType = ComplexReferenceChildType.Component; break; case "componentGroup": childType = ComplexReferenceChildType.ComponentGroup; break; case "feature": childType = ComplexReferenceChildType.Feature; break; case "fragment": childType = ComplexReferenceChildType.Fragment; break; case "module": childType = ComplexReferenceChildType.Module; break; } break; case "primary": primary = Common.IsYes(reader.Value, SourceLineNumberCollection.FromFileName(intermediate.Path), "complexReference", "primary", parentId); break; } } if (ComplexReferenceParentType.Unknown == parentType) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown ComplexReferenceParentType type"); } if (null == parentId) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "ComplexReference missing required attribute: 'parentId'"); } if (ComplexReferenceChildType.Unknown == childType) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "Unknown ComplexReferenceChildType type"); } if (null == childId) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), "ComplexReference missing required attribute: 'childId'"); } if (!empty && reader.Read() && XmlNodeType.EndElement != reader.MoveToContent()) { throw new WixInvalidIntermediateException(SourceLineNumberCollection.FromFileName(intermediate.Path), String.Format("Unexpected content while processing 'complexReference': {0}", reader.NodeType.ToString())); } section.ComplexReferences.Add(new ComplexReference(parentType, parentId, parentLanguage, childType, childId, primary)); }
/// <summary> /// Parses a component group reference element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">ComplexReferenceParentType of parent element.</param> /// <param name="parentId">Identifier of parent element (usually a Feature or Module).</param> /// <param name="parentLanguage">Optional language of parent (only useful for Modules).</param> private void ParseComponentGroupRefElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, string parentLanguage) { Debug.Assert(ComplexReferenceParentType.ComponentGroup == parentType || ComplexReferenceParentType.FeatureGroup == parentType || ComplexReferenceParentType.Feature == parentType || ComplexReferenceParentType.Module == parentType); SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; YesNoType primary = YesNoType.NotSet; foreach (XmlAttribute attrib in node.Attributes) { if (0 == attrib.NamespaceURI.Length || attrib.NamespaceURI == this.schema.TargetNamespace) { switch (attrib.LocalName) { case "Id": id = this.core.GetAttributeValue(sourceLineNumbers, attrib); if (!CompilerCore.IsIdentifier(id)) { this.core.OnMessage(WixWarnings.DeprecatedComponentGroupId(sourceLineNumbers, node.LocalName)); } this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "WixComponentGroup", id); break; case "Primary": primary = this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } 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); } } } this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, parentLanguage, ComplexReferenceChildType.ComponentGroup, id, (YesNoType.Yes == primary)); }
public void CreateWixGroupSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { if (null == parentId || ComplexReferenceParentType.Unknown == parentType) { return; } if (null == childId) { throw new ArgumentNullException(nameof(childId)); } section.AddSymbol(new WixGroupSymbol(sourceLineNumbers) { ParentId = parentId, ParentType = parentType, ChildId = childId, ChildType = childType, }); }
/// <summary> /// Parses a PatchFamilyGroup reference element. /// </summary> /// <param name="node">Element to parse.</param> /// <param name="parentType">The type of parent.</param> /// <param name="parentId">Identifier of parent element.</param> private void ParsePatchFamilyGroupRefElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { Debug.Assert(ComplexReferenceParentType.PatchFamilyGroup == parentType || ComplexReferenceParentType.Patch == parentType); 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.GetAttributeValue(sourceLineNumbers, attrib); this.core.CreateWixSimpleReferenceRow(sourceLineNumbers, "WixPatchFamilyGroup", id); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } 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 (!this.core.EncounteredError) { this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamilyGroup, id, true); } }
public void CreateComplexReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) { section.AddSymbol(new WixComplexReferenceSymbol(sourceLineNumbers) { Parent = parentId, ParentType = parentType, ParentLanguage = parentLanguage, Child = childId, ChildType = childType, IsPrimary = isPrimary }); this.CreateWixGroupSymbol(section, sourceLineNumbers, parentType, parentId, childType, childId); }
private void ParseFeatureGroupElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { 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.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.ParseExtensionAttribute(sourceLineNumbers, (XmlElement)node, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } int lastDisplay = 0; foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "ComponentGroupRef": this.ParseComponentGroupRefElement(child, ComplexReferenceParentType.FeatureGroup, id, null); break; case "ComponentRef": this.ParseComponentRefElement(child, ComplexReferenceParentType.FeatureGroup, id, null); break; case "Component": this.ParseComponentElement(child, ComplexReferenceParentType.FeatureGroup, id, null, CompilerCore.IntegerNotSet, null, null); break; case "Feature": this.ParseFeatureElement(child, ComplexReferenceParentType.FeatureGroup, id, ref lastDisplay); break; case "FeatureGroupRef": this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.FeatureGroup, id); break; case "FeatureRef": this.ParseFeatureRefElement(child, ComplexReferenceParentType.FeatureGroup, id); break; case "MergeRef": this.ParseMergeRefElement(child, ComplexReferenceParentType.FeatureGroup, id); break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "WixFeatureGroup"); row[0] = id; //Add this FeatureGroup and its parent in WixGroup. this.core.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.FeatureGroup, id); } }
/// <summary> /// Parses a PatchFamily element. /// </summary> /// <param name="node">The element to parse.</param> private void ParsePatchFamilyElement(XmlNode node, ComplexReferenceParentType parentType, string parentId) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); string id = null; string productCode = null; string version = null; int attributes = 0; 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; case "ProductCode": productCode = this.core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); break; case "Version": version = this.core.GetAttributeVersionValue(sourceLineNumbers, attrib, false); break; case "Supersede": if (YesNoType.Yes == this.core.GetAttributeYesNoValue(sourceLineNumbers, attrib)) { attributes |= 0x1; } break; default: this.core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.core.UnsupportedExtensionAttribute(sourceLineNumbers, attrib); } } if (null == id) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Id")); } if (String.IsNullOrEmpty(version)) { this.core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name, "Version")); } else if (!CompilerCore.IsValidProductVersion(version)) { this.core.OnMessage(WixErrors.InvalidProductVersion(sourceLineNumbers, version)); } // find unexpected child elements foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "BinaryRef": this.ParsePatchChildRefElement(child, "Binary"); break; case "ComponentRef": this.ParsePatchChildRefElement(child, "Component"); break; case "CustomActionRef": this.ParsePatchChildRefElement(child, "CustomAction"); break; case "DirectoryRef": this.ParsePatchChildRefElement(child, "Directory"); break; case "DigitalCertificateRef": this.ParsePatchChildRefElement(child, "MsiDigitalCertificate"); break; case "FeatureRef": this.ParsePatchChildRefElement(child, "Feature"); break; case "IconRef": this.ParsePatchChildRefElement(child, "Icon"); break; case "PropertyRef": this.ParsePatchChildRefElement(child, "Property"); break; case "UIRef": this.ParsePatchChildRefElement(child, "WixUI"); break; default: this.core.UnexpectedElement(node, child); break; } } else { this.core.ParseExtensionElement(sourceLineNumbers, (XmlElement)node, (XmlElement)child); } } } if (!this.core.EncounteredError) { Row row = this.core.CreateRow(sourceLineNumbers, "MsiPatchSequence"); row[0] = id; row[1] = productCode; row[2] = version; row[3] = attributes; if (ComplexReferenceParentType.Unknown != parentType) { this.core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.PatchFamily, id, ComplexReferenceParentType.Patch == parentType); } } }
/// <summary> /// Parse Payload element. /// </summary> /// <param name="node">Element to parse</param> /// <param name="parentType">ComplexReferenceParentType of parent element. (BA or PayloadGroup)</param> /// <param name="parentId">Identifier of parent element.</param> private string ParsePayloadElement(XmlNode node, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { Debug.Assert(ComplexReferenceParentType.PayloadGroup == parentType || ComplexReferenceParentType.Package == parentType || ComplexReferenceParentType.Container == parentType); Debug.Assert(ComplexReferenceChildType.Unknown == previousType || ComplexReferenceChildType.PayloadGroup == previousType || ComplexReferenceChildType.Payload == previousType); string id = ParsePayloadElementContent(node, parentType, parentId, previousType, previousId, true); foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { default: this.core.UnexpectedElement(node, child); break; } } else { this.core.UnsupportedExtensionElement(node, child); } } } return id; }
public void CreateWixGroupRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType childType, string childId) { this.CreateWixGroupSymbol(section, sourceLineNumbers, parentType, parentId, childType, childId); }