// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Dtf.WindowsInstaller
{
using System;
using System.IO;
using System.Text;
using System.Resources;
using System.Reflection;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
///
/// Receives an exception from
///
/// indicating the reason a particular patch is not applicable to a product.
///
/// MSP file path, XML file path, or XML blob that was passed to
///
/// exception indicating the reason the patch is not applicable
///
/// If is an or subclass, then
/// its and
/// properties will indicate a more specific reason the patch was not applicable.
///
/// The could also be a FileNotFoundException if the
/// patch string was a file path.
///
public delegate void InapplicablePatchHandler(string patch, Exception exception);
///
/// Provides static methods for installing and configuring products and patches.
///
public static partial class Installer
{
private static bool rebootRequired;
private static bool rebootInitiated;
private static ResourceManager errorResources;
///
/// Indicates whether a system reboot is required after running an installation or configuration operation.
///
public static bool RebootRequired
{
get
{
return Installer.rebootRequired;
}
}
///
/// Indicates whether a system reboot has been initiated after running an installation or configuration operation.
///
public static bool RebootInitiated
{
get
{
return Installer.rebootInitiated;
}
}
///
/// Enables the installer's internal user interface. Then this user interface is used
/// for all subsequent calls to user-interface-generating installer functions in this process.
///
/// Specifies the level of complexity of the user interface
/// Handle to a window, which becomes the owner of any user interface created.
/// A pointer to the previous owner of the user interface is returned.
/// The previous user interface level
///
/// Win32 MSI API:
/// MsiSetInternalUI
///
[SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference")]
public static InstallUIOptions SetInternalUI(InstallUIOptions uiOptions, ref IntPtr windowHandle)
{
return (InstallUIOptions) NativeMethods.MsiSetInternalUI((uint) uiOptions, ref windowHandle);
}
///
/// Enables the installer's internal user interface. Then this user interface is used
/// for all subsequent calls to user-interface-generating installer functions in this process.
/// The owner of the user interface does not change.
///
/// Specifies the level of complexity of the user interface
/// The previous user interface level
///
/// Win32 MSI API:
/// MsiSetInternalUI
///
public static InstallUIOptions SetInternalUI(InstallUIOptions uiOptions)
{
return (InstallUIOptions) NativeMethods.MsiSetInternalUI((uint) uiOptions, IntPtr.Zero);
}
///
/// Enables logging of the selected message type for all subsequent install sessions in
/// the current process space.
///
/// One or more mode flags specifying the type of messages to log
/// Full path to the log file. A null path disables logging,
/// in which case the logModes paraneter is ignored.
/// an invalid log mode was specified
/// This method takes effect on any new installation processes. Calling this
/// method from within a custom action will not start logging for that installation.
public static void EnableLog(InstallLogModes logModes, string logFile)
{
Installer.EnableLog(logModes, logFile, false, true);
}
///
/// Enables logging of the selected message type for all subsequent install sessions in
/// the current process space.
///
/// One or more mode flags specifying the type of messages to log
/// Full path to the log file. A null path disables logging,
/// in which case the logModes paraneter is ignored.
/// If true, the log lines will be appended to any existing file content.
/// If false, the log file will be truncated if it exists. The default is false.
/// If true, the log will be flushed after every line.
/// If false, the log will be flushed every 20 lines. The default is true.
/// an invalid log mode was specified
///
/// This method takes effect on any new installation processes. Calling this
/// method from within a custom action will not start logging for that installation.
///
/// Win32 MSI API:
/// MsiEnableLog
///
public static void EnableLog(InstallLogModes logModes, string logFile, bool append, bool flushEveryLine)
{
uint ret = NativeMethods.MsiEnableLog((uint) logModes, logFile, (append ? (uint) 1 : 0) + (flushEveryLine ? (uint) 2 : 0));
if (ret != 0 && ret != (uint) NativeMethods.Error.FILE_INVALID)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
}
///
/// increments the usage count for a particular feature and returns the installation state for
/// that feature. This method should be used to indicate an application's intent to use a feature.
///
/// The product code of the product.
/// The feature to be used.
/// Must have the value .
/// The installed state of the feature.
///
/// The UseFeature method should only be used on features known to be published. The application
/// should determine the status of the feature by calling either the FeatureState method or
/// Features method.
///
/// Win32 MSI APIs:
/// MsiUseFeature,
/// MsiUseFeatureEx
///
public static InstallState UseFeature(string productCode, string feature, InstallMode installMode)
{
int installState = NativeMethods.MsiUseFeatureEx(productCode, feature, unchecked ((uint) installMode), 0);
return (InstallState) installState;
}
///
/// Opens an installer package for use with functions that access the product database and install engine,
/// returning an Session object.
///
/// Path to the package
/// Specifies whether or not the create a Session object that ignores the
/// computer state and that is incapable of changing the current computer state. A value of false yields
/// the normal behavior. A value of true creates a "safe" Session object that cannot change of the current
/// machine state.
/// A Session object allowing access to the product database and install engine
/// The product could not be opened
/// The installer configuration data is corrupt
///
/// Note that only one Session object can be opened by a single process. OpenPackage cannot be used in a
/// custom action because the active installation is the only session allowed.
///
/// A "safe" Session object ignores the current computer state when opening the package and prevents
/// changes to the current computer state.
///
/// The Session object should be 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.
///
/// Win32 MSI APIs:
/// MsiOpenPackage,
/// MsiOpenPackageEx
///
public static Session OpenPackage(string packagePath, bool ignoreMachineState)
{
int sessionHandle;
uint ret = NativeMethods.MsiOpenPackageEx(packagePath, ignoreMachineState ? (uint) 1 : 0, out sessionHandle);
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
return new Session((IntPtr) sessionHandle, true);
}
///
/// Opens an installer package for use with functions that access the product database and install engine,
/// returning an Session object.
///
/// Database used to create the session
/// Specifies whether or not the create a Session object that ignores the
/// computer state and that is incapable of changing the current computer state. A value of false yields
/// the normal behavior. A value of true creates a "safe" Session object that cannot change of the current
/// machine state.
/// A Session object allowing access to the product database and install engine
/// The product could not be opened
/// The installer configuration data is corrupt
///
/// Note that only one Session object can be opened by a single process. OpenPackage cannot be used in a
/// custom action because the active installation is the only session allowed.
///
/// A "safe" Session object ignores the current computer state when opening the package and prevents
/// changes to the current computer state.
///
/// The Session object should be 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.
///
/// Win32 MSI APIs:
/// MsiOpenPackage,
/// MsiOpenPackageEx
///
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
public static Session OpenPackage(Database database, bool ignoreMachineState)
{
if (database == null)
{
throw new ArgumentNullException("database");
}
return Installer.OpenPackage(
String.Format(CultureInfo.InvariantCulture, "#{0}", database.Handle),
ignoreMachineState);
}
///
/// Opens an installer package for an installed product using the product code.
///
/// Product code of the installed product
/// A Session object allowing access to the product database and install engine,
/// or null if the specified product is not installed.
/// An unknown product was requested
/// The product could not be opened
/// The installer configuration data is corrupt
///
/// 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.
///
/// The Session object should be 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.
///
/// Win32 MSI API:
/// MsiOpenProduct
///
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);
}
///
/// Gets the full component path, performing any necessary installation. This method prompts for source if
/// necessary and increments the usage count for the feature.
///
/// Product code for the product that contains the feature with the necessary component
/// Feature ID of the feature with the necessary component
/// Component code of the necessary component
/// Installation mode; this can also include bits from
/// Path to the component
///
/// Win32 MSI API:
/// MsiProvideComponent
///
public static string ProvideComponent(string product, string feature, string component, InstallMode installMode)
{
StringBuilder pathBuf = new StringBuilder(512);
uint pathBufSize = (uint) pathBuf.Capacity;
uint ret = NativeMethods.MsiProvideComponent(product, feature, component, unchecked((uint)installMode), pathBuf, ref pathBufSize);
if (ret == (uint) NativeMethods.Error.MORE_DATA)
{
pathBuf.Capacity = (int) ++pathBufSize;
ret = NativeMethods.MsiProvideComponent(product, feature, component, unchecked((uint)installMode), pathBuf, ref pathBufSize);
}
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
return pathBuf.ToString();
}
///
/// 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.
///
/// 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.
/// Specifies a qualifier into a list of advertising components (from PublishComponent Table).
/// Installation mode; this can also include bits from
/// Optional; specifies the product to match that has published the qualified component.
/// Path to the component
///
/// Win32 MSI APIs:
/// MsiProvideQualifiedComponent
/// MsiProvideQualifiedComponentEx
///
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();
}
///
/// 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.
///
/// Assembly name
/// 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.
/// Installation mode; this can also include bits from
/// True if this is a Win32 assembly, false if it is a .NET assembly
/// Path to the assembly
///
/// Win32 MSI API:
/// MsiProvideAssembly
///
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();
}
///
/// Installs files that are unexpectedly missing.
///
/// Product code for the product that owns the component to be installed
/// Component to be installed
/// Specifies the way the component should be installed.
/// the user exited the installation
///
/// Win32 MSI API:
/// MsiInstallMissingComponent
///
public static void InstallMissingComponent(string product, string component, InstallState installState)
{
uint ret = NativeMethods.MsiInstallMissingComponent(product, component, (int) installState);
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
}
///
/// Installs files that are unexpectedly missing.
///
/// Product code for the product that owns the file to be installed
/// File to be installed
/// the user exited the installation
///
/// Win32 MSI API:
/// MsiInstallMissingFile
///
public static void InstallMissingFile(string product, string file)
{
uint ret = NativeMethods.MsiInstallMissingFile(product, file);
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
}
///
/// Reinstalls a feature.
///
/// Product code for the product containing the feature to be reinstalled
/// Feature to be reinstalled
/// Reinstall modes
/// the user exited the installation
///
/// Win32 MSI API:
/// MsiReinstallFeature
///
public static void ReinstallFeature(string product, string feature, ReinstallModes reinstallModes)
{
uint ret = NativeMethods.MsiReinstallFeature(product, feature, (uint) reinstallModes);
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
}
///
/// Reinstalls a product.
///
/// Product code for the product to be reinstalled
/// Reinstall modes
/// the user exited the installation
///
/// Win32 MSI API:
/// MsiReinstallProduct
///
public static void ReinstallProduct(string product, ReinstallModes reinstallModes)
{
uint ret = NativeMethods.MsiReinstallProduct(product, (uint) reinstallModes);
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
}
///
/// Opens an installer package and initializes an install session.
///
/// path to the patch package
/// command line property settings
/// There was an error installing the product
///
/// To completely remove a product, set REMOVE=ALL in .
///
/// This method displays the user interface with the current settings and
/// log mode. You can change user interface settings with the
/// and functions. You can set the log mode with the
/// function.
///
/// The and properties should be
/// tested after calling this method.
///
/// Win32 MSI API:
/// MsiInstallProduct
///
public static void InstallProduct(string packagePath, string commandLine)
{
uint ret = NativeMethods.MsiInstallProduct(packagePath, commandLine);
Installer.CheckInstallResult(ret);
}
///
/// Installs or uninstalls a product.
///
/// Product code of the product to be configured.
/// Specifies the default installation configuration of the
/// product. The parameter is ignored and all features
/// are installed if the parameter is set to any other
/// value than . This parameter must be either 0
/// (install using authored feature levels), 65535 (install all features), or a value
/// between 0 and 65535 to install a subset of available features.
/// Specifies the installation state for the product.
/// Specifies the command line property settings. This should
/// be a list of the format Property=Setting Property=Setting.
/// There was an error configuring the product
///
/// This method displays the user interface with the current settings and
/// log mode. You can change user interface settings with the
/// and functions. You can set the log mode with the
/// function.
///
/// The and properties should be
/// tested after calling this method.
///
/// Win32 MSI APIs:
/// MsiConfigureProduct,
/// MsiConfigureProductEx
///
public static void ConfigureProduct(string productCode, int installLevel, InstallState installState, string commandLine)
{
uint ret = NativeMethods.MsiConfigureProductEx(productCode, installLevel, (int) installState, commandLine);
Installer.CheckInstallResult(ret);
}
///
/// Configures the installed state for a product feature.
///
/// Product code of the product to be configured.
/// Specifies the feature ID for the feature to be configured.
/// Specifies the installation state for the feature.
/// There was an error configuring the feature
///
/// The and properties should be
/// tested after calling this method.
///
/// Win32 MSI API:
/// MsiConfigureFeature
///
public static void ConfigureFeature(string productCode, string feature, InstallState installState)
{
uint ret = NativeMethods.MsiConfigureFeature(productCode, feature, (int) installState);
Installer.CheckInstallResult(ret);
}
///
/// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes
/// an installation and sets the PATCH property to the path of the patch package.
///
/// path to the patch package
/// optional command line property settings
/// There was an error applying the patch
///
/// The and properties should be
/// tested after calling this method.
///
/// Win32 MSI API:
/// MsiApplyPatch
///
public static void ApplyPatch(string patchPackage, string commandLine)
{
Installer.ApplyPatch(patchPackage, null, InstallType.Default, commandLine);
}
///
/// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes
/// an installation and sets the PATCH property to the path of the patch package.
///
/// path to the patch package
/// path to the product to be patched, if installType
/// is set to
/// type of installation to patch
/// optional command line property settings
/// There was an error applying the patch
///
/// The and properties should be
/// tested after calling this method.
///
/// Win32 MSI API:
/// MsiApplyPatch
///
public static void ApplyPatch(string patchPackage, string installPackage, InstallType installType, string commandLine)
{
uint ret = NativeMethods.MsiApplyPatch(patchPackage, installPackage, (int) installType, commandLine);
Installer.CheckInstallResult(ret);
}
///
/// Removes one or more patches from a single product. To remove a patch from
/// multiple products, RemovePatches must be called for each product.
///
/// List of patches to remove. Each patch can be specified by the GUID
/// of the patch or the full path to the patch package.
/// The ProductCode (GUID) of the product from which the patches
/// are removed. This parameter cannot be null.
/// optional command line property settings
/// There was an error removing the patches
///
/// The and properties should be
/// tested after calling this method.
///
/// Win32 MSI API:
/// MsiRemovePatches
///
public static void RemovePatches(IList patches, string productCode, string commandLine)
{
if (patches == null || patches.Count == 0)
{
throw new ArgumentNullException("patches");
}
if (productCode == null)
{
throw new ArgumentNullException("productCode");
}
StringBuilder patchList = new StringBuilder();
foreach (string patch in patches)
{
if (patch != null)
{
if (patchList.Length != 0)
{
patchList.Append(';');
}
patchList.Append(patch);
}
}
if (patchList.Length == 0)
{
throw new ArgumentNullException("patches");
}
uint ret = NativeMethods.MsiRemovePatches(patchList.ToString(), productCode, (int) InstallType.SingleInstance, commandLine);
Installer.CheckInstallResult(ret);
}
///
/// Determines which patches apply to a specified product MSI and in what sequence.
///
/// Full path to an MSI file that is the target product
/// for the set of 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.
/// 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.
/// An array of selected patch strings from , indicating
/// the set of applicable patches. The items are re-ordered to be in the best sequence.
///
/// If an item in is a file path but does not end in .MSP or .XML,
/// it is assumed to be an MSP file.
///
/// As this overload uses InstallContext.None, it does not consider the current state of
/// the system.
///
/// Win32 MSI API:
/// MsiDetermineApplicablePatches
///
public static IList DetermineApplicablePatches(
string productPackage,
string[] patches,
InapplicablePatchHandler errorHandler)
{
return DetermineApplicablePatches(productPackage, patches, errorHandler, null, UserContexts.None);
}
///
/// 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.
///
/// 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.
/// 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.
/// 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.
/// 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 is set to
/// or , then
/// must be null. For the current user context,
/// can be null and can be set to
/// or .
/// 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 , ,
/// , or .
/// An array of selected patch strings from , indicating
/// the set of applicable patches. The items are re-ordered to be in the best sequence.
///
/// If an item in is a file path but does not end in .MSP or .XML,
/// it is assumed to be an MSP file.
///
/// 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.
///
/// Win32 MSI APIs:
/// MsiDetermineApplicablePatches
/// MsiDeterminePatchSequence
///
public static IList 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 patchSeq = new List(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;
}
///
/// Applies one or more patches to products that are eligible to receive the patch.
/// For each product listed by the patch package as eligible to receive the patch, ApplyPatch invokes
/// an installation and sets the PATCH property to the path of the patch package.
///
/// The set of patch packages to be applied.
/// Each item is the full path to an MSP file.
/// Provides the ProductCode of the product being patched. If this parameter
/// is null, the patches are applied to all products that are eligible to receive these patches.
/// optional command line property settings
///
/// Win32 MSI API:
/// MsiApplyMultiplePatches
///
public static void ApplyMultiplePatches(
IList patchPackages, string productCode, string commandLine)
{
if (patchPackages == null || patchPackages.Count == 0)
{
throw new ArgumentNullException("patchPackages");
}
StringBuilder patchList = new StringBuilder();
foreach (string patch in patchPackages)
{
if (patch != null)
{
if (patchList.Length != 0)
{
patchList.Append(';');
}
patchList.Append(patch);
}
}
if (patchList.Length == 0)
{
throw new ArgumentNullException("patchPackages");
}
uint ret = NativeMethods.MsiApplyMultiplePatches(patchList.ToString(), productCode, commandLine);
Installer.CheckInstallResult(ret);
}
///
/// 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
///
/// instead of the full patch file.
///
/// Full path to the patch being queried.
/// XML string containing patch data.
///
/// Win32 MSI API:
/// MsiExtractPatchXMLData
///
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();
}
///
/// [MSI 3.1] Migrates a user's application configuration data to a new SID.
///
/// Previous user SID that data is to be migrated from
/// New user SID that data is to be migrated to
///
/// Win32 MSI API:
/// MsiNotifySidChange
///
public static void NotifySidChange(string oldSid, string newSid)
{
uint ret = NativeMethods.MsiNotifySidChange(oldSid, newSid);
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
}
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);
}
}
private static int GetPatchStringDataType(string patchData)
{
if (patchData.IndexOf("<", StringComparison.Ordinal) >= 0 &&
patchData.IndexOf(">", StringComparison.Ordinal) >= 0)
{
return 2; // XML blob
}
else if (String.Compare(Path.GetExtension(patchData), ".xml",
StringComparison.OrdinalIgnoreCase) == 0)
{
return 1; // XML file path
}
else
{
return 0; // MSP file path
}
}
}
}