GetPatches(
string patchCode,
string targetProductCode,
string userSid,
UserContexts context,
PatchStates states)
{
StringBuilder buf = new StringBuilder(40);
StringBuilder targetProductBuf = new StringBuilder(40);
UserContexts targetContext;
StringBuilder targetSidBuf = new StringBuilder(40);
for (uint i = 0; ; i++)
{
uint targetSidBufSize = (uint) targetSidBuf.Capacity;
uint ret = NativeMethods.MsiEnumPatchesEx(
targetProductCode,
userSid,
context,
(uint) states,
i,
buf,
targetProductBuf,
out targetContext,
targetSidBuf,
ref targetSidBufSize);
if (ret == (uint) NativeMethods.Error.MORE_DATA)
{
targetSidBuf.Capacity = (int) ++targetSidBufSize;
ret = NativeMethods.MsiEnumPatchesEx(
targetProductCode,
userSid,
context,
(uint) states,
i,
buf,
targetProductBuf,
out targetContext,
targetSidBuf,
ref targetSidBufSize);
}
if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS)
{
break;
}
if (ret != 0)
{
throw InstallerException.ExceptionFromReturnCode(ret);
}
string thisPatchCode = buf.ToString();
if (patchCode == null || patchCode == thisPatchCode)
{
yield return new PatchInstallation(
buf.ToString(),
targetProductBuf.ToString(),
targetSidBuf.ToString(),
targetContext);
}
}
}
private string productCode;
///
/// Creates a new object for accessing information about a patch installation on the current system.
///
/// Patch code (GUID) of the patch.
/// ProductCode (GUID) the patch has been applied to.
/// This parameter may be null for patches that are registered only and not yet
/// applied to any product.
///
/// All available user contexts will be queried.
///
public PatchInstallation(string patchCode, string productCode)
: this(patchCode, productCode, null, UserContexts.All)
{
}
///
/// Creates a new object for accessing information about a patch installation on the current system.
///
/// Registered patch code (GUID) of the patch.
/// ProductCode (GUID) the patch has been applied to.
/// This parameter may be null for patches that are registered only and not yet
/// applied to any product.
/// The specific user, when working in a user context. This
/// parameter may be null to indicate the current user. The parameter must be null
/// when working in a machine context.
/// The user context. The calling process must have administrative
/// privileges to get information for a product installed for a user other than the
/// current user.
///
/// If the is null, the Patch object may
/// only be used to read and update the patch's SourceList information.
///
public PatchInstallation(string patchCode, string productCode, string userSid, UserContexts context)
: base(patchCode, userSid, context)
{
if (String.IsNullOrEmpty(patchCode))
{
throw new ArgumentNullException("patchCode");
}
this.productCode = productCode;
}
///
/// Gets the patch code (GUID) of the patch.
///
public string PatchCode
{
get
{
return this.InstallationCode;
}
}
///
/// Gets the ProductCode (GUID) of the product.
///
public string ProductCode
{
get
{
return this.productCode;
}
}
///
/// Gets a value indicating whether this patch is currently installed.
///
public override bool IsInstalled
{
get
{
return (this.State & PatchStates.Applied) != 0;
}
}
///
/// Gets a value indicating whether this patch is marked as obsolte.
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Obsoleted")]
public bool IsObsoleted
{
get
{
return (this.State & PatchStates.Obsoleted) != 0;
}
}
///
/// Gets a value indicating whether this patch is present but has been
/// superseded by a more recent installed patch.
///
public bool IsSuperseded
{
get
{
return (this.State & PatchStates.Superseded) != 0;
}
}
internal override int InstallationType
{
get
{
const int MSICODE_PATCH = 0x40000000;
return MSICODE_PATCH;
}
}
///
/// Gets the installation state of this instance of the patch.
///
/// An unknown patch was requested
/// The installer configuration data is corrupt
public PatchStates State
{
get
{
string stateString = this["State"];
return (PatchStates) Int32.Parse(stateString, CultureInfo.InvariantCulture.NumberFormat);
}
}
///
/// Gets the cached patch file that the product uses.
///
public string LocalPackage
{
get
{
return this["LocalPackage"];
}
}
///
/// Gets the set of patch transforms that the last patch
/// installation applied to the product.
///
///
/// This value may not be available for per-user, non-managed applications
/// if the user is not logged on.
///
public string Transforms
{
get
{
// TODO: convert to IList?
return this["Transforms"];
}
}
///
/// Gets the date and time when the patch is applied to the product.
///
public DateTime InstallDate
{
get
{
try
{
return DateTime.ParseExact(
this["InstallDate"], "yyyyMMdd", CultureInfo.InvariantCulture);
}
catch (FormatException)
{
return DateTime.MinValue;
}
}
}
///
/// True patch is marked as possible to uninstall from the product.
///
///
/// Even if this property is true, the installer can still block the
/// uninstallation if this patch is required by another patch that
/// cannot be uninstalled.
///
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Uninstallable")]
public bool Uninstallable
{
get
{
return this["Uninstallable"] == "1";
}
}
///
/// Get the registered display name for the patch.
///
public string DisplayName
{
get
{
return this["DisplayName"];
}
}
///
/// Gets the registered support information URL for the patch.
///
public Uri MoreInfoUrl
{
get
{
string value = this["MoreInfoURL"];
if (!String.IsNullOrEmpty(value))
{
try
{
return new Uri(value);
}
catch (UriFormatException) { }
}
return null;
}
}
///
/// Gets information about a specific patch installation.
///
/// The property being retrieved; see remarks for valid properties.
/// The property value, or an empty string if the property is not set for the patch.
/// An unknown patch or property was requested
/// The installer configuration data is corrupt
///
/// Win32 MSI APIs:
/// MsiGetPatchInfo,
/// MsiGetPatchInfoEx
///
public override string this[string propertyName]
{
get
{
StringBuilder buf = new StringBuilder("");
uint bufSize = 0;
uint ret;
if (this.Context == UserContexts.UserManaged ||
this.Context == UserContexts.UserUnmanaged ||
this.Context == UserContexts.Machine)
{
ret = NativeMethods.MsiGetPatchInfoEx(
this.PatchCode,
this.ProductCode,
this.UserSid,
this.Context,
propertyName,
buf,
ref bufSize);
if (ret == (uint) NativeMethods.Error.MORE_DATA)
{
buf.Capacity = (int) ++bufSize;
ret = NativeMethods.MsiGetPatchInfoEx(
this.PatchCode,
this.ProductCode,
this.UserSid,
this.Context,
propertyName,
buf,
ref bufSize);
}
}
else
{
ret = NativeMethods.MsiGetPatchInfo(
this.PatchCode,
propertyName,
buf,
ref bufSize);
if (ret == (uint) NativeMethods.Error.MORE_DATA)
{
buf.Capacity = (int) ++bufSize;
ret = NativeMethods.MsiGetPatchInfo(
this.PatchCode,
propertyName,
buf,
ref bufSize);
}
}
if (ret != 0)
{
return null;
}
return buf.ToString();
}
}
}
}