예제 #1
0
        /// <summary>
        /// Determines which patches apply to a specified product and in what sequence.  If
        /// the product is installed, this method accounts for patches that have already been applied to
        /// the product and accounts for obsolete and superceded patches.
        /// </summary>
        /// <param name="product">The product that is the target for the set of patches.  This may be
        /// either a ProductCode (GUID) of a product that is currently installed, or the path to a an
        /// MSI file.</param>
        /// <param name="patches">An array of strings specifying the patches to be checked.  Each item
        /// may be the path to an MSP file, the path an XML file, or just an XML blob.</param>
        /// <param name="errorHandler">Callback to be invoked for each inapplicable patch, reporting the
        /// reason the patch is not applicable.  This value may be left null if that information is not
        /// desired.</param>
        /// <param name="userSid">Specifies a security identifier (SID) of a user. This parameter restricts
        /// the context of enumeration for this user account. This parameter cannot be the special SID
        /// strings s-1-1-0 (everyone) or s-1-5-18 (local system). If <paramref name="context"/> is set to
        /// <see cref="UserContexts.None"/> or <see cref="UserContexts.Machine"/>, then
        /// <paramref name="userSid"/> must be null. For the current user context, <paramref name="userSid"/>
        /// can be null and <paramref name="context"/> can be set to <see cref="UserContexts.UserManaged"/>
        /// or <see cref="UserContexts.UserUnmanaged"/>.</param>
        /// <param name="context">Restricts the enumeration to per-user-unmanaged, per-user-managed,
        /// or per-machine context, or (if referring to an MSI) to no system context at all.  This
        /// parameter can be <see cref="UserContexts.Machine"/>, <see cref="UserContexts.UserManaged"/>,
        /// <see cref="UserContexts.UserUnmanaged"/>, or <see cref="UserContexts.None"/>.</param>
        /// <returns>An array of selected patch strings from <paramref name="patches"/>, indicating
        /// the set of applicable patches.  The items are re-ordered to be in the best sequence.</returns>
        /// <remarks><p>
        /// If an item in <paramref name="patches"/> is a file path but does not end in .MSP or .XML,
        /// it is assumed to be an MSP file.
        /// </p><p>
        /// Passing an InstallContext of None only analyzes the MSI file; it does not consider the
        /// current state of the system. You cannot use InstallContext.None with a ProductCode GUID.
        /// </p><p>
        /// Win32 MSI APIs:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidetermineapplicablepatches.asp">MsiDetermineApplicablePatches</a>
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msideterminepatchsequence.asp">MsiDeterminePatchSequence</a>
        /// </p></remarks>
        public static IList <string> DetermineApplicablePatches(
            string product,
            string[] patches,
            InapplicablePatchHandler errorHandler,
            string userSid,
            UserContexts context)
        {
            if (string.IsNullOrWhiteSpace(product))
            {
                throw new ArgumentNullException("product");
            }

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

            NativeMethods.MsiPatchSequenceData[] sequenceData = new NativeMethods.MsiPatchSequenceData[patches.Length];
            for (int i = 0; i < patches.Length; i++)
            {
                if (string.IsNullOrWhiteSpace(patches[i]))
                {
                    throw new ArgumentNullException("patches[" + i + "]");
                }

                sequenceData[i].szPatchData    = patches[i];
                sequenceData[i].ePatchDataType = GetPatchStringDataType(patches[i]);
                sequenceData[i].dwOrder        = -1;
                sequenceData[i].dwStatus       = 0;
            }

            uint ret;

            if (context == UserContexts.None)
            {
                ret = NativeMethods.MsiDetermineApplicablePatches(product, (uint)sequenceData.Length, sequenceData);
            }
            else
            {
                ret = NativeMethods.MsiDeterminePatchSequence(product, userSid, context, (uint)sequenceData.Length, sequenceData);
            }

            if (errorHandler != null)
            {
                for (int i = 0; i < sequenceData.Length; i++)
                {
                    if (sequenceData[i].dwOrder < 0 && sequenceData[i].dwStatus != 0)
                    {
                        errorHandler(sequenceData[i].szPatchData, InstallerException.ExceptionFromReturnCode(sequenceData[i].dwStatus));
                    }
                }
            }

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

            IList <string> patchSeq = new List <string>(patches.Length);

            for (int i = 0; i < sequenceData.Length; i++)
            {
                for (int j = 0; j < sequenceData.Length; j++)
                {
                    if (sequenceData[j].dwOrder == i)
                    {
                        patchSeq.Add(sequenceData[j].szPatchData);
                    }
                }
            }
            return(patchSeq);
        }
