Example #1
1
File: Binder.cs Project: 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();
            }
        }
Example #2
0
            // This code configures Web API. The Startup class is specified as a type
            // parameter in the WebApp.Start method.
            public void Configuration(IAppBuilder appBuilder)
            {
                // Configure Web API for self-host.
                HttpConfiguration config = new HttpConfiguration();

                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/v{version}/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                    );
                config.Services.Replace(typeof(IHttpControllerSelector), new VersionedApiControllerSelector(config));
                config.DependencyResolver = new DependencyResolver();

                if (ConfigurationCallback != null)
                {
                    ConfigurationCallback.Invoke(config);
                }

                DependencyContainer.Register((c, np) => new DefaultControllerIdentificationDetector(config));
                DependencyContainer.Register((c, np) => new DefaultRequestControllerIdentificationDetector(config));

                appBuilder.UseWebApi(config);
            }
Example #3
0
        /// <summary>
        /// Merges in any modules to the output database.
        /// </summary>
        /// <param name="databasePath">Path to database.</param>
        /// <param name="output">Output that specifies database and modules to merge.</param>
        /// <remarks>Expects that output's database has already been generated.</remarks>
        private void MergeModules(string databasePath, Output output)
        {
            Debug.Assert(OutputType.Product == output.Type);

            if (0 == output.Modules.Count)   // no work to do
            {
                return;
            }

            IMsmMerge2 merge = null;
            bool commit = false;
            bool logOpen = false;
            bool databaseOpen = false;
            bool moduleOpen = false;
            try
            {
                bool foundError = false;
                MsmMerge msm = new MsmMerge();
                merge = (IMsmMerge2)msm;

                merge.OpenLog(String.Concat(this.tempFiles.BasePath, Path.DirectorySeparatorChar, "merge.log"));
                logOpen = true;

                merge.OpenDatabase(databasePath);
                databaseOpen = true;

                // process all the merge rows
                foreach (MergeRow mergeRow in output.Modules)
                {
                    string mergeModulePath = null;
                    try
                    {
                        mergeModulePath = this.extension.FileResolutionHandler(mergeRow.SourceFile, FileResolutionType.Module);
                    }
                    catch (WixFileNotFoundException wfnfe)
                    {
                        this.OnMessage(WixErrors.BinderExtensionMissingFile(mergeRow.SourceLineNumbers, ErrorLevel.Normal, wfnfe.Message));
                        foundError = true;
                        continue;
                    }

                    try
                    {
                        merge.OpenModule(mergeModulePath, mergeRow.Language);
                    }
                    catch (COMException ce)
                    {
                        if (-2147023273 == ce.ErrorCode) // 0x80070657 - ERROR_INSTALL_LANGUAGE_UNSUPPORTED
                        {
                            throw new WixUnknownMergeLanguageException(mergeRow.SourceLineNumbers, mergeRow.Id, mergeModulePath, mergeRow.Language, ce);
                        }
                        else
                        {
                            throw;
                        }
                    }
                    moduleOpen = true;

                    ConnectToFeature connection = output.ModulesToFeatures[mergeRow.Id];
                    if (null == connection)
                    {
                        throw new WixMergeModuleMissingFeatureException(mergeRow.SourceLineNumbers, mergeRow.Id);
                    }

                    string configData = mergeRow.ConfigurationData;
                    if (null != configData)
                    {
                        ConfigurationCallback callback = new ConfigurationCallback(configData);
                        merge.MergeEx(connection.PrimaryFeature, mergeRow.Directory, callback);
                    }
                    else
                    {
                        merge.Merge(connection.PrimaryFeature, mergeRow.Directory);
                    }

                    /*
                    IMsmErrors errorCollection = null;
                    merge.get_Errors(out errorCollection);
                    long count = errorCollection.get_Count();

                    if (0 < count)
                    {

                        throw new WixMergeFailureException(null, this.tempFiles.BasePath, count, null);
                    }
                    */

                    foreach (string connectTo in connection.ConnectFeatures)
                    {
                        merge.Connect(connectTo);
                    }

                    // if the module has files and creating layout
                    if (mergeRow.HasFiles && !this.suppressLayout)
                    {
                        string hashedMergeId = mergeRow.Id.GetHashCode().ToString("X4", CultureInfo.InvariantCulture.NumberFormat);

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

                        string mergeIdPath = String.Concat(this.tempFiles.BasePath, Path.DirectorySeparatorChar, "MergeId.", hashedMergeId);
                        Directory.CreateDirectory(mergeIdPath);

                        WixExtractCab extCab = null;
                        try
                        {
                            extCab = new WixExtractCab();
                            extCab.Extract(moduleCabPath, mergeIdPath);
                        }
                        catch (WixCabExtractionException wce)
                        {
                            COMException comException = wce.InnerException as COMException;
                            foundError = true;
                            if (null != comException && 0x80070002 == unchecked((uint)comException.ErrorCode))
                            {
                                extCab = null; // Cab doesn't exist, so drop the object.
                                this.OnMessage(WixErrors.CabFileDoesNotExist(moduleCabPath, mergeModulePath, mergeIdPath));
                            }
                            else
                            {
                                this.OnMessage(WixErrors.CabExtractionFailed(moduleCabPath, mergeModulePath, mergeIdPath));
                            }
                        }
                        finally
                        {
                            if (null != extCab)
                            {
                                try
                                {
                                    extCab.Close();
                                }
                                catch (WixCabExtractionException)
                                {
                                    this.OnMessage(WixErrors.CabClosureFailed(moduleCabPath));
                                }
                            }
                        }
                    }

                    moduleOpen = false;
                    merge.CloseModule();
                }

                commit = !foundError; // if all seems to have progressed cleanly, feel free to commit the changes to the database
            }
            finally
            {
                if (moduleOpen)
                {
                    merge.CloseModule();
                }
                if (databaseOpen)
                {
                    merge.CloseDatabase(commit);
                }
                if (logOpen)
                {
                    merge.CloseLog();
                }
            }

            // create a Hashtable of all the suppressed sequence types
            Hashtable suppressedTableNames = new Hashtable();
            if (output.SuppressAdminSequence)
            {
                suppressedTableNames[Action.SequenceTypeToString(SequenceType.adminExecute)] = null;
                suppressedTableNames[Action.SequenceTypeToString(SequenceType.adminUI)] = null;
            }
            if (output.SuppressAdvertiseSequence)
            {
                suppressedTableNames[Action.SequenceTypeToString(SequenceType.advertiseExecute)] = null;
            }
            if (output.SuppressUISequence)
            {
                suppressedTableNames[Action.SequenceTypeToString(SequenceType.adminUI)] = null;
                suppressedTableNames[Action.SequenceTypeToString(SequenceType.installUI)] = null;
            }

            using (Database db = new Database(databasePath, OpenDatabase.Direct))
            {
                OutputTable suppressActionOutputTable = output.OutputTables["SuppressAction"];

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

                            using (View view = db.OpenExecuteView(query))
                            {
                                Record record;

                                if (view.Fetch(out record))
                                {
                                    this.OnMessage(WixWarnings.SuppressMergedAction((string)row[1], row[0].ToString()));
                                    view.Modify(ModifyView.Delete, record);
                                    record.Close();
                                }
                            }
                        }
                    }
                }

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

                    using (View view = db.OpenExecuteView(String.Concat("SELECT `Action` FROM ", tableName)))
                    {
                        Record resultRecord;
                        while (view.Fetch(out resultRecord))
                        {
                            this.OnMessage(WixWarnings.SuppressMergedAction(resultRecord.GetString(1), tableName));
                            resultRecord.Close();
                        }
                    }

                    // 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` = ?")))
                    {
                        Record record = new Record(1);
                        record.SetString(1, tableName);
                        view.Execute(record);
                    }
                }

                // now update the Attributes column for the files from the Merge Modules
                using (View view = db.OpenView("SELECT `Sequence`, `Attributes` FROM `File` WHERE `File`=?"))
                {
                    foreach (FileMediaInformation fmi in output.FileMediaInformationCollection)
                    {
                        if (!fmi.IsInModule)
                        {
                            continue;
                        }

                        Record record = new Record(1);
                        record.SetString(1, fmi.File);
                        view.Execute(record);

                        Record recordUpdate;
                        view.Fetch(out recordUpdate);

                        if (null == recordUpdate)
                        {
                            throw new WixMergeFailureException(null, this.tempFiles.BasePath, 1, null);
                        }

                        recordUpdate.SetInteger(1, fmi.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 (FileCompressionValue.Yes == fmi.FileCompression)
                        {
                            attributes |= MsiInterop.MsidbFileAttributesCompressed;
                        }
                        else if (FileCompressionValue.No == fmi.FileCompression)
                        {
                            attributes |= MsiInterop.MsidbFileAttributesNoncompressed;
                        }
                        else // not specified
                        {
                            Debug.Assert(FileCompressionValue.NotSpecified == fmi.FileCompression);

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

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

                db.Commit();
            }
        }