/// <summary> /// Removes properties defined by this extension. /// </summary> /// <param name="tables">The collection of tables.</param> private void FinalizeProperties() { string[] properties = new string[] { "DISABLEDEPENDENCYCHECK", "IGNOREDEPENDENCIES" }; foreach (string property in properties) { Wix.Property elem = this.Core.GetIndexedElement("Property", property) as Wix.Property; if (null != elem) { // If a value is defined, log a warning we're removing it. if (!String.IsNullOrEmpty(elem.Value)) { this.Core.OnMessage(DependencyWarnings.PropertyRemoved(elem.Id)); } // If the property row was found, remove it from its parent. if (null != elem.ParentElement) { Wix.IParentElement elemParent = elem.ParentElement as Wix.IParentElement; if (null != elemParent) { elemParent.RemoveChild(elem); } } } } }
/// <summary> /// Decompiles the WixDependencyRef table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileWixDependencyRefTable(Table table) { foreach (Row row in table.Rows) { RequiresRef requiresRef = new RequiresRef(); requiresRef.Id = (string)row[1]; Provides provides = (Provides)this.Core.GetIndexedElement("WixDependencyProvider", (string)row[0]); if (null != provides) { provides.AddChild(requiresRef); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "WixDependencyProvider_", (string)row[0], "WixDependencyProvider")); } // Get the cached keys for the provider and dependency IDs and generate registry rows. string providesKey = null; string requiresKey = null; if (null != provides && this.keyCache.ContainsKey(provides.Id)) { providesKey = this.keyCache[provides.Id]; } else { this.Core.OnMessage(DependencyWarnings.ProvidesKeyNotFound(row.SourceLineNumbers, provides.Id)); } if (this.keyCache.ContainsKey(requiresRef.Id)) { requiresKey = this.keyCache[requiresRef.Id]; } else { this.Core.OnMessage(DependencyWarnings.RequiresKeyNotFound(row.SourceLineNumbers, requiresRef.Id)); } if (!this.Core.EncounteredError) { // Add the dependency-specific registry keys to be removed during finalization. // Only remove specific keys that the compiler writes. string keyRequires = String.Format(@"{0}{1}\{2}\{3}", DependencyCommon.RegistryRoot, requiresKey, DependencyCommon.RegistryDependents, providesKey); this.registryValues.Add(keyRequires, "*"); this.registryValues.Add(keyRequires, "MinVersion"); this.registryValues.Add(keyRequires, "MaxVersion"); this.registryValues.Add(keyRequires, "Attributes"); } } }
/// <summary> /// Processes a child element of a Component for the Compiler. /// </summary> /// <param name="parentElement">Parent element of element to process.</param> /// <param name="element">Element to process.</param> /// <param name="context">Extra information about the context in which this element is being parsed.</param> /// <returns>The component key path type if set.</returns> public override ComponentKeyPath ParsePossibleKeyPathElement(XElement parentElement, XElement element, IDictionary <string, string> context) { SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(parentElement); ComponentKeyPath keyPath = null; switch (parentElement.Name.LocalName) { case "Component": string componentId = context["ComponentId"]; // 64-bit components may cause issues downlevel. bool win64 = false; Boolean.TryParse(context["Win64"], out win64); switch (element.Name.LocalName) { case "Provides": if (win64) { this.Core.OnMessage(DependencyWarnings.Win64Component(sourceLineNumbers, componentId)); } keyPath = this.ParseProvidesElement(element, PackageType.None, componentId); break; default: this.Core.UnexpectedElement(parentElement, element); break; } break; default: this.Core.UnexpectedElement(parentElement, element); break; } return(keyPath); }
/// <summary> /// Processes a child element of a Component for the Compiler. /// </summary> /// <param name="sourceLineNumbers">Source line number for the parent element.</param> /// <param name="parentElement">Parent element of element to process.</param> /// <param name="element">Element to process.</param> /// <param name="keyPath">Explicit key path.</param> /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param> /// <returns>The component key path type if set.</returns> public override CompilerExtension.ComponentKeypathType ParseElement(SourceLineNumberCollection sourceLineNumbers, XmlElement parentElement, XmlElement element, ref string keyPath, params string[] contextValues) { CompilerExtension.ComponentKeypathType keyPathType = CompilerExtension.ComponentKeypathType.None; switch (parentElement.LocalName) { case "Component": string componentId = contextValues[0]; // 64-bit components may cause issues downlevel. bool win64 = false; Boolean.TryParse(contextValues[2], out win64); switch (element.LocalName) { case "Provides": if (win64) { this.Core.OnMessage(DependencyWarnings.Win64Component(sourceLineNumbers, componentId)); } keyPathType = this.ParseProvidesElement(element, PackageType.None, ref keyPath, componentId); break; default: this.Core.UnexpectedElement(parentElement, element); break; } break; default: this.Core.UnexpectedElement(parentElement, element); break; } return(keyPathType); }
/// <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 CompilerExtension.ComponentKeypathType ParseProvidesElement(XmlNode node, PackageType packageType, ref string keyPath, string parentId) { SourceLineNumberCollection sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); CompilerExtension.ComponentKeypathType keyPathType = CompilerExtension.ComponentKeypathType.None; string id = null; string key = null; string version = null; string displayName = null; int attributes = 0; int illegalChar = -1; 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 "Key": key = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; case "Version": version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib, true); break; case "DisplayName": displayName = this.Core.GetAttributeValue(sourceLineNumbers, attrib); break; default: this.Core.UnexpectedAttribute(sourceLineNumbers, attrib); break; } } else { this.Core.UnsupportedExtensionAttribute(sourceLineNumbers, 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.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.LocalName, "Key")); } else if (PackageType.None == packageType) { // Make sure the ProductCode is authored and set the key. this.Core.CreateWixSimpleReferenceRow(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.LocalName, "Version")); } // Need the element ID for child element processing, so generate now if not authored. if (String.IsNullOrEmpty(id)) { id = this.Core.GenerateIdentifier("dep", node.LocalName, parentId, key); } foreach (XmlNode child in node.ChildNodes) { if (XmlNodeType.Element == child.NodeType) { if (child.NamespaceURI == this.schema.TargetNamespace) { switch (child.LocalName) { case "Requires": this.ParseRequiresElement(child, id, PackageType.None == packageType); break; case "RequiresRef": this.ParseRequiresRefElement(child, id, PackageType.None == packageType); break; default: this.Core.UnexpectedElement(node, child); break; } } else { this.Core.UnsupportedExtensionElement(node, child); } } } if (!this.Core.EncounteredError) { // Create the row in the provider table. Row row = this.Core.CreateRow(sourceLineNumbers, "WixDependencyProvider"); row[0] = 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.CreateWixSimpleReferenceRow(sourceLineNumbers, "CustomAction", "WixDependencyCheck_ARM"); } else { // All other supported platforms use x86. this.Core.CreateWixSimpleReferenceRow(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"); row[0] = this.Core.GenerateIdentifier("reg", id, "(Default)"); row[1] = -1; row[2] = keyProvides; row[3] = null; row[4] = "[ProductCode]"; row[5] = parentId; // Use the Version registry value as the key path if not already set. string idVersion = this.Core.GenerateIdentifier("reg", id, "Version"); if (String.IsNullOrEmpty(keyPath)) { keyPath = idVersion; keyPathType = CompilerExtension.ComponentKeypathType.Registry; } row = this.Core.CreateRow(sourceLineNumbers, "Registry"); row[0] = 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"); row[0] = this.Core.GenerateIdentifier("reg", 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"); row[0] = this.Core.GenerateIdentifier("reg", id, "Attributes"); row[1] = -1; row[2] = keyProvides; row[3] = "Attributes"; row[4] = String.Concat("#", attributes.ToString(CultureInfo.InvariantCulture.NumberFormat)); row[5] = parentId; } } } return(keyPathType); }