/// <summary> /// Mutate a WiX document. /// </summary> /// <param name="wix">The Wix document element.</param> public override void Mutate(Wix.Wix wix) { this.components.Clear(); this.directoryPaths.Clear(); this.webAddresses.Clear(); this.webDirs.Clear(); this.webDirProperties.Clear(); this.webFilters.Clear(); this.webSites.Clear(); this.webVirtualDirs.Clear(); this.rootElement = null; this.IndexElement(wix); this.MutateWebAddresses(); this.MutateWebDirs(); this.MutateWebDirProperties(); this.MutateWebSites(); this.MutateWebVirtualDirs(); // this must come after the web virtual dirs in case they harvest a directory containing a web filter file this.MutateWebFilters(); // this must come after the web site identifiers are created this.MutateComponents(); }
/// <summary> /// Mutate a WiX document. /// </summary> /// <param name="wix">The Wix document element.</param> public override void Mutate(Wix.Wix wix) { this.directoryPaths.Clear(); this.filePaths.Clear(); this.webFilters.Clear(); this.webSites.Clear(); this.webVirtualDirs.Clear(); this.IndexElement(wix); this.MutateWebFilters(); this.MutateWebSites(); this.MutateWebVirtualDirs(); }
/// <summary> /// Index an element. /// </summary> /// <param name="element">The element to index.</param> private void IndexElement(Wix.ISchemaElement element) { if (element is IIs.WebFilter) { this.webFilters.Add(element); } else if (element is IIs.WebSite) { this.webSites.Add(element); } else if (element is IIs.WebVirtualDir) { this.webVirtualDirs.Add(element); } else if (element is Wix.Directory) { Wix.Directory directory = (Wix.Directory)element; if (null != directory.Id && null != directory.FileSource) { this.directoryPaths.Add(directory.FileSource, directory.Id); } } else if (element is Wix.File) { Wix.File file = (Wix.File)element; if (null != file.Id && null != file.Source) { this.filePaths[file.Source] = String.Concat("[#", file.Id, "]"); } } // index the child elements if (element is Wix.IParentElement) { foreach (Wix.ISchemaElement childElement in ((Wix.IParentElement)element).Children) { this.IndexElement(childElement); } } }
/// <summary> /// Mutate a WiX document. /// </summary> /// <param name="wix">The Wix document element.</param> /// <returns>true if mutation was successful</returns> public bool Mutate(Wix.Wix wix) { bool encounteredError = false; try { foreach (MutatorExtension mutatorExtension in this.extensions.Values) { if (null == mutatorExtension.Core) { mutatorExtension.Core = this.core; } mutatorExtension.Mutate(wix); } } finally { encounteredError = this.core.EncounteredError; } // return the Wix document element only if mutation completed successfully return !encounteredError; }
/// <summary> /// Get the path to a file in the source image. /// </summary> /// <param name="file">The file.</param> /// <returns>The path to the file in the source image.</returns> private string GetSourcePath(Wix.File file) { StringBuilder sourcePath = new StringBuilder(); Wix.Component component = (Wix.Component)file.ParentElement; for (Wix.Directory directory = (Wix.Directory)component.ParentElement; null != directory; directory = directory.ParentElement as Wix.Directory) { string name; if (!this.shortNames && null != directory.SourceName) { name = directory.SourceName; } else if (null != directory.ShortSourceName) { name = directory.ShortSourceName; } else if (!this.shortNames || null == directory.ShortName) { name = directory.Name; } else { name = directory.ShortName; } if (0 == sourcePath.Length) { sourcePath.Append(name); } else { sourcePath.Insert(0, Path.DirectorySeparatorChar); sourcePath.Insert(0, name); } } return sourcePath.ToString(); }
/// <summary> /// Mutate a WiX document. /// </summary> /// <param name="wix">The Wix document element.</param> public override void Mutate(Wix.Wix wix) { this.components.Clear(); this.directories.Clear(); this.directoryPaths.Clear(); this.filePaths.Clear(); this.files.Clear(); this.registryValues.Clear(); // index elements in this wix document this.IndexElement(wix); this.MutateDirectories(); this.MutateFiles(); this.MutateRegistryValues(); // must occur after all the registry values have been formatted this.MutateComponents(); }
/// <summary> /// Index an element. /// </summary> /// <param name="element">The element to index.</param> private void IndexElement(Wix.ISchemaElement element) { if (element is Wix.Component) { // Component elements only need to be indexed if COM registry values will be strongly typed if (!this.suppressCOMElements) { this.components.Add(element); } } else if (element is Wix.Directory) { this.directories.Add(element); } else if (element is Wix.File) { this.files.Add(element); } else if (element is Wix.RegistryValue) { this.registryValues.Add(element); } // index the child elements if (element is Wix.IParentElement) { foreach (Wix.ISchemaElement childElement in ((Wix.IParentElement)element).Children) { this.IndexElement(childElement); } } }
/// <summary> /// Index an element. /// </summary> /// <param name="element">The element to index.</param> private void IndexElement(Wix.ISchemaElement element) { if (element is Wix.Component) { this.components.Add(element); } else if (element is Wix.ComponentGroup) { this.componentGroups.Add(element); } else if (element is Wix.Directory) { this.directories.Add(element); } else if (element is Wix.DirectoryRef) { this.directoryRefs.Add(element); } else if (element is Wix.Feature) { this.features.Add(element); } else if (element is Wix.File) { this.files.Add(element); } else if (element is Wix.Module || element is Wix.PatchCreation || element is Wix.Product) { Debug.Assert(null == this.rootElement); this.rootElement = (Wix.IParentElement)element; } // index the child elements if (element is Wix.IParentElement) { foreach (Wix.ISchemaElement childElement in ((Wix.IParentElement)element).Children) { this.IndexElement(childElement); } } }
/// <summary> /// Mutate an element. /// </summary> /// <param name="parentElement">The parent of the element to mutate.</param> /// <param name="element">The element to mutate.</param> private void MutateElement(Wix.IParentElement parentElement, Wix.ISchemaElement element) { if (element is Wix.File) { this.MutateFile(parentElement, (Wix.File)element); } // mutate the child elements if (element is Wix.IParentElement) { ArrayList childElements = new ArrayList(); // copy the child elements to a temporary array (to allow them to be deleted/moved) foreach (Wix.ISchemaElement childElement in ((Wix.IParentElement)element).Children) { childElements.Add(childElement); } foreach (Wix.ISchemaElement childElement in childElements) { this.MutateElement((Wix.IParentElement)element, childElement); } } }
/// <summary> /// Applies the condition and sequence to a standard action element based on the action row data. /// </summary> /// <param name="actionRow">Action row data from the database.</param> /// <param name="actionElement">Element to be sequenced.</param> private void SequenceStandardAction(WixActionRow actionRow, Wix.ActionSequenceType actionElement) { if (null != actionRow.Condition) { actionElement.Content = actionRow.Condition; } if ((null != actionRow.Before || null != actionRow.After) && 0 == actionRow.Sequence) { this.core.OnMessage(WixWarnings.DecompiledStandardActionRelativelyScheduledInModule(actionRow.SourceLineNumbers, actionRow.SequenceTable.ToString(), actionRow.Action)); } else if (0 < actionRow.Sequence) { actionElement.Sequence = actionRow.Sequence; } }
/// <summary> /// Gets the RegistryRootType from an integer representation of the root. /// </summary> /// <param name="sourceLineNumbers">The source line information for the root.</param> /// <param name="tableName">The name of the table containing the field.</param> /// <param name="field">The field containing the root value.</param> /// <param name="registryRootType">The strongly-typed representation of the root.</param> /// <returns>true if the value could be converted; false otherwise.</returns> private bool GetRegistryRootType(SourceLineNumberCollection sourceLineNumbers, string tableName, Field field, out Wix.RegistryRootType registryRootType) { switch (Convert.ToInt32(field.Data)) { case (-1): registryRootType = Wix.RegistryRootType.HKMU; return true; case MsiInterop.MsidbRegistryRootClassesRoot: registryRootType = Wix.RegistryRootType.HKCR; return true; case MsiInterop.MsidbRegistryRootCurrentUser: registryRootType = Wix.RegistryRootType.HKCU; return true; case MsiInterop.MsidbRegistryRootLocalMachine: registryRootType = Wix.RegistryRootType.HKLM; return true; case MsiInterop.MsidbRegistryRootUsers: registryRootType = Wix.RegistryRootType.HKU; return true; default: this.core.OnMessage(WixWarnings.IllegalColumnValue(sourceLineNumbers, tableName, field.Column.Name, field.Data)); registryRootType = Wix.RegistryRootType.HKCR; // assign anything to satisfy the out parameter return false; } }
/// <summary> /// Adds a ComponentRef to the main ComponentGroup. /// </summary> /// <param name="component">The component to add.</param> private void AddComponentRef(Wix.Component component) { Wix.ComponentRef componentRef = new Wix.ComponentRef(); componentRef.Id = component.Id; this.componentGroup.AddChild(componentRef); }
/// <summary> /// Converts a Module to a ComponentGroup and adds all of its relevant elements to the main fragment. /// </summary> /// <param name="wix">The output object representing an unbound merge module.</param> private void ConvertModule(Wix.Wix wix) { Wix.Product product = Melter.GetProduct(wix); List<string> customActionsRemoved = new List<string>(); Dictionary<Wix.Custom, Wix.InstallExecuteSequence> customsToRemove = new Dictionary<Wix.Custom, Wix.InstallExecuteSequence>(); foreach (Wix.ISchemaElement child in product.Children) { Wix.Directory childDir = child as Wix.Directory; if (null != childDir) { bool isTargetDir = this.WalkDirectory(childDir); if (isTargetDir) { continue; } } else { Wix.Dependency childDep = child as Wix.Dependency; if (null != childDep) { this.AddPropertyRef(childDep.RequiredId); continue; } else if (child is Wix.Package) { continue; } else if (child is Wix.CustomAction) { Wix.CustomAction customAction = child as Wix.CustomAction; string directoryId; if (StartsWithStandardDirectoryId(customAction.Id, out directoryId) && customAction.Property == customAction.Id) { customActionsRemoved.Add(customAction.Id); continue; } } else if (child is Wix.InstallExecuteSequence) { Wix.InstallExecuteSequence installExecuteSequence = child as Wix.InstallExecuteSequence; foreach (Wix.ISchemaElement sequenceChild in installExecuteSequence.Children) { Wix.Custom custom = sequenceChild as Wix.Custom; string directoryId; if (custom != null && StartsWithStandardDirectoryId(custom.Action, out directoryId)) { customsToRemove.Add(custom, installExecuteSequence); } } } } this.fragment.AddChild(child); } // For any customaction that we removed, also remove the scheduling of that action. foreach (Wix.Custom custom in customsToRemove.Keys) { if (customActionsRemoved.Contains(custom.Action)) { ((Wix.InstallExecuteSequence)customsToRemove[custom]).RemoveChild(custom); } } AddProperty(this.moduleId, this.id); wix.RemoveChild(product); wix.AddChild(this.fragment); this.fragment.AddChild(this.componentGroup); this.fragment.AddChild(this.primaryDirectoryRef); }
/// <summary> /// Index an element. /// </summary> /// <param name="element">The element to index.</param> private void IndexElement(Wix.ISchemaElement element) { if (element is IIs.WebAddress) { this.webAddresses.Add(element); } else if (element is IIs.WebDir) { this.webDirs.Add(element); } else if (element is IIs.WebDirProperties) { this.webDirProperties.Add(element); } else if (element is IIs.WebFilter) { this.webFilters.Add(element); } else if (element is IIs.WebSite) { this.webSites.Add(element); } else if (element is IIs.WebVirtualDir) { this.webVirtualDirs.Add(element); } else if (element is Wix.Component) { this.components.Add(element); } else if (element is Wix.Directory) { Wix.Directory directory = (Wix.Directory)element; if (null != directory.FileSource) { this.directoryPaths.Add(directory.FileSource, directory); } } else if (element is Wix.Fragment || element is Wix.Module || element is Wix.PatchCreation || element is Wix.Product) { this.rootElement = (Wix.IParentElement)element; } // index the child elements if (element is Wix.IParentElement) { foreach (Wix.ISchemaElement childElement in ((Wix.IParentElement)element).Children) { this.IndexElement(childElement); } } }
/// <summary> /// Gets the module from the Wix object. /// </summary> /// <param name="wix">The Wix object.</param> /// <returns>The Module in the Wix object, null if no Module was found</returns> private static Wix.Product GetProduct(Wix.Wix wix) { foreach (Wix.ISchemaElement element in wix.Children) { Wix.Product productElement = element as Wix.Product; if (null != productElement) { return productElement; } } return null; }
/// <summary> /// Returns a ComponentRef for each Component in the Directory tree. /// </summary> /// <param name="directory">The root Directory of the components.</param> /// <returns>Returns all of the Components in a directory.</returns> private Wix.ComponentRef[] GetComponentRefs(Wix.Directory directory) { ArrayList componentRefs = new ArrayList(); foreach (Wix.ISchemaElement element in directory.Children) { if (element is Wix.Component) { Wix.Component component = (Wix.Component)element; Wix.ComponentRef componentRef = new Wix.ComponentRef(); componentRef.Id = component.Id; componentRefs.Add(componentRef); } else if (element is Wix.Directory) { componentRefs.AddRange(this.GetComponentRefs((Wix.Directory)element)); } } return (Wix.ComponentRef[])componentRefs.ToArray(typeof(Wix.ComponentRef)); }
/// <summary> /// Harvest a directory. /// </summary> /// <param name="path">The path of the directory.</param> /// <param name="relativePath">The relative path that will be used when harvesting.</param> /// <param name="directory">The directory for this path.</param> /// <returns>The number of files harvested.</returns> private int HarvestDirectory(string path, string relativePath, Wix.Directory directory) { int fileCount = 0; // harvest the child directories foreach (string childDirectoryPath in Directory.GetDirectories(path)) { Wix.Directory childDirectory = new Wix.Directory(); childDirectory.Name = Path.GetFileName(childDirectoryPath); childDirectory.FileSource = childDirectoryPath; if (this.setUniqueIdentifiers) { childDirectory.Id = this.Core.GenerateIdentifier(DirectoryPrefix, directory.Id, childDirectory.Name); } int childFileCount = this.HarvestDirectory(childDirectoryPath, String.Concat(relativePath, childDirectory.Name, "\\"), childDirectory); // keep the directory if it contained any files (or empty directories are being kept) if (0 < childFileCount || this.keepEmptyDirectories) { directory.AddChild(childDirectory); } fileCount += childFileCount; } // harvest the files string[] files = Directory.GetFiles(path); if (0 < files.Length) { foreach (string filePath in Directory.GetFiles(path)) { string fileName = Path.GetFileName(filePath); Wix.Component component = new Wix.Component(); Wix.File file = this.fileHarvester.HarvestFile(filePath); file.Source = String.Concat(relativePath, fileName); if (this.setUniqueIdentifiers) { file.Id = this.Core.GenerateIdentifier(FilePrefix, directory.Id, fileName); component.Id = this.Core.GenerateIdentifier(ComponentPrefix, directory.Id, file.Id); } component.AddChild(file); directory.AddChild(component); } } else if (0 == fileCount && this.keepEmptyDirectories) { Wix.Component component = new Wix.Component(); component.KeyPath = Wix.YesNoType.yes; if (this.setUniqueIdentifiers) { component.Id = this.Core.GenerateIdentifier(ComponentPrefix, directory.Id); } Wix.CreateFolder createFolder = new Wix.CreateFolder(); component.AddChild(createFolder); directory.AddChild(component); } return fileCount + files.Length; }
/// <summary> /// Mutate a Wix element. /// </summary> /// <param name="wix">The Wix element to mutate.</param> private void MutateWix(Wix.Wix wix) { if (TemplateType.Fragment != this.templateType) { if (null != this.rootElement || 0 != this.features.Count) { throw new Exception("The template option cannot be used with Feature, Product, or Module elements present."); } // create a package element although it won't always be used Wix.Package package = new Wix.Package(); if (TemplateType.Module == this.templateType) { package.Id = this.GetGuid(); } else { package.Compressed = Wix.YesNoType.yes; } package.InstallerVersion = 200; Wix.Directory targetDir = new Wix.Directory(); targetDir.Id = "TARGETDIR"; targetDir.Name = "SourceDir"; foreach (Wix.DirectoryRef directoryRef in this.directoryRefs) { if (String.Equals(directoryRef.Id, "TARGETDIR", StringComparison.OrdinalIgnoreCase)) { Wix.IParentElement parent = directoryRef.ParentElement as Wix.IParentElement; foreach (Wix.ISchemaElement element in directoryRef.Children) { targetDir.AddChild(element); } parent.RemoveChild(directoryRef); if (null != ((Wix.ISchemaElement)parent).ParentElement) { int i = 0; foreach (Wix.ISchemaElement element in parent.Children) { i++; } if (0 == i) { Wix.IParentElement supParent = (Wix.IParentElement)((Wix.ISchemaElement)parent).ParentElement; supParent.RemoveChild((Wix.ISchemaElement)parent); } } break; } } if (TemplateType.Module == this.templateType) { Wix.Module module = new Wix.Module(); module.Id = "PUT-MODULE-NAME-HERE"; module.Language = "1033"; module.Version = "1.0.0.0"; package.Manufacturer = "PUT-COMPANY-NAME-HERE"; module.AddChild(package); module.AddChild(targetDir); wix.AddChild(module); this.rootElement = module; } else // product { Wix.Product product = new Wix.Product(); product.Id = this.GetGuid(); product.Language = "1033"; product.Manufacturer = "PUT-COMPANY-NAME-HERE"; product.Name = "PUT-PRODUCT-NAME-HERE"; product.UpgradeCode = this.GetGuid(); product.Version = "1.0.0.0"; product.AddChild(package); product.AddChild(targetDir); Wix.Media media = new Wix.Media(); media.Id = "1"; media.Cabinet = "product.cab"; media.EmbedCab = Wix.YesNoType.yes; product.AddChild(media); Wix.Feature feature = new Wix.Feature(); feature.Id = "ProductFeature"; feature.Title = "PUT-FEATURE-TITLE-HERE"; feature.Level = 1; product.AddChild(feature); this.features.Add(feature); wix.AddChild(product); this.rootElement = product; } } }
/// <summary> /// Set the common control attributes in a control element. /// </summary> /// <param name="attributes">The control attributes.</param> /// <param name="control">The control element.</param> private static void SetControlAttributes(int attributes, Wix.Control control) { if (0 == (attributes & MsiInterop.MsidbControlAttributesEnabled)) { control.Disabled = Wix.YesNoType.yes; } if (MsiInterop.MsidbControlAttributesIndirect == (attributes & MsiInterop.MsidbControlAttributesIndirect)) { control.Indirect = Wix.YesNoType.yes; } if (MsiInterop.MsidbControlAttributesInteger == (attributes & MsiInterop.MsidbControlAttributesInteger)) { control.Integer = Wix.YesNoType.yes; } if (MsiInterop.MsidbControlAttributesLeftScroll == (attributes & MsiInterop.MsidbControlAttributesLeftScroll)) { control.LeftScroll = Wix.YesNoType.yes; } if (MsiInterop.MsidbControlAttributesRightAligned == (attributes & MsiInterop.MsidbControlAttributesRightAligned)) { control.RightAligned = Wix.YesNoType.yes; } if (MsiInterop.MsidbControlAttributesRTLRO == (attributes & MsiInterop.MsidbControlAttributesRTLRO)) { control.RightToLeft = Wix.YesNoType.yes; } if (MsiInterop.MsidbControlAttributesSunken == (attributes & MsiInterop.MsidbControlAttributesSunken)) { control.Sunken = Wix.YesNoType.yes; } if (0 == (attributes & MsiInterop.MsidbControlAttributesVisible)) { control.Hidden = Wix.YesNoType.yes; } }
/// <summary> /// Walks a directory structure obtaining Component Id's and Standard Directory Id's. /// </summary> /// <param name="directory">The Directory to walk.</param> /// <returns>true if the directory is TARGETDIR.</returns> private bool WalkDirectory(Wix.Directory directory) { bool isTargetDir = false; if ("TARGETDIR" == directory.Id) { isTargetDir = true; } string standardDirectoryId = null; if (Melter.StartsWithStandardDirectoryId(directory.Id, out standardDirectoryId) && !isTargetDir) { this.AddSetPropertyCustomAction(directory.Id, String.Format(CultureInfo.InvariantCulture, "[{0}]", standardDirectoryId)); } foreach (Wix.ISchemaElement child in directory.Children) { Wix.Directory childDir = child as Wix.Directory; if (null != childDir) { if (isTargetDir) { this.primaryDirectoryRef.AddChild(child); } this.WalkDirectory(childDir); } else { Wix.Component childComponent = child as Wix.Component; if (null != childComponent) { if (isTargetDir) { this.primaryDirectoryRef.AddChild(child); } this.AddComponentRef(childComponent); } } } return isTargetDir; }
/// <summary> /// Insert DigitalCertificate records associated with passed msiPackageCertificate or msiPatchCertificate table. /// </summary> /// <param name="table">The table being decompiled.</param> /// <param name="parent">DigitalCertificate parent</param> private void AddCertificates(Table table, Wix.IParentElement parent) { foreach (Row row in table.Rows) { Wix.DigitalCertificate digitalCertificate = (Wix.DigitalCertificate)this.core.GetIndexedElement("MsiDigitalCertificate", Convert.ToString(row[1])); if (null != digitalCertificate) { parent.AddChild(digitalCertificate); } else { this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "DigitalCertificate_", Convert.ToString(row[1]), "MsiDigitalCertificate")); } } }
/// <summary> /// Mutate a WiX document. /// </summary> /// <param name="wix">The Wix document element.</param> public virtual void Mutate(Wix.Wix wix) { }
/// <summary> /// Applies the condition and relative sequence to an action element based on the action row data. /// </summary> /// <param name="actionRow">Action row data from the database.</param> /// <param name="actionElement">Element to be sequenced.</param> private static void SequenceRelativeAction(WixActionRow actionRow, Wix.ActionModuleSequenceType actionElement) { if (null != actionRow.Condition) { actionElement.Content = actionRow.Condition; } if (null != actionRow.Before) { actionElement.Before = actionRow.Before; } else if (null != actionRow.After) { actionElement.After = actionRow.After; } else if (0 < actionRow.Sequence) { actionElement.Sequence = actionRow.Sequence; } }
/// <summary> /// Mutate a WiX document. /// </summary> /// <param name="wix">The Wix document element.</param> public override void Mutate(Wix.Wix wix) { this.components.Clear(); this.directories.Clear(); this.directoryRefs.Clear(); this.features.Clear(); this.files.Clear(); this.fragments.Clear(); this.rootElement = null; // index elements in this wix document this.IndexElement(wix); this.MutateWix(wix); this.MutateFiles(); this.MutateDirectories(); this.MutateComponents(); if (null != this.componentGroupName) { this.CreateComponentGroup(wix); } // add the components to the product feature after all the identifiers have been set if (TemplateType.Product == this.templateType) { Wix.Feature feature = (Wix.Feature)this.features[0]; foreach (Wix.ComponentGroup group in this.componentGroups) { Wix.ComponentGroupRef componentGroupRef = new Wix.ComponentGroupRef(); componentGroupRef.Id = group.Id; feature.AddChild(componentGroupRef); } } else if (TemplateType.Module == this.templateType) { foreach (Wix.ISchemaElement element in wix.Children) { if (element is Wix.Module) { foreach (Wix.ComponentGroup group in this.componentGroups) { Wix.ComponentGroupRef componentGroupRef = new Wix.ComponentGroupRef(); componentGroupRef.Id = group.Id; ((Wix.IParentElement)element).AddChild(componentGroupRef); } break; } } } //if(!this.createFragments && TemplateType.Product foreach (Wix.Fragment fragment in this.fragments.Values) { wix.AddChild(fragment); } }
private void HarvestProjectOutputGroupFile(string baseDir, string projectName, string pogName, string pogFileSource, string filePath, string fileName, string link, Wix.IParentElement parentDir, string parentDirId, Wix.Component component, Wix.File file, Dictionary<string, bool> seenList) { string varFormat = VariableFormat; if (this.generateWixVars) { varFormat = WixVariableFormat; } if (pogName.Equals("Satellites", StringComparison.OrdinalIgnoreCase)) { Wix.Directory locDirectory = new Wix.Directory(); locDirectory.Name = Path.GetFileName(Path.GetDirectoryName(Path.GetFullPath(filePath))); file.Source = String.Concat(String.Format(CultureInfo.InvariantCulture, varFormat, projectName, pogFileSource), "\\", locDirectory.Name, "\\", Path.GetFileName(filePath)); if (!seenList.ContainsKey(file.Source)) { parentDir.AddChild(locDirectory); locDirectory.AddChild(component); component.AddChild(file); seenList.Add(file.Source, true); if (this.setUniqueIdentifiers) { locDirectory.Id = this.Core.GenerateIdentifier(DirectoryPrefix, parentDirId, locDirectory.Name); file.Id = this.Core.GenerateIdentifier(FilePrefix, locDirectory.Id, fileName); component.Id = this.Core.GenerateIdentifier(ComponentPrefix, locDirectory.Id, file.Id); } else { locDirectory.Id = HarvesterCore.GetIdentifierFromName(String.Format(DirectoryIdFormat, (parentDir is Wix.DirectoryRef) ? ((Wix.DirectoryRef)parentDir).Id : parentDirId, locDirectory.Name)); file.Id = HarvesterCore.GetIdentifierFromName(String.Format(CultureInfo.InvariantCulture, VSProjectHarvester.FileIdFormat, projectName, pogName, String.Concat(locDirectory.Name, ".", fileName))); component.Id = HarvesterCore.GetIdentifierFromName(String.Format(CultureInfo.InvariantCulture, VSProjectHarvester.ComponentIdFormat, projectName, pogName, String.Concat(locDirectory.Name, ".", fileName))); } } } else { file.Source = GenerateSourceFilePath(baseDir, projectName, pogFileSource, filePath, link, varFormat); if (!seenList.ContainsKey(file.Source)) { component.AddChild(file); parentDir.AddChild(component); seenList.Add(file.Source, true); if (this.setUniqueIdentifiers) { file.Id = this.Core.GenerateIdentifier(FilePrefix, parentDirId, fileName); component.Id = this.Core.GenerateIdentifier(ComponentPrefix, parentDirId, file.Id); } else { file.Id = HarvesterCore.GetIdentifierFromName(String.Format(CultureInfo.InvariantCulture, VSProjectHarvester.FileIdFormat, projectName, pogName, fileName)); component.Id = HarvesterCore.GetIdentifierFromName(String.Format(CultureInfo.InvariantCulture, VSProjectHarvester.ComponentIdFormat, projectName, pogName, fileName)); } } } }
/// <summary> /// Creates a component group with a given name. /// </summary> /// <param name="wix">The Wix document element.</param> private void CreateComponentGroup(Wix.Wix wix) { Wix.ComponentGroup componentGroup = new Wix.ComponentGroup(); componentGroup.Id = this.componentGroupName; this.componentGroups.Add(componentGroup); Wix.Fragment cgFragment = new Wix.Fragment(); cgFragment.AddChild(componentGroup); wix.AddChild(cgFragment); int componentCount = 0; for (; componentCount < this.components.Count; componentCount++) { Wix.Component c = this.components[componentCount] as Wix.Component; if (this.createFragments) { if (c.ParentElement is Wix.Directory) { Wix.Directory parentDirectory = c.ParentElement as Wix.Directory; componentGroup.AddChild(c); c.Directory = parentDirectory.Id; parentDirectory.RemoveChild(c); } else if (c.ParentElement is Wix.DirectoryRef) { Wix.DirectoryRef parentDirectory = c.ParentElement as Wix.DirectoryRef; componentGroup.AddChild(c); c.Directory = parentDirectory.Id; parentDirectory.RemoveChild(c); // Remove whole fragment if moving the component to the component group just leaves an empty DirectoryRef if (0 < fragments.Count && parentDirectory.ParentElement is Wix.Fragment) { Wix.Fragment parentFragment = parentDirectory.ParentElement as Wix.Fragment; int childCount = 0; foreach (Wix.ISchemaElement element in parentFragment.Children) { childCount++; } // Component should always have an Id but the SortedList creation allows for null and bases the name on the fragment count which we cannot reverse engineer here. if (1 == childCount && !String.IsNullOrEmpty(c.Id)) { int removeIndex = fragments.IndexOfKey(String.Concat("Component:", c.Id)); if (0 <= removeIndex) { fragments.RemoveAt(removeIndex); } } } } } else { Wix.ComponentRef componentRef = new Wix.ComponentRef(); componentRef.Id = c.Id; componentGroup.AddChild(componentRef); } } }
/// <summary> /// Mutate a file. /// </summary> /// <param name="parentElement">The parent of the element to mutate.</param> /// <param name="file">The file to mutate.</param> private void MutateFile(Wix.IParentElement parentElement, Wix.File file) { if (null != file.Source) { string fileExtension = Path.GetExtension(file.Source); string fileSource = this.Core.ResolveFilePath(file.Source); if (String.Equals(".ax", fileExtension, StringComparison.OrdinalIgnoreCase) || // DirectShow filter String.Equals(".dll", fileExtension, StringComparison.OrdinalIgnoreCase) || String.Equals(".exe", fileExtension, StringComparison.OrdinalIgnoreCase) || String.Equals(".ocx", fileExtension, StringComparison.OrdinalIgnoreCase)) // ActiveX { // try the assembly harvester try { AssemblyHarvester assemblyHarvester = new AssemblyHarvester(); this.Core.OnMessage(UtilVerboses.HarvestingAssembly(fileSource)); Wix.RegistryValue[] registryValues = assemblyHarvester.HarvestRegistryValues(fileSource); foreach (Wix.RegistryValue registryValue in registryValues) { parentElement.AddChild(registryValue); } } catch (BadImageFormatException) // not an assembly, try raw DLL. { // try the self-reg harvester try { DllHarvester dllHarvester = new DllHarvester(); this.Core.OnMessage(UtilVerboses.HarvestingSelfReg(fileSource)); Wix.RegistryValue[] registryValues = dllHarvester.HarvestRegistryValues(fileSource); foreach (Wix.RegistryValue registryValue in registryValues) { parentElement.AddChild(registryValue); } } catch (TargetInvocationException tie) { if (tie.InnerException is EntryPointNotFoundException) { // No DllRegisterServer(), which is fine by me. } else { this.Core.OnMessage(UtilWarnings.SelfRegHarvestFailed(fileSource, tie.Message)); } } catch (Exception ex) { this.Core.OnMessage(UtilWarnings.SelfRegHarvestFailed(fileSource, ex.Message)); } } catch (Exception ex) { this.Core.OnMessage(UtilWarnings.AssemblyHarvestFailed(fileSource, ex.Message)); } } else if (String.Equals(".olb", fileExtension, StringComparison.OrdinalIgnoreCase) || // type library String.Equals(".tlb", fileExtension, StringComparison.OrdinalIgnoreCase)) // type library { // try the type library harvester try { TypeLibraryHarvester typeLibHarvester = new TypeLibraryHarvester(); this.Core.OnMessage(UtilVerboses.HarvestingTypeLib(fileSource)); Wix.RegistryValue[] registryValues = typeLibHarvester.HarvestRegistryValues(fileSource); foreach (Wix.RegistryValue registryValue in registryValues) { parentElement.AddChild(registryValue); } } catch (COMException ce) { // 0x8002801C (TYPE_E_REGISTRYACCESS) // If we don't have permission to harvest typelibs, it's likely because we're on // Vista or higher and aren't an Admin, or don't have the appropriate QFE installed. if (!this.calledPerUserTLibReg && (0x8002801c == unchecked((uint)ce.ErrorCode))) { this.Core.OnMessage(WixWarnings.InsufficientPermissionHarvestTypeLib()); } else if (0x80029C4A == unchecked((uint)ce.ErrorCode)) // generic can't load type library { this.Core.OnMessage(UtilWarnings.TypeLibLoadFailed(fileSource, ce.Message)); } } } } }
/// <summary> /// Harvest files from one output group of a VS project. /// </summary> /// <param name="baseDir">The base directory of the files.</param> /// <param name="projectName">Name of the project, to be used as a prefix for generated identifiers.</param> /// <param name="pogName">Name of the project output group, used for generating identifiers for WiX elements.</param> /// <param name="pogFileSource">The ProjectOutputGroup file source.</param> /// <param name="outputGroupFiles">The files from one output group to harvest.</param> /// <param name="parent">The parent element that will contain the components of the harvested files.</param> /// <returns>The number of files harvested.</returns> private int HarvestProjectOutputGroupFiles(string baseDir, string projectName, string pogName, string pogFileSource, IEnumerable outputGroupFiles, Wix.IParentElement parent) { int fileCount = 0; Wix.ISchemaElement exeFile = null; Wix.ISchemaElement appConfigFile = null; // Keep track of files inserted // Files can have different absolute paths but get mapped to the same SourceFile // after the project variables have been used. For example, a WiX project that // is building multiple cultures will have many output MSIs/MSMs, but will all get // mapped to $(var.ProjName.TargetDir)\ProjName.msm. These duplicates would // prevent generated code from compiling. Dictionary<string, bool> seenList = new Dictionary<string,bool>(); foreach (object output in outputGroupFiles) { string filePath = output.ToString(); string fileName = Path.GetFileName(filePath); string fileDir = Path.GetDirectoryName(filePath); string link = null; MethodInfo getMetadataMethod = output.GetType().GetMethod("GetMetadata"); if (getMetadataMethod != null) { link = (string)getMetadataMethod.Invoke(output, new object[] { "Link" }); if (!String.IsNullOrEmpty(link)) { fileDir = Path.GetDirectoryName(Path.Combine(baseDir, link)); } } Wix.IParentElement parentDir = parent; // Ignore Containers and PayloadGroups because they do not have a nested structure. if (baseDir != null && !String.Equals(Path.GetDirectoryName(baseDir), fileDir, StringComparison.OrdinalIgnoreCase) && this.GenerateType != GenerateType.Container && this.GenerateType != GenerateType.PackageGroup && this.GenerateType != GenerateType.PayloadGroup) { Uri baseUri = new Uri(baseDir); Uri relativeUri = baseUri.MakeRelativeUri(new Uri(fileDir)); parentDir = this.GetSubDirElement(parentDir, relativeUri); } string parentDirId = null; if (parentDir is Wix.DirectoryRef) { parentDirId = this.directoryRefSeed; } else if (parentDir is Wix.Directory) { parentDirId = ((Wix.Directory)parentDir).Id; } if (this.GenerateType == GenerateType.Container || this.GenerateType == GenerateType.PayloadGroup) { Wix.Payload payload = new Wix.Payload(); HarvestProjectOutputGroupPayloadFile(baseDir, projectName, pogName, pogFileSource, filePath, fileName, link, parentDir, payload, seenList); } else if (this.GenerateType == GenerateType.PackageGroup) { HarvestProjectOutputGroupPackage(projectName, pogName, pogFileSource, filePath, fileName, link, parentDir, seenList); } else { Wix.Component component = new Wix.Component(); Wix.File file = new Wix.File(); HarvestProjectOutputGroupFile(baseDir, projectName, pogName, pogFileSource, filePath, fileName, link, parentDir, parentDirId, component, file, seenList); if (String.Equals(Path.GetExtension(file.Source), ".exe", StringComparison.OrdinalIgnoreCase)) { exeFile = file; } else if (file.Source.EndsWith("app.config", StringComparison.OrdinalIgnoreCase)) { appConfigFile = file; } } fileCount++; } // Special case for the app.config file in the Binaries POG... // The POG refers to the files in the OBJ directory, while the // generated WiX code references them in the bin directory. // The app.config file gets renamed to match the exe name. if ("Binaries" == pogName && null != exeFile && null != appConfigFile) { if (appConfigFile is Wix.File) { Wix.File appConfigFileAsWixFile = appConfigFile as Wix.File; Wix.File exeFileAsWixFile = exeFile as Wix.File; // Case insensitive replace appConfigFileAsWixFile.Source = Regex.Replace(appConfigFileAsWixFile.Source, @"app\.config", Path.GetFileName(exeFileAsWixFile.Source) + ".config", RegexOptions.IgnoreCase); } } return fileCount; }
/// <summary> /// Add a scraped directory to the UI. /// </summary> /// <param name="nodes">The NodeCollection under which the new directory should be added.</param> /// <param name="rootDirectory">Root of the scraped directory info's.</param> /// <param name="directory">The scraped directory to add.</param> /// <param name="skip">true if the directory itself shouldn't be added; false otherwise.</param> private void AddDirectory(TreeNodeCollection nodes, string currentPath, Wix.Directory rootDirectory, Wix.Directory directory, bool skip) { // get the directory icon, add it to the image list, then free it immediately if (!skip) { Icon folderIcon = NativeMethods.GetDirectoryIcon(true, false); DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(currentPath, directory.Name)); TreeNode node = (TreeNode)this.Invoke(this.addTreeNodeCallback, new object[] { nodes, folderIcon, directory.Name, directoryInfo, false }); folderIcon.Dispose(); // add sub-directories and files to this node nodes = node.Nodes; currentPath = Path.Combine(currentPath, directory.Name); } foreach (Wix.ISchemaElement element in directory.Children) { Wix.Component component = element as Wix.Component; if (null != component) { foreach (Wix.ISchemaElement child in component.Children) { Wix.File file = child as Wix.File; if (null != file) { bool selected = false; FileInfo fileInfo = new FileInfo(Path.Combine(currentPath, file.Name)); // if there is no application entry point and we've found an executable make this the application entry point if (this.packageBuilder.ApplicationEntry == null && String.Compare(fileInfo.Extension, ".exe", true, CultureInfo.InvariantCulture) == 0) { //this.packageBuilder.ApplicationEntry = fileInfo.FullName.Substring(rootDirectory.FullName.Length + 1); selected = true; } // get the file icon, add it to the image list, then free it immediately Icon fileIcon = NativeMethods.GetFileIcon(fileInfo.FullName, true, false); this.Invoke(this.addTreeNodeCallback, new object[] { nodes, fileIcon, file.Name, fileInfo, selected }); fileIcon.Dispose(); } } } else { Wix.Directory subDirectory = element as Wix.Directory; if (null != subDirectory) { this.AddDirectory(nodes, currentPath, rootDirectory, subDirectory, false); } } } }
/// <summary> /// Mutate a WiX document. /// </summary> /// <param name="wix">The Wix document element.</param> public override void Mutate(Wix.Wix wix) { this.MutateElement(null, wix); }