예제 #2
0
        /// <summary>
        /// Determines which patches apply to a specified product and in what sequence.  If
        /// the product is installed, this method accounts for patches that have already been applied to
        /// the product and accounts for obsolete and superceded patches.
        /// </summary>
        /// <param name="product">The product that is the target for the set of patches.  This may be
        /// either a ProductCode (GUID) of a product that is currently installed, or the path to a an
        /// MSI file.</param>
        /// <param name="patches">An array of strings specifying the patches to be checked.  Each item
        /// may be the path to an MSP file, the path an XML file, or just an XML blob.</param>
        /// <param name="errorHandler">Callback to be invoked for each inapplicable patch, reporting the
        /// reason the patch is not applicable.  This value may be left null if that information is not
        /// desired.</param>
        /// <param name="userSid">Specifies a security identifier (SID) of a user. This parameter restricts
        /// the context of enumeration for this user account. This parameter cannot be the special SID
        /// strings s-1-1-0 (everyone) or s-1-5-18 (local system). If <paramref name="context"/> is set to
        /// <see cref="UserContexts.None"/> or <see cref="UserContexts.Machine"/>, then
        /// <paramref name="userSid"/> must be null. For the current user context, <paramref name="userSid"/>
        /// can be null and <paramref name="context"/> can be set to <see cref="UserContexts.UserManaged"/>
        /// or <see cref="UserContexts.UserUnmanaged"/>.</param>
        /// <param name="context">Restricts the enumeration to per-user-unmanaged, per-user-managed,
        /// or per-machine context, or (if referring to an MSI) to no system context at all.  This
        /// parameter can be <see cref="UserContexts.Machine"/>, <see cref="UserContexts.UserManaged"/>,
        /// <see cref="UserContexts.UserUnmanaged"/>, or <see cref="UserContexts.None"/>.</param>
        /// <returns>An array of selected patch strings from <paramref name="patches"/>, indicating
        /// the set of applicable patches.  The items are re-ordered to be in the best sequence.</returns>
        /// <remarks><p>
        /// If an item in <paramref name="patches"/> is a file path but does not end in .MSP or .XML,
        /// it is assumed to be an MSP file.
        /// </p><p>
        /// Passing an InstallContext of None only analyzes the MSI file; it does not consider the
        /// current state of the system. You cannot use InstallContext.None with a ProductCode GUID.
        /// </p><p>
        /// Win32 MSI APIs:
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidetermineapplicablepatches.asp">MsiDetermineApplicablePatches</a>
        /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msideterminepatchsequence.asp">MsiDeterminePatchSequence</a>
        /// </p></remarks>
        public static IList<string> DetermineApplicablePatches(
            string product,
            string[] patches,
            InapplicablePatchHandler errorHandler,
            string userSid,
            UserContexts context)
        {
            if (string.IsNullOrWhiteSpace(product))
            {
            throw new ArgumentNullException("product");
            }

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

            NativeMethods.MsiPatchSequenceData[] sequenceData = new NativeMethods.MsiPatchSequenceData[patches.Length];
            for (int i = 0; i < patches.Length; i++)
            {
            if (string.IsNullOrWhiteSpace(patches[i]))
            {
                throw new ArgumentNullException("patches[" + i + "]");
            }

            sequenceData[i].szPatchData = patches[i];
            sequenceData[i].ePatchDataType = GetPatchStringDataType(patches[i]);
            sequenceData[i].dwOrder = -1;
            sequenceData[i].dwStatus = 0;
            }

            uint ret;
            if (context == UserContexts.None)
            {
            ret = NativeMethods.MsiDetermineApplicablePatches(product, (uint) sequenceData.Length, sequenceData);
            }
            else
            {
            ret = NativeMethods.MsiDeterminePatchSequence(product, userSid, context, (uint) sequenceData.Length, sequenceData);
            }

            if (errorHandler != null)
            {
            for (int i = 0; i < sequenceData.Length; i++)
            {
                if (sequenceData[i].dwOrder < 0 && sequenceData[i].dwStatus != 0)
                {
                    errorHandler(sequenceData[i].szPatchData, InstallerException.ExceptionFromReturnCode(sequenceData[i].dwStatus));
                }
            }
            }

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

            IList<string> patchSeq = new List<string>(patches.Length);
            for (int i = 0; i < sequenceData.Length; i++)
            {
            for (int j = 0; j < sequenceData.Length; j++)
            {
                if (sequenceData[j].dwOrder == i)
                {
                    patchSeq.Add(sequenceData[j].szPatchData);
                }
            }
            }
            return patchSeq;
        }