Validator.cs :  » Installers-Generators » WiX » Microsoft » Tools » WindowsInstallerXml » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Installers Generators » WiX 
WiX » Microsoft » Tools » WindowsInstallerXml » Validator.cs
//-------------------------------------------------------------------------------------------------
// <copyright file="Validator.cs" company="Microsoft">
//    Copyright (c) Microsoft Corporation.  All rights reserved.
//    
//    The use and distribution terms for this software are covered by the
//    Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
//    which can be found in the file CPL.TXT at the root of this distribution.
//    By using this software in any fashion, you are agreeing to be bound by
//    the terms of this license.
//    
//    You must not remove this notice, or any other, from this software.
// </copyright>
// 
// <summary>
// Runs internal consistency evaluators (ICEs) from cub files against a database.
// </summary>
//-------------------------------------------------------------------------------------------------

namespace Microsoft.Tools.WindowsInstallerXml{
    using System;
    using System.CodeDom.Compiler;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization;
    using System.IO;
    using Microsoft.Tools.WindowsInstallerXml.Msi;
    using Microsoft.Tools.WindowsInstallerXml.Msi.Interop;

    /// <summary>
    /// Runs internal consistency evaluators (ICEs) from cub files against a database.
    /// </summary>
    public sealed class Validator : IMessageHandler
    {
        private string actionName;
        private StringCollection cubeFiles;
        private bool encounteredError;
        private ValidatorExtension extension;
        private string[] ices;
        private Output output;
        private string[] suppressedICEs;
        private TempFileCollection tempFiles;
        private InstallUIHandler validationUIHandler;
        private bool validationSessionComplete;

        /// <summary>
        /// Instantiate a new Validator.
        /// </summary>
        public Validator()
        {
            this.cubeFiles = new StringCollection();
            this.extension = new ValidatorExtension();
            this.validationUIHandler = new InstallUIHandler(this.ValidationUIHandler);
        }

        /// <summary>
        /// Gets or sets a <see cref="ValidatorExtension"/> that directs messages from the validator.
        /// </summary>
        /// <value>A <see cref="ValidatorExtension"/> that directs messages from the validator.</value>
        public ValidatorExtension Extension
        {
            get { return this.extension; }
            set { this.extension = value; }
        }

        /// <summary>
        /// Gets or sets the list of ICEs to run.
        /// </summary>
        /// <value>The list of ICEs.</value>
        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
        public string[] ICEs
        {
            get { return this.ices; }
            set { this.ices = value; }
        }

        /// <summary>
        /// Gets or sets the output used for finding source line information.
        /// </summary>
        /// <value>The output used for finding source line information.</value>
        public Output Output
        {
            // cache Output object until validation for changes in extension
            get { return this.output; }
            set { this.output = value; }
        }

        /// <summary>
        /// Gets or sets the suppressed ICEs.
        /// </summary>
        /// <value>The suppressed ICEs.</value>
        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
        public string[] SuppressedICEs
        {
            get { return this.suppressedICEs; }
            set { this.suppressedICEs = value; }
        }

        /// <summary>
        /// Gets or sets the temporary path for the Binder.  If left null, the binder
        /// will use %TEMP% environment variable.
        /// </summary>
        /// <value>Path to temp files.</value>
        public string TempFilesLocation
        {
            get
            {
                return null == this.tempFiles ? String.Empty : this.tempFiles.BasePath;
            }

            set
            {
                if (null == value)
                {
                    this.tempFiles = new TempFileCollection();
                }
                else
                {
                    this.tempFiles = new TempFileCollection(value);
                }
            }
        }

        /// <summary>
        /// Add a cube file to the validation run.
        /// </summary>
        /// <param name="cubeFile">A cube file.</param>
        public void AddCubeFile(string cubeFile)
        {
            this.cubeFiles.Add(cubeFile);
        }

        /// <summary>
        /// Validate a database.
        /// </summary>
        /// <param name="databaseFile">The database to validate.</param>
        /// <returns>true if validation succeeded; false otherwise.</returns>
        public bool Validate(string databaseFile)
        {
            Dictionary<string, string> indexedICEs = new Dictionary<string, string>();
            Dictionary<string, string> indexedSuppressedICEs = new Dictionary<string, string>();
            int previousUILevel = (int)InstallUILevels.Basic;
            IntPtr previousHwnd = IntPtr.Zero;
            InstallUIHandler previousUIHandler = null;

            if (null == databaseFile)
            {
                throw new ArgumentNullException("databaseFile");
            }

            // initialize the validator extension
            this.extension.DatabaseFile = databaseFile;
            this.extension.Output = this.output;
            this.extension.InitializeValidator();

            // if we don't have the temporary files object yet, get one
            if (null == this.tempFiles)
            {
                this.tempFiles = new TempFileCollection();
            }
            Directory.CreateDirectory(this.TempFilesLocation); // ensure the base path is there

            // index the ICEs
            if (null != this.ices)
            {
                foreach (string ice in this.ices)
                {
                    indexedICEs[ice] = null;
                }
            }

            // index the suppressed ICEs
            if (null != this.suppressedICEs)
            {
                foreach (string suppressedICE in this.suppressedICEs)
                {
                    indexedSuppressedICEs[suppressedICE] = null;
                }
            }

            // copy the database to a temporary location so it can be manipulated
            string tempDatabaseFile = Path.Combine(this.TempFilesLocation, Path.GetFileName(databaseFile));
            File.Copy(databaseFile, tempDatabaseFile);

            // remove the read-only property from the temporary database
            FileAttributes attributes = File.GetAttributes(tempDatabaseFile);
            File.SetAttributes(tempDatabaseFile, attributes & ~FileAttributes.ReadOnly);

            try
            {
                using (Database database = new Database(tempDatabaseFile, OpenDatabase.Direct))
                {
                    bool propertyTableExists = database.TableExists("Property");
                    string productCode = null;

                    // remove the product code from the database before opening a session to prevent opening an installed product
                    if (propertyTableExists)
                    {
                        using (View view = database.OpenExecuteView("SELECT `Value` FROM `Property` WHERE Property = 'ProductCode'"))
                        {
                            Record record = null;

                            try
                            {
                                if (null != (record = view.Fetch()))
                                {
                                    productCode = record.GetString(1);

                                    using (View dropProductCodeView = database.OpenExecuteView("DELETE FROM `Property` WHERE `Property` = 'ProductCode'"))
                                    {
                                    }
                                }
                            }
                            finally
                            {
                                if (null != record)
                                {
                                    record.Close();
                                }
                            }
                        }
                    }

                    // merge in the cube databases
                    foreach (string cubeFile in this.cubeFiles)
                    {
                        try
                        {
                            using (Database cubeDatabase = new Database(cubeFile, OpenDatabase.ReadOnly))
                            {
                                try
                                {
                                    database.Merge(cubeDatabase, "MergeConflicts");
                                }
                                catch
                                {
                                    // ignore merge errors since they are expected in the _Validation table
                                }
                            }
                        }
                        catch (Win32Exception e)
                        {
                            if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED
                            {
                                throw new WixException(WixErrors.CubeFileNotFound(cubeFile));
                            }

                            throw;
                        }
                    }

                    // commit the database before proceeding to ensure the streams don't get confused
                    database.Commit();

                    // the property table may have been added to the database
                    // from a cub database without the proper validation rows
                    if (!propertyTableExists)
                    {
                        using (View view = database.OpenExecuteView("DROP table `Property`"))
                        {
                        }
                    }

                    // get all the action names for ICEs which have not been suppressed
                    List<string> actions = new List<string>();
                    using (View view = database.OpenExecuteView("SELECT `Action` FROM `_ICESequence` ORDER BY `Sequence`"))
                    {
                        while (true)
                        {
                            using (Record record = view.Fetch())
                            {
                                if (null == record)
                                {
                                    break;
                                }

                                string action = record.GetString(1);

                                if (!indexedSuppressedICEs.ContainsKey(action))
                                {
                                    actions.Add(action);
                                }
                            }
                        }
                    }

                    if (0 != indexedICEs.Count)
                    {
                        // Walk backwards and remove those that arent in the list
                        for (int i = actions.Count - 1; 0 <= i; i--)
                        {
                            if (!indexedICEs.ContainsKey(actions[i]))
                            {
                                actions.RemoveAt(i);
                            }
                        }
                    }

                    // disable the internal UI handler and set an external UI handler
                    previousUILevel = Installer.SetInternalUI((int)InstallUILevels.None, ref previousHwnd);
                    previousUIHandler = Installer.SetExternalUI(this.validationUIHandler, (int)InstallLogModes.Error | (int)InstallLogModes.Warning | (int)InstallLogModes.User, IntPtr.Zero);

                    // create a session for running the ICEs
                    this.validationSessionComplete = false;
                    using (Session session = new Session(database))
                    {
                        // add the product code back into the database
                        if (null != productCode)
                        {
                            using (View view = database.OpenExecuteView(String.Format(CultureInfo.InvariantCulture, "INSERT INTO `Property` (`Property`, `Value`) VALUES ('ProductCode', '{0}')", productCode)))
                            {
                            }
                        }

                        foreach (string action in actions)
                        {
                            this.actionName = action;
                            try
                            {
                                session.DoAction(action);
                            }
                            catch (Win32Exception e)
                            {
                                if (!this.encounteredError)
                                {
                                    throw e;
                                }
                                else
                                {
                                    this.encounteredError = false;
                                }
                            }
                            this.actionName = null;
                        }

                        // Mark the validation session complete so we ignore any messages that MSI may fire
                        // during session clean-up.
                        this.validationSessionComplete = true;
                    }
                }
            }
            catch (Win32Exception e)
            {
                // avoid displaying errors twice since one may have already occurred in the UI handler
                if (!this.encounteredError)
                {
                    if (0x6E == e.NativeErrorCode) // ERROR_OPEN_FAILED
                    {
                        // databaseFile is not passed since during light
                        // this would be the temporary copy and there would be
                        // no final output since the error occured; during smoke
                        // they should know the path passed into smoke
                        this.OnMessage(WixErrors.ValidationFailedToOpenDatabase());
                    }
                    else if (0x654 == e.NativeErrorCode)
                    {
                        this.OnMessage(WixErrors.ValidationFailedDueToInvalidPackage());
                    }
                    else if (0x658 == e.NativeErrorCode)
                    {
                        this.OnMessage(WixErrors.ValidationFailedDueToMultilanguageMergeModule());
                    }
                    else if (0x659 == e.NativeErrorCode)
                    {
                        this.OnMessage(WixWarnings.ValidationFailedDueToSystemPolicy());
                    }
                    else
                    {
                        string msgTemp = e.Message;

                        if (null != this.actionName)
                        {
                            msgTemp = String.Concat("Action - '", this.actionName, "' ", e.Message);
                        }

                        this.OnMessage(WixErrors.Win32Exception(e.NativeErrorCode, msgTemp));
                    }
                }
            }
            finally
            {
                Installer.SetExternalUI(previousUIHandler, 0, IntPtr.Zero);
                Installer.SetInternalUI(previousUILevel, ref previousHwnd);

                this.validationSessionComplete = false; // no validation session at this point, so reset the completion flag.

                this.cubeFiles.Clear();
                this.extension.FinalizeValidator();
            }

            return !this.encounteredError;
        }

        /// <summary>
        /// Cleans up the temp files used by the Validator.
        /// </summary>
        /// <returns>True if all files were deleted, false otherwise.</returns>
        public bool DeleteTempFiles()
        {
            if (null == this.tempFiles)
            {
                return true; // no work to do
            }
            else
            {
                bool deleted = Common.DeleteTempFiles(this.tempFiles.BasePath, this);

                if (deleted)
                {
                    this.tempFiles = null; // temp files have been deleted, no need to remember this now
                }

                return deleted;
            }
        }

        /// <summary>
        /// Sends a message to the message delegate if there is one.
        /// </summary>
        /// <param name="mea">Message event arguments.</param>
        public void OnMessage(MessageEventArgs e)
        {
            WixErrorEventArgs errorEventArgs = e as WixErrorEventArgs;

            if (null != errorEventArgs)
            {
                this.encounteredError = true;
            }

            this.extension.OnMessage(e);
        }

        /// <summary>
        /// The validation external UI handler.
        /// </summary>
        /// <param name="context">Pointer to an application context.
        /// This parameter can be used for error checking.</param>
        /// <param name="messageType">Specifies a combination of one message box style,
        /// one message box icon type, one default button, and one installation message type.</param>
        /// <param name="message">Specifies the message text.</param>
        /// <returns>-1 for an error, 0 if no action was taken, 1 if OK, 3 to abort.</returns>
        private int ValidationUIHandler(IntPtr context, uint messageType, string message)
        {
            try
            {
                // If we're getting messges during the validation session, send them to
                // the extension. Otherwise, ignore the messages.
                if (!this.validationSessionComplete)
                {
                    this.extension.Log(message, this.actionName);
                }
            }
            catch (WixException ex)
            {
                this.OnMessage(ex.Error);
            }

            return 1;
        }
    }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.