Exemple #1
0
 /// <summary>
 /// Determines which patches apply to a specified product MSI and in what sequence.
 /// </summary>
 /// <param name="productPackage">Full path to an MSI file that is the target product
 /// for the set of patches.</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>
 /// <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>
 /// As this overload uses InstallContext.None, it does not consider the current state of
 /// the system.
 /// </p><p>
 /// Win32 MSI API:
 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidetermineapplicablepatches.asp">MsiDetermineApplicablePatches</a>
 /// </p></remarks>
 public static IList <string> DetermineApplicablePatches(
     string productPackage,
     string[] patches,
     InapplicablePatchHandler errorHandler)
 {
     return(DetermineApplicablePatches(productPackage, patches, errorHandler, null, UserContexts.None));
 }
Exemple #2
0
        private IEnumerable <PatchSequence> DetermineApplicablePatches(string product, string userSid, UserContexts context)
        {
            var patches = this.Patches.ToArray();
            InapplicablePatchHandler handler = (patch, ex) => this.OnInapplicablePatch(new InapplicablePatchEventArgs(patch, product, ex));

            // Keep track of the sequence.
            int i = 0;

            // The current implementation does not return a null list.
            var applicable = Installer.DetermineApplicablePatches(product, patches, handler, userSid, context);

            foreach (var path in applicable)
            {
                yield return(new PatchSequence()
                {
                    Patch = path,
                    Sequence = i++,
                    Product = product,
                    UserSid = userSid,
                    UserContext = context,
                });
            }
        }
    /// <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.IsNullOrEmpty(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.IsNullOrEmpty(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;
    }
 /// <summary>
 /// Determines which patches apply to a specified product MSI and in what sequence.
 /// </summary>
 /// <param name="productPackage">Full path to an MSI file that is the target product
 /// for the set of patches.</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>
 /// <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>
 /// As this overload uses InstallContext.None, it does not consider the current state of
 /// the system.
 /// </p><p>
 /// Win32 MSI API:
 /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msidetermineapplicablepatches.asp">MsiDetermineApplicablePatches</a>
 /// </p></remarks>
 public static IList<string> DetermineApplicablePatches(
     string productPackage,
     string[] patches,
     InapplicablePatchHandler errorHandler)
 {
     return DetermineApplicablePatches(productPackage, patches, errorHandler, null, UserContexts.None);
 }
Exemple #5
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);
        }