Example #1
0
        /// <summary>
        /// Removes all source media from the list.
        /// </summary>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistclearallex.asp">MsiSourceListClearAllEx</a>
        /// </p></remarks>
        public void Clear()
        {
            uint ret = NativeMethods.MsiSourceListClearAllEx(
                this.installation.InstallationCode,
                this.installation.UserSid,
                this.installation.Context,
                (uint)NativeMethods.SourceType.Media | (uint)this.installation.InstallationType);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #2
0
        /// <summary>
        /// Forces the installer to search the source list for a valid
        /// source the next time a source is required. For example, when the
        /// installer performs an installation or reinstallation, or when it
        /// requires the path for a component that is set to run from source.
        /// </summary>
        /// <remarks><p>
        /// Win32 MSI APIs:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistforceresolution.asp">MsiSourceListForceResolution</a>,
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistforceresolutionex.asp">MsiSourceListForceResolutionEx</a>
        /// </p></remarks>
        public void ForceResolution()
        {
            uint ret = NativeMethods.MsiSourceListForceResolutionEx(
                this.installation.InstallationCode,
                this.installation.UserSid,
                this.installation.Context,
                (uint)this.installation.InstallationType);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #3
0
        private static IntPtr[] Begin(string transactionName, TransactionAttributes attributes)
        {
            int    hTransaction;
            IntPtr hChangeOfOwnerEvent;
            uint   ret = NativeMethods.MsiBeginTransaction(transactionName, (int)attributes, out hTransaction, out hChangeOfOwnerEvent);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }

            return(new IntPtr[] { (IntPtr)hTransaction, hChangeOfOwnerEvent });
        }
Example #4
0
        private static void CheckInstallResult(uint ret)
        {
            switch (ret)
            {
            case (uint)NativeMethods.Error.SUCCESS: break;

            case (uint)NativeMethods.Error.SUCCESS_REBOOT_REQUIRED: Installer.rebootRequired = true; break;

            case (uint)NativeMethods.Error.SUCCESS_REBOOT_INITIATED: Installer.rebootInitiated = true; break;

            default: throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #5
0
        /// <summary>
        /// Sets the value of a field to a nullable integer.
        /// </summary>
        /// <param name="field">Specifies the field to set.</param>
        /// <param name="value">new value of the field</param>
        /// <exception cref="ArgumentOutOfRangeException">The field is less than 0 or greater than the
        /// number of fields in the Record.</exception>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msirecordsetinteger.asp">MsiRecordSetInteger</a>
        /// </p></remarks>
        /// <seealso cref="SetInteger(int,int)"/>
        public void SetNullableInteger(int field, int?value)
        {
            this.CheckRange(field);

            uint ret = RemotableNativeMethods.MsiRecordSetInteger(
                (int)this.Handle,
                (uint)field,
                value.HasValue ? (int)value : Int32.MinValue);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
        /// <summary>
        /// Apply a transform to the database, specifying error conditions to suppress.
        /// </summary>
        /// <param name="transformFile">Path to the transform file</param>
        /// <param name="errorConditionsToSuppress">Error conditions that are to be suppressed</param>
        /// <exception cref="InstallerException">the transform could not be applied</exception>
        /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabaseapplytransform.asp">MsiDatabaseApplyTransform</a>
        /// </p></remarks>
        public void ApplyTransform(string transformFile, TransformErrors errorConditionsToSuppress)
        {
            if (String.IsNullOrEmpty(transformFile))
            {
                throw new ArgumentNullException("transformFile");
            }

            uint ret = NativeMethods.MsiDatabaseApplyTransform((int)this.Handle, transformFile, (int)errorConditionsToSuppress);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #7
0
        /// <summary>
        /// Enumerates product installations based on certain criteria.
        /// </summary>
        /// <param name="productCode">ProductCode (GUID) of the product instances to be enumerated. Only
        /// instances of products within the scope of the context specified by the
        /// <paramref name="userSid"/> and <paramref name="context"/> parameters will be
        /// enumerated. This parameter may be set to null to enumerate all products in the specified
        /// context.</param>
        /// <param name="userSid">Specifies a security identifier (SID) that restricts the context
        /// of enumeration. A SID value other than s-1-1-0 is considered a user SID and restricts
        /// enumeration to the current user or any user in the system. The special SID string
        /// s-1-1-0 (Everyone) specifies enumeration across all users in the system. This parameter
        /// can be set to null to restrict the enumeration scope to the current user. When
        /// <paramref name="context"/> is set to the machine context only,
        /// <paramref name="userSid"/> must be null.</param>
        /// <param name="context">Specifies the user context.</param>
        /// <returns>An enumeration of product objects for enumerated product instances.</returns>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msienumproductsex.asp">MsiEnumProductsEx</a>
        /// </p></remarks>
        public static IEnumerable <ProductInstallation> GetProducts(
            string productCode, string userSid, UserContexts context)
        {
            StringBuilder buf = new StringBuilder(40);
            UserContexts  targetContext;
            StringBuilder targetSidBuf = new StringBuilder(40);

            for (uint i = 0; ; i++)
            {
                uint targetSidBufSize = (uint)targetSidBuf.Capacity;
                uint ret = NativeMethods.MsiEnumProductsEx(
                    productCode,
                    userSid,
                    context,
                    i,
                    buf,
                    out targetContext,
                    targetSidBuf,
                    ref targetSidBufSize);
                if (ret == (uint)NativeMethods.Error.MORE_DATA)
                {
                    targetSidBuf.Capacity = (int)++targetSidBufSize;
                    ret = NativeMethods.MsiEnumProductsEx(
                        productCode,
                        userSid,
                        context,
                        i,
                        buf,
                        out targetContext,
                        targetSidBuf,
                        ref targetSidBufSize);
                }

                if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS)
                {
                    break;
                }

                if (ret != 0)
                {
                    throw InstallerException.ExceptionFromReturnCode(ret);
                }

                yield return(new ProductInstallation(
                                 buf.ToString(),
                                 targetSidBuf.ToString(),
                                 targetContext));
            }
        }
Example #8
0
        public void Execute(Record executeParams)
        {
            uint ret = RemotableNativeMethods.MsiViewExecute(
                (int)this.Handle,
                (executeParams != null ? (int)executeParams.Handle : 0));

            if (ret == (uint)NativeMethods.Error.BAD_QUERY_SYNTAX)
            {
                throw new BadQuerySyntaxException(this.sql);
            }
            else if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #9
0
        /// <summary>
        /// Finalizes the persistent form of the database. All persistent data is written
        /// to the writeable database, and no temporary columns or rows are written.
        /// </summary>
        /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
        /// <remarks><p>
        /// For a database open in <see cref="DatabaseOpenMode.ReadOnly"/> mode, this method has no effect.
        /// </p><p>
        /// For a database open in <see cref="DatabaseOpenMode.CreateDirect" /> or <see cref="DatabaseOpenMode.Direct" />
        /// mode, it is not necessary to call this method because the database will be automatically committed
        /// when it is closed. However this method may be called at any time to persist the current state of tables
        /// loaded into memory.
        /// </p><p>
        /// For a database open in <see cref="DatabaseOpenMode.Create" /> or <see cref="DatabaseOpenMode.Transact" />
        /// mode, no changes will be persisted until this method is called. If the database object is closed without
        /// calling this method, the database file remains unmodified.
        /// </p><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidatabasecommit.asp">MsiDatabaseCommit</a>
        /// </p></remarks>
        public void Commit()
        {
            if (this.summaryInfo != null && !this.summaryInfo.IsClosed)
            {
                this.summaryInfo.Persist();
                this.summaryInfo.Close();
                this.summaryInfo = null;
            }
            uint ret = NativeMethods.MsiDatabaseCommit((int)this.Handle);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #10
0
        /// <summary>
        /// Gets the count of all rows in the table that satisfy a given condition.
        /// </summary>
        /// <param name="table">Name of the table whose rows are to be counted</param>
        /// <param name="where">Conditional expression, such as could be placed on the end of a SQL WHERE clause</param>
        /// <returns>The count of all rows in the table satisfying the condition</returns>
        /// <exception cref="BadQuerySyntaxException">the SQL WHERE syntax is invalid</exception>
        /// <exception cref="InstallerException">the View could not be executed</exception>
        /// <exception cref="InvalidHandleException">the Database handle is invalid</exception>
        public int CountRows(string table, string where)
        {
            if (String.IsNullOrEmpty(table))
            {
                throw new ArgumentNullException("table");
            }

            // to support temporary tables like _Streams, run the query even if the table isn't persistent
            TableInfo tableInfo   = this.Tables[table];
            string    primaryKeys = tableInfo == null ? "*" : String.Concat("`", tableInfo.PrimaryKeys[0], "`");
            int       count;

            try
            {
                using (View view = this.OpenView(
                           "SELECT {0} FROM `{1}`{2}",
                           primaryKeys,
                           table,
                           (where != null && where.Length != 0 ? " WHERE " + where : "")))
                {
                    view.Execute();
                    for (count = 0; ; count++)
                    {
                        // Avoid creating unnecessary Record objects by not calling View.Fetch().
                        int  recordHandle;
                        uint ret = RemotableNativeMethods.MsiViewFetch((int)view.Handle, out recordHandle);
                        if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS)
                        {
                            break;
                        }

                        if (ret != 0)
                        {
                            throw InstallerException.ExceptionFromReturnCode(ret);
                        }

                        RemotableNativeMethods.MsiCloseHandle(recordHandle);
                    }
                }
            }
            catch (BadQuerySyntaxException)
            {
                // table was missing
                count = 0;
            }

            return(count);
        }
Example #11
0
        /// <summary>
        /// Makes the current process the owner of the multi-package installation transaction.
        /// </summary>
        /// <param name="attributes">Select optional behavior when joining the transaction.</param>
        /// <exception cref="InvalidHandleException">The transaction handle is not valid.</exception>
        /// <exception cref="InstallerException">The transaction could not be joined.</exception>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msijointransaction.asp">MsiJoinTransaction</a>
        /// </p></remarks>
        public void Join(TransactionAttributes attributes)
        {
            IntPtr hChangeOfOwnerEvent;
            uint   ret = NativeMethods.MsiJoinTransaction((int)this.Handle, (int)attributes, out hChangeOfOwnerEvent);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }

            this.ownerChangeEvent = hChangeOfOwnerEvent;
            if (this.ownerChangeEvent != IntPtr.Zero && this.ownerChangeListeners.Count >= 1)
            {
                new Thread(this.WaitForOwnerChange).Start();
            }
        }
Example #12
0
        /// <summary>
        /// Executes an action sequence described in the specified table.
        /// </summary>
        /// <param name="sequenceTable">Name of the table containing the action sequence.</param>
        /// <exception cref="InvalidHandleException">the Session handle is invalid</exception>
        /// <exception cref="InstallCanceledException">the user exited the installation</exception>
        /// <remarks><p>
        /// This method queries the specified table, ordering the actions by the numbers in the Sequence column.
        /// For each row retrieved, an action is executed, provided that any supplied condition expression does
        /// not evaluate to FALSE.
        /// </p><p>
        /// An action sequence containing any actions that update the system, such as the InstallFiles and
        /// WriteRegistryValues actions, cannot be run by calling DoActionSequence. The exception to this rule is if
        /// DoActionSequence is called from a custom action that is scheduled in the InstallExecuteSequence table
        /// between the InstallInitialize and InstallFinalize actions. Actions that do not update the system, such
        /// as AppSearch or CostInitialize, can be called.
        /// </p><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisequence.asp">MsiSequence</a>
        /// </p></remarks>
        public void DoActionSequence(string sequenceTable)
        {
            if (String.IsNullOrEmpty(sequenceTable))
            {
                throw new ArgumentNullException("sequenceTable");
            }

            this.ValidateSessionAccess();

            uint ret = RemotableNativeMethods.MsiSequence((int)this.Handle, sequenceTable, 0);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #13
0
        /// <summary>
        /// Checks to see if sufficient disk space is present for the current installation.
        /// </summary>
        /// <returns>True if there is sufficient disk space; false otherwise.</returns>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiverifydiskspace.asp">MsiVerifyDiskSpace</a>
        /// </p></remarks>
        public bool VerifyDiskSpace()
        {
            this.ValidateSessionAccess();

            uint ret = RemotableNativeMethods.MsiVerifyDiskSpace((int)this.Handle);

            if (ret == (uint)NativeMethods.Error.DISK_FULL)
            {
                return(false);
            }
            else if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(true);
        }
Example #14
0
        public void CreateFromInstallerExceptionForRecord()
        {
            // Construct an InstallerException from Windows Installer record data.
            var iex = new InstallerException();
            var data = new object[] { 1715, "TEST" };
            iex.GetType().GetField("errorData", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(iex, data);

            using (var psiex = new PSInstallerException(iex))
            {
                var error= psiex.ErrorRecord;

                Assert.IsNotNull(error);
                Assert.AreEqual("Installed TEST", psiex.Message, true);
                Assert.AreEqual("TEST", error.TargetObject as string, true);
            }
        }
Example #15
0
        /// <summary>
        /// Sets a record stream field from a file. Stream data cannot be inserted into temporary fields.
        /// </summary>
        /// <param name="field">Specifies the field of the Record to set.</param>
        /// <param name="filePath">Specifies the path to the file containing the stream.</param>
        /// <exception cref="ArgumentOutOfRangeException">The field is less than 0 or greater than the
        /// number of fields in the Record.</exception>
        /// <remarks><p>
        /// The contents of the specified file are read into a stream object. The stream persists if
        /// the Record is inserted into the Database and the Database is committed.
        /// </p><p>
        /// To reset the stream to its beginning you must pass in null for filePath.
        /// Do not pass an empty string, "", to reset the stream.
        /// </p><p>
        /// Setting a stream with this method is more efficient than setting a field to a
        /// FileStream object.
        /// </p><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msirecordsetstream.asp">MsiRecordsetStream</a>
        /// </p></remarks>
        public void SetStream(int field, string filePath)
        {
            this.CheckRange(field);

            if (String.IsNullOrEmpty(filePath))
            {
                throw new ArgumentNullException("filePath");
            }

            uint ret = RemotableNativeMethods.MsiRecordSetStream((int)this.Handle, (uint)field, filePath);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #16
0
        /// <summary>
        /// Removes a specified disk from the set of registered disks.
        /// </summary>
        /// <param name="diskId">ID of the disk to remove</param>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistclearmediadisk.asp">MsiSourceListClearMediaDisk</a>
        /// </p></remarks>
        public bool Remove(int diskId)
        {
            uint ret = NativeMethods.MsiSourceListClearMediaDisk(
                this.installation.InstallationCode,
                this.installation.UserSid,
                this.installation.Context,
                (uint)this.installation.InstallationType,
                (uint)diskId);

            if (ret != 0)
            {
                // TODO: Figure out when to return false.
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(true);
        }
Example #17
0
        /// <summary>
        /// Adds or updates a disk of the media source for the product or patch.
        /// </summary>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistaddmediadisk.asp">MsiSourceListAddMediaDisk</a>
        /// </p></remarks>
        public void Add(MediaDisk item)
        {
            uint ret = NativeMethods.MsiSourceListAddMediaDisk(
                this.installation.InstallationCode,
                this.installation.UserSid,
                this.installation.Context,
                (uint)this.installation.InstallationType,
                (uint)item.DiskId,
                item.VolumeLabel,
                item.DiskPrompt);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #18
0
        /// <summary>
        /// Generates an advertise script. The method enables the installer to write to a
        /// script the registry and shortcut information used to assign or publish a product.
        /// </summary>
        /// <param name="packagePath">Path to the package of the product being advertised</param>
        /// <param name="scriptFilePath">path to script file to be created with the advertise information</param>
        /// <param name="transforms">Semi-colon delimited list of transforms to be applied. This parameter may be null.</param>
        /// <param name="locale">The language to use if the source supports multiple languages</param>
        /// <param name="processor">Targeted processor architecture.</param>
        /// <param name="instance">True to install multiple instances through product code changing transform.
        /// Advertises a new instance of the product. Requires that the <paramref name="transforms"/> parameter
        /// includes the instance transform that changes the product code.</param>
        /// <seealso cref="AdvertiseProduct"/>
        /// <remarks><p>
        /// Win32 MSI APIs:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiadvertiseproduct.asp">MsiAdvertiseProduct</a>,
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiadvertiseproductex.asp">MsiAdvertiseProductEx</a>
        /// </p></remarks>
        public static void GenerateAdvertiseScript(
            string packagePath,
            string scriptFilePath,
            string transforms,
            int locale,
            ProcessorArchitecture processor,
            bool instance)
        {
            if (String.IsNullOrEmpty(packagePath))
            {
                throw new ArgumentNullException("packagePath");
            }

            if (String.IsNullOrEmpty(scriptFilePath))
            {
                throw new ArgumentNullException("scriptFilePath");
            }

            if (!File.Exists(packagePath))
            {
                throw new FileNotFoundException(null, packagePath);
            }

            uint platform = 0;

            switch (processor)
            {
            case ProcessorArchitecture.X86: platform = (uint)1; break;

            case ProcessorArchitecture.IA64: platform = (uint)2; break;

            case ProcessorArchitecture.Amd64: platform = (uint)4; break;
            }

            uint ret = NativeMethods.MsiAdvertiseProductEx(
                packagePath,
                scriptFilePath,
                transforms,
                (ushort)locale,
                platform,
                instance ? (uint)1 : 0);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #19
0
        public IList <InstallCost> GetTotalCost()
        {
            this.ValidateSessionAccess();

            IList <InstallCost> costs    = new List <InstallCost>();
            StringBuilder       driveBuf = new StringBuilder(20);

            for (uint i = 0; true; i++)
            {
                int  cost, tempCost;
                uint driveBufSize = (uint)driveBuf.Capacity;
                uint ret          = RemotableNativeMethods.MsiEnumComponentCosts(
                    (int)this.Handle,
                    null,
                    i,
                    (int)InstallState.Default,
                    driveBuf,
                    ref driveBufSize,
                    out cost,
                    out tempCost);
                if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS)
                {
                    break;
                }
                if (ret == (uint)NativeMethods.Error.MORE_DATA)
                {
                    driveBuf.Capacity = (int)++driveBufSize;
                    ret = RemotableNativeMethods.MsiEnumComponentCosts(
                        (int)this.Handle,
                        null,
                        i,
                        (int)InstallState.Default,
                        driveBuf,
                        ref driveBufSize,
                        out cost,
                        out tempCost);
                }

                if (ret != 0)
                {
                    throw InstallerException.ExceptionFromReturnCode(ret);
                }
                costs.Add(new InstallCost(driveBuf.ToString(), cost * 512L, tempCost * 512L));
            }
            return(costs);
        }
Example #20
0
        /// <summary>
        /// Examines a shortcut and returns its product, feature name, and component if available.
        /// </summary>
        /// <param name="shortcut">Full path to a shortcut</param>
        /// <returns>ShortcutTarget structure containing target product code, feature, and component code</returns>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msigetshortcuttarget.asp">MsiGetShortcutTarget</a>
        /// </p></remarks>
        public static ShortcutTarget GetShortcutTarget(string shortcut)
        {
            StringBuilder productBuf   = new StringBuilder(40);
            StringBuilder featureBuf   = new StringBuilder(40);
            StringBuilder componentBuf = new StringBuilder(40);

            uint ret = NativeMethods.MsiGetShortcutTarget(shortcut, productBuf, featureBuf, componentBuf);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(new ShortcutTarget(
                       productBuf.Length > 0 ? productBuf.ToString() : null,
                       featureBuf.Length > 0 ? featureBuf.ToString() : null,
                       componentBuf.Length > 0 ? componentBuf.ToString() : null));
        }
Example #21
0
        /// <summary>
        /// Gets the full component path for a qualified component that is published by a product and
        /// performs any necessary installation. This method prompts for source if necessary and increments
        /// the usage count for the feature.
        /// </summary>
        /// <param name="component">Specifies the component ID for the requested component. This may not be the
        /// GUID for the component itself but rather a server that provides the correct functionality, as in the
        /// ComponentId column of the PublishComponent table.</param>
        /// <param name="qualifier">Specifies a qualifier into a list of advertising components (from PublishComponent Table).</param>
        /// <param name="installMode">Installation mode; this can also include bits from <see cref="ReinstallModes"/></param>
        /// <param name="product">Optional; specifies the product to match that has published the qualified component.</param>
        /// <returns>Path to the component</returns>
        /// <remarks><p>
        /// Win32 MSI APIs:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiprovidequalifiedcomponent.asp">MsiProvideQualifiedComponent</a>
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiprovidequalifiedcomponentex.asp">MsiProvideQualifiedComponentEx</a>
        /// </p></remarks>
        public static string ProvideQualifiedComponent(string component, string qualifier, InstallMode installMode, string product)
        {
            StringBuilder pathBuf     = new StringBuilder(512);
            uint          pathBufSize = (uint)pathBuf.Capacity;
            uint          ret         = NativeMethods.MsiProvideQualifiedComponentEx(component, qualifier, unchecked ((uint)installMode), product, 0, 0, pathBuf, ref pathBufSize);

            if (ret == (uint)NativeMethods.Error.MORE_DATA)
            {
                pathBuf.Capacity = (int)++pathBufSize;
                ret = NativeMethods.MsiProvideQualifiedComponentEx(component, qualifier, unchecked ((uint)installMode), product, 0, 0, pathBuf, ref pathBufSize);
            }

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(pathBuf.ToString());
        }
Example #22
0
        /// <summary>
        /// Extracts information from a patch that can be used to determine whether the patch
        /// applies on a target system. The method returns an XML string that can be provided to
        /// <see cref="DetermineApplicablePatches(string,string[],InapplicablePatchHandler,string,UserContexts)"/>
        /// instead of the full patch file.
        /// </summary>
        /// <param name="patchPath">Full path to the patch being queried.</param>
        /// <returns>XML string containing patch data.</returns>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiextractpatchxmldata.asp">MsiExtractPatchXMLData</a>
        /// </p></remarks>
        public static string ExtractPatchXmlData(string patchPath)
        {
            StringBuilder buf     = new StringBuilder("");
            uint          bufSize = 0;
            uint          ret     = NativeMethods.MsiExtractPatchXMLData(patchPath, 0, buf, ref bufSize);

            if (ret == (uint)NativeMethods.Error.MORE_DATA)
            {
                buf.Capacity = (int)++bufSize;
                ret          = NativeMethods.MsiExtractPatchXMLData(patchPath, 0, buf, ref bufSize);
            }

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(buf.ToString());
        }
Example #23
0
        public void Modify(ViewModifyMode mode, Record record)
        {
            if (record == null)
            {
                throw new ArgumentNullException("record");
            }

            uint ret = RemotableNativeMethods.MsiViewModify((int)this.Handle, (int)mode, (int)record.Handle);

            if (mode == ViewModifyMode.Insert || mode == ViewModifyMode.InsertTemporary)
            {
                record.IsFormatStringInvalid = true;
            }
            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #24
0
        /// <summary>
        /// Gets the full path to a Windows Installer component containing an assembly. This method prompts for a source and
        /// increments the usage count for the feature.
        /// </summary>
        /// <param name="assemblyName">Assembly name</param>
        /// <param name="appContext">Set to null for global assemblies. For private assemblies, set to the full path of the
        /// application configuration file (.cfg file) or executable file (.exe) of the application to which the assembly
        /// has been made private.</param>
        /// <param name="installMode">Installation mode; this can also include bits from <see cref="ReinstallModes"/></param>
        /// <param name="isWin32Assembly">True if this is a Win32 assembly, false if it is a .NET assembly</param>
        /// <returns>Path to the assembly</returns>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiprovideassembly.asp">MsiProvideAssembly</a>
        /// </p></remarks>
        public static string ProvideAssembly(string assemblyName, string appContext, InstallMode installMode, bool isWin32Assembly)
        {
            StringBuilder pathBuf     = new StringBuilder(512);
            uint          pathBufSize = (uint)pathBuf.Capacity;
            uint          ret         = NativeMethods.MsiProvideAssembly(assemblyName, appContext, unchecked ((uint)installMode), (isWin32Assembly ? (uint)1 : 0), pathBuf, ref pathBufSize);

            if (ret == (uint)NativeMethods.Error.MORE_DATA)
            {
                pathBuf.Capacity = (int)++pathBufSize;
                ret = NativeMethods.MsiProvideAssembly(assemblyName, appContext, unchecked ((uint)installMode), (isWin32Assembly ? (uint)1 : 0), pathBuf, ref pathBufSize);
            }

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(pathBuf.ToString());
        }
Example #25
0
        /// <summary>
        /// Opens an installer package for an installed product using the product code.
        /// </summary>
        /// <param name="productCode">Product code of the installed product</param>
        /// <returns>A Session object allowing access to the product database and install engine,
        /// or null if the specified product is not installed.</returns>
        /// <exception cref="ArgumentException">An unknown product was requested</exception>
        /// <exception cref="InstallerException">The product could not be opened</exception>
        /// <exception cref="InstallerException">The installer configuration data is corrupt</exception>
        /// <remarks><p>
        /// Note that only one Session object can be opened by a single process. OpenProduct cannot be
        /// used in a custom action because the active installation is the only session allowed.
        /// </p><p>
        /// The Session object should be <see cref="InstallerHandle.Close"/>d after use.
        /// It is best that the handle be closed manually as soon as it is no longer
        /// needed, as leaving lots of unused handles open can degrade performance.
        /// </p><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenproduct.asp">MsiOpenProduct</a>
        /// </p></remarks>
        public static Session OpenProduct(string productCode)
        {
            int  sessionHandle;
            uint ret = NativeMethods.MsiOpenProduct(productCode, out sessionHandle);

            if (ret != 0)
            {
                if (ret == (uint)NativeMethods.Error.UNKNOWN_PRODUCT)
                {
                    return(null);
                }
                else
                {
                    throw InstallerException.ExceptionFromReturnCode(ret);
                }
            }
            return(new Session((IntPtr)sessionHandle, true));
        }
Example #26
0
        /// <summary>
        /// Gets the set of all products with a specified upgrade code. This method lists the
        /// currently installed and advertised products that have the specified UpgradeCode
        /// property in their Property table.
        /// </summary>
        /// <param name="upgradeCode">Upgrade code of related products</param>
        /// <returns>Enumeration of product codes</returns>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msienumrelatedproducts.asp">MsiEnumRelatedProducts</a>
        /// </p></remarks>
        public static IEnumerable <ProductInstallation> GetRelatedProducts(string upgradeCode)
        {
            StringBuilder buf = new StringBuilder(40);

            for (uint i = 0; true; i++)
            {
                uint ret = NativeMethods.MsiEnumRelatedProducts(upgradeCode, 0, i, buf);
                if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS)
                {
                    break;
                }
                if (ret != 0)
                {
                    throw InstallerException.ExceptionFromReturnCode(ret);
                }
                yield return(new ProductInstallation(buf.ToString()));
            }
        }
Example #27
0
        /// <summary>
        /// Sets the designated mode flag for the current install session.
        /// </summary>
        /// <param name="mode">The type of mode to be set.</param>
        /// <param name="value">The desired value of the mode.</param>
        /// <exception cref="InvalidHandleException">the Session handle is invalid</exception>
        /// <exception cref="ArgumentOutOfRangeException">an invalid mode flag was specified</exception>
        /// <exception cref="InvalidOperationException">the mode cannot not be set</exception>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetmode.asp">MsiSetMode</a>
        /// </p></remarks>
        public void SetMode(InstallRunMode mode, bool value)
        {
            this.ValidateSessionAccess();

            uint ret = RemotableNativeMethods.MsiSetMode((int)this.Handle, (uint)mode, value);

            if (ret != 0)
            {
                if (ret == (uint)NativeMethods.Error.ACCESS_DENIED)
                {
                    throw new InvalidOperationException();
                }
                else
                {
                    throw InstallerException.ExceptionFromReturnCode(ret);
                }
            }
        }
Example #28
0
        /// <summary>
        /// Generates an advertise script. The method enables the installer to write to a
        /// script the registry and shortcut information used to assign or publish a product.
        /// </summary>
        /// <param name="packagePath">Path to the package of the product being advertised</param>
        /// <param name="scriptFilePath">path to script file to be created with the advertise information</param>
        /// <param name="transforms">Semi-colon delimited list of transforms to be applied. This parameter may be null.</param>
        /// <param name="locale">The language to use if the source supports multiple languages</param>
        /// <exception cref="FileNotFoundException">the specified package file does not exist</exception>
        /// <seealso cref="AdvertiseProduct"/>
        /// <remarks><p>
        /// Win32 MSI APIs:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiadvertiseproduct.asp">MsiAdvertiseProduct</a>,
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiadvertiseproductex.asp">MsiAdvertiseProductEx</a>
        /// </p></remarks>
        public static void GenerateAdvertiseScript(string packagePath, string scriptFilePath, string transforms, int locale)
        {
            if (String.IsNullOrEmpty(packagePath))
            {
                throw new ArgumentNullException("packagePath");
            }

            if (!File.Exists(packagePath))
            {
                throw new FileNotFoundException(null, packagePath);
            }

            uint ret = NativeMethods.MsiAdvertiseProduct(packagePath, scriptFilePath, transforms, (ushort)locale);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
        }
Example #29
0
        /// <summary>
        /// Calculates the disk space required by the feature and its selected children and parent features.
        /// </summary>
        /// <param name="includeParents">If true, the parent features are included in the cost.</param>
        /// <param name="includeChildren">If true, the child features are included in the cost.</param>
        /// <param name="installState">Specifies the installation state.</param>
        /// <returns>The disk space requirement in bytes.</returns>
        /// <remarks><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msigetfeaturecost.asp">MsiGetFeatureCost</a>
        /// </p></remarks>
        public long GetCost(bool includeParents, bool includeChildren, InstallState installState)
        {
            const int MSICOSTTREE_CHILDREN = 1;
            const int MSICOSTTREE_PARENTS  = 2;

            int  cost;
            uint ret = RemotableNativeMethods.MsiGetFeatureCost(
                (int)this.session.Handle,
                this.name,
                (includeParents ? MSICOSTTREE_PARENTS : 0) | (includeChildren ? MSICOSTTREE_CHILDREN : 0),
                (int)installState,
                out cost);

            if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(cost * 512L);
        }
Example #30
0
        /// <summary>
        /// Fetches the next sequential record from the view, or null if there are no more records.
        /// </summary>
        /// <exception cref="InstallerException">the View is not in an active state</exception>
        /// <exception cref="InvalidHandleException">the View handle is invalid</exception>
        /// <remarks><p>
        /// The Record object should be <see cref="InstallerHandle.Close"/>d after use.
        /// It is best that the handle be closed manually as soon as it is no longer
        /// needed, as leaving lots of unused handles open can degrade performance.
        /// </p><p>
        /// Win32 MSI API:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiviewfetch.asp">MsiViewFetch</a>
        /// </p></remarks>
        public Record Fetch()
        {
            int  recordHandle;
            uint ret = RemotableNativeMethods.MsiViewFetch((int)this.Handle, out recordHandle);

            if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS)
            {
                return(null);
            }
            else if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }

            Record r = new Record((IntPtr)recordHandle, true, this);

            r.IsFormatStringInvalid = true;
            return(r);
        }
Example #31
0
        public bool Merge(Record record)
        {
            if (record == null)
            {
                throw new ArgumentNullException("record");
            }

            uint ret = RemotableNativeMethods.MsiViewModify((int)this.Handle, (int)ViewModifyMode.Merge, (int)record.Handle);

            if (ret == (uint)NativeMethods.Error.FUNCTION_FAILED)
            {
                return(false);
            }
            else if (ret != 0)
            {
                throw InstallerException.ExceptionFromReturnCode(ret);
            }
            return(true);
        }
Example #32
0
 /// <summary>
 /// Creates a <see cref="PSInstallerException"/> from the given inner exception.
 /// </summary>
 /// <param name="innerException">The <see cref="InstallerException"/> containing error details.</param>
 public PSInstallerException(InstallerException innerException)
     : base(null, innerException)
 {
     this.errorRecord = null;
     this.record = null;
 }