예제 #1
1
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Merges in any modules to the output database.
        /// </summary>
        /// <param name="tempDatabaseFile">The temporary database file.</param>
        /// <param name="output">Output that specifies database and modules to merge.</param>
        /// <param name="fileRows">The indexed file rows.</param>
        /// <param name="suppressedTableNames">The names of tables that are suppressed.</param>
        /// <remarks>Expects that output's database has already been generated.</remarks>
        private void MergeModules(string tempDatabaseFile, Output output, FileRowCollection fileRows, StringCollection suppressedTableNames)
        {
            Debug.Assert(OutputType.Product == output.Type);

            Table wixMergeTable = output.Tables["WixMerge"];
            Table wixFeatureModulesTable = output.Tables["WixFeatureModules"];

            // check for merge rows to see if there is any work to do
            if (null == wixMergeTable || 0 == wixMergeTable.Rows.Count)
            {
                return;
            }

            IMsmMerge2 merge = null;
            bool commit = true;
            bool logOpen = false;
            bool databaseOpen = false;
            string logPath = null;
            try
            {
                merge = NativeMethods.GetMsmMerge();

                logPath = Path.Combine(this.TempFilesLocation, "merge.log");
                merge.OpenLog(logPath);
                logOpen = true;

                merge.OpenDatabase(tempDatabaseFile);
                databaseOpen = true;

                // process all the merge rows
                foreach (WixMergeRow wixMergeRow in wixMergeTable.Rows)
                {
                    bool moduleOpen = false;

                    try
                    {
                        short mergeLanguage;

                        try
                        {
                            mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture);
                        }
                        catch (System.FormatException)
                        {
                            this.core.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language));
                            continue;
                        }

                        this.core.OnMessage(WixVerboses.OpeningMergeModule(wixMergeRow.SourceFile, mergeLanguage));
                        merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
                        moduleOpen = true;

                        // If there is merge configuration data, create a callback object to contain it all.
                        ConfigurationCallback callback = null;
                        if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData))
                        {
                            callback = new ConfigurationCallback(wixMergeRow.ConfigurationData);
                        }

                        // merge the module into the database that's being built
                        this.core.OnMessage(WixVerboses.MergingMergeModule(wixMergeRow.SourceFile));
                        merge.MergeEx(wixMergeRow.Feature, wixMergeRow.Directory, callback);

                        // connect any non-primary features
                        if (null != wixFeatureModulesTable)
                        {
                            foreach (Row row in wixFeatureModulesTable.Rows)
                            {
                                if (wixMergeRow.Id == (string)row[1])
                                {
                                    this.core.OnMessage(WixVerboses.ConnectingMergeModule(wixMergeRow.SourceFile, (string)row[0]));
                                    merge.Connect((string)row[0]);
                                }
                            }
                        }
                    }
                    catch (COMException)
                    {
                        commit = false;
                    }
                    finally
                    {
                        IMsmErrors mergeErrors = merge.Errors;

                        // display all the errors encountered during the merge operations for this module
                        for (int i = 1; i <= mergeErrors.Count; i++)
                        {
                            IMsmError mergeError = mergeErrors[i];
                            StringBuilder databaseKeys = new StringBuilder();
                            StringBuilder moduleKeys = new StringBuilder();

                            // build a string of the database keys
                            for (int j = 1; j <= mergeError.DatabaseKeys.Count; j++)
                            {
                                if (1 != j)
                                {
                                    databaseKeys.Append(';');
                                }
                                databaseKeys.Append(mergeError.DatabaseKeys[j]);
                            }

                            // build a string of the module keys
                            for (int j = 1; j <= mergeError.ModuleKeys.Count; j++)
                            {
                                if (1 != j)
                                {
                                    moduleKeys.Append(';');
                                }
                                moduleKeys.Append(mergeError.ModuleKeys[j]);
                            }

                            // display the merge error based on the msm error type
                            switch (mergeError.Type)
                            {
                                case MsmErrorType.msmErrorExclusion:
                                    this.core.OnMessage(WixErrors.MergeExcludedModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleKeys.ToString()));
                                    break;
                                case MsmErrorType.msmErrorFeatureRequired:
                                    this.core.OnMessage(WixErrors.MergeFeatureRequired(wixMergeRow.SourceLineNumbers, mergeError.ModuleTable, moduleKeys.ToString(), wixMergeRow.SourceFile, wixMergeRow.Id));
                                    break;
                                case MsmErrorType.msmErrorLanguageFailed:
                                    this.core.OnMessage(WixErrors.MergeLanguageFailed(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
                                    break;
                                case MsmErrorType.msmErrorLanguageUnsupported:
                                    this.core.OnMessage(WixErrors.MergeLanguageUnsupported(wixMergeRow.SourceLineNumbers, mergeError.Language, wixMergeRow.SourceFile));
                                    break;
                                case MsmErrorType.msmErrorResequenceMerge:
                                    this.core.OnMessage(WixWarnings.MergeRescheduledAction(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
                                    break;
                                case MsmErrorType.msmErrorTableMerge:
                                    if ("_Validation" != mergeError.DatabaseTable) // ignore merge errors in the _Validation table
                                    {
                                        this.core.OnMessage(WixWarnings.MergeTableFailed(wixMergeRow.SourceLineNumbers, mergeError.DatabaseTable, databaseKeys.ToString(), wixMergeRow.SourceFile));
                                    }
                                    break;
                                case MsmErrorType.msmErrorPlatformMismatch:
                                    this.core.OnMessage(WixErrors.MergePlatformMismatch(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile));
                                    break;
                                default:
                                    this.core.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorWithType, Enum.GetName(typeof(MsmErrorType), mergeError.Type), logPath), "InvalidOperationException", Environment.StackTrace));
                                    break;
                            }
                        }

                        if (0 >= mergeErrors.Count && !commit)
                        {
                            this.core.OnMessage(WixErrors.UnexpectedException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedMergerErrorInSourceFile, wixMergeRow.SourceFile, logPath), "InvalidOperationException", Environment.StackTrace));
                        }

                        if (moduleOpen)
                        {
                            merge.CloseModule();
                        }
                    }
                }
            }
            finally
            {
                if (databaseOpen)
                {
                    merge.CloseDatabase(commit);
                }

                if (logOpen)
                {
                    merge.CloseLog();
                }
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return;
            }

            using (Database db = new Database(tempDatabaseFile, OpenDatabase.Direct))
            {
                Table suppressActionTable = output.Tables["WixSuppressAction"];

                // suppress individual actions
                if (null != suppressActionTable)
                {
                    foreach (Row row in suppressActionTable.Rows)
                    {
                        if (db.TableExists((string)row[0]))
                        {
                            string query = String.Format(CultureInfo.InvariantCulture, "SELECT * FROM {0} WHERE `Action` = '{1}'", row[0].ToString(), (string)row[1]);

                            using (View view = db.OpenExecuteView(query))
                            {
                                using (Record record = view.Fetch())
                                {
                                    if (null != record)
                                    {
                                        this.core.OnMessage(WixWarnings.SuppressMergedAction((string)row[1], row[0].ToString()));
                                        view.Modify(ModifyView.Delete, record);
                                    }
                                }
                            }
                        }
                    }
                }

                // query for merge module actions in suppressed sequences and drop them
                foreach (string tableName in suppressedTableNames)
                {
                    if (!db.TableExists(tableName))
                    {
                        continue;
                    }

                    using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName)))
                    {
                        while (true)
                        {
                            using (Record resultRecord = view.Fetch())
                            {
                                if (null == resultRecord)
                                {
                                    break;
                                }

                                this.core.OnMessage(WixWarnings.SuppressMergedAction(resultRecord.GetString(1), tableName));
                            }
                        }
                    }

                    // drop suppressed sequences
                    using (View view = db.OpenExecuteView(String.Concat("DROP TABLE ", tableName)))
                    {
                    }

                    // delete the validation rows
                    using (View view = db.OpenView(String.Concat("DELETE FROM _Validation WHERE `Table` = ?")))
                    {
                        using (Record record = new Record(1))
                        {
                            record.SetString(1, tableName);
                            view.Execute(record);
                        }
                    }
                }

                // now update the Attributes column for the files from the Merge Modules
                this.core.OnMessage(WixVerboses.ResequencingMergeModuleFiles());
                using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?"))
                {
                    foreach (FileRow fileRow in fileRows)
                    {
                        if (!fileRow.FromModule)
                        {
                            continue;
                        }

                        using (Record record = new Record(1))
                        {
                            record.SetString(1, fileRow.File);
                            view.Execute(record);
                        }

                        using (Record recordUpdate = view.Fetch())
                        {
                            if (null == recordUpdate)
                            {
                                throw new InvalidOperationException("Failed to fetch a File row from the database that was merged in from a module.");
                            }

                            recordUpdate.SetInteger(1, fileRow.Sequence);

                            // update the file attributes to match the compression specified
                            // on the Merge element or on the Package element
                            int attributes = 0;

                            // get the current value if its not null
                            if (!recordUpdate.IsNull(2))
                            {
                                attributes = recordUpdate.GetInteger(2);
                            }

                            if (YesNoType.Yes == fileRow.Compressed)
                            {
                                // these are mutually exclusive
                                attributes |= MsiInterop.MsidbFileAttributesCompressed;
                                attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
                            }
                            else if (YesNoType.No == fileRow.Compressed)
                            {
                                // these are mutually exclusive
                                attributes |= MsiInterop.MsidbFileAttributesNoncompressed;
                                attributes &= ~MsiInterop.MsidbFileAttributesCompressed;
                            }
                            else // not specified
                            {
                                Debug.Assert(YesNoType.NotSet == fileRow.Compressed);

                                // clear any compression bits
                                attributes &= ~MsiInterop.MsidbFileAttributesCompressed;
                                attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
                            }
                            recordUpdate.SetInteger(2, attributes);

                            view.Modify(ModifyView.Update, recordUpdate);
                        }
                    }
                }

                db.Commit();
            }
        }
예제 #2
0
        /// <summary>
        /// Assigns the file rows to media rows based on Media or MediaTemplate authoring. Updates uncompressed files collection.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        public void AssignFiles(FileRowCollection fileRows)
        {
            bool     autoAssign          = false;
            MediaRow mergeModuleMediaRow = null;
            Table    mediaTable          = this.output.Tables["Media"];
            Table    mediaTemplateTable  = this.output.Tables["WixMediaTemplate"];

            // If both tables are authored, it is an error.
            if ((mediaTemplateTable != null && mediaTemplateTable.Rows.Count > 0) && (mediaTable != null && mediaTable.Rows.Count > 1))
            {
                throw new WixException(WixErrors.MediaTableCollision(null));
            }

            autoAssign = mediaTemplateTable != null && OutputType.Module != this.output.Type ? true : false;

            // When building merge module, all the files go to "#MergeModule.CABinet"
            if (OutputType.Module == this.output.Type)
            {
                Table mergeModuleMediaTable = new Table(null, this.core.TableDefinitions["Media"]);
                mergeModuleMediaRow         = (MediaRow)mergeModuleMediaTable.CreateRow(null);
                mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet";

                this.cabinets.Add(mergeModuleMediaRow, new FileRowCollection());
            }

            if (autoAssign)
            {
                this.AutoAssignFiles(mediaTable, fileRows);
            }
            else
            {
                this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, fileRows);
            }
        }
예제 #3
0
 /// <summary>
 /// Instantiate a new CabinetWorkItem.
 /// </summary>
 /// <param name="fileRows">The collection of files in this cabinet.</param>
 /// <param name="cabinetFile">The cabinet file.</param>
 /// <param name="maxThreshold">Maximum threshold for each cabinet.</param>
 /// <param name="compressionLevel">The compression level of the cabinet.</param>
 /// <param name="binderFileManager">The binder file manager.</param>
 public CabinetWorkItem(FileRowCollection fileRows, string cabinetFile, int maxThreshold, Cab.CompressionLevel compressionLevel, BinderFileManager binderFileManager)
 {
     this.cabinetFile = cabinetFile;
     this.compressionLevel = compressionLevel;
     this.fileRows = fileRows;
     this.binderFileManager = binderFileManager;
     this.maxThreshold = maxThreshold;
 }
예제 #4
0
 /// <summary>
 /// Instantiate a new CabinetWorkItem.
 /// </summary>
 /// <param name="fileRows">The collection of files in this cabinet.</param>
 /// <param name="cabinetFile">The cabinet file.</param>
 /// <param name="maxThreshold">Maximum threshold for each cabinet.</param>
 /// <param name="compressionLevel">The compression level of the cabinet.</param>
 /// <param name="binderFileManager">The binder file manager.</param>
 public CabinetWorkItem(FileRowCollection fileRows, string cabinetFile, int maxThreshold, Cab.CompressionLevel compressionLevel, BinderFileManager binderFileManager)
 {
     this.cabinetFile       = cabinetFile;
     this.compressionLevel  = compressionLevel;
     this.fileRows          = fileRows;
     this.binderFileManager = binderFileManager;
     this.maxThreshold      = maxThreshold;
 }
예제 #5
0
        /// <summary>
        /// Constructor for auto media assigner.
        /// </summary>
        /// <param name="output">Output</param>
        /// <param name="core">Binder core.</param>
        /// <param name="filesCompressed">True if files are compressed by default. </param>
        public AutoMediaAssigner(Output output, BinderCore core, bool filesCompressed)
        {
            this.output              = output;
            this.core                = core;
            this.filesCompressed     = filesCompressed;
            this.cabinetNameTemplate = "Cab{0}.cab";

            uncompressedFileRows = new FileRowCollection();
            mediaRows            = new MediaRowCollection();
            cabinets             = new Hashtable();
        }
        /// <summary>
        /// Constructor for auto media assigner.
        /// </summary>
        /// <param name="output">Output</param>
        /// <param name="core">Binder core.</param>
        /// <param name="filesCompressed">True if files are compressed by default. </param>
        public AutoMediaAssigner(Output output, BinderCore core, bool filesCompressed)
        {
            this.output = output;
            this.core = core;
            this.filesCompressed = filesCompressed;
            this.cabinetNameTemplate = "Cab{0}.cab";

            uncompressedFileRows = new FileRowCollection();
            mediaRows = new MediaRowCollection();
            cabinets = new Hashtable();
        }
예제 #7
0
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Process uncompressed files.
        /// </summary>
        /// <param name="tempDatabaseFile">The temporary database file.</param>
        /// <param name="fileRows">The collection of files to copy into the image.</param>
        /// <param name="fileTransfers">Array of files to be transfered.</param>
        /// <param name="mediaRows">The indexed media rows.</param>
        /// <param name="layoutDirectory">The directory in which the image should be layed out.</param>
        /// <param name="compressed">Flag if source image should be compressed.</param>
        /// <param name="longNamesInImage">Flag if long names should be used.</param>
        private void ProcessUncompressedFiles(string tempDatabaseFile, FileRowCollection fileRows, ArrayList fileTransfers, MediaRowCollection mediaRows, string layoutDirectory, bool compressed, bool longNamesInImage)
        {
            if (0 == fileRows.Count || this.core.EncounteredError)
            {
                return;
            }

            Hashtable directories = new Hashtable();
            using (Database db = new Database(tempDatabaseFile, OpenDatabase.ReadOnly))
            {
                using (View directoryView = db.OpenExecuteView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`"))
                {
                    while (true)
                    {
                        using (Record directoryRecord = directoryView.Fetch())
                        {
                            if (null == directoryRecord)
                            {
                                break;
                            }

                            string sourceName = Installer.GetName(directoryRecord.GetString(3), true, longNamesInImage);

                            directories.Add(directoryRecord.GetString(1), new ResolvedDirectory(directoryRecord.GetString(2), sourceName));
                        }
                    }
                }

                using (View fileView = db.OpenView("SELECT `Directory_`, `FileName` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_` AND `File`.`File`=?"))
                {
                    using (Record fileQueryRecord = new Record(1))
                    {
                        // for each file in the array of uncompressed files
                        foreach (FileRow fileRow in fileRows)
                        {
                            string relativeFileLayoutPath = null;

                            string mediaLayoutDirectory = this.FileManager.ResolveMedia(mediaRows[fileRow.DiskId], layoutDirectory);

                            // setup up the query record and find the appropriate file in the
                            // previously executed file view
                            fileQueryRecord[1] = fileRow.File;
                            fileView.Execute(fileQueryRecord);

                            using (Record fileRecord = fileView.Fetch())
                            {
                                if (null == fileRecord)
                                {
                                    throw new WixException(WixErrors.FileIdentifierNotFound(fileRow.SourceLineNumbers, fileRow.File));
                                }

                                relativeFileLayoutPath = Binder.GetFileSourcePath(directories, fileRecord[1], fileRecord[2], compressed, longNamesInImage);
                            }

                            // finally put together the base media layout path and the relative file layout path
                            string fileLayoutPath = Path.Combine(mediaLayoutDirectory, relativeFileLayoutPath);
                            FileTransfer transfer;
                            if (FileTransfer.TryCreate(fileRow.Source, fileLayoutPath, false, "File", fileRow.SourceLineNumbers, out transfer))
                            {
                                fileTransfers.Add(transfer);
                            }
                        }
                    }
                }
            }
        }
예제 #8
0
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Retrieve files and their information from merge modules.
        /// </summary>
        /// <param name="output">Internal representation of the msi database to operate upon.</param>
        /// <param name="fileRows">The indexed file rows.</param>
        private void ProcessMergeModules(Output output, FileRowCollection fileRows)
        {
            Table wixMergeTable = output.Tables["WixMerge"];
            if (null != wixMergeTable)
            {
                IMsmMerge2 merge = NativeMethods.GetMsmMerge();

                // Get the output's minimum installer version
                int outputInstallerVersion = int.MinValue;
                Table summaryInformationTable = output.Tables["_SummaryInformation"];
                if (null != summaryInformationTable)
                {
                    foreach (Row row in summaryInformationTable.Rows)
                    {
                        if (14 == (int)row[0])
                        {
                            outputInstallerVersion = Convert.ToInt32(row[1], CultureInfo.InvariantCulture);
                            break;
                        }
                    }
                }

                foreach (Row row in wixMergeTable.Rows)
                {
                    bool containsFiles = false;
                    WixMergeRow wixMergeRow = (WixMergeRow)row;

                    try
                    {
                        // read the module's File table to get its FileMediaInformation entries and gather any other information needed from the module.
                        using (Database db = new Database(wixMergeRow.SourceFile, OpenDatabase.ReadOnly))
                        {
                            if (db.TableExists("File") && db.TableExists("Component"))
                            {
                                Hashtable uniqueModuleFileIdentifiers = System.Collections.Specialized.CollectionsUtil.CreateCaseInsensitiveHashtable();

                                using (View view = db.OpenExecuteView("SELECT `File`, `Directory_` FROM `File`, `Component` WHERE `Component_`=`Component`"))
                                {
                                    // add each file row from the merge module into the file row collection (check for errors along the way)
                                    while (true)
                                    {
                                        using (Record record = view.Fetch())
                                        {
                                            if (null == record)
                                            {
                                                break;
                                            }

                                            // NOTE: this is very tricky - the merge module file rows are not added to the
                                            // file table because they should not be created via idt import.  Instead, these
                                            // rows are created by merging in the actual modules
                                            FileRow fileRow = new FileRow(null, this.core.TableDefinitions["File"]);
                                            fileRow.File = record[1];
                                            fileRow.Compressed = wixMergeRow.FileCompression;
                                            fileRow.Directory = record[2];
                                            fileRow.DiskId = wixMergeRow.DiskId;
                                            fileRow.FromModule = true;
                                            fileRow.PatchGroup = -1;
                                            fileRow.Source = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", wixMergeRow.Number.ToString(CultureInfo.InvariantCulture.NumberFormat), Path.DirectorySeparatorChar, record[1]);

                                            FileRow collidingFileRow = fileRows[fileRow.File];
                                            FileRow collidingModuleFileRow = (FileRow)uniqueModuleFileIdentifiers[fileRow.File];

                                            if (null == collidingFileRow && null == collidingModuleFileRow)
                                            {
                                                fileRows.Add(fileRow);

                                                // keep track of file identifiers in this merge module
                                                uniqueModuleFileIdentifiers.Add(fileRow.File, fileRow);
                                            }
                                            else // collision(s) detected
                                            {
                                                // case-sensitive collision with another merge module or a user-authored file identifier
                                                if (null != collidingFileRow)
                                                {
                                                    this.core.OnMessage(WixErrors.DuplicateModuleFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, collidingFileRow.File));
                                                }

                                                // case-insensitive collision with another file identifier in the same merge module
                                                if (null != collidingModuleFileRow)
                                                {
                                                    this.core.OnMessage(WixErrors.DuplicateModuleCaseInsensitiveFileIdentifier(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, fileRow.File, collidingModuleFileRow.File));
                                                }
                                            }

                                            containsFiles = true;
                                        }
                                    }
                                }
                            }

                            // Get the summary information to detect the Schema
                            using (SummaryInformation summaryInformation = new SummaryInformation(db))
                            {
                                string moduleInstallerVersionString = summaryInformation.GetProperty(14);

                                try
                                {
                                    int moduleInstallerVersion = Convert.ToInt32(moduleInstallerVersionString, CultureInfo.InvariantCulture);
                                    if (moduleInstallerVersion > outputInstallerVersion)
                                    {
                                        this.core.OnMessage(WixWarnings.InvalidHigherInstallerVersionInModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, moduleInstallerVersion, outputInstallerVersion));
                                    }
                                }
                                catch (FormatException)
                                {
                                    throw new WixException(WixErrors.MissingOrInvalidModuleInstallerVersion(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile, moduleInstallerVersionString));
                                }
                            }
                        }
                    }
                    catch (FileNotFoundException)
                    {
                        throw new WixException(WixErrors.FileNotFound(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile));
                    }
                    catch (Win32Exception)
                    {
                        throw new WixException(WixErrors.CannotOpenMergeModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.SourceFile));
                    }

                    // if the module has files and creating layout
                    if (containsFiles && !this.suppressLayout)
                    {
                        bool moduleOpen = false;
                        short mergeLanguage;

                        try
                        {
                            mergeLanguage = Convert.ToInt16(wixMergeRow.Language, CultureInfo.InvariantCulture);
                        }
                        catch (System.FormatException)
                        {
                            this.core.OnMessage(WixErrors.InvalidMergeLanguage(wixMergeRow.SourceLineNumbers, wixMergeRow.Id, wixMergeRow.Language));
                            continue;
                        }

                        try
                        {
                            merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage);
                            moduleOpen = true;

                            string safeMergeId = wixMergeRow.Number.ToString(CultureInfo.InvariantCulture.NumberFormat);

                            // extract the module cabinet, then explode all of the files to a temp directory
                            string moduleCabPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, safeMergeId, ".module.cab");
                            merge.ExtractCAB(moduleCabPath);

                            string mergeIdPath = String.Concat(this.TempFilesLocation, Path.DirectorySeparatorChar, "MergeId.", safeMergeId);
                            Directory.CreateDirectory(mergeIdPath);

                            using (WixExtractCab extractCab = new WixExtractCab())
                            {
                                try
                                {
                                    extractCab.Extract(moduleCabPath, mergeIdPath);
                                }
                                catch (FileNotFoundException)
                                {
                                    throw new WixException(WixErrors.CabFileDoesNotExist(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath));
                                }
                                catch
                                {
                                    throw new WixException(WixErrors.CabExtractionFailed(moduleCabPath, wixMergeRow.SourceFile, mergeIdPath));
                                }
                            }
                        }
                        catch (COMException ce)
                        {
                            throw new WixException(WixErrors.UnableToOpenModule(wixMergeRow.SourceLineNumbers, wixMergeRow.SourceFile, ce.Message));
                        }
                        finally
                        {
                            if (moduleOpen)
                            {
                                merge.CloseModule();
                            }
                        }
                    }
                }
            }
        }
예제 #9
0
 /// <summary>
 /// Instantiate a new CabinetWorkItem.
 /// </summary>
 /// <param name="fileRows">The collection of files in this cabinet.</param>
 /// <param name="cabinetFile">The cabinet file.</param>
 /// <param name="compressionLevel">The compression level of the cabinet.</param>
 public CabinetWorkItem(FileRowCollection fileRows, string cabinetFile, Cab.CompressionLevel compressionLevel)
 {
     this.cabinetFile      = cabinetFile;
     this.compressionLevel = compressionLevel;
     this.fileRows         = fileRows;
 }
예제 #10
0
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Writes the paths to the content files included in the package to a text file.
        /// </summary>
        /// <param name="path">Path to write file.</param>
        /// <param name="fileRows">Collection of file rows whose source will be written to file.</param>
        private void CreateContentsFile(string path, FileRowCollection fileRows)
        {
            string directory = Path.GetDirectoryName(path);
            if (!Directory.Exists(directory))
            {
                Directory.CreateDirectory(directory);
            }

            using (StreamWriter contents = new StreamWriter(path, false))
            {
                foreach (FileRow fileRow in fileRows)
                {
                    contents.WriteLine(fileRow.Source);
                }
            }
        }
예제 #11
0
        /// <summary>
        /// Assign files to cabinets based on Media authoring.
        /// </summary>
        /// <param name="mediaTable"></param>
        /// <param name="mergeModuleMediaRow"></param>
        /// <param name="fileRows"></param>
        private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, FileRowCollection fileRows)
        {
            if (OutputType.Module != this.output.Type)
            {
                if (null != mediaTable)
                {
                    Dictionary<string, MediaRow> cabinetMediaRows = new Dictionary<string, MediaRow>(StringComparer.InvariantCultureIgnoreCase);
                    foreach (MediaRow mediaRow in mediaTable.Rows)
                    {
                        // If the Media row has a cabinet, make sure it is unique across all Media rows.
                        if (!String.IsNullOrEmpty(mediaRow.Cabinet))
                        {
                            MediaRow existingRow;
                            if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow))
                            {
                                this.core.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet));
                                this.core.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet));
                            }
                            else
                            {
                                cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow);
                            }
                        }

                        this.mediaRows.Add(mediaRow);
                    }
                }

                foreach (MediaRow mediaRow in this.mediaRows)
                {
                    if (null != mediaRow.Cabinet)
                    {
                        this.cabinets.Add(mediaRow, new FileRowCollection());
                    }
                }
            }

            foreach (FileRow fileRow in fileRows)
            {
                if (OutputType.Module == output.Type)
                {
                    ((FileRowCollection)this.cabinets[mergeModuleMediaRow]).Add(fileRow);
                }
                else
                {
                    MediaRow mediaRow = this.mediaRows[fileRow.DiskId];

                    // When building a product, if the current file is not to be compressed or if 
                    // the package set not to be compressed, don't cab it.
                    if (OutputType.Product == output.Type &&
                        (YesNoType.No == fileRow.Compressed ||
                        (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed)))
                    {
                        uncompressedFileRows.Add(fileRow);
                    }
                    else // file in a Module or marked compressed
                    {
                        FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[mediaRow];

                        if (null != cabinetFileRow)
                        {
                            cabinetFileRow.Add(fileRow);
                        }
                        else
                        {
                            this.core.OnMessage(WixErrors.ExpectedMediaCabinet(fileRow.SourceLineNumbers, fileRow.File, fileRow.DiskId));
                        }
                    }
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Assign files to cabinets based on MediaTemplate authoring.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        private void AutoAssignFiles(Table mediaTable, FileRowCollection fileRows)
        {
            const int MaxCabIndex = 999;

            ulong currentPreCabSize = 0;
            ulong maxPreCabSizeInBytes;
            int   maxPreCabSizeInMB = 0;
            int   currentCabIndex   = 0;

            MediaRow currentMediaRow = null;

            Table mediaTemplateTable = this.output.Tables["WixMediaTemplate"];

            // Auto assign files to cabinets based on maximum uncompressed media size
            mediaTable.Rows.Clear();
            WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0];

            if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate))
            {
                this.cabinetNameTemplate = mediaTemplateRow.CabinetTemplate;
            }

            string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS");

            try
            {
                // Override authored mums value if environment variable is authored.
                if (!String.IsNullOrEmpty(mumsString))
                {
                    maxPreCabSizeInMB = Int32.Parse(mumsString);
                }
                else
                {
                    maxPreCabSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize;
                }

                maxPreCabSizeInBytes = (ulong)maxPreCabSizeInMB * 1024 * 1024;
            }
            catch (FormatException)
            {
                throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString));
            }
            catch (OverflowException)
            {
                throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB));
            }

            foreach (FileRow fileRow in fileRows)
            {
                // When building a product, if the current file is not to be compressed or if
                // the package set not to be compressed, don't cab it.
                if (OutputType.Product == output.Type &&
                    (YesNoType.No == fileRow.Compressed ||
                     (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed)))
                {
                    uncompressedFileRows.Add(fileRow);
                    continue;
                }

                FileInfo fileInfo = null;

                // Get the file size
                try
                {
                    fileInfo = new FileInfo(fileRow.Source);
                }
                catch (ArgumentException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (PathTooLongException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (NotSupportedException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }

                if (fileInfo.Exists)
                {
                    if (fileInfo.Length > Int32.MaxValue)
                    {
                        throw new WixException(WixErrors.FileTooLarge(fileRow.SourceLineNumbers, fileRow.Source));
                    }

                    fileRow.FileSize = Convert.ToInt32(fileInfo.Length, CultureInfo.InvariantCulture);
                }

                if (currentCabIndex == MaxCabIndex)
                {
                    // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                    continue;
                }

                // Update current cab size.
                currentPreCabSize += (ulong)fileRow.FileSize;

                if (currentPreCabSize > maxPreCabSizeInBytes)
                {
                    // Overflow due to current file
                    currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel);

                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                    // Now files larger than MaxUncompressedMediaSize will be the only file in its cabinet so as to respect MaxUncompressedMediaSize
                    currentPreCabSize = (ulong)fileRow.FileSize;
                }
                else
                {
                    // File fits in the current cab.
                    if (currentMediaRow == null)
                    {
                        // Create new cab and MediaRow
                        currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex, mediaTemplateRow.CompressionLevel);
                    }

                    // Associate current file with current cab.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                }
            }

            // If there are uncompressed files and no MediaRow, create a default one.
            if (uncompressedFileRows.Count > 0 && mediaTable.Rows.Count == 0)
            {
                MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null);
                defaultMediaRow.DiskId = 1;
                mediaRows.Add(defaultMediaRow);
            }
        }
예제 #13
0
파일: Binder.cs 프로젝트: zooba/wix3
        private bool BindDatabase(Output output, string databaseFile)
        {
            foreach (BinderExtension extension in this.extensions)
            {
                extension.DatabaseInitialize(output);
            }

            bool compressed = false;
            FileRowCollection fileRows = new FileRowCollection(OutputType.Patch == output.Type);
            bool longNames = false;
            MediaRowCollection mediaRows = new MediaRowCollection();
            Hashtable suppressModularizationIdentifiers = null;
            StringCollection suppressedTableNames = new StringCollection();
            Table propertyTable = output.Tables["Property"];

            this.WriteBuildInfoTable(output, databaseFile);

            // gather all the wix variables
            Table wixVariableTable = output.Tables["WixVariable"];
            if (null != wixVariableTable)
            {
                foreach (WixVariableRow wixVariableRow in wixVariableTable.Rows)
                {
                    this.WixVariableResolver.AddVariable(wixVariableRow);
                }
            }

            // gather all the suppress modularization identifiers
            Table wixSuppressModularizationTable = output.Tables["WixSuppressModularization"];
            if (null != wixSuppressModularizationTable)
            {
                suppressModularizationIdentifiers = new Hashtable(wixSuppressModularizationTable.Rows.Count);

                foreach (Row row in wixSuppressModularizationTable.Rows)
                {
                    suppressModularizationIdentifiers[row[0]] = null;
                }
            }

            // localize fields, resolve wix variables, and resolve file paths
            Hashtable cabinets = new Hashtable();
            ArrayList delayedFields = new ArrayList();
            this.ResolveFields(output.Tables, cabinets, delayedFields);

            // if there are any fields to resolve later, create the cache to populate during bind
            IDictionary<string, string> variableCache = null;
            if (0 < delayedFields.Count)
            {
                variableCache = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
            }

            this.LocalizeUI(output.Tables);

            // process the summary information table before the other tables
            string modularizationGuid = this.BindDatabaseSummaryInfo(output, out longNames, out compressed);

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // modularize identifiers and add tables with real streams to the import tables
            if (OutputType.Module == output.Type)
            {
                foreach (Table table in output.Tables)
                {
                    table.Modularize(modularizationGuid, suppressModularizationIdentifiers);
                }

                // Reset the special property lists after modularization. The linker creates these properties before modularization
                // so we have to reconstruct them for merge modules after modularization in the binder.
                Table wixPropertyTable = output.Tables["WixProperty"];
                if (null != wixPropertyTable)
                {
                    // Create lists of the properties that contribute to the special lists of properties.
                    SortedList adminProperties = new SortedList();
                    SortedList secureProperties = new SortedList();
                    SortedList hiddenProperties = new SortedList();

                    foreach (WixPropertyRow wixPropertyRow in wixPropertyTable.Rows)
                    {
                        if (wixPropertyRow.Admin)
                        {
                            adminProperties[wixPropertyRow.Id] = null;
                        }

                        if (wixPropertyRow.Hidden)
                        {
                            hiddenProperties[wixPropertyRow.Id] = null;
                        }

                        if (wixPropertyRow.Secure)
                        {
                            secureProperties[wixPropertyRow.Id] = null;
                        }
                    }

                    if (0 < adminProperties.Count || 0 < hiddenProperties.Count || 0 < secureProperties.Count)
                    {
                        Table table = output.Tables["Property"];
                        foreach (Row propertyRow in table.Rows)
                        {
                            if ("AdminProperties" == (string)propertyRow[0])
                            {
                                propertyRow[1] = GetPropertyListString(adminProperties);
                            }

                            if ("MsiHiddenProperties" == (string)propertyRow[0])
                            {
                                propertyRow[1] = GetPropertyListString(hiddenProperties);
                            }

                            if ("SecureCustomProperties" == (string)propertyRow[0])
                            {
                                propertyRow[1] = GetPropertyListString(secureProperties);
                            }
                        }
                    }
                }
            }

            // merge unreal table data into the real tables
            // this must occur after all variables and source paths have been resolved
            this.MergeUnrealTables(output.Tables);

            if (this.core.EncounteredError)
            {
                return false;
            }

            if (OutputType.Patch == output.Type)
            {
                foreach (SubStorage substorage in output.SubStorages)
                {
                    Output transform = (Output)substorage.Data;
                    this.ResolveFields(transform.Tables, cabinets, null);
                    this.MergeUnrealTables(transform.Tables);
                }
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // index the File table for quicker access later
            // this must occur after the unreal data has been merged in
            Table fileTable = output.Tables["File"];
            if (null != fileTable)
            {
                fileRows.AddRange(fileTable.Rows);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // add binder variables for all properties
            propertyTable = output.Tables["Property"];
            if (null != propertyTable)
            {
                foreach (Row propertyRow in propertyTable.Rows)
                {
                    string property = propertyRow[0].ToString();

                    // set the ProductCode if its generated
                    if (OutputType.Product == output.Type && "ProductCode" == property && "*" == propertyRow[1].ToString())
                    {
                        propertyRow[1] = Common.GenerateGuid();

                        // Update the target ProductCode in any instance transforms
                        foreach (SubStorage subStorage in output.SubStorages)
                        {
                            Output subStorageOutput = (Output)subStorage.Data;
                            if (OutputType.Transform != subStorageOutput.Type)
                            {
                                continue;
                            }

                            Table instanceSummaryInformationTable = subStorageOutput.Tables["_SummaryInformation"];
                            foreach (Row row in instanceSummaryInformationTable.Rows)
                            {
                                if ((int)SummaryInformation.Transform.ProductCodes == (int)row[0])
                                {
                                    row[1] = ((string)row[1]).Replace("*", (string)propertyRow[1]);
                                    break;
                                }
                            }
                        }
                    }

                    // add the property name and value to the variableCache
                    if (0 != delayedFields.Count)
                    {
                        string key = String.Concat("property.", Demodularize(output, modularizationGuid, property));
                        variableCache[key] = (string)propertyRow[1];
                    }
                }
            }

            // extract files that come from cabinet files (this does not extract files from merge modules)
            this.ExtractCabinets(cabinets);

            // retrieve files and their information from merge modules
            if (OutputType.Product == output.Type)
            {
                this.ProcessMergeModules(output, fileRows);
            }
            else if (OutputType.Patch == output.Type)
            {
                // merge transform data into the output object
                this.CopyTransformData(output, fileRows);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // assign files to media
            AutoMediaAssigner autoMediaAssigner = new AutoMediaAssigner(output, this.core, compressed);
            autoMediaAssigner.AssignFiles(fileRows);

            // update file version, hash, assembly, etc.. information
            this.core.OnMessage(WixVerboses.UpdatingFileInformation());
            Hashtable indexedFileRows = this.UpdateFileInformation(output, fileRows, autoMediaAssigner.MediaRows, variableCache, modularizationGuid);

            // set generated component guids
            this.SetComponentGuids(output);

            // With the Component Guids set now we can create instance transforms.
            this.CreateInstanceTransforms(output);

            this.ValidateComponentGuids(output);

            this.UpdateControlText(output);

            if (0 < delayedFields.Count)
            {
                this.ResolveDelayedFields(output, delayedFields, variableCache, modularizationGuid);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // Extended binder extensions can be called now that fields are resolved.
            foreach (BinderExtension extension in this.extensions)
            {
                BinderExtensionEx extensionEx = extension as BinderExtensionEx;
                if (null != extensionEx)
                {
                    output.EnsureTable(this.core.TableDefinitions["WixBindUpdatedFiles"]);
                    extensionEx.DatabaseAfterResolvedFields(output);
                }
            }

            Table updatedFiles = output.Tables["WixBindUpdatedFiles"];
            if (null != updatedFiles)
            {
                foreach (Row updatedFile in updatedFiles.Rows)
                {
                    FileRow updatedFileRow = (FileRow)indexedFileRows[updatedFile[0]];
                    this.UpdateFileRow(output, null, modularizationGuid, indexedFileRows, updatedFileRow, true);
                }
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // create cabinet files and process uncompressed files
            string layoutDirectory = Path.GetDirectoryName(databaseFile);
            FileRowCollection uncompressedFileRows = null;
            if (!this.suppressLayout || OutputType.Module == output.Type)
            {
                this.core.OnMessage(WixVerboses.CreatingCabinetFiles());
                uncompressedFileRows = this.CreateCabinetFiles(output, fileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, autoMediaAssigner);
            }

            if (OutputType.Patch == output.Type)
            {
                // copy output data back into the transforms
                this.CopyTransformData(output, null);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // add back suppressed tables which must be present prior to merging in modules
            if (OutputType.Product == output.Type)
            {
                Table wixMergeTable = output.Tables["WixMerge"];

                if (null != wixMergeTable && 0 < wixMergeTable.Rows.Count)
                {
                    foreach (SequenceTable sequence in Enum.GetValues(typeof(SequenceTable)))
                    {
                        string sequenceTableName = sequence.ToString();
                        Table sequenceTable = output.Tables[sequenceTableName];

                        if (null == sequenceTable)
                        {
                            sequenceTable = output.EnsureTable(this.core.TableDefinitions[sequenceTableName]);
                        }

                        if (0 == sequenceTable.Rows.Count)
                        {
                            suppressedTableNames.Add(sequenceTableName);
                        }
                    }
                }
            }

            foreach (BinderExtension extension in this.extensions)
            {
                extension.DatabaseFinalize(output);
            }

            // generate database file
            this.core.OnMessage(WixVerboses.GeneratingDatabase());
            string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(databaseFile));
            this.GenerateDatabase(output, tempDatabaseFile, false, false);

            FileTransfer transfer;
            if (FileTransfer.TryCreate(tempDatabaseFile, databaseFile, true, output.Type.ToString(), null, out transfer)) // note where this database needs to move in the future
            {
                transfer.Built = true;
                this.fileTransfers.Add(transfer);
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return false;
            }

            // Output the output to a file
            if (null != this.pdbFile)
            {
                Pdb pdb = new Pdb(null);
                pdb.Output = output;
                pdb.Save(this.pdbFile, null, this.WixVariableResolver, this.TempFilesLocation);
            }

            // merge modules
            if (OutputType.Product == output.Type)
            {
                this.core.OnMessage(WixVerboses.MergingModules());
                this.MergeModules(tempDatabaseFile, output, fileRows, suppressedTableNames);

                // stop processing if an error previously occurred
                if (this.core.EncounteredError)
                {
                    return false;
                }
            }

            // inspect the MSI prior to running ICEs
            InspectorCore inspectorCore = new InspectorCore(this.MessageHandler);
            foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
            {
                inspectorExtension.Core = inspectorCore;
                inspectorExtension.InspectDatabase(tempDatabaseFile, output);

                // reset
                inspectorExtension.Core = null;
            }

            if (inspectorCore.EncounteredError)
            {
                return false;
            }

            // validate the output if there is an MSI validator
            if (null != this.validator)
            {
                Stopwatch stopwatch = Stopwatch.StartNew();

                // set the output file for source line information
                this.validator.Output = output;

                this.core.OnMessage(WixVerboses.ValidatingDatabase());
                this.core.EncounteredError = !this.validator.Validate(tempDatabaseFile);

                stopwatch.Stop();
                this.core.OnMessage(WixVerboses.ValidatedDatabase(stopwatch.ElapsedMilliseconds));

                // stop processing if an error previously occurred
                if (this.core.EncounteredError)
                {
                    return false;
                }
            }

            // process uncompressed files
            if (!this.suppressLayout)
            {
                this.ProcessUncompressedFiles(tempDatabaseFile, uncompressedFileRows, this.fileTransfers, autoMediaAssigner.MediaRows, layoutDirectory, compressed, longNames);
            }

            // layout media
            try
            {
                this.core.OnMessage(WixVerboses.LayingOutMedia());
                this.LayoutMedia(this.fileTransfers, this.suppressAclReset);
            }
            finally
            {
                if (!String.IsNullOrEmpty(this.contentsFile))
                {
                    this.CreateContentsFile(this.contentsFile, fileRows);
                }

                if (!String.IsNullOrEmpty(this.outputsFile))
                {
                    this.CreateOutputsFile(this.outputsFile, this.fileTransfers, this.pdbFile);
                }

                if (!String.IsNullOrEmpty(this.builtOutputsFile))
                {
                    this.CreateBuiltOutputsFile(this.builtOutputsFile, this.fileTransfers, this.pdbFile);
                }
            }

            return !this.core.EncounteredError;
        }
예제 #14
0
        public virtual CabinetBuildOption ResolveCabinet(FileRowCollection fileRows, ref string cabinetPath)
        {
            if (fileRows == null)
            {
                throw new ArgumentNullException("fileRows");
            }

            // no special behavior specified, use the default
            if (null == this.cabCachePath && !this.reuseCabinets)
            {
                return(CabinetBuildOption.BuildAndMove);
            }

            // if a cabinet cache path was provided, change the location for the cabinet
            // to be built to
            if (null != this.cabCachePath)
            {
                string cabinetName = Path.GetFileName(cabinetPath);
                cabinetPath = Path.Combine(this.cabCachePath, cabinetName);
            }

            // if we still think we're going to reuse the cabinet check to see if the cabinet exists first
            if (this.reuseCabinets)
            {
                bool cabinetValid = false;

                if (BinderFileManager.CheckFileExists(cabinetPath))
                {
                    // check to see if
                    // 1. any files are added or removed
                    // 2. order of files changed or names changed
                    // 3. modified time changed
                    cabinetValid = true;

                    // Need to force garbage collection of WixEnumerateCab to ensure the handle
                    // associated with it is closed before it is reused.
                    using (Cab.WixEnumerateCab wixEnumerateCab = new Cab.WixEnumerateCab())
                    {
                        ArrayList fileList = wixEnumerateCab.Enumerate(cabinetPath);

                        if (fileRows.Count != fileList.Count)
                        {
                            cabinetValid = false;
                        }
                        else
                        {
                            int i = 0;
                            foreach (FileRow fileRow in fileRows)
                            {
                                // First check that the file identifiers match because that is quick and easy.
                                CabinetFileInfo cabFileInfo = fileList[i] as CabinetFileInfo;
                                cabinetValid = (cabFileInfo.FileId == fileRow.File);
                                if (cabinetValid)
                                {
                                    // Still valid so ensure the source time stamp hasn't changed. Thus we need
                                    // to convert the source file time stamp into a cabinet compatible data/time.
                                    DateTime sourceFileTime = File.GetLastWriteTime(fileRow.Source);
                                    ushort   sourceCabDate;
                                    ushort   sourceCabTime;

                                    Cab.Interop.CabInterop.DateTimeToCabDateAndTime(sourceFileTime, out sourceCabDate, out sourceCabTime);
                                    cabinetValid = (cabFileInfo.Date == sourceCabDate && cabFileInfo.Time == sourceCabTime);
                                }

                                if (!cabinetValid)
                                {
                                    break;
                                }

                                i++;
                            }
                        }
                    }
                }

                return(cabinetValid ? CabinetBuildOption.Copy : CabinetBuildOption.BuildAndCopy);
            }
            else // by default move the built cabinet
            {
                return(CabinetBuildOption.BuildAndMove);
            }
        }
예제 #15
0
        public virtual CabinetBuildOption ResolveCabinet(FileRowCollection fileRows, ref string cabinetPath)
        {
            if (fileRows == null)
            {
                throw new ArgumentNullException("fileRows");
            }

            // no special behavior specified, use the default
            if (null == this.cabCachePath && !this.reuseCabinets)
            {
                return CabinetBuildOption.BuildAndMove;
            }

            // if a cabinet cache path was provided, change the location for the cabinet
            // to be built to
            if (null != this.cabCachePath)
            {
                string cabinetName = Path.GetFileName(cabinetPath);
                cabinetPath = Path.Combine(this.cabCachePath, cabinetName);
            }

            // if we still think we're going to reuse the cabinet check to see if the cabinet exists first
            if (this.reuseCabinets)
            {
                bool cabinetValid = false;

                if (BinderFileManager.CheckFileExists(cabinetPath))
                {
                    // check to see if
                    // 1. any files are added or removed
                    // 2. order of files changed or names changed
                    // 3. modified time changed
                    cabinetValid = true;

                    // Need to force garbage collection of WixEnumerateCab to ensure the handle
                    // associated with it is closed before it is reused.
                    using (Cab.WixEnumerateCab wixEnumerateCab = new Cab.WixEnumerateCab())
                    {
                        ArrayList fileList = wixEnumerateCab.Enumerate(cabinetPath);

                        if (fileRows.Count != fileList.Count)
                        {
                            cabinetValid = false;
                        }
                        else
                        {
                            int i = 0;
                            foreach (FileRow fileRow in fileRows)
                            {
                                // First check that the file identifiers match because that is quick and easy.
                                CabinetFileInfo cabFileInfo = fileList[i] as CabinetFileInfo;
                                cabinetValid = (cabFileInfo.FileId == fileRow.File);
                                if (cabinetValid)
                                {
                                    // Still valid so ensure the source time stamp hasn't changed. Thus we need
                                    // to convert the source file time stamp into a cabinet compatible data/time.
                                    FileInfo fileInfo = new FileInfo(fileRow.Source);
                                    ushort sourceCabDate;
                                    ushort sourceCabTime;

                                    Cab.Interop.CabInterop.DateTimeToCabDateAndTime(fileInfo.LastWriteTime, out sourceCabDate, out sourceCabTime);
                                    cabinetValid = (cabFileInfo.Date == sourceCabDate && cabFileInfo.Time == sourceCabTime)
                                        && (cabFileInfo.Size == fileInfo.Length);
                                }

                                if (!cabinetValid)
                                {
                                    break;
                                }

                                i++;
                            }
                        }
                    }
                }

                return (cabinetValid ? CabinetBuildOption.Copy : CabinetBuildOption.BuildAndCopy);
            }
            else // by default move the built cabinet
            {
                return CabinetBuildOption.BuildAndMove;
            }
        }
예제 #16
0
        /// <summary>
        /// Assigns the file rows to media rows based on Media or MediaTemplate authoring. Updates uncompressed files collection.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        public void AssignFiles(FileRowCollection fileRows)
        {
            bool autoAssign = false;
            MediaRow mergeModuleMediaRow = null;
            Table mediaTable = this.output.Tables["Media"];
            Table mediaTemplateTable = this.output.Tables["WixMediaTemplate"];

            // If both tables are authored, it is an error.
            if ((mediaTemplateTable != null && mediaTemplateTable.Rows.Count > 0) &&( mediaTable != null && mediaTable.Rows.Count > 1))
            {
                throw new WixException(WixErrors.MediaTableCollision(null));
            }

            autoAssign = mediaTemplateTable != null && OutputType.Module != this.output.Type ? true : false;

            // When building merge module, all the files go to "#MergeModule.CABinet"
            if (OutputType.Module == this.output.Type)
            {
                Table mergeModuleMediaTable = new Table(null, this.core.TableDefinitions["Media"]);
                mergeModuleMediaRow = (MediaRow)mergeModuleMediaTable.CreateRow(null);
                mergeModuleMediaRow.Cabinet = "#MergeModule.CABinet";

                this.cabinets.Add(mergeModuleMediaRow, new FileRowCollection());
            }

            if (autoAssign)
            {
                this.AutoAssignFiles(mediaTable, fileRows);
            }
            else
            {
                this.ManuallyAssignFiles(mediaTable, mergeModuleMediaRow, fileRows);
            }
        }
예제 #17
0
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Update several msi tables with data contained in files references in the File table.
        /// </summary>
        /// <remarks>
        /// For versioned files, update the file version and language in the File table.  For
        /// unversioned files, add a row to the MsiFileHash table for the file.  For assembly
        /// files, add a row to the MsiAssembly table and add AssemblyName information by adding
        /// MsiAssemblyName rows.
        /// </remarks>
        /// <param name="output">Internal representation of the msi database to operate upon.</param>
        /// <param name="fileRows">The indexed file rows.</param>
        /// <param name="mediaRows">The indexed media rows.</param>
        /// <param name="infoCache">A hashtable to populate with the file information (optional).</param>
        /// <param name="modularizationGuid">The modularization guid (used in case of a merge module).</param>
        private Hashtable UpdateFileInformation(Output output, FileRowCollection fileRows, MediaRowCollection mediaRows, IDictionary<string, string> infoCache, string modularizationGuid)
        {
            // Index for all the fileId's
            // NOTE: When dealing with patches, there is a file table for each transform. In most cases, the data in these rows will be the same, however users of this index need to be aware of this.
            Hashtable fileRowIndex = new Hashtable(fileRows.Count);
            Table mediaTable = output.Tables["Media"];

            // calculate sequence numbers and media disk id layout for all file media information objects
            if (OutputType.Module == output.Type)
            {
                int lastSequence = 0;
                foreach (FileRow fileRow in fileRows)
                {
                    fileRow.Sequence = ++lastSequence;
                    fileRowIndex[fileRow.File] = fileRow;
                }
            }
            else if (null != mediaTable)
            {
                int lastSequence = 0;
                MediaRow mediaRow = null;
                SortedList patchGroups = new SortedList();

                // sequence the non-patch-added files
                foreach (FileRow fileRow in fileRows)
                {
                    fileRowIndex[fileRow.File] = fileRow;
                    if (null == mediaRow)
                    {
                        mediaRow = mediaRows[fileRow.DiskId];
                        if (OutputType.Patch == output.Type)
                        {
                            // patch Media cannot start at zero
                            lastSequence = mediaRow.LastSequence;
                        }
                    }
                    else if (mediaRow.DiskId != fileRow.DiskId)
                    {
                        mediaRow.LastSequence = lastSequence;
                        mediaRow = mediaRows[fileRow.DiskId];
                    }

                    if (0 < fileRow.PatchGroup)
                    {
                        ArrayList patchGroup = (ArrayList)patchGroups[fileRow.PatchGroup];

                        if (null == patchGroup)
                        {
                            patchGroup = new ArrayList();
                            patchGroups.Add(fileRow.PatchGroup, patchGroup);
                        }

                        patchGroup.Add(fileRow);
                    }
                    else
                    {
                        fileRow.Sequence = ++lastSequence;
                    }
                }

                if (null != mediaRow)
                {
                    mediaRow.LastSequence = lastSequence;
                    mediaRow = null;
                }

                // sequence the patch-added files
                foreach (ArrayList patchGroup in patchGroups.Values)
                {
                    foreach (FileRow fileRow in patchGroup)
                    {
                        if (null == mediaRow)
                        {
                            mediaRow = mediaRows[fileRow.DiskId];
                        }
                        else if (mediaRow.DiskId != fileRow.DiskId)
                        {
                            mediaRow.LastSequence = lastSequence;
                            mediaRow = mediaRows[fileRow.DiskId];
                        }

                        fileRow.Sequence = ++lastSequence;
                    }
                }

                if (null != mediaRow)
                {
                    mediaRow.LastSequence = lastSequence;
                }
            }
            else
            {
                foreach (FileRow fileRow in fileRows)
                {
                    fileRowIndex[fileRow.File] = fileRow;
                }
            }

            // no more work to do here if there are no file rows in the file table
            // note that this does not mean there are no files - the files from
            // merge modules are never put in the output's file table
            Table fileTable = output.Tables["File"];
            if (null == fileTable)
            {
                return fileRowIndex;
            }

            // gather information about files that did not come from merge modules
            foreach (FileRow row in fileTable.Rows)
            {
                UpdateFileRow(output, infoCache, modularizationGuid, fileRowIndex, row, false);
            }

            return fileRowIndex;
        }
예제 #18
0
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Copy file data between transform substorages and the patch output object
        /// </summary>
        /// <param name="output">The output to bind.</param>
        /// <param name="allFileRows">True if copying from transform to patch, false the other way.</param>
        /// <returns>true if binding completed successfully; false otherwise</returns>
        private bool CopyTransformData(Output output, FileRowCollection allFileRows)
        {
            bool copyToPatch = (allFileRows != null);
            bool copyFromPatch = !copyToPatch;
            if (OutputType.Patch != output.Type)
            {
                return true;
            }

            Hashtable patchMediaRows = new Hashtable();
            Hashtable patchMediaFileRows = new Hashtable();
            Table patchFileTable = output.EnsureTable(this.core.TableDefinitions["File"]);
            if (copyFromPatch)
            {
                // index patch files by diskId+fileId
                foreach (FileRow patchFileRow in patchFileTable.Rows)
                {
                    int diskId = patchFileRow.DiskId;
                    if (!patchMediaFileRows.Contains(diskId))
                    {
                        patchMediaFileRows[diskId] = new FileRowCollection();
                    }
                    FileRowCollection mediaFileRows = (FileRowCollection)patchMediaFileRows[diskId];
                    mediaFileRows.Add(patchFileRow);
                }

                Table patchMediaTable = output.EnsureTable(this.core.TableDefinitions["Media"]);
                foreach (MediaRow patchMediaRow in patchMediaTable.Rows)
                {
                    patchMediaRows[patchMediaRow.DiskId] = patchMediaRow;
                }
            }

            // index paired transforms
            Hashtable pairedTransforms = new Hashtable();
            foreach (SubStorage substorage in output.SubStorages)
            {
                if ("#" == substorage.Name.Substring(0, 1))
                {
                    pairedTransforms[substorage.Name.Substring(1)] = substorage.Data;
                }
            }

            try
            {
                // copy File bind data into substorages
                foreach (SubStorage substorage in output.SubStorages)
                {
                    if ("#" == substorage.Name.Substring(0, 1))
                    {
                        // no changes necessary for paired transforms
                        continue;
                    }

                    Output mainTransform = (Output)substorage.Data;
                    Table mainWixFileTable = mainTransform.Tables["WixFile"];
                    Table mainMsiFileHashTable = mainTransform.Tables["MsiFileHash"];

                    int numWixFileRows = (null != mainWixFileTable) ? mainWixFileTable.Rows.Count : 0;
                    int numMsiFileHashRows = (null != mainMsiFileHashTable) ? mainMsiFileHashTable.Rows.Count : 0;

                    this.FileManager.ActiveSubStorage = substorage;
                    Hashtable wixFiles = new Hashtable(numWixFileRows);
                    Hashtable mainMsiFileHashIndex = new Hashtable(numMsiFileHashRows);
                    Table mainFileTable = mainTransform.Tables["File"];
                    Output pairedTransform = (Output)pairedTransforms[substorage.Name];

                    if (null != mainWixFileTable)
                    {
                        // Index the WixFile table for later use.
                        foreach (WixFileRow row in mainWixFileTable.Rows)
                        {
                            wixFiles.Add(row.Fields[0].Data.ToString(), row);
                        }
                    }

                    // copy Media.LastSequence and index the MsiFileHash table if it exists.
                    if (copyFromPatch)
                    {
                        Table pairedMediaTable = pairedTransform.Tables["Media"];
                        foreach (MediaRow pairedMediaRow in pairedMediaTable.Rows)
                        {
                            MediaRow patchMediaRow = (MediaRow)patchMediaRows[pairedMediaRow.DiskId];
                            pairedMediaRow.Fields[1] = patchMediaRow.Fields[1];
                        }

                        if (null != mainMsiFileHashTable)
                        {
                            // Index the MsiFileHash table for later use.
                            foreach (Row row in mainMsiFileHashTable.Rows)
                            {
                                mainMsiFileHashIndex.Add(row[0], row);
                            }
                        }

                        // Validate file row changes for keypath-related issues
                        this.ValidateFileRowChanges(mainTransform);
                    }

                    // index File table of pairedTransform
                    FileRowCollection pairedFileRows = new FileRowCollection();
                    Table pairedFileTable = pairedTransform.Tables["File"];
                    if (null != pairedFileTable)
                    {
                        pairedFileRows.AddRange(pairedFileTable.Rows);
                    }

                    if (null != mainFileTable)
                    {
                        if (copyFromPatch)
                        {
                            // Remove the MsiFileHash table because it will be updated later with the final file hash for each file
                            mainTransform.Tables.Remove("MsiFileHash");
                        }

                        foreach (FileRow mainFileRow in mainFileTable.Rows)
                        {
                            if (mainFileRow.Operation == RowOperation.Delete)
                            {
                                continue;
                            }

                            if (!copyToPatch && mainFileRow.Operation == RowOperation.None)
                            {
                                continue;
                            }
                            // When copying to the patch, we need compare the underlying files and include all file changes.
                            else if (copyToPatch)
                            {
                                WixFileRow wixFileRow = (WixFileRow)wixFiles[mainFileRow.Fields[0].Data.ToString()];
                                ObjectField objectField = (ObjectField)wixFileRow.Fields[6];
                                FileRow pairedFileRow = pairedFileRows[mainFileRow.Fields[0].Data.ToString()];

                                // If the file is new, we always need to add it to the patch.
                                if (mainFileRow.Operation != RowOperation.Add)
                                {
                                    // If PreviousData doesn't exist, target and upgrade layout point to the same location. No need to compare.
                                    if (null == objectField.PreviousData)
                                    {
                                        if (mainFileRow.Operation == RowOperation.None)
                                        {
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        // TODO: should this entire condition be placed in the binder file manager?
                                        if ((0 == (PatchAttributeType.Ignore & wixFileRow.PatchAttributes)) &&
                                            !this.FileManager.CompareFiles(objectField.PreviousData.ToString(), objectField.Data.ToString()))
                                        {
                                            // If the file is different, we need to mark the mainFileRow and pairedFileRow as modified.
                                            mainFileRow.Operation = RowOperation.Modify;
                                            if (null != pairedFileRow)
                                            {
                                                // Always patch-added, but never non-compressed.
                                                pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded;
                                                pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
                                                pairedFileRow.Fields[6].Modified = true;
                                                pairedFileRow.Operation = RowOperation.Modify;
                                            }
                                        }
                                        else
                                        {
                                            // The File is same. We need mark all the attributes as unchanged.
                                            mainFileRow.Operation = RowOperation.None;
                                            foreach (Field field in mainFileRow.Fields)
                                            {
                                                field.Modified = false;
                                            }

                                            if (null != pairedFileRow)
                                            {
                                                pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesPatchAdded;
                                                pairedFileRow.Fields[6].Modified = false;
                                                pairedFileRow.Operation = RowOperation.None;
                                            }
                                            continue;
                                        }
                                    }
                                }
                                else if (null != pairedFileRow) // RowOperation.Add
                                {
                                    // Always patch-added, but never non-compressed.
                                    pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded;
                                    pairedFileRow.Attributes &= ~MsiInterop.MsidbFileAttributesNoncompressed;
                                    pairedFileRow.Fields[6].Modified = true;
                                    pairedFileRow.Operation = RowOperation.Add;
                                }
                            }

                            // index patch files by diskId+fileId
                            int diskId = mainFileRow.DiskId;
                            if (!patchMediaFileRows.Contains(diskId))
                            {
                                patchMediaFileRows[diskId] = new FileRowCollection();
                            }
                            FileRowCollection mediaFileRows = (FileRowCollection)patchMediaFileRows[diskId];

                            string fileId = mainFileRow.File;
                            FileRow patchFileRow = mediaFileRows[fileId];
                            if (copyToPatch)
                            {
                                if (null == patchFileRow)
                                {
                                    patchFileRow = (FileRow)patchFileTable.CreateRow(null);
                                    patchFileRow.CopyFrom(mainFileRow);
                                    mediaFileRows.Add(patchFileRow);
                                    allFileRows.Add(patchFileRow);
                                }
                                else
                                {
                                    // TODO: confirm the rest of data is identical?

                                    // make sure Source is same. Otherwise we are silently ignoring a file.
                                    if (0 != String.Compare(patchFileRow.Source, mainFileRow.Source, StringComparison.OrdinalIgnoreCase))
                                    {
                                        this.core.OnMessage(WixErrors.SameFileIdDifferentSource(mainFileRow.SourceLineNumbers, fileId, patchFileRow.Source, mainFileRow.Source));
                                    }
                                    // capture the previous file versions (and associated data) from this targeted instance of the baseline into the current filerow.
                                    patchFileRow.AppendPreviousDataFrom(mainFileRow);
                                }
                            }
                            else
                            {
                                // copy data from the patch back to the transform
                                if (null != patchFileRow)
                                {
                                    FileRow pairedFileRow = (FileRow)pairedFileRows[fileId];
                                    for (int i = 0; i < patchFileRow.Fields.Length; i++)
                                    {
                                        string patchValue = patchFileRow[i] == null ? "" : patchFileRow[i].ToString();
                                        string mainValue = mainFileRow[i] == null ? "" : mainFileRow[i].ToString();

                                        if (1 == i)
                                        {
                                            // File.Component_ changes should not come from the shared file rows
                                            // that contain the file information as each individual transform might
                                            // have different changes (or no changes at all).
                                        }
                                        // File.Attributes should not changed for binary deltas
                                        else if (6 == i)
                                        {
                                            if (null != patchFileRow.Patch)
                                            {
                                                // File.Attribute should not change for binary deltas
                                                pairedFileRow.Attributes = mainFileRow.Attributes;
                                                mainFileRow.Fields[i].Modified = false;
                                            }
                                        }
                                        // File.Sequence is updated in pairedTransform, not mainTransform
                                        else if (7 == i)
                                        {
                                            // file sequence is updated in Patch table instead of File table for delta patches
                                            if (null != patchFileRow.Patch)
                                            {
                                                pairedFileRow.Fields[i].Modified = false;
                                            }
                                            else
                                            {
                                                pairedFileRow[i] = patchFileRow[i];
                                                pairedFileRow.Fields[i].Modified = true;
                                            }
                                            mainFileRow.Fields[i].Modified = false;
                                        }
                                        else if (patchValue != mainValue)
                                        {
                                            mainFileRow[i] = patchFileRow[i];
                                            mainFileRow.Fields[i].Modified = true;
                                            if (mainFileRow.Operation == RowOperation.None)
                                            {
                                                mainFileRow.Operation = RowOperation.Modify;
                                            }
                                        }
                                    }

                                    // copy MsiFileHash row for this File
                                    Row patchHashRow;
                                    if (mainMsiFileHashIndex.ContainsKey(patchFileRow.File))
                                    {
                                        patchHashRow = (Row)mainMsiFileHashIndex[patchFileRow.File];
                                    }
                                    else
                                    {
                                        patchHashRow = patchFileRow.HashRow;
                                    }

                                    if (null != patchHashRow)
                                    {
                                        Table mainHashTable = mainTransform.EnsureTable(this.core.TableDefinitions["MsiFileHash"]);
                                        Row mainHashRow = mainHashTable.CreateRow(mainFileRow.SourceLineNumbers);
                                        for (int i = 0; i < patchHashRow.Fields.Length; i++)
                                        {
                                            mainHashRow[i] = patchHashRow[i];
                                            if (i > 1)
                                            {
                                                // assume all hash fields have been modified
                                                mainHashRow.Fields[i].Modified = true;
                                            }
                                        }

                                        // assume the MsiFileHash operation follows the File one
                                        mainHashRow.Operation = mainFileRow.Operation;
                                    }

                                    // copy MsiAssemblyName rows for this File
                                    RowCollection patchAssemblyNameRows = patchFileRow.AssemblyNameRows;
                                    if (null != patchAssemblyNameRows)
                                    {
                                        Table mainAssemblyNameTable = mainTransform.EnsureTable(this.core.TableDefinitions["MsiAssemblyName"]);
                                        foreach (Row patchAssemblyNameRow in patchAssemblyNameRows)
                                        {
                                            // Copy if there isn't an identical modified/added row already in the transform.
                                            bool foundMatchingModifiedRow = false;
                                            foreach (Row mainAssemblyNameRow in mainAssemblyNameTable.Rows)
                                            {
                                                if (RowOperation.None != mainAssemblyNameRow.Operation && mainAssemblyNameRow.GetPrimaryKey('/').Equals(patchAssemblyNameRow.GetPrimaryKey('/')))
                                                {
                                                    foundMatchingModifiedRow = true;
                                                    break;
                                                }
                                            }

                                            if (!foundMatchingModifiedRow)
                                            {
                                                Row mainAssemblyNameRow = mainAssemblyNameTable.CreateRow(mainFileRow.SourceLineNumbers);
                                                for (int i = 0; i < patchAssemblyNameRow.Fields.Length; i++)
                                                {
                                                    mainAssemblyNameRow[i] = patchAssemblyNameRow[i];
                                                }

                                                // assume value field has been modified
                                                mainAssemblyNameRow.Fields[2].Modified = true;
                                                mainAssemblyNameRow.Operation = mainFileRow.Operation;
                                            }
                                        }
                                    }

                                    // Add patch header for this file
                                    if (null != patchFileRow.Patch)
                                    {
                                        // Add the PatchFiles action automatically to the AdminExecuteSequence and InstallExecuteSequence tables.
                                        AddPatchFilesActionToSequenceTable(SequenceTable.AdminExecuteSequence, mainTransform, pairedTransform, mainFileRow);
                                        AddPatchFilesActionToSequenceTable(SequenceTable.InstallExecuteSequence, mainTransform, pairedTransform, mainFileRow);

                                        // Add to Patch table
                                        Table patchTable = pairedTransform.EnsureTable(this.core.TableDefinitions["Patch"]);
                                        if (0 == patchTable.Rows.Count)
                                        {
                                            patchTable.Operation = TableOperation.Add;
                                        }
                                        Row patchRow = patchTable.CreateRow(mainFileRow.SourceLineNumbers);
                                        patchRow[0] = patchFileRow.File;
                                        patchRow[1] = patchFileRow.Sequence;
                                        FileInfo patchFile = new FileInfo(patchFileRow.Source);
                                        patchRow[2] = (int)patchFile.Length;
                                        patchRow[3] = 0 == (PatchAttributeType.AllowIgnoreOnError & patchFileRow.PatchAttributes) ? 0 : 1;
                                        string streamName = patchTable.Name + "." + patchRow[0] + "." + patchRow[1];
                                        if (MsiInterop.MsiMaxStreamNameLength < streamName.Length)
                                        {
                                            streamName = "_" + Guid.NewGuid().ToString("D").ToUpper(CultureInfo.InvariantCulture).Replace('-', '_');
                                            Table patchHeadersTable = pairedTransform.EnsureTable(this.core.TableDefinitions["MsiPatchHeaders"]);
                                            if (0 == patchHeadersTable.Rows.Count)
                                            {
                                                patchHeadersTable.Operation = TableOperation.Add;
                                            }
                                            Row patchHeadersRow = patchHeadersTable.CreateRow(mainFileRow.SourceLineNumbers);
                                            patchHeadersRow[0] = streamName;
                                            patchHeadersRow[1] = patchFileRow.Patch;
                                            patchRow[5] = streamName;
                                            patchHeadersRow.Operation = RowOperation.Add;
                                        }
                                        else
                                        {
                                            patchRow[4] = patchFileRow.Patch;
                                        }
                                        patchRow.Operation = RowOperation.Add;
                                    }
                                }
                                else
                                {
                                    // TODO: throw because all transform rows should have made it into the patch
                                }
                            }
                        }
                    }

                    if (copyFromPatch)
                    {
                        output.Tables.Remove("Media");
                        output.Tables.Remove("File");
                        output.Tables.Remove("MsiFileHash");
                        output.Tables.Remove("MsiAssemblyName");
                    }
                }
            }
            finally
            {
                this.FileManager.ActiveSubStorage = null;
            }

            return true;
        }
예제 #19
0
파일: Linker.cs 프로젝트: zooba/wix3
        public Output Link(SectionCollection sections, ArrayList transforms, OutputType expectedOutputType)
        {
            Output output = null;

            try
            {
                SymbolCollection allSymbols;
                Section entrySection;
                bool containsModuleSubstitution = false;
                bool containsModuleConfiguration = false;

                StringCollection referencedSymbols = new StringCollection();
                ArrayList unresolvedReferences = new ArrayList();

                ConnectToFeatureCollection componentsToFeatures = new ConnectToFeatureCollection();
                ConnectToFeatureCollection featuresToFeatures = new ConnectToFeatureCollection();
                ConnectToFeatureCollection modulesToFeatures = new ConnectToFeatureCollection();

                this.activeOutput = null;
                this.encounteredError = false;

                SortedList adminProperties = new SortedList();
                SortedList secureProperties = new SortedList();
                SortedList hiddenProperties = new SortedList();

                RowCollection actionRows = new RowCollection();
                RowCollection suppressActionRows = new RowCollection();

                TableDefinitionCollection customTableDefinitions = new TableDefinitionCollection();
                RowCollection customRows = new RowCollection();

                StringCollection generatedShortFileNameIdentifiers = new StringCollection();
                Hashtable generatedShortFileNames = new Hashtable();

                Hashtable multipleFeatureComponents = new Hashtable();

                Hashtable wixVariables = new Hashtable();

                // verify that modularization types match for foreign key relationships
                foreach (TableDefinition tableDefinition in this.tableDefinitions)
                {
                    foreach (ColumnDefinition columnDefinition in tableDefinition.Columns)
                    {
                        if (null != columnDefinition.KeyTable && 0 > columnDefinition.KeyTable.IndexOf(';') && columnDefinition.IsKeyColumnSet)
                        {
                            try
                            {
                                TableDefinition keyTableDefinition = this.tableDefinitions[columnDefinition.KeyTable];

                                if (0 >= columnDefinition.KeyColumn || keyTableDefinition.Columns.Count < columnDefinition.KeyColumn)
                                {
                                    this.OnMessage(WixErrors.InvalidKeyColumn(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn));
                                }
                                else if (keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType != columnDefinition.ModularizeType && ColumnModularizeType.CompanionFile != columnDefinition.ModularizeType)
                                {
                                    this.OnMessage(WixErrors.CollidingModularizationTypes(tableDefinition.Name, columnDefinition.Name, columnDefinition.KeyTable, columnDefinition.KeyColumn, columnDefinition.ModularizeType.ToString(), keyTableDefinition.Columns[columnDefinition.KeyColumn - 1].ModularizeType.ToString()));
                                }
                            }
                            catch (WixMissingTableDefinitionException)
                            {
                                // ignore missing table definitions - this error is caught in other places
                            }
                        }
                    }
                }

                // add in the extension sections
                foreach (WixExtension extension in this.extensions)
                {
                    Library library = extension.GetLibrary(this.tableDefinitions);

                    if (null != library)
                    {
                        sections.AddRange(library.Sections);
                    }
                }

                // first find the entry section and create the symbols hash for all the sections
                sections.FindEntrySectionAndLoadSymbols(this.allowIdenticalRows, this, expectedOutputType, out entrySection, out allSymbols);

                // should have found an entry section by now
                if (null == entrySection)
                {
                    throw new WixException(WixErrors.MissingEntrySection(expectedOutputType.ToString()));
                }

                // add the missing standard action symbols
                this.LoadStandardActionSymbols(allSymbols);

                // now that we know where we're starting from, create the output object
                output = new Output(null);
                output.EntrySection = entrySection; // Note: this entry section will get added to the Output.Sections collection later
                if (null != this.localizer && -1 != this.localizer.Codepage)
                {
                    output.Codepage = this.localizer.Codepage;
                }
                this.activeOutput = output;

                // Resolve the symbol references to find the set of sections we
                // care about for linking.  Of course, we start with the entry
                // section (that's how it got its name after all).
                output.Sections.AddRange(output.EntrySection.ResolveReferences(output.Type, allSymbols, referencedSymbols, unresolvedReferences, this));

                // Flattening the complex references that participate in groups.
                this.FlattenSectionsComplexReferences(output.Sections);

                if (this.encounteredError)
                {
                    return null;
                }

                // The hard part in linking is processing the complex references.
                this.ProcessComplexReferences(output, output.Sections, referencedSymbols, componentsToFeatures, featuresToFeatures, modulesToFeatures);
                for (int i = 0; i < unresolvedReferences.Count; ++i)
                {
                    Section.SimpleReferenceSection referenceSection = (Section.SimpleReferenceSection)unresolvedReferences[i];
                    if (this.allowUnresolvedReferences)
                    {
                        this.OnMessage(WixWarnings.UnresolvedReferenceWarning(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName));
                    }
                    else
                    {
                        this.OnMessage(WixErrors.UnresolvedReference(referenceSection.WixSimpleReferenceRow.SourceLineNumbers, referenceSection.Section.Type.ToString(), referenceSection.Section.Id, referenceSection.WixSimpleReferenceRow.SymbolicName));
                    }
                }

                if (this.encounteredError)
                {
                    return null;
                }

                SymbolCollection unreferencedSymbols = output.Sections.GetOrphanedSymbols(referencedSymbols, this);

                // Display a warning message for Components that were never referenced by a Feature.
                foreach (Symbol symbol in unreferencedSymbols)
                {
                    if ("Component" == symbol.Row.Table.Name)
                    {
                        this.OnMessage(WixErrors.OrphanedComponent(symbol.Row.SourceLineNumbers, (string)symbol.Row[0]));
                    }
                }

                Dictionary<string, List<Symbol>> duplicatedSymbols = output.Sections.GetDuplicateSymbols(this);

                // Display a warning message for Components that were never referenced by a Feature.
                foreach (List<Symbol> duplicatedSymbolList in duplicatedSymbols.Values)
                {
                    Symbol symbol = duplicatedSymbolList[0];

                    // Certain tables allow duplicates because they allow overrides.
                    if (symbol.Row.Table.Name != "WixAction" &&
                        symbol.Row.Table.Name != "WixVariable")
                    {
                        this.OnMessage(WixErrors.DuplicateSymbol(symbol.Row.SourceLineNumbers, symbol.Name));

                        for (int i = 1; i < duplicatedSymbolList.Count; i++)
                        {
                            Symbol duplicateSymbol = duplicatedSymbolList[i];
                            this.OnMessage(WixErrors.DuplicateSymbol2(duplicateSymbol.Row.SourceLineNumbers));
                        }
                    }
                }

                if (this.encounteredError)
                {
                    return null;
                }

                if (null != this.unreferencedSymbolsFile)
                {
                    sections.GetOrphanedSymbols(referencedSymbols, this).OutputSymbols(this.unreferencedSymbolsFile);
                }

                // resolve the feature to feature connects
                this.ResolveFeatureToFeatureConnects(featuresToFeatures, allSymbols);

                // start generating OutputTables and OutputRows for all the sections in the output
                RowCollection ensureTableRows = new RowCollection();
                int sectionCount = 0;
                foreach (Section section in output.Sections)
                {
                    sectionCount++;
                    string sectionId = section.Id;
                    if (null == sectionId && this.sectionIdOnRows)
                    {
                        sectionId = "wix.section." + sectionCount.ToString(CultureInfo.InvariantCulture);
                    }

                    foreach (Table table in section.Tables)
                    {
                        // By default, copy rows unless we've been asked to drop unreal tables from
                        // the output and it's an unreal table and *not* a UX Manifest table.
                        bool copyRows = true;
                        if (this.dropUnrealTables && table.Definition.IsUnreal && !table.Definition.IsBootstrapperApplicationData)
                        {
                            copyRows = false;
                        }

                        // handle special tables
                        switch (table.Name)
                        {
                            case "AppSearch":
                                this.activeOutput.EnsureTable(this.tableDefinitions["Signature"]);
                                break;

                            case "Class":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 2, 11, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "ChainPackage":
                            case "ChainPackageGroup":
                            case "MsiProperty":
                                copyRows = true;
                                break;

                            case "CustomAction":
                                if (OutputType.Module == this.activeOutput.Type)
                                {
                                    this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]);
                                    this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]);
                                }

                                foreach (Row row in table.Rows)
                                {
                                    // For script CAs that specify HideTarget we should also hide the CA data property for the action.
                                    int bits = Convert.ToInt32(row[1]);
                                    if (MsiInterop.MsidbCustomActionTypeHideTarget == (bits & MsiInterop.MsidbCustomActionTypeHideTarget) &&
                                        MsiInterop.MsidbCustomActionTypeInScript == (bits & MsiInterop.MsidbCustomActionTypeInScript))
                                    {
                                        hiddenProperties[Convert.ToString(row[0])] = null;
                                    }
                                }
                                break;

                            case "Dialog":
                                this.activeOutput.EnsureTable(this.tableDefinitions["ListBox"]);
                                break;

                            case "Directory":
                                foreach (Row row in table.Rows)
                                {
                                    if (OutputType.Module == this.activeOutput.Type)
                                    {
                                        string directory = row[0].ToString();
                                        if (Util.IsStandardDirectory(directory))
                                        {
                                            // if the directory table contains references to standard windows folders
                                            // mergemod.dll will add customactions to set the MSM directory to
                                            // the same directory as the standard windows folder and will add references to
                                            // custom action to all the standard sequence tables.  A problem will occur
                                            // if the MSI does not have these tables as mergemod.dll does not add these
                                            // tables to the MSI if absent.  This code adds the tables in case mergemod.dll
                                            // needs them.
                                            this.activeOutput.EnsureTable(this.tableDefinitions["CustomAction"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["AdminExecuteSequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["AdminUISequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["AdvtExecuteSequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["InstallExecuteSequence"]);
                                            this.activeOutput.EnsureTable(this.tableDefinitions["InstallUISequence"]);
                                        }
                                        else
                                        {
                                            foreach (string standardDirectory in Util.StandardDirectories.Keys)
                                            {
                                                if (directory.StartsWith(standardDirectory, StringComparison.Ordinal))
                                                {
                                                    this.OnMessage(WixWarnings.StandardDirectoryConflictInMergeModule(row.SourceLineNumbers, directory, standardDirectory));
                                                }
                                            }
                                        }
                                    }
                                }
                                break;

                            case "Extension":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 1, 4, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "ModuleSubstitution":
                                containsModuleSubstitution = true;
                                break;

                            case "ModuleConfiguration":
                                containsModuleConfiguration = true;
                                break;

                            case "MsiAssembly":
                                if (this.suppressMsiAssemblyTable)
                                {
                                    copyRows = false;
                                }
                                else if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 0, 1, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "ProgId":
                                // the Extension table is required with a ProgId table
                                this.activeOutput.EnsureTable(this.tableDefinitions["Extension"]);
                                break;

                            case "Property":
                                for (int i = 0; i < table.Rows.Count; i++)
                                {
                                    if (null == table.Rows[i][1])
                                    {
                                        table.Rows.RemoveAt(i);
                                        i--;
                                    }
                                }
                                break;

                            case "PublishComponent":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 2, 4, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "Shortcut":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 3, 4, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "TypeLib":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 2, 6, componentsToFeatures, multipleFeatureComponents);
                                }
                                break;

                            case "Upgrade":
                                foreach (UpgradeRow row in table.Rows)
                                {
                                    secureProperties[row.ActionProperty] = null;
                                }
                                break;

                            case "Variable":
                                copyRows = true;
                                break;

                            case "WixAction":
                                if (this.sectionIdOnRows)
                                {
                                    foreach (Row row in table.Rows)
                                    {
                                        row.SectionId = sectionId;
                                    }
                                }
                                actionRows.AddRange(table.Rows);
                                break;

                            case "WixBBControl":
                            case "WixControl":
                                copyRows = true;
                                break;

                            case "WixCustomTable":
                                this.LinkCustomTable(table, customTableDefinitions);
                                copyRows = false; // we've created table definitions from these rows, no need to process them any longer
                                break;

                            case "WixCustomRow":
                                foreach (Row row in table.Rows)
                                {
                                    row.SectionId = (this.sectionIdOnRows ? sectionId : null);
                                    customRows.Add(row);
                                }
                                copyRows = false;
                                break;

                            case "WixEnsureTable":
                                ensureTableRows.AddRange(table.Rows);
                                break;

                            case "WixFile":
                                foreach (Row row in table.Rows)
                                {
                                    // DiskId is not valid when creating a module, so set it to
                                    // 0 for all files to ensure proper sorting in the binder
                                    if (OutputType.Module == this.activeOutput.Type)
                                    {
                                        row[5] = 0;
                                    }

                                    // if the short file name was generated, check for collisions
                                    if (0x1 == (int)row[9])
                                    {
                                        generatedShortFileNameIdentifiers.Add((string)row[0]);
                                    }
                                }
                                copyRows = true;
                                break;

                            case "WixFragment":
                                copyRows = true;
                                break;

                            case "WixGroup":
                                copyRows = true;
                                break;

                            case "WixInstanceTransforms":
                                copyRows = true;
                                break;

                            case "WixMedia":
                                copyRows = true;
                                break;

                            case "WixMerge":
                                if (OutputType.Product == output.Type)
                                {
                                    this.ResolveFeatures(table.Rows, 0, 7, modulesToFeatures, null);
                                }
                                copyRows = true;
                                break;

                            case "WixOrdering":
                                copyRows = true;
                                break;

                            case "WixProperty":
                                foreach (WixPropertyRow wixPropertyRow in table.Rows)
                                {
                                    if (wixPropertyRow.Admin)
                                    {
                                        adminProperties[wixPropertyRow.Id] = null;
                                    }

                                    if (wixPropertyRow.Hidden)
                                    {
                                        hiddenProperties[wixPropertyRow.Id] = null;
                                    }

                                    if (wixPropertyRow.Secure)
                                    {
                                        secureProperties[wixPropertyRow.Id] = null;
                                    }
                                }
                                break;

                            case "WixSuppressAction":
                                suppressActionRows.AddRange(table.Rows);
                                break;

                            case "WixSuppressModularization":
                                // just copy the rows to the output
                                copyRows = true;
                                break;

                            case "WixVariable":
                                // check for colliding values and collect the wix variable rows
                                foreach (WixVariableRow row in table.Rows)
                                {
                                    WixVariableRow collidingRow = (WixVariableRow)wixVariables[row.Id];

                                    if (null == collidingRow || (collidingRow.Overridable && !row.Overridable))
                                    {
                                        wixVariables[row.Id] = row;
                                    }
                                    else if (!row.Overridable || (collidingRow.Overridable && row.Overridable))
                                    {
                                        this.OnMessage(WixErrors.WixVariableCollision(row.SourceLineNumbers, row.Id));
                                    }
                                }
                                copyRows = false;
                                break;
                            case "WixPatchRef":
                            case "WixPatchBaseline":
                            case "WixPatchId":
                                copyRows = true;
                                break;
                        }

                        if (copyRows)
                        {
                            Table outputTable = this.activeOutput.EnsureTable(this.tableDefinitions[table.Name]);
                            this.CopyTableRowsToOutputTable(table, outputTable, sectionId);
                        }
                    }
                }

                // Verify that there were no duplicate fragment Id's.
                Table wixFragmentTable = this.activeOutput.Tables["WixFragment"];
                Hashtable fragmentIdIndex = new Hashtable();
                if (null != wixFragmentTable)
                {
                    foreach (Row row in wixFragmentTable.Rows)
                    {
                        string fragmentId = row.Fields[0].Data.ToString();
                        if (!fragmentIdIndex.ContainsKey(fragmentId))
                        {
                            fragmentIdIndex.Add(fragmentId, row.SourceLineNumbers);
                        }
                        else
                        {
                            this.OnMessage(WixErrors.DuplicateSymbol(row.SourceLineNumbers, fragmentId));
                            if (null != fragmentIdIndex[fragmentId])
                            {
                                this.OnMessage(WixErrors.DuplicateSymbol2((SourceLineNumberCollection)fragmentIdIndex[fragmentId]));
                            }
                        }
                    }
                }

                // copy the module to feature connections into the output
                if (0 < modulesToFeatures.Count)
                {
                    Table wixFeatureModulesTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixFeatureModules"]);

                    foreach (ConnectToFeature connectToFeature in modulesToFeatures)
                    {
                        foreach (string feature in connectToFeature.ConnectFeatures)
                        {
                            Row row = wixFeatureModulesTable.CreateRow(null);
                            row[0] = feature;
                            row[1] = connectToFeature.ChildId;
                        }
                    }
                }

                // ensure the creation of tables that need to exist
                if (0 < ensureTableRows.Count)
                {
                    foreach (Row row in ensureTableRows)
                    {
                        string tableId = (string)row[0];
                        TableDefinition tableDef = null;

                        try
                        {
                            tableDef = this.tableDefinitions[tableId];
                        }
                        catch (WixMissingTableDefinitionException)
                        {
                            tableDef = customTableDefinitions[tableId];
                        }

                        this.activeOutput.EnsureTable(tableDef);
                    }
                }

                // copy all the suppress action rows to the output to suppress actions from merge modules
                if (0 < suppressActionRows.Count)
                {
                    Table suppressActionTable = this.activeOutput.EnsureTable(this.tableDefinitions["WixSuppressAction"]);
                    suppressActionTable.Rows.AddRange(suppressActionRows);
                }

                // sequence all the actions
                this.SequenceActions(actionRows, suppressActionRows);

                // check for missing table and add them or display an error as appropriate
                switch (this.activeOutput.Type)
                {
                    case OutputType.Module:
                        this.activeOutput.EnsureTable(this.tableDefinitions["Component"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["Directory"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["FeatureComponents"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["File"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["ModuleComponents"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["ModuleSignature"]);
                        break;
                    case OutputType.PatchCreation:
                        Table imageFamiliesTable = this.activeOutput.Tables["ImageFamilies"];
                        Table targetImagesTable = this.activeOutput.Tables["TargetImages"];
                        Table upgradedImagesTable = this.activeOutput.Tables["UpgradedImages"];

                        if (null == imageFamiliesTable || 1 > imageFamiliesTable.Rows.Count)
                        {
                            this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("ImageFamilies"));
                        }

                        if (null == targetImagesTable || 1 > targetImagesTable.Rows.Count)
                        {
                            this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("TargetImages"));
                        }

                        if (null == upgradedImagesTable || 1 > upgradedImagesTable.Rows.Count)
                        {
                            this.OnMessage(WixErrors.ExpectedRowInPatchCreationPackage("UpgradedImages"));
                        }

                        this.activeOutput.EnsureTable(this.tableDefinitions["Properties"]);
                        break;
                    case OutputType.Product:
                        this.activeOutput.EnsureTable(this.tableDefinitions["File"]);
                        this.activeOutput.EnsureTable(this.tableDefinitions["Media"]);
                        break;
                }

                this.CheckForIllegalTables(this.activeOutput);

                // add the custom row data
                foreach (Row row in customRows)
                {
                    TableDefinition customTableDefinition = (TableDefinition)customTableDefinitions[row[0].ToString()];
                    Table customTable = this.activeOutput.EnsureTable(customTableDefinition);
                    Row customRow = customTable.CreateRow(row.SourceLineNumbers);

                    customRow.SectionId = row.SectionId;

                    string[] data = row[1].ToString().Split(Common.CustomRowFieldSeparator);

                    for (int i = 0; i < data.Length; ++i)
                    {
                        bool foundColumn = false;
                        string[] item = data[i].Split(colonCharacter, 2);

                        for (int j = 0; j < customRow.Fields.Length; ++j)
                        {
                            if (customRow.Fields[j].Column.Name == item[0])
                            {
                                if (0 < item[1].Length)
                                {
                                    if (ColumnType.Number == customRow.Fields[j].Column.Type)
                                    {
                                        try
                                        {
                                            customRow.Fields[j].Data = Convert.ToInt32(item[1], CultureInfo.InvariantCulture);
                                        }
                                        catch (FormatException)
                                        {
                                            this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1]));
                                        }
                                        catch (OverflowException)
                                        {
                                            this.OnMessage(WixErrors.IllegalIntegerValue(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1]));
                                        }
                                    }
                                    else if (ColumnCategory.Identifier == customRow.Fields[j].Column.Category)
                                    {
                                        if (CompilerCore.IsIdentifier(item[1]) || Common.IsValidBinderVariable(item[1]) || ColumnCategory.Formatted == customRow.Fields[j].Column.Category)
                                        {
                                            customRow.Fields[j].Data = item[1];
                                        }
                                        else
                                        {
                                            this.OnMessage(WixErrors.IllegalIdentifier(row.SourceLineNumbers, "Data", item[1]));
                                        }
                                    }
                                    else
                                    {
                                        customRow.Fields[j].Data = item[1];
                                    }
                                }
                                foundColumn = true;
                                break;
                            }
                        }

                        if (!foundColumn)
                        {
                            this.OnMessage(WixErrors.UnexpectedCustomTableColumn(row.SourceLineNumbers, item[0]));
                        }
                    }

                    for (int i = 0; i < customTableDefinition.Columns.Count; ++i)
                    {
                        if (!customTableDefinition.Columns[i].IsNullable && (null == customRow.Fields[i].Data || 0 == customRow.Fields[i].Data.ToString().Length))
                        {
                            this.OnMessage(WixErrors.NoDataForColumn(row.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name));
                        }
                    }
                }

                //correct the section Id in FeatureComponents table
                if (this.sectionIdOnRows)
                {
                    Hashtable componentSectionIds = new Hashtable();
                    Table componentTable = output.Tables["Component"];

                    if (null != componentTable)
                    {
                        foreach (Row componentRow in componentTable.Rows)
                        {
                            componentSectionIds.Add(componentRow.Fields[0].Data.ToString(), componentRow.SectionId);
                        }
                    }

                    Table featureComponentsTable = output.Tables["FeatureComponents"];

                    if (null != featureComponentsTable)
                    {
                        foreach (Row featureComponentsRow in featureComponentsTable.Rows)
                        {
                            if (componentSectionIds.Contains(featureComponentsRow.Fields[1].Data.ToString()))
                            {
                                featureComponentsRow.SectionId = (string)componentSectionIds[featureComponentsRow.Fields[1].Data.ToString()];
                            }
                        }
                    }
                }

                // update the special properties
                if (0 < adminProperties.Count)
                {
                    Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]);

                    Row row = propertyTable.CreateRow(null);
                    row[0] = "AdminProperties";
                    row[1] = GetPropertyListString(adminProperties);
                }

                if (0 < secureProperties.Count)
                {
                    Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]);

                    Row row = propertyTable.CreateRow(null);
                    row[0] = "SecureCustomProperties";
                    row[1] = GetPropertyListString(secureProperties);
                }

                if (0 < hiddenProperties.Count)
                {
                    Table propertyTable = this.activeOutput.EnsureTable(this.tableDefinitions["Property"]);

                    Row row = propertyTable.CreateRow(null);
                    row[0] = "MsiHiddenProperties";
                    row[1] = GetPropertyListString(hiddenProperties);
                }

                // add the ModuleSubstitution table to the ModuleIgnoreTable
                if (containsModuleSubstitution)
                {
                    Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]);

                    Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null);
                    moduleIgnoreTableRow[0] = "ModuleSubstitution";
                }

                // add the ModuleConfiguration table to the ModuleIgnoreTable
                if (containsModuleConfiguration)
                {
                    Table moduleIgnoreTableTable = this.activeOutput.EnsureTable(this.tableDefinitions["ModuleIgnoreTable"]);

                    Row moduleIgnoreTableRow = moduleIgnoreTableTable.CreateRow(null);
                    moduleIgnoreTableRow[0] = "ModuleConfiguration";
                }

                // index all the file rows
                FileRowCollection indexedFileRows = new FileRowCollection();
                Table fileTable = this.activeOutput.Tables["File"];
                if (null != fileTable)
                {
                    indexedFileRows.AddRange(fileTable.Rows);
                }

                // flag all the generated short file name collisions
                foreach (string fileId in generatedShortFileNameIdentifiers)
                {
                    FileRow fileRow = indexedFileRows[fileId];

                    string[] names = fileRow.FileName.Split('|');
                    string shortFileName = names[0];

                    // create lists of conflicting generated short file names
                    if (!generatedShortFileNames.Contains(shortFileName))
                    {
                        generatedShortFileNames.Add(shortFileName, new ArrayList());
                    }
                    ((ArrayList)generatedShortFileNames[shortFileName]).Add(fileRow);
                }

                // check for generated short file name collisions
                foreach (DictionaryEntry entry in generatedShortFileNames)
                {
                    string shortFileName = (string)entry.Key;
                    ArrayList fileRows = (ArrayList)entry.Value;

                    if (1 < fileRows.Count)
                    {
                        // sort the rows by DiskId
                        fileRows.Sort();

                        this.OnMessage(WixWarnings.GeneratedShortFileNameConflict(((FileRow)fileRows[0]).SourceLineNumbers, shortFileName));

                        for (int i = 1; i < fileRows.Count; i++)
                        {
                            FileRow fileRow = (FileRow)fileRows[i];

                            if (null != fileRow.SourceLineNumbers)
                            {
                                this.OnMessage(WixWarnings.GeneratedShortFileNameConflict2(fileRow.SourceLineNumbers));
                            }
                        }
                    }
                }

                // copy the wix variable rows to the output after all overriding has been accounted for.
                if (0 < wixVariables.Count)
                {
                    Table wixVariableTable = output.EnsureTable(this.tableDefinitions["WixVariable"]);

                    foreach (WixVariableRow row in wixVariables.Values)
                    {
                        wixVariableTable.Rows.Add(row);
                    }
                }

                // Bundles have groups of data that must be flattened in a way different from other types.
                this.FlattenBundleTables(output);

                if (this.encounteredError)
                {
                    return null;
                }

                this.CheckOutputConsistency(output);

                // inspect the output
                InspectorCore inspectorCore = new InspectorCore(this.Message);
                foreach (InspectorExtension inspectorExtension in this.inspectorExtensions)
                {
                    inspectorExtension.Core = inspectorCore;
                    inspectorExtension.InspectOutput(output);

                    // reset
                    inspectorExtension.Core = null;
                }

                if (inspectorCore.EncounteredError)
                {
                    this.encounteredError = true;
                }
            }
            finally
            {
                this.activeOutput = null;
            }

            return (this.encounteredError ? null : output);
        }
예제 #20
0
        public Output BuildPairedTransform(string patchId, string clientPatchId, Output mainTransform, MediaRow mediaRow, int validationFlags, out string productCode)
        {
            productCode = null;
            Output pairedTransform = new Output(null);
            pairedTransform.Type = OutputType.Transform;
            pairedTransform.Codepage = mainTransform.Codepage;

            // lookup productVersion property to correct summaryInformation
            string newProductVersion = null;
            Table mainPropertyTable = mainTransform.Tables["Property"];
            if (null != mainPropertyTable)
            {
                foreach (Row row in mainPropertyTable.Rows)
                {
                    if ("ProductVersion" == (string)row[0])
                    {
                        newProductVersion = (string)row[1];
                    }
                }
            }

            // TODO: build class for manipulating SummaryInformation table
            Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"];
            // add required properties
            Hashtable mainSummaryRows = new Hashtable();
            foreach (Row mainSummaryRow in mainSummaryTable.Rows)
            {
                mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow;
            }
            if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
            {
                Row mainSummaryRow = mainSummaryTable.CreateRow(null);
                mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
                mainSummaryRow[1] = validationFlags.ToString(CultureInfo.InvariantCulture);
            }

            // copy summary information from core transform
            Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]);
            foreach (Row mainSummaryRow in mainSummaryTable.Rows)
            {
                string value = (string)mainSummaryRow[1];
                switch ((SummaryInformation.Transform)mainSummaryRow[0])
                {
                    case SummaryInformation.Transform.ProductCodes:
                        string[] propertyData = value.Split(';');
                        string oldProductVersion = propertyData[0].Substring(38);
                        string upgradeCode = propertyData[2];
                        productCode = propertyData[0].Substring(0, 38);
                        if (newProductVersion == null)
                        {
                            newProductVersion = oldProductVersion;
                        }

                        // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade
                        mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
                        value = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
                        break;
                    case SummaryInformation.Transform.ValidationFlags:
                        // use validation flags authored into the patch XML
                        mainSummaryRow[1] = value = validationFlags.ToString(CultureInfo.InvariantCulture);
                        break;
                }
                Row pairedSummaryRow = pairedSummaryTable.CreateRow(null);
                pairedSummaryRow[0] = mainSummaryRow[0];
                pairedSummaryRow[1] = value;
            }

            if (productCode == null)
            {
                throw new InvalidOperationException(WixStrings.EXP_CouldnotDetermineProductCodeFromTransformSummaryInfo);
            }

            // copy File table
            Table mainFileTable = mainTransform.Tables["File"];
            if (null != mainFileTable && 0 < mainFileTable.Rows.Count)
            {
                // We require file source information.
                Table mainWixFileTable = mainTransform.Tables["WixFile"];
                if (null == mainWixFileTable)
                {
                    throw new WixException(WixErrors.AdminImageRequired(productCode));
                }

                FileRowCollection mainFileRows = new FileRowCollection();
                mainFileRows.AddRange(mainFileTable.Rows);

                Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition);
                foreach (WixFileRow mainWixFileRow in mainWixFileTable.Rows)
                {
                    FileRow mainFileRow = mainFileRows[mainWixFileRow.File];

                    // set File.Sequence to non null to satisfy transform bind
                    mainFileRow.Sequence = 1;

                    // delete's don't need rows in the paired transform
                    if (mainFileRow.Operation == RowOperation.Delete)
                    {
                        continue;
                    }

                    FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null);
                    pairedFileRow.Operation = RowOperation.Modify;
                    for (int i = 0; i < mainFileRow.Fields.Length; i++)
                    {
                        pairedFileRow[i] = mainFileRow[i];
                    }

                    // override authored media for patch bind
                    // TODO: consider using File/@DiskId for patch media
                    mainFileRow.DiskId = mediaRow.DiskId;
                    mainWixFileRow.DiskId = mediaRow.DiskId;
                    // suppress any change to File.Sequence to avoid bloat
                    mainFileRow.Fields[7].Modified = false;

                    // force File row to appear in the transform
                    switch (mainFileRow.Operation)
                    {
                        case RowOperation.Modify:
                        case RowOperation.Add:
                            // set msidbFileAttributesPatchAdded
                            pairedFileRow.Attributes |= MsiInterop.MsidbFileAttributesPatchAdded;
                            pairedFileRow.Fields[6].Modified = true;
                            pairedFileRow.Operation = mainFileRow.Operation;
                            break;
                        default:
                            pairedFileRow.Fields[6].Modified = false;
                            break;
                    }
                }
            }

            // add Media row to pairedTransform
            Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]);
            Row pairedMediaRow = pairedMediaTable.CreateRow(null);
            pairedMediaRow.Operation = RowOperation.Add;
            for (int i = 0; i < mediaRow.Fields.Length; i++)
            {
                pairedMediaRow[i] = mediaRow[i];
            }

            // add PatchPackage for this Media
            Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]);
            pairedPackageTable.Operation = TableOperation.Add;
            Row pairedPackageRow = pairedPackageTable.CreateRow(null);
            pairedPackageRow.Operation = RowOperation.Add;
            pairedPackageRow[0] = patchId;
            pairedPackageRow[1] = mediaRow.DiskId;

            // add property to both identify client patches and whether those patches are removable or not
            int allowRemoval = 0;
            Table msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"];
            if (null != msiPatchMetadataTable)
            {
                foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows)
                {
                    // get the value of the standard AllowRemoval property, if present
                    string company = (string)msiPatchMetadataRow[0];
                    if ((null == company || 0 == company.Length) && "AllowRemoval" == (string)msiPatchMetadataRow[1])
                    {
                        allowRemoval = Int32.Parse((string)msiPatchMetadataRow[2], CultureInfo.InvariantCulture);
                    }
                }
            }

            // add the property to the patch transform's Property table
            Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]);
            pairedPropertyTable.Operation = TableOperation.Add;
            Row pairedPropertyRow = pairedPropertyTable.CreateRow(null);
            pairedPropertyRow.Operation = RowOperation.Add;
            pairedPropertyRow[0] = string.Concat(clientPatchId, ".AllowRemoval");
            pairedPropertyRow[1] = allowRemoval.ToString(CultureInfo.InvariantCulture);

            // add this patch code GUID to the patch transform to identify
            // which patches are installed, including in multi-patch
            // installations.
            pairedPropertyRow = pairedPropertyTable.CreateRow(null);
            pairedPropertyRow.Operation = RowOperation.Add;
            pairedPropertyRow[0] = string.Concat(clientPatchId, ".PatchCode");
            pairedPropertyRow[1] = patchId;

            // add PATCHNEWPACKAGECODE to apply to admin layouts
            pairedPropertyRow = pairedPropertyTable.CreateRow(null);
            pairedPropertyRow.Operation = RowOperation.Add;
            pairedPropertyRow[0] = "PATCHNEWPACKAGECODE";
            pairedPropertyRow[1] = patchId;

            // add PATCHNEWSUMMARYCOMMENTS and PATCHNEWSUMMARYSUBJECT to apply to admin layouts
            Table _summaryInformationTable = this.patch.Tables["_SummaryInformation"];
            if (null != _summaryInformationTable)
            {
                foreach (Row row in _summaryInformationTable.Rows)
                {
                    if (3 == (int)row[0]) // PID_SUBJECT
                    {
                        pairedPropertyRow = pairedPropertyTable.CreateRow(null);
                        pairedPropertyRow.Operation = RowOperation.Add;
                        pairedPropertyRow[0] = "PATCHNEWSUMMARYSUBJECT";
                        pairedPropertyRow[1] = row[1];
                    }
                    else if (6 == (int)row[0]) // PID_COMMENTS
                    {
                        pairedPropertyRow = pairedPropertyTable.CreateRow(null);
                        pairedPropertyRow.Operation = RowOperation.Add;
                        pairedPropertyRow[0] = "PATCHNEWSUMMARYCOMMENTS";
                        pairedPropertyRow[1] = row[1];
                    }
                }
            }

            return pairedTransform;
        }
예제 #21
0
        /// <summary>
        /// Assign files to cabinets based on Media authoring.
        /// </summary>
        /// <param name="mediaTable"></param>
        /// <param name="mergeModuleMediaRow"></param>
        /// <param name="fileRows"></param>
        private void ManuallyAssignFiles(Table mediaTable, MediaRow mergeModuleMediaRow, FileRowCollection fileRows)
        {
            if (OutputType.Module != this.output.Type)
            {
                if (null != mediaTable)
                {
                    Dictionary <string, MediaRow> cabinetMediaRows = new Dictionary <string, MediaRow>(StringComparer.InvariantCultureIgnoreCase);
                    foreach (MediaRow mediaRow in mediaTable.Rows)
                    {
                        // If the Media row has a cabinet, make sure it is unique across all Media rows.
                        if (!String.IsNullOrEmpty(mediaRow.Cabinet))
                        {
                            MediaRow existingRow;
                            if (cabinetMediaRows.TryGetValue(mediaRow.Cabinet, out existingRow))
                            {
                                this.core.OnMessage(WixErrors.DuplicateCabinetName(mediaRow.SourceLineNumbers, mediaRow.Cabinet));
                                this.core.OnMessage(WixErrors.DuplicateCabinetName2(existingRow.SourceLineNumbers, existingRow.Cabinet));
                            }
                            else
                            {
                                cabinetMediaRows.Add(mediaRow.Cabinet, mediaRow);
                            }
                        }

                        this.mediaRows.Add(mediaRow);
                    }
                }

                foreach (MediaRow mediaRow in this.mediaRows)
                {
                    if (null != mediaRow.Cabinet)
                    {
                        this.cabinets.Add(mediaRow, new FileRowCollection());
                    }
                }
            }

            foreach (FileRow fileRow in fileRows)
            {
                if (OutputType.Module == output.Type)
                {
                    ((FileRowCollection)this.cabinets[mergeModuleMediaRow]).Add(fileRow);
                }
                else
                {
                    MediaRow mediaRow = this.mediaRows[fileRow.DiskId];

                    if (null == mediaRow)
                    {
                        this.core.OnMessage(WixErrors.MissingMedia(fileRow.SourceLineNumbers, fileRow.DiskId));
                        continue;
                    }

                    // When building a product, if the current file is not to be compressed or if
                    // the package set not to be compressed, don't cab it.
                    if (OutputType.Product == output.Type &&
                        (YesNoType.No == fileRow.Compressed ||
                         (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed)))
                    {
                        uncompressedFileRows.Add(fileRow);
                    }
                    else // file in a Module or marked compressed
                    {
                        FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[mediaRow];

                        if (null != cabinetFileRow)
                        {
                            cabinetFileRow.Add(fileRow);
                        }
                        else
                        {
                            this.core.OnMessage(WixErrors.ExpectedMediaCabinet(fileRow.SourceLineNumbers, fileRow.File, fileRow.DiskId));
                        }
                    }
                }
            }
        }
예제 #22
0
        /// <summary>
        /// Create the #transform for the given main transform.
        /// </summary>
        /// <param name="patchId">patch GUID from patch authoring.</param>
        /// <param name="mainTransform">transform generated by torch.</param>
        /// <param name="mediaRow">media authored into patch.</param>
        /// <param name="productCode">output string to receive ProductCode.</param>
        public Output BuildPairedTransform(string patchId, Output mainTransform, MediaRow mediaRow, ref string productCode)
        {
            Output pairedTransform = new Output(null);

            pairedTransform.Type     = OutputType.Transform;
            pairedTransform.Codepage = mainTransform.Codepage;

            // lookup productVersion property to correct summaryInformation
            string newProductVersion = null;
            Table  mainPropertyTable = mainTransform.Tables["Property"];

            if (mainPropertyTable != null)
            {
                foreach (Row row in mainPropertyTable.Rows)
                {
                    if ("ProductVersion" == (string)row[0])
                    {
                        newProductVersion = (string)row[1];
                    }
                }
            }

            // TODO: build class for manipulating SummaryInformation table
            Table mainSummaryTable = mainTransform.Tables["_SummaryInformation"];
            // add required properties
            Hashtable mainSummaryRows = new Hashtable();

            foreach (Row mainSummaryRow in mainSummaryTable.Rows)
            {
                mainSummaryRows[mainSummaryRow[0]] = mainSummaryRow;
            }
            if (!mainSummaryRows.Contains((int)SummaryInformation.Transform.ValidationFlags))
            {
                Row mainSummaryRow = mainSummaryTable.CreateRow(null);
                mainSummaryRow[0] = (int)SummaryInformation.Transform.ValidationFlags;
                mainSummaryRow[1] = "0";
            }

            // copy summary information from core transform
            Table pairedSummaryTable = pairedTransform.EnsureTable(this.tableDefinitions["_SummaryInformation"]);

            foreach (Row mainSummaryRow in mainSummaryTable.Rows)
            {
                string value = (string)mainSummaryRow[1];
                switch ((SummaryInformation.Transform)mainSummaryRow[0])
                {
                case SummaryInformation.Transform.ProductCodes:
                    string[] propertyData      = value.Split(';');
                    string   oldProductVersion = propertyData[0].Substring(38);
                    string   upgradeCode       = propertyData[2];
                    productCode = propertyData[0].Substring(0, 38);
                    if (newProductVersion == null)
                    {
                        newProductVersion = oldProductVersion;
                    }

                    // force mainTranform to old;new;upgrade and pairedTransform to new;new;upgrade
                    mainSummaryRow[1] = String.Concat(productCode, oldProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
                    value             = String.Concat(productCode, newProductVersion, ';', productCode, newProductVersion, ';', upgradeCode);
                    break;

                case SummaryInformation.Transform.ValidationFlags:
                    // TODO: ensure this row exists in mainSummaryTable!!!!
                    // TODO: author these settings in patch XML or set in torch.exe
                    int i = Convert.ToInt32(value);
                    i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingRow;
                    i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingRow;
                    i |= (int)SummaryInformation.TransformFlags.ErrorAddExistingTable;
                    i |= (int)SummaryInformation.TransformFlags.ErrorDeleteMissingTable;
                    i |= (int)SummaryInformation.TransformFlags.ErrorUpdateMissingRow;
                    i |= (int)SummaryInformation.TransformFlags.ValidateProduct;
                    mainSummaryRow[1] = value = i.ToString();
                    break;
                }
                Row pairedSummaryRow = pairedSummaryTable.CreateRow(null);
                pairedSummaryRow[0] = mainSummaryRow[0];
                pairedSummaryRow[1] = value;
            }

            if (productCode == null)
            {
                throw new InvalidOperationException("Could not determine ProductCode from transform summary information");
            }

            // copy File table
            Table mainFileTable    = mainTransform.Tables["File"];
            Table mainWixFileTable = mainTransform.Tables["WixFile"];

            if (mainFileTable != null)
            {
                FileRowCollection mainFileRows = new FileRowCollection();
                mainFileRows.AddRange(mainFileTable.Rows);

                Table pairedFileTable = pairedTransform.EnsureTable(mainFileTable.Definition);
                foreach (Row mainWixFileRow in mainWixFileTable.Rows)
                {
                    FileRow mainFileRow = mainFileRows[(string)mainWixFileRow[0]];

                    // set File.Sequence to non null to satisfy transform bind
                    mainFileRow.Sequence = 1;

                    // delete's don't need rows in the paired transform
                    if (mainFileRow.Operation == RowOperation.Delete)
                    {
                        continue;
                    }

                    FileRow pairedFileRow = (FileRow)pairedFileTable.CreateRow(null);
                    pairedFileRow.Operation = RowOperation.Modify;
                    for (int i = 0; i < mainFileRow.Fields.Length; i++)
                    {
                        object value = mainFileRow[i];
                        pairedFileRow[i] = value;
                    }

                    // override authored media for patch bind
                    // TODO: consider using File/@DiskId for patch media
                    mainFileRow.DiskId = mediaRow.DiskId;
                    mainWixFileRow[5]  = mediaRow.DiskId;
                    // suppress any change to File.Sequence to avoid bloat
                    mainFileRow.Fields[7].Modified = false;

                    // force File row to appear in the transform
                    if (RowOperation.Modify == mainFileRow.Operation)
                    {
                        mainFileRow.Operation            = RowOperation.Modify;
                        pairedFileRow.Attributes        |= MsiInterop.MsidbFileAttributesPatchAdded;
                        pairedFileRow.Fields[6].Modified = true;
                        pairedFileRow.Operation          = RowOperation.Modify;
                    }
                    else if (RowOperation.Add == mainFileRow.Operation)
                    {
                        // set msidbFileAttributesPatchAdded
                        pairedFileRow.Attributes        |= MsiInterop.MsidbFileAttributesPatchAdded;
                        pairedFileRow.Fields[6].Modified = true;
                        pairedFileRow.Operation          = RowOperation.Add;
                    }
                    else
                    {
                        pairedFileRow.Attributes         = mainFileRow.Attributes;
                        pairedFileRow.Fields[6].Modified = false;
                    }
                }
            }

            // add Media row to pairedTransform
            Table pairedMediaTable = pairedTransform.EnsureTable(this.tableDefinitions["Media"]);
            Row   pairedMediaRow   = pairedMediaTable.CreateRow(null);

            pairedMediaRow.Operation = RowOperation.Add;
            for (int i = 0; i < mediaRow.Fields.Length; i++)
            {
                pairedMediaRow[i] = mediaRow[i];
            }

            // add PatchPackage for this Media
            Table pairedPackageTable = pairedTransform.EnsureTable(this.tableDefinitions["PatchPackage"]);

            pairedPackageTable.Operation = TableOperation.Add;
            Row pairedPackageRow = pairedPackageTable.CreateRow(null);

            pairedPackageRow.Operation = RowOperation.Add;
            pairedPackageRow[0]        = patchId;
            pairedPackageRow[1]        = mediaRow.DiskId;

            // add property to both identify client patches and whether those patches are removable or not
            string patchPropertyId       = new Guid(patchId).ToString("N", CultureInfo.InvariantCulture).ToUpper();
            int    allowRemoval          = 0;
            Table  msiPatchMetadataTable = this.patch.Tables["MsiPatchMetadata"];

            if (null != msiPatchMetadataTable)
            {
                foreach (Row msiPatchMetadataRow in msiPatchMetadataTable.Rows)
                {
                    if (string.Empty == (string)msiPatchMetadataRow[0] && "AllowRemoval" == (string)msiPatchMetadataRow[1])
                    {
                        allowRemoval = Convert.ToInt32((string)msiPatchMetadataRow[2]);
                    }
                }
            }
            Table pairedPropertyTable = pairedTransform.EnsureTable(this.tableDefinitions["Property"]);

            pairedPropertyTable.Operation = TableOperation.Add;
            Row pairedPropertyRow = pairedPropertyTable.CreateRow(null);

            pairedPropertyRow.Operation = RowOperation.Add;
            pairedPropertyRow[0]        = string.Format(CultureInfo.InvariantCulture, "_{0}.AllowRemoval", patchPropertyId);
            pairedPropertyRow[1]        = allowRemoval.ToString();

            return(pairedTransform);
        }
예제 #23
0
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Creates cabinet files.
        /// </summary>
        /// <param name="output">Output to generate image for.</param>
        /// <param name="fileRows">The indexed file rows.</param>
        /// <param name="fileTransfers">Array of files to be transfered.</param>
        /// <param name="mediaRows">The indexed media rows.</param>
        /// <param name="layoutDirectory">The directory in which the image should be layed out.</param>
        /// <param name="compressed">Flag if source image should be compressed.</param>
        /// <returns>The uncompressed file rows.</returns>
        private FileRowCollection CreateCabinetFiles(Output output, FileRowCollection fileRows, ArrayList fileTransfers, MediaRowCollection mediaRows, string layoutDirectory, bool compressed, AutoMediaAssigner autoMediaAssigner)
        {
            this.SetCabbingThreadCount();

            // Send Binder object to Facilitate NewCabNamesCallBack Callback
            CabinetBuilder cabinetBuilder = new CabinetBuilder(this.cabbingThreadCount, Marshal.GetFunctionPointerForDelegate(this.newCabNamesCallBack));

            // Supply Compile MediaTemplate Attributes to Cabinet Builder
            int MaximumCabinetSizeForLargeFileSplitting;
            int MaximumUncompressedMediaSize;
            this.GetMediaTemplateAttributes(out MaximumCabinetSizeForLargeFileSplitting, out MaximumUncompressedMediaSize);
            cabinetBuilder.MaximumCabinetSizeForLargeFileSplitting = MaximumCabinetSizeForLargeFileSplitting;
            cabinetBuilder.MaximumUncompressedMediaSize = MaximumUncompressedMediaSize;

            if (null != this.MessageHandler)
            {
                cabinetBuilder.Message += new MessageEventHandler(this.MessageHandler);
            }

            foreach (DictionaryEntry entry in autoMediaAssigner.Cabinets)
            {
                MediaRow mediaRow = (MediaRow)entry.Key;
                FileRowCollection files = (FileRowCollection)entry.Value;

                string cabinetDir = this.FileManager.ResolveMedia(mediaRow, layoutDirectory);

                CabinetWorkItem cabinetWorkItem = this.CreateCabinetWorkItem(output, cabinetDir, mediaRow, files, fileTransfers);
                if (null != cabinetWorkItem)
                {
                    cabinetBuilder.Enqueue(cabinetWorkItem);
                }
            }

            // stop processing if an error previously occurred
            if (this.core.EncounteredError)
            {
                return null;
            }

            // create queued cabinets with multiple threads
            int cabError = cabinetBuilder.CreateQueuedCabinets();
            if (0 != cabError)
            {
                this.core.EncounteredError = true;
                return null;
            }

            return autoMediaAssigner.UncompressedFileRows;
        }
예제 #24
0
        /// <summary>
        /// Assigne files to cabinets based on MediaTemplate authoring.
        /// </summary>
        /// <param name="fileRows">FileRowCollection</param>
        private void AutoAssignFiles(Table mediaTable, FileRowCollection fileRows)
        {
            const int MaxCabIndex = 999;

            ulong currentPreCabSize = 0;
            ulong maxPreCabSizeInBytes;
            int maxPreCabSizeInMB = 0;
            int currentCabIndex = 0;

            MediaRow currentMediaRow = null;

            Table mediaTemplateTable = this.output.Tables["WixMediaTemplate"];

            // Auto assign files to cabinets based on maximum uncompressed media size
            mediaTable.Rows.Clear();
            WixMediaTemplateRow mediaTemplateRow = (WixMediaTemplateRow)mediaTemplateTable.Rows[0];

            if (!String.IsNullOrEmpty(mediaTemplateRow.CabinetTemplate))
            {
                this.cabinetNameTemplate = mediaTemplateRow.CabinetTemplate;
            }

            string mumsString = Environment.GetEnvironmentVariable("WIX_MUMS");

            try
            {
                // Override authored mums value if environment variable is authored.
                if (!String.IsNullOrEmpty(mumsString))
                {
                    maxPreCabSizeInMB = Int32.Parse(mumsString);
                }
                else
                {
                    maxPreCabSizeInMB = mediaTemplateRow.MaximumUncompressedMediaSize;
                }

                maxPreCabSizeInBytes = (ulong)maxPreCabSizeInMB * 1024 * 1024;
            }
            catch (FormatException)
            {
                throw new WixException(WixErrors.IllegalEnvironmentVariable("WIX_MUMS", mumsString));
            }
            catch (OverflowException)
            {
                throw new WixException(WixErrors.MaximumUncompressedMediaSizeTooLarge(null, maxPreCabSizeInMB));
            }

            foreach (FileRow fileRow in fileRows)
            {
                // When building a product, if the current file is not to be compressed or if 
                // the package set not to be compressed, don't cab it.
                if (OutputType.Product == output.Type &&
                    (YesNoType.No == fileRow.Compressed ||
                    (YesNoType.NotSet == fileRow.Compressed && !this.filesCompressed)))
                {
                    uncompressedFileRows.Add(fileRow);
                    continue;
                }

                FileInfo fileInfo = null;

                // Get the file size
                try
                {
                    fileInfo = new FileInfo(fileRow.Source);
                }
                catch (ArgumentException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (PathTooLongException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }
                catch (NotSupportedException)
                {
                    this.core.OnMessage(WixErrors.InvalidFileName(fileRow.SourceLineNumbers, fileRow.Source));
                }

                if (fileInfo.Exists)
                {
                    if (fileInfo.Length > Int32.MaxValue)
                    {
                        throw new WixException(WixErrors.FileTooLarge(fileRow.SourceLineNumbers, fileRow.Source));
                    }

                    fileRow.FileSize = Convert.ToInt32(fileInfo.Length, CultureInfo.InvariantCulture);
                }

                if (currentCabIndex == MaxCabIndex)
                {
                    // Associate current file with last cab (irrespective of the size) and cab index is not incremented anymore.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                    continue;
                }

                // Update current cab size.
                currentPreCabSize += (ulong)fileRow.FileSize;

                if (currentPreCabSize > maxPreCabSizeInBytes)
                {
                    // Overflow due to current file
                    if (currentPreCabSize == (ulong)fileRow.FileSize)
                    {
                        // Only one file in this cab.
                        currentMediaRow = AddMediaRow(mediaTable, ++currentCabIndex);

                        FileRowCollection cabinetFileRow = (FileRowCollection)cabinets[currentMediaRow];
                        fileRow.DiskId = currentCabIndex;
                        cabinetFileRow.Add(fileRow);
                        currentPreCabSize = 0;
                    }
                    else
                    {
                        currentMediaRow = this.AddMediaRow(mediaTable, ++currentCabIndex);

                        // Finish current media row and create new one.
                        FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                        fileRow.DiskId = currentCabIndex;
                        cabinetFileRow.Add(fileRow);
                        currentPreCabSize = (ulong)fileRow.FileSize;
                    }
                }
                else
                {
                    // File fits in the current cab.
                    if (currentMediaRow == null)
                    {
                        // Create new cab and MediaRow
                        currentMediaRow = AddMediaRow(mediaTable, ++currentCabIndex);
                    }

                    // Associate current file with current cab.
                    FileRowCollection cabinetFileRow = (FileRowCollection)this.cabinets[currentMediaRow];
                    fileRow.DiskId = currentCabIndex;
                    cabinetFileRow.Add(fileRow);
                }
            }

            // If there are uncompressed files and no MediaRow, create a default one.
            if (uncompressedFileRows.Count > 0 && mediaTable.Rows.Count == 0 )
            {
                 MediaRow defaultMediaRow = (MediaRow)mediaTable.CreateRow(null);
                 defaultMediaRow.DiskId = 1;
                 mediaRows.Add(defaultMediaRow);
            }
        }
예제 #25
0
파일: Binder.cs 프로젝트: zooba/wix3
        /// <summary>
        /// Creates a work item to create a cabinet.
        /// </summary>
        /// <param name="output">Output for the current database.</param>
        /// <param name="cabinetDir">Directory to create cabinet in.</param>
        /// <param name="mediaRow">MediaRow containing information about the cabinet.</param>
        /// <param name="fileRows">Collection of files in this cabinet.</param>
        /// <param name="fileTransfers">Array of files to be transfered.</param>
        /// <returns>created CabinetWorkItem object</returns>
        private CabinetWorkItem CreateCabinetWorkItem(Output output, string cabinetDir, MediaRow mediaRow, FileRowCollection fileRows, ArrayList fileTransfers)
        {
            CabinetWorkItem cabinetWorkItem = null;
            string tempCabinetFile = Path.Combine(this.TempFilesLocation, mediaRow.Cabinet);

            // check for an empty cabinet
            if (0 == fileRows.Count)
            {
                string cabinetName = mediaRow.Cabinet;

                // remove the leading '#' from the embedded cabinet name to make the warning easier to understand
                if (cabinetName.StartsWith("#", StringComparison.Ordinal))
                {
                    cabinetName = cabinetName.Substring(1);
                }

                // If building a patch, remind them to run -p for torch.
                if (OutputType.Patch == output.Type)
                {
                    this.core.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName, true));
                }
                else
                {
                    this.core.OnMessage(WixWarnings.EmptyCabinet(mediaRow.SourceLineNumbers, cabinetName));
                }
            }

            CabinetBuildOption cabinetBuildOption = this.FileManager.ResolveCabinet(fileRows, ref tempCabinetFile);

            // create a cabinet work item if it's not being skipped
            if (CabinetBuildOption.BuildAndCopy == cabinetBuildOption || CabinetBuildOption.BuildAndMove == cabinetBuildOption)
            {
                int maxThreshold = 0; // default to the threshold for best smartcabbing (makes smallest cabinet).
                Cab.CompressionLevel compressionLevel = this.defaultCompressionLevel;

                if (mediaRow.HasExplicitCompressionLevel)
                {
                    compressionLevel = mediaRow.CompressionLevel;
                }

                cabinetWorkItem = new CabinetWorkItem(fileRows, tempCabinetFile, maxThreshold, compressionLevel, this.FileManager);
            }
            else // reuse the cabinet from the cabinet cache.
            {
                this.core.OnMessage(WixVerboses.ReusingCabCache(mediaRow.SourceLineNumbers, mediaRow.Cabinet, tempCabinetFile));

                try
                {
                    // Ensure the cached cabinet timestamp is current to prevent perpetual incremental builds. The
                    // problematic scenario goes like this. Imagine two cabinets in the cache. Update a file that
                    // goes into one of the cabinets. One cabinet will get rebuilt, the other will be copied from
                    // the cache. Now the file (an input) has a newer timestamp than the reused cabient (an output)
                    // causing the project to look like it perpetually needs a rebuild until all of the reused
                    // cabinets get newer timestamps.
                    File.SetLastWriteTime(tempCabinetFile, DateTime.Now);
                }
                catch (Exception e)
                {
                    this.core.OnMessage(WixWarnings.CannotUpdateCabCache(mediaRow.SourceLineNumbers, tempCabinetFile, e.Message));
                }
            }

            if (mediaRow.Cabinet.StartsWith("#", StringComparison.Ordinal))
            {
                Table streamsTable = output.EnsureTable(this.core.TableDefinitions["_Streams"]);

                Row streamRow = streamsTable.CreateRow(null);
                streamRow[0] = mediaRow.Cabinet.Substring(1);
                streamRow[1] = tempCabinetFile;
            }
            else
            {
                string destinationPath = Path.Combine(cabinetDir, mediaRow.Cabinet);
                FileTransfer transfer;
                if (FileTransfer.TryCreate(tempCabinetFile, destinationPath, CabinetBuildOption.BuildAndMove == cabinetBuildOption, "Cabinet", mediaRow.SourceLineNumbers, out transfer))
                {
                    transfer.Built = true;
                    fileTransfers.Add(transfer);
                }
            }

            return cabinetWorkItem;
        }
예제 #26
0
        /// <summary>
        /// Resolves the source path of a cabinet file.
        /// </summary>
        /// <param name="fileRows">Collection of files in this cabinet.</param>
        /// <param name="cabinetPath">Path to cabinet to generate.  Path may be modified by delegate.</param>
        /// <returns>The CabinetBuildOption.  By default the cabinet is built and moved to its target location.</returns>
        public virtual CabinetBuildOption ResolveCabinet(FileRowCollection fileRows, ref string cabinetPath)
        {
            // no special behavior specified, use the default
            if (null == this.cabCachePath && !this.reuseCabinets)
            {
                return(CabinetBuildOption.BuildAndMove);
            }

            // if a cabinet cache path was provided, change the location for the cabinet
            // to be built to
            if (null != this.cabCachePath)
            {
                string cabinetName = Path.GetFileName(cabinetPath);
                cabinetPath = Path.Combine(this.cabCachePath, cabinetName);
            }

            // if we still think we're going to reuse the cabinet check to see if the cabinet exists first
            if (this.reuseCabinets)
            {
                bool cabinetExists = false;

                if (File.Exists(cabinetPath))
                {
                    // check to see if
                    // 1. any files are added or removed
                    // 2. order of files changed or names changed
                    // 3. modified time changed
                    cabinetExists = true;

                    Cab.WixEnumerateCab wixEnumerateCab = new Cab.WixEnumerateCab();
                    ArrayList           fileList        = wixEnumerateCab.Enumerate(cabinetPath);

                    if (fileRows.Count != fileList.Count)
                    {
                        cabinetExists = false;
                    }
                    else
                    {
                        int i = 0;
                        foreach (FileRow fileRow in fileRows)
                        {
                            CabinetFileInfo fileInfo = fileList[i] as CabinetFileInfo;
                            DateTime        fileTime = File.GetLastWriteTime(fileRow.Source);

                            ushort cabDate;
                            ushort cabTime;
                            Cab.Interop.CabInterop.DateTimeToCabDateAndTime(fileTime, out cabDate, out cabTime);
                            if (fileRow.File != fileInfo.FileId || fileInfo.Date != cabDate || fileInfo.Time != cabTime)
                            {
                                cabinetExists = false;
                                break;
                            }
                            i++;
                        }
                    }
                }

                return(cabinetExists ? CabinetBuildOption.Copy : CabinetBuildOption.BuildAndCopy);
            }
            else // by default move the built cabinet
            {
                return(CabinetBuildOption.BuildAndMove);
            }
        }