/// <summary> /// Recursively loops through a directory, changing an attribute on all of the underlying files. /// An example is to add/remove the ReadOnly flag from each file. /// </summary> /// <param name="path">The directory path to start deleting from.</param> /// <param name="fileAttribute">The FileAttribute to change on each file.</param> /// <param name="messageHandler">The message handler.</param> /// <param name="markAttribute">If true, add the attribute to each file. If false, remove it.</param> private static void RecursiveFileAttributes(string path, FileAttributes fileAttribute, bool markAttribute, IMessageHandler messageHandler) { foreach (string subDirectory in Directory.GetDirectories(path)) { RecursiveFileAttributes(subDirectory, fileAttribute, markAttribute, messageHandler); } foreach (string filePath in Directory.GetFiles(path)) { FileAttributes attributes = File.GetAttributes(filePath); if (markAttribute) { attributes = attributes | fileAttribute; // add to list of attributes } else if (fileAttribute == (attributes & fileAttribute)) // if attribute set { attributes = attributes ^ fileAttribute; // remove from list of attributes } try { File.SetAttributes(filePath, attributes); } catch (UnauthorizedAccessException) { messageHandler.OnMessage(WixWarnings.AccessDeniedForSettingAttributes(null, filePath)); } } }
/// <summary> /// Decompile the FileShare table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileFileShareTable(Table table) { foreach (Row row in table.Rows) { Util.FileShare fileShare = new Util.FileShare(); fileShare.Id = (string)row[0]; fileShare.Name = (string)row[1]; if (null != row[3]) { fileShare.Description = (string)row[3]; } // the Directory_ column is set by the parent Component // the User_ and Permissions columns are deprecated Wix.Component component = (Wix.Component) this.Core.GetIndexedElement("Component", (string)row[2]); if (null != component) { component.AddChild(fileShare); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component")); } this.Core.IndexElement(row, fileShare); } }
/// <summary> /// Decompile the AddinRegistration table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileAddinRegistrationTable(Table table) { foreach (Row row in table.Rows) { var file = (WixSerialize.File)Core.GetIndexedElement("File", (string)row[1]); var item = new AddinRegistration { ProgId = row[0].ToString(), FriendlyName = row[2].ToString(), Description = row[3].ToString(), VisioEditionAttribute = int.Parse(row[4].ToString()), CommandLineSafe = int.Parse(row[5].ToString()), LoadBehavior = int.Parse(row[6].ToString()), Type = int.Parse(row[7].ToString()) }; if (null != file) { file.AddChild(item); } else { Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "File_", (string)row[1], "File")); } } }
/// <summary> /// Decompile the WixHttpUrlAce table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileWixHttpUrlAceTable(Table table) { foreach (Row row in table.Rows) { Http.UrlAce urlace = new Http.UrlAce(); urlace.Id = (string)row[0]; urlace.SecurityPrincipal = (string)row[2]; switch (Convert.ToInt32(row[3])) { case HttpConstants.GENERIC_ALL: default: urlace.Rights = Http.UrlAce.RightsType.all; break; case HttpConstants.GENERIC_EXECUTE: urlace.Rights = Http.UrlAce.RightsType.register; break; case HttpConstants.GENERIC_WRITE: urlace.Rights = Http.UrlAce.RightsType.@delegate; break; } string reservationId = (string)row[1]; Http.UrlReservation urlReservation = (Http.UrlReservation) this.Core.GetIndexedElement("WixHttpUrlReservation", reservationId); if (null != urlReservation) { urlReservation.AddChild(urlace); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, urlace.Id, "WixHttpUrlReservation_", reservationId, "WixHttpUrlReservation")); } } }
/// <summary> /// Decompile the HelpNamespace table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileHelpNamespaceTable(Table table) { foreach (Row row in table.Rows) { VS.HelpCollection helpCollection = new VS.HelpCollection(); helpCollection.Id = (string)row[0]; helpCollection.Name = (string)row[1]; if (null != row[3]) { helpCollection.Description = (string)row[3]; } if (this.Core.RootElement is Wix.Module) { helpCollection.SuppressCustomActions = VS.YesNoType.yes; } Wix.File file = (Wix.File) this.Core.GetIndexedElement("File", (string)row[2]); if (null != file) { file.AddChild(helpCollection); } else if (0 != String.Compare(helpCollection.Id, "MS_VSIPCC_v80", StringComparison.Ordinal) && 0 != String.Compare(helpCollection.Id, "MS.VSIPCC.v90", StringComparison.Ordinal)) { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "File_Collection", (string)row[2], "File")); } this.Core.IndexElement(row, helpCollection); } }
/// <summary> /// Decompile the HelpPlugin table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileHelpPluginTable(Table table) { foreach (Row row in table.Rows) { VS.PlugCollectionInto plugCollectionInto = new VS.PlugCollectionInto(); plugCollectionInto.TargetCollection = (string)row[1]; if (null != row[2]) { plugCollectionInto.TableOfContents = (string)row[2]; } if (null != row[3]) { plugCollectionInto.Attributes = (string)row[3]; } if (null != row[4]) { plugCollectionInto.TargetTableOfContents = (string)row[4]; } VS.HelpCollection helpCollection = (VS.HelpCollection) this.Core.GetIndexedElement("HelpNamespace", (string)row[0]); if (null != helpCollection) { helpCollection.AddChild(plugCollectionInto); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "HelpNamespace_", (string)row[0], "HelpNamespace")); } } }
internal static string GetAttributeIdentifierValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, Action <MessageEventArgs> messageHandler) { string value = Common.GetAttributeValue(sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly, messageHandler); if (Common.IsIdentifier(value)) { if (72 < value.Length && null != messageHandler) { messageHandler(WixWarnings.IdentifierTooLong(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value)); } return(value); } else { if (value.StartsWith("[", StringComparison.Ordinal) && value.EndsWith("]", StringComparison.Ordinal) && null != messageHandler) { messageHandler(WixErrors.IllegalIdentifierLooksLikeFormatted(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value)); } else if (null != messageHandler) { messageHandler(WixErrors.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value)); } return(String.Empty); } }
/// <summary> /// Decompile the MessageQueueGroupPermission table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileMessageQueueGroupPermissionTable(Table table) { foreach (Row row in table.Rows) { Msmq.MessageQueuePermission queuePermission = new Msmq.MessageQueuePermission(); queuePermission.Id = (string)row[0]; if (null != row[2]) { queuePermission.MessageQueue = (string)row[2]; } queuePermission.Group = (string)row[3]; DecompileMessageQueuePermissionAttributes(row, queuePermission); Wix.Component component = (Wix.Component) this.Core.GetIndexedElement("Component", (string)row[1]); if (null != component) { component.AddChild(queuePermission); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); } } }
private void ResolveBundleInstallScope(WixBundleRow bundleInfo, IEnumerable <PackageFacade> facades) { foreach (PackageFacade facade in facades) { if (bundleInfo.PerMachine && YesNoDefaultType.No == facade.Package.PerMachine) { Messaging.Instance.OnMessage(WixVerboses.SwitchingToPerUserPackage(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId)); bundleInfo.PerMachine = false; break; } } foreach (PackageFacade facade in facades) { // Update package scope from bundle scope if default. if (YesNoDefaultType.Default == facade.Package.PerMachine) { facade.Package.PerMachine = bundleInfo.PerMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No; } // We will only register packages in the same scope as the bundle. Warn if any packages with providers // are in a different scope and not permanent (permanents typically don't need a ref-count). if (!bundleInfo.PerMachine && YesNoDefaultType.Yes == facade.Package.PerMachine && !facade.Package.Permanent && 0 < facade.Provides.Count) { Messaging.Instance.OnMessage(WixWarnings.NoPerMachineDependencies(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId)); } } }
/// <summary> /// Generates a valid identifier as needed /// </summary> /// <param name="identifier">Identifier to verify.</param> /// <param name="table">table from which identifier came from.</param> /// <returns>Valid identifier</returns> public string GetValidIdentifier(string identifier, string table) { string generatedName = identifier; if (!DecompilerCore.LegalIdentifierFirstCharacter.IsMatch(generatedName)) { generatedName = String.Concat("_", generatedName); } if (72 < generatedName.Length) { generatedName = generatedName.Substring(0, 72); } if (!DecompilerCore.LegalIdentifierCharacters.IsMatch(generatedName)) { char[] badName = generatedName.ToCharArray(); foreach (char test in badName) { if (!DecompilerCore.LegalIdentifierNonFirstCharacter.IsMatch(test.ToString())) { generatedName = generatedName.Replace(test.ToString(), "_"); } } } if (generatedName != identifier) { this.OnMessage(WixWarnings.GeneratingIdentifier(null, WarningLevel.Major, identifier, table, generatedName)); } return(generatedName); }
/// <summary> /// Main running method for the application. /// </summary> /// <param name="args">Commandline arguments to the application.</param> /// <returns>Returns the application error code.</returns> private int Run(string[] args) { try { // parse the command line this.ParseCommandLine(args); // exit if there was an error parsing the command line (otherwise the logo appears after error messages) if (Messaging.Instance.EncounteredError) { return(Messaging.Instance.LastErrorNumber); } if (!(String.IsNullOrEmpty(this.inputFile) ^ String.IsNullOrEmpty(this.outputFile))) { this.showHelp = true; } if (this.showLogo) { AppCommon.DisplayToolHeader(); } if (this.showHelp) { Console.WriteLine(RetinaStrings.HelpMessage); AppCommon.DisplayToolFooter(); return(Messaging.Instance.LastErrorNumber); } foreach (string parameter in this.invalidArgs) { Messaging.Instance.OnMessage(WixWarnings.UnsupportedCommandLineArgument(parameter)); } this.invalidArgs = null; if (!String.IsNullOrEmpty(this.inputFile)) { this.ExtractBinaryWixlibFiles(); } else { this.RebuildWixlib(); } } catch (WixException we) { Messaging.Instance.OnMessage(we.Error); } catch (Exception e) { Messaging.Instance.OnMessage(WixErrors.UnexpectedException(e.Message, e.GetType().ToString(), e.StackTrace)); if (e is NullReferenceException || e is SEHException) { throw; } } return(Messaging.Instance.LastErrorNumber); }
/// <summary> /// Finalize the Perfmon table. /// </summary> /// <param name="tables">The collection of all tables.</param> /// <remarks> /// Since the PerfCounter element nests under a File element, but /// the Perfmon table does not have a foreign key relationship with /// the File table (instead it has a formatted string that usually /// refers to a file row - but doesn't have to), the nesting must /// be inferred during finalization. /// </remarks> private void FinalizePerfmonTable(TableCollection tables) { Table perfmonTable = tables["Perfmon"]; if (null != perfmonTable) { foreach (Row row in perfmonTable.Rows) { string formattedFile = (string)row[1]; Util.PerfCounter perfCounter = (Util.PerfCounter) this.Core.GetIndexedElement(row); // try to "de-format" the File column's value to determine the proper parent File element if ((formattedFile.StartsWith("[#") || formattedFile.StartsWith("[!")) && formattedFile.EndsWith("]")) { string fileId = formattedFile.Substring(2, formattedFile.Length - 3); Wix.File file = (Wix.File) this.Core.GetIndexedElement("File", fileId); if (null != file) { file.AddChild(perfCounter); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, perfmonTable.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "File", formattedFile, "File")); } } else { // TODO: warn about this being undecompilable because its not well-formed } } } }
private void WriteBurnManifestContainerAttributes(XmlTextWriter writer, string executableName, WixBundleContainerRow container) { writer.WriteAttributeString("Id", container.Id); writer.WriteAttributeString("FileSize", container.Size.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Hash", container.Hash); if (ContainerType.Detached == container.Type) { string resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id, container.Name); if (!String.IsNullOrEmpty(resolvedUrl)) { writer.WriteAttributeString("DownloadUrl", resolvedUrl); } else if (!String.IsNullOrEmpty(container.DownloadUrl)) { writer.WriteAttributeString("DownloadUrl", container.DownloadUrl); } writer.WriteAttributeString("FilePath", container.Name); } else if (ContainerType.Attached == container.Type) { if (!String.IsNullOrEmpty(container.DownloadUrl)) { Messaging.Instance.OnMessage(WixWarnings.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id)); } writer.WriteAttributeString("FilePath", executableName); // attached containers use the name of the bundle since they are attached to the executable. writer.WriteAttributeString("AttachedIndex", container.AttachedContainerIndex.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Attached", "yes"); writer.WriteAttributeString("Primary", "yes"); } }
/// <summary> /// Decompile the HelpNamespace table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileHelpNamespaceTable(Table table) { foreach (Row row in table.Rows) { VS.HelpCollection helpCollection = new VS.HelpCollection(); helpCollection.Id = (string)row[0]; helpCollection.Name = (string)row[1]; if (null != row[3]) { helpCollection.Description = (string)row[3]; } Wix.File file = (Wix.File) this.Core.GetIndexedElement("File", (string)row[2]); if (null != file) { file.AddChild(helpCollection); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "File_Collection", (string)row[2], "File")); } this.Core.IndexElement(row, helpCollection); } }
/// <summary> /// Set an MsiAssemblyName row. If it was directly authored, override the value, otherwise /// create a new row. /// </summary> /// <param name="assemblyNameTable">MsiAssemblyName table.</param> /// <param name="file">FileFacade containing the assembly read for the MsiAssemblyName row.</param> /// <param name="name">MsiAssemblyName name.</param> /// <param name="value">MsiAssemblyName value.</param> private void SetMsiAssemblyName(Table assemblyNameTable, FileFacade file, string name, string value) { // check for null value (this can occur when grabbing the file version from an assembly without one) if (String.IsNullOrEmpty(value)) { Messaging.Instance.OnMessage(WixWarnings.NullMsiAssemblyNameValue(file.File.SourceLineNumbers, file.File.Component, name)); } else { Row assemblyNameRow = null; // override directly authored value foreach (Row row in assemblyNameTable.Rows) { if ((string)row[0] == file.File.Component && (string)row[1] == name) { assemblyNameRow = row; break; } } // if the assembly will be GAC'd and the name in the file table doesn't match the name in the MsiAssemblyName table, error because the install will fail. if ("name" == name && FileAssemblyType.DotNetAssembly == file.WixFile.AssemblyType && String.IsNullOrEmpty(file.WixFile.AssemblyApplication) && !String.Equals(Path.GetFileNameWithoutExtension(file.File.LongFileName), value, StringComparison.OrdinalIgnoreCase)) { Messaging.Instance.OnMessage(WixErrors.GACAssemblyIdentityWarning(file.File.SourceLineNumbers, Path.GetFileNameWithoutExtension(file.File.LongFileName), value)); } if (null == assemblyNameRow) { assemblyNameRow = assemblyNameTable.CreateRow(file.File.SourceLineNumbers); assemblyNameRow[0] = file.File.Component; assemblyNameRow[1] = name; assemblyNameRow[2] = value; // put the MsiAssemblyName row in the same section as the related File row assemblyNameRow.SectionId = file.File.SectionId; if (null == file.AssemblyNames) { file.AssemblyNames = new List <Row>(); } file.AssemblyNames.Add(assemblyNameRow); } else { assemblyNameRow[2] = value; } if (this.VariableCache != null) { string key = String.Format(CultureInfo.InvariantCulture, "assembly{0}.{1}", name, BindDatabaseCommand.Demodularize(this.Output.Type, this.ModularizationGuid, file.File.File)).ToLowerInvariant(); this.VariableCache[key] = (string)assemblyNameRow[2]; } } }
/// <summary> /// Logs a message from the <see cref="Validator"/>. /// </summary> /// <param name="message">A <see cref="String"/> of tab-delmited tokens /// in the validation message.</param> /// <param name="action">The name of the action to which the message /// belongs.</param> /// <exception cref="ArgumentNullException">The message cannot be null. /// </exception> /// <exception cref="WixException">The message does not contain four (4) /// or more tab-delimited tokens.</exception> /// <remarks> /// <para><paramref name="message"/> a tab-delimited set of tokens, /// formatted according to Windows Installer guidelines for ICE /// message. The following table lists what each token by index /// should mean.</para> /// <para><paramref name="action"/> a name that represents the ICE /// action that was executed (e.g. 'ICE08').</para> /// <list type="table"> /// <listheader> /// <term>Index</term> /// <description>Description</description> /// </listheader> /// <item> /// <term>0</term> /// <description>Name of the ICE.</description> /// </item> /// <item> /// <term>1</term> /// <description>Message type. See the following list.</description> /// </item> /// <item> /// <term>2</term> /// <description>Detailed description.</description> /// </item> /// <item> /// <term>3</term> /// <description>Help URL or location.</description> /// </item> /// <item> /// <term>4</term> /// <description>Table name.</description> /// </item> /// <item> /// <term>5</term> /// <description>Column name.</description> /// </item> /// <item> /// <term>6</term> /// <description>This and remaining fields are primary keys /// to identify a row.</description> /// </item> /// </list> /// <para>The message types are one of the following value.</para> /// <list type="table"> /// <listheader> /// <term>Value</term> /// <description>Message Type</description> /// </listheader> /// <item> /// <term>0</term> /// <description>Failure message reporting the failure of the /// ICE custom action.</description> /// </item> /// <item> /// <term>1</term> /// <description>Error message reporting database authoring that /// case incorrect behavior.</description> /// </item> /// <item> /// <term>2</term> /// <description>Warning message reporting database authoring that /// causes incorrect behavior in certain cases. Warnings can also /// report unexpected side-effects of database authoring. /// </description> /// </item> /// <item> /// <term>3</term> /// <description>Informational message.</description> /// </item> /// </list> /// </remarks> public virtual void Log(string message, string action) { if (message == null) { throw new ArgumentNullException("message"); } string[] messageParts = message.Split('\t'); if (3 > messageParts.Length) { if (null == action) { throw new WixException(WixErrors.UnexpectedExternalUIMessage(message)); } else { throw new WixException(WixErrors.UnexpectedExternalUIMessage(message, action)); } } SourceLineNumberCollection messageSourceLineNumbers = null; if (6 < messageParts.Length) { string[] primaryKeys = new string[messageParts.Length - 6]; Array.Copy(messageParts, 6, primaryKeys, 0, primaryKeys.Length); messageSourceLineNumbers = this.GetSourceLineNumbers(messageParts[4], primaryKeys); } else // use the file name as the source line information { messageSourceLineNumbers = this.sourceLineNumbers; } switch (messageParts[1]) { case "0": case "1": this.OnMessage(WixErrors.ValidationError(messageSourceLineNumbers, messageParts[0], messageParts[2])); break; case "2": this.OnMessage(WixWarnings.ValidationWarning(messageSourceLineNumbers, messageParts[0], messageParts[2])); break; case "3": this.OnMessage(WixVerboses.ValidationInfo(messageParts[0], messageParts[2])); break; default: throw new WixException(WixErrors.InvalidValidatorMessageType(messageParts[1])); } }
/// <summary> /// Finds the entry section and loads the symbols from an array of intermediates. /// </summary> /// <param name="allowIdenticalRows">Flag specifying whether identical rows are allowed or not.</param> /// <param name="messageHandler">Message handler object to route all errors through.</param> /// <param name="entrySection">Located entry section.</param> /// <param name="allSymbols">Collection of symbols loaded.</param> internal void FindEntrySectionAndLoadSymbols( bool allowIdenticalRows, IMessageHandler messageHandler, out Section entrySection, out SymbolCollection allSymbols) { entrySection = null; allSymbols = new SymbolCollection(); foreach (Section section in this.collection) { if (SectionType.Product == section.Type || SectionType.Module == section.Type || SectionType.PatchCreation == section.Type || SectionType.Patch == section.Type) { if (null == entrySection) { entrySection = section; } else { messageHandler.OnMessage(WixErrors.MultipleEntrySections(entrySection.SourceLineNumbers, entrySection.Id, section.Id)); messageHandler.OnMessage(WixErrors.MultipleEntrySections2(section.SourceLineNumbers)); } } foreach (Symbol symbol in section.GetSymbols(messageHandler)) { try { Symbol existingSymbol = allSymbols[symbol.Name]; if (null == existingSymbol) { allSymbols.Add(symbol); } else if (allowIdenticalRows && existingSymbol.Row.IsIdentical(symbol.Row)) { messageHandler.OnMessage(WixWarnings.IdenticalRowWarning(symbol.Row.SourceLineNumbers, existingSymbol.Name)); messageHandler.OnMessage(WixWarnings.IdenticalRowWarning2(existingSymbol.Row.SourceLineNumbers)); } else { allSymbols.AddDuplicate(symbol); } } catch (DuplicateSymbolsException) { // if there is already a duplicate symbol, just // another to the list, don't bother trying to // see if there are any identical symbols allSymbols.AddDuplicate(symbol); } } } }
/// <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> /// Gets the source line information (if available) for a row by its table name and primary key. /// </summary> /// <param name="tableName">The table name of the row.</param> /// <param name="primaryKeys">The primary keys of the row.</param> /// <returns>The source line number information if found; null otherwise.</returns> protected SourceLineNumberCollection GetSourceLineNumbers(string tableName, string[] primaryKeys) { // source line information only exists if an output file was supplied if (null != this.output) { // index the source line information if it hasn't been indexed already if (null == this.indexedSourceLineNumbers) { this.indexedSourceLineNumbers = new Hashtable(); // index each real table foreach (Table table in this.output.Tables) { // skip unreal tables if (table.Definition.IsUnreal) { continue; } // index each row foreach (Row row in table.Rows) { // skip rows that don't contain source line information if (null == row.SourceLineNumbers) { continue; } // index the row using its table name and primary key string primaryKey = row.GetPrimaryKey(';'); if (null != primaryKey) { string key = String.Concat(table.Name, ":", primaryKey); if (this.indexedSourceLineNumbers.ContainsKey(key)) { this.OnMessage(WixWarnings.DuplicatePrimaryKey(row.SourceLineNumbers, primaryKey, table.Name)); } else { this.indexedSourceLineNumbers.Add(key, row.SourceLineNumbers); } } } } } return((SourceLineNumberCollection)this.indexedSourceLineNumbers[String.Concat(tableName, ":", String.Join(";", primaryKeys))]); } // use the file name as the source line information return(this.sourceLineNumbers); }
/// <summary> /// Mutate a file. /// </summary> /// <param name="parentElement">The parent of the element to mutate.</param> /// <param name="file">The file to mutate.</param> protected void MutateFile(Wix.IParentElement parentElement, Wix.File file) { if (null == file.Source) { return; } string fileExtension = Path.GetExtension(file.Source); string fileSource = this.Core.ResolveFilePath(file.Source); if (String.Equals(".dll", fileExtension, StringComparison.OrdinalIgnoreCase) || String.Equals(".ocx", fileExtension, StringComparison.OrdinalIgnoreCase)) // ActiveX { mutateDllComServer(parentElement, fileSource); } else if (String.Equals(".exe", fileExtension, StringComparison.OrdinalIgnoreCase)) { mutateExeComServer(parentElement, fileSource); } else if (string.Equals(".plb", fileExtension, StringComparison.OrdinalIgnoreCase) || string.Equals(".tlb", fileExtension, StringComparison.OrdinalIgnoreCase)) { // try the type library harvester try { ATLTypeLibraryHarvester atlTypeLibHarvester = new ATLTypeLibraryHarvester(); this.Core.OnMessage(UtilVerboses.HarvestingTypeLib(fileSource)); Wix.RegistryValue[] registryValues = atlTypeLibHarvester.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> /// Decompile the HelpFile table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileHelpFileTable(Table table) { foreach (Row row in table.Rows) { VS.HelpFile helpFile = new VS.HelpFile(); helpFile.Id = (string)row[0]; helpFile.Name = (string)row[1]; if (null != row[2]) { helpFile.Language = (int)row[2]; } if (null != row[4]) { helpFile.Index = (string)row[4]; } if (null != row[5]) { helpFile.Search = (string)row[5]; } if (null != row[6]) { helpFile.AttributeIndex = (string)row[6]; } if (null != row[7]) { helpFile.SampleLocation = (string)row[7]; } if (this.Core.RootElement is Wix.Module) { helpFile.SuppressCustomActions = VS.YesNoType.yes; } Wix.File file = (Wix.File) this.Core.GetIndexedElement("File", (string)row[3]); if (null != file) { file.AddChild(helpFile); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "File_HxS", (string)row[3], "File")); } } }
/// <summary> /// Does any housekeeping after Bind. /// </summary> /// <param name="tidy">Whether or not any actual tidying should be done.</param> public void Cleanup(bool tidy) { if (tidy) { if (!this.DeleteTempFiles()) { this.core.OnMessage(WixWarnings.FailedToDeleteTempDir(this.TempFilesLocation)); } } else { this.core.OnMessage(WixVerboses.BinderTempDirLocatedAt(this.TempFilesLocation)); } }
/// <summary> /// Generates a valid short filename as needed. /// </summary> /// <param name="originalName">The original file name.</param> /// <param name="table">table from which identifier came from.</param> /// <param name="id">Identifier for the file.</param> /// <param name="columnName">Column name of the file.</param> /// <returns>Valid identifier.</returns> public string GetValidShortName(string originalName, string table, string id, string columnName) { string generatedName = originalName; if (0 < generatedName.Length && !DecompilerCore.LegalShortFilename.IsMatch(generatedName)) { generatedName = Guid.NewGuid().ToString(); generatedName = generatedName.Replace("-", "_"); string generatedExt = generatedName.Substring(10, 3); generatedName = String.Concat(generatedName.Substring(0, 8), ".", generatedExt); this.OnMessage(WixWarnings.GeneratingShortName(null, WarningLevel.Major, originalName, generatedName, table, id, columnName)); } return(generatedName); }
/// <summary> /// Creates a cabinet using the wixcab.dll interop layer. /// </summary> /// <param name="cabinetWorkItem">CabinetWorkItem containing information about the cabinet to create.</param> private void CreateCabinet(CabinetWorkItem cabinetWorkItem) { Messaging.Instance.OnMessage(WixVerboses.CreateCabinet(cabinetWorkItem.CabinetFile)); int maxCabinetSize = 0; // The value of 0 corresponds to default of 2GB which means no cabinet splitting ulong maxPreCompressedSizeInBytes = 0; if (MaximumCabinetSizeForLargeFileSplitting != 0) { // User Specified Max Cab Size for File Splitting, So Check if this cabinet has a single file larger than MaximumUncompressedFileSize // If a file is larger than MaximumUncompressedFileSize, then the cabinet containing it will have only this file if (cabinetWorkItem.FileRows.Count == 1) { // Cabinet has Single File, Check if this is Large File than needs Splitting into Multiple cabs // Get the Value for Max Uncompressed Media Size maxPreCompressedSizeInBytes = (ulong)MaximumUncompressedMediaSize * 1024 * 1024; foreach (FileRow fileRow in cabinetWorkItem.FileRows) // No other easy way than looping to get the only row { if ((ulong)fileRow.FileSize >= maxPreCompressedSizeInBytes) { // If file is larger than MaximumUncompressedFileSize set Maximum Cabinet Size for Cabinet Splitting maxCabinetSize = MaximumCabinetSizeForLargeFileSplitting; } } } } // create the cabinet file string cabinetFileName = Path.GetFileName(cabinetWorkItem.CabinetFile); string cabinetDirectory = Path.GetDirectoryName(cabinetWorkItem.CabinetFile); using (WixCreateCab cab = new WixCreateCab(cabinetFileName, cabinetDirectory, cabinetWorkItem.FileRows.Count, maxCabinetSize, cabinetWorkItem.MaxThreshold, cabinetWorkItem.CompressionLevel)) { foreach (FileRow fileRow in cabinetWorkItem.FileRows) { bool retainRangeWarning = false; // TODO: bring this line back when we find a better way to get the binder file manager here. // cabinetWorkItem.BinderFileManager.ResolvePatch(fileRow, out retainRangeWarning); if (retainRangeWarning) { // TODO: get patch family to add to warning message for PatchWiz parity. Messaging.Instance.OnMessage(WixWarnings.RetainRangeMismatch(fileRow.SourceLineNumbers, fileRow.File)); } cab.AddFile(fileRow); } cab.Complete(newCabNamesCallBackAddress); } }
/// <summary> /// Add a row to the <paramref name="index"/> using the primary key. /// </summary> /// <param name="index">The indexed rows.</param> /// <param name="row">The row to index.</param> private void AddIndexedRow(IDictionary index, Row row) { string primaryKey = row.GetPrimaryKey('/'); if (null != primaryKey) { // Overriding WixActionRows have a primary key defined and take precedence in the index. if (row is WixActionRow) { WixActionRow currentRow = (WixActionRow)row; if (index.Contains(primaryKey)) { // If the current row is not overridable, see if the indexed row is. if (!currentRow.Overridable) { WixActionRow indexedRow = index[primaryKey] as WixActionRow; if (null != indexedRow && indexedRow.Overridable) { // The indexed key is overridable and should be replaced // (not removed and re-added which results in two Array.Copy // operations for SortedList, or may be re-hashing in other // implementations of IDictionary). index[primaryKey] = currentRow; } } // If we got this far, the row does not need to be indexed. return; } } // Nothing else should be added more than once. if (!index.Contains(primaryKey)) { index.Add(primaryKey, row); } else if (this.showPedanticMessages) { this.OnMessage(WixWarnings.DuplicatePrimaryKey(row.SourceLineNumbers, primaryKey, row.Table.Name)); } } else // use the string representation of the row as its primary key (it may not be unique) { // this is provided for compatibility with unreal tables with no primary key // all real tables must specify at least one column as the primary key primaryKey = row.ToString(); index[primaryKey] = row; } }
public void Execute() { var optimizePatchSizeForLargeFiles = this.WixPatchId?.OptimizePatchSizeForLargeFiles ?? false; var apiPatchingSymbolFlags = (PatchSymbolFlags)(this.WixPatchId?.ApiPatchingSymbolFlags ?? 0); #if TODO_PATCHING_DELTA foreach (FileFacade facade in this.FileFacades) { if (RowOperation.Modify == facade.File.Operation && 0 != (facade.WixFile.PatchAttributes & PatchAttributeType.IncludeWholeFile)) { string deltaBase = String.Concat("delta_", facade.File.File); string deltaFile = Path.Combine(this.IntermediateFolder, String.Concat(deltaBase, ".dpf")); string headerFile = Path.Combine(this.IntermediateFolder, String.Concat(deltaBase, ".phd")); bool retainRangeWarning = false; if (PatchAPI.PatchInterop.CreateDelta( deltaFile, facade.WixFile.Source, facade.DeltaPatchFile.Symbols, facade.DeltaPatchFile.RetainOffsets, new[] { facade.WixFile.PreviousSource }, facade.DeltaPatchFile.PreviousSymbols.Split(new[] { ';' }), facade.DeltaPatchFile.PreviousIgnoreLengths.Split(new[] { ';' }), facade.DeltaPatchFile.PreviousIgnoreOffsets.Split(new[] { ';' }), facade.DeltaPatchFile.PreviousRetainLengths.Split(new[] { ';' }), facade.DeltaPatchFile.PreviousRetainOffsets.Split(new[] { ';' }), apiPatchingSymbolFlags, optimizePatchSizeForLargeFiles, out retainRangeWarning)) { PatchAPI.PatchInterop.ExtractDeltaHeader(deltaFile, headerFile); facade.WixFile.Source = deltaFile; facade.WixFile.DeltaPatchHeaderSource = headerFile; } if (retainRangeWarning) { // TODO: get patch family to add to warning message for PatchWiz parity. Messaging.Instance.OnMessage(WixWarnings.RetainRangeMismatch(facade.File.SourceLineNumbers, facade.File.File)); } } } #endif throw new NotImplementedException(); }
/// <summary> /// Decompile the MsiDriverPackages table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileMsiDriverPackagesTable(Table table) { foreach (Row row in table.Rows) { DifxApp.Driver driver = new DifxApp.Driver(); int attributes = (int)row[1]; if (0x1 == (attributes & 0x1)) { driver.ForceInstall = DifxApp.YesNoType.yes; } if (0x2 == (attributes & 0x2)) { driver.PlugAndPlayPrompt = DifxApp.YesNoType.no; } if (0x4 == (attributes & 0x4)) { driver.AddRemovePrograms = DifxApp.YesNoType.no; } if (0x8 == (attributes & 0x8)) { driver.Legacy = DifxApp.YesNoType.yes; } if (0x10 == (attributes & 0x10)) { driver.DeleteFiles = DifxApp.YesNoType.yes; } if (null != row[2]) { driver.Sequence = (int)row[2]; } Wix.Component component = (Wix.Component) this.Core.GetIndexedElement("Component", (string)row[0]); if (null != component) { component.AddChild(driver); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component", (string)row[0], "Component")); } } }
/// <summary> /// Rebuild the Wixlib using the original Wixlib and updated files. /// </summary> private void RebuildWixlib() { Librarian librarian = new Librarian(); WixVariableResolver wixVariableResolver = new WixVariableResolver(); BlastBinderFileManager binderFileManager = new BlastBinderFileManager(this.outputFile); if (0 == Retina.GetCabinetFileIdToFileNameMap(this.outputFile).Count) { this.messageHandler.Display(this, WixWarnings.NotABinaryWixlib(this.outputFile)); return; } Library library = Library.Load(this.outputFile, librarian.TableDefinitions, false, false); library.Save(this.outputFile, binderFileManager, wixVariableResolver); }
/// <summary> /// Decompiles the WixDependencyProvider table. /// </summary> /// <param name="table">The table to decompile.</param> private void DecompileWixDependencyProviderTable(Table table) { foreach (Row row in table.Rows) { Provides provides = new Provides(); provides.Id = (string)row[0]; provides.Key = (string)row[2]; if (null != row[3]) { provides.Version = (string)row[3]; } if (null != row[4]) { provides.DisplayName = (string)row[4]; } // Nothing to parse for attributes currently. Wix.Component component = (Wix.Component) this.Core.GetIndexedElement("Component", (string)row[1]); if (null != component) { component.AddChild(provides); } else { this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", (string)row[1], "Component")); } // Index the provider to parent the RequiresRef elements. this.Core.IndexElement(row, provides); // Add the provider-specific registry keys to be removed during finalization. // Only remove specific keys that the compiler writes. string keyProvides = String.Concat(DependencyCommon.RegistryRoot, provides.Key); this.registryValues.Add(keyProvides, null); this.registryValues.Add(keyProvides, "Version"); this.registryValues.Add(keyProvides, "DisplayName"); this.registryValues.Add(keyProvides, "Attributes"); // Cache the provider key. this.keyCache[provides.Id] = provides.Key; } }
/// <summary> /// Rebuild the Wixlib using the original Wixlib and updated files. /// </summary> private void RebuildWixlib() { if (0 == Retina.GetCabinetFileIdToFileNameMap(this.outputFile).Count) { Messaging.Instance.OnMessage(WixWarnings.NotABinaryWixlib(this.outputFile)); return; } Librarian librarian = new Librarian(); Library library = Library.Load(this.outputFile, librarian.TableDefinitions, false, false); LibraryBinaryFileResolver resolver = new LibraryBinaryFileResolver() { FileManager = new BlastBinderFileManager(this.outputFile) }; library.Save(this.outputFile, resolver); }