/// <summary> /// Checks whether a transform is valid for this Database, according to its validation data and flags. /// </summary> /// <param name="transformFile">Path to the transform file</param> /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns> /// <exception cref="InstallerException">the transform could not be applied</exception> /// <exception cref="InvalidHandleException">the Database handle is invalid</exception> public bool IsTransformValid(string transformFile) { if (String.IsNullOrEmpty(transformFile)) { throw new ArgumentNullException("transformFile"); } using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false)) { return(this.IsTransformValid(transformSummInfo)); } }
/// <summary> /// Closes the database handle. After closing a handle, further method calls may throw <see cref="InvalidHandleException"/>. /// </summary> /// <param name="disposing">If true, the method has been called directly or /// indirectly by a user's code, so managed and unmanaged resources will be /// disposed. If false, only unmanaged resources will be disposed.</param> protected override void Dispose(bool disposing) { if (!this.IsClosed && (this.OpenMode == DatabaseOpenMode.CreateDirect || this.OpenMode == DatabaseOpenMode.Direct)) { // Always commit a direct-opened database before closing. // This avoids unexpected corruption of the database. this.Commit(); } base.Dispose(disposing); if (disposing) { if (this.summaryInfo != null) { this.summaryInfo.Close(); this.summaryInfo = null; } if (this.deleteOnClose != null) { foreach (string path in this.deleteOnClose) { try { if (Directory.Exists(path)) { Directory.Delete(path, true); } else { if (File.Exists(path)) { File.Delete(path); } } } catch (IOException) { } catch (UnauthorizedAccessException) { } } this.deleteOnClose = null; } } }
/// <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); } }
/// <summary> /// Apply a transform to the database, suppressing any error conditions /// specified by the transform's summary information. /// </summary> /// <param name="transformFile">Path to the transform file</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) { if (String.IsNullOrEmpty(transformFile)) { throw new ArgumentNullException("transformFile"); } TransformErrors errorConditionsToSuppress; using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false)) { int errorConditions = transformSummInfo.CharacterCount & 0xFFFF; errorConditionsToSuppress = (TransformErrors) errorConditions; } this.ApplyTransform(transformFile, errorConditionsToSuppress); }
/// <summary> /// Apply a transform to the database, suppressing any error conditions /// specified by the transform's summary information. /// </summary> /// <param name="transformFile">Path to the transform file</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) { if (String.IsNullOrEmpty(transformFile)) { throw new ArgumentNullException("transformFile"); } TransformErrors errorConditionsToSuppress; using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false)) { int errorConditions = transformSummInfo.CharacterCount & 0xFFFF; errorConditionsToSuppress = (TransformErrors)errorConditions; } this.ApplyTransform(transformFile, errorConditionsToSuppress); }
/// <summary> /// Checks whether a transform is valid for this Database, according to its SummaryInfo data. /// </summary> /// <param name="transformSummaryInfo">SummaryInfo data of a transform file</param> /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns> /// <exception cref="InstallerException">error processing summary info</exception> /// <exception cref="InvalidHandleException">the Database or SummaryInfo handle is invalid</exception> public bool IsTransformValid(SummaryInfo transformSummaryInfo) { if (transformSummaryInfo == null) { throw new ArgumentNullException("transformSummaryInfo"); } string[] rev = transformSummaryInfo.RevisionNumber.Split(new char[] { ';' }, 3); string targetProductCode = rev[0].Substring(0, 38); string targetProductVersion = rev[0].Substring(38); string upgradeCode = rev[2]; string[] templ = transformSummaryInfo.Template.Split(new char[] { ';' }, 2); int targetProductLanguage = 0; if (templ.Length >= 2 && templ[1].Length > 0) { targetProductLanguage = Int32.Parse(templ[1], CultureInfo.InvariantCulture.NumberFormat); } int flags = transformSummaryInfo.CharacterCount; int validateFlags = flags >> 16; string thisProductCode = this.ExecutePropertyQuery("ProductCode"); string thisProductVersion = this.ExecutePropertyQuery("ProductVersion"); string thisUpgradeCode = this.ExecutePropertyQuery("UpgradeCode"); string thisProductLang = this.ExecutePropertyQuery("ProductLanguage"); int thisProductLanguage = 0; if (!String.IsNullOrEmpty(thisProductLang)) { thisProductLanguage = Int32.Parse(thisProductLang, CultureInfo.InvariantCulture.NumberFormat); } if ((validateFlags & (int)TransformValidations.Product) != 0 && thisProductCode != targetProductCode) { return(false); } if ((validateFlags & (int)TransformValidations.UpgradeCode) != 0 && thisUpgradeCode != upgradeCode) { return(false); } if ((validateFlags & (int)TransformValidations.Language) != 0 && targetProductLanguage != 0 && thisProductLanguage != targetProductLanguage) { return(false); } Version thisProductVer = new Version(thisProductVersion); Version targetProductVer = new Version(targetProductVersion); if ((validateFlags & (int)TransformValidations.UpdateVersion) != 0) { if (thisProductVer.Major != targetProductVer.Major) { return(false); } if (thisProductVer.Minor != targetProductVer.Minor) { return(false); } if (thisProductVer.Build != targetProductVer.Build) { return(false); } } else if ((validateFlags & (int)TransformValidations.MinorVersion) != 0) { if (thisProductVer.Major != targetProductVer.Major) { return(false); } if (thisProductVer.Minor != targetProductVer.Minor) { return(false); } } else if ((validateFlags & (int)TransformValidations.MajorVersion) != 0) { if (thisProductVer.Major != targetProductVer.Major) { return(false); } } return(true); }
private DataView GetPatchData(string patchCode) { DataTable table = new DataTable("PatchProperties"); table.Locale = CultureInfo.InvariantCulture; table.Columns.Add("PatchPropertiesProperty", typeof(string)); table.Columns.Add("PatchPropertiesValue", typeof(string)); table.Rows.Add(new object[] { "PatchCode", patchCode }); PatchInstallation patch = new PatchInstallation(patchCode, null); string localPackage = null; foreach(string property in new string[] { "InstallDate", "LocalPackage", "State", "Transforms", "Uninstallable", }) { try { string value = patch[property]; table.Rows.Add(new object[] { property, (value != null ? value : "") }); if(property == "LocalPackage") localPackage = value; } catch(InstallerException iex) { table.Rows.Add(new object[] { property, iex.Message }); } catch(ArgumentException) { } } if(localPackage != null) { try { using(SummaryInfo patchSummaryInfo = new SummaryInfo(localPackage, false)) { table.Rows.Add(new object[] { "Title", patchSummaryInfo.Title }); table.Rows.Add(new object[] { "Subject", patchSummaryInfo.Subject }); table.Rows.Add(new object[] { "Author", patchSummaryInfo.Author }); table.Rows.Add(new object[] { "Comments", patchSummaryInfo.Comments }); table.Rows.Add(new object[] { "TargetProductCodes", patchSummaryInfo.Template }); string obsoletedPatchCodes = patchSummaryInfo.RevisionNumber.Substring(patchSummaryInfo.RevisionNumber.IndexOf('}') + 1); table.Rows.Add(new object[] { "ObsoletedPatchCodes", obsoletedPatchCodes }); table.Rows.Add(new object[] { "TransformNames", patchSummaryInfo.LastSavedBy }); } } catch(InstallerException) { } catch(IOException) { } catch(SecurityException) { } } return new DataView(table, "", "PatchPropertiesProperty ASC", DataViewRowState.CurrentRows); }
/// <summary> /// Closes the database handle. After closing a handle, further method calls may throw <see cref="InvalidHandleException"/>. /// </summary> /// <param name="disposing">If true, the method has been called directly or /// indirectly by a user's code, so managed and unmanaged resources will be /// disposed. If false, only unmanaged resources will be disposed.</param> internal override void Dispose(bool disposing) { if (!this.IsClosed && (this.OpenMode == DatabaseOpenMode.CreateDirect || this.OpenMode == DatabaseOpenMode.Direct)) { // Always commit a direct-opened database before closing. // This avoids unexpected corruption of the database. this.Commit(); } base.Dispose(disposing); if (disposing) { if (this.summaryInfo != null) { this.summaryInfo.Close(); this.summaryInfo = null; } if (this.deleteOnClose != null) { foreach (string path in this.deleteOnClose) { try { if (Directory.Exists(path)) { Directory.Delete(path, true); } else { if (File.Exists(path)) File.Delete(path); } } catch (IOException) { } catch (UnauthorizedAccessException) { } } this.deleteOnClose = null; } } }
/// <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> internal 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); } }
/// <summary> /// Gets a SummaryInfo object that can be used to examine, update, and add /// properties to the summary information stream of a package or transform. /// </summary> /// <param name="packagePath">Path to the package (database) or transform</param> /// <param name="enableWrite">True to reserve resources for writing summary information properties.</param> /// <exception cref="FileNotFoundException">the package does not exist or could not be read</exception> /// <exception cref="InstallerException">the package is an invalid format</exception> /// <remarks><p> /// The SummaryInfo 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/msigetsummaryinformation.asp">MsiGetSummaryInformation</a> /// </p></remarks> public SummaryInfo(string packagePath, bool enableWrite) : base((IntPtr)SummaryInfo.OpenSummaryInfo(packagePath, enableWrite), true) { }
/// <summary> /// Checks whether a transform is valid for this Database, according to its SummaryInfo data. /// </summary> /// <param name="transformSummaryInfo">SummaryInfo data of a transform file</param> /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns> /// <exception cref="InstallerException">error processing summary info</exception> /// <exception cref="InvalidHandleException">the Database or SummaryInfo handle is invalid</exception> public bool IsTransformValid(SummaryInfo transformSummaryInfo) { if (transformSummaryInfo == null) { throw new ArgumentNullException("transformSummaryInfo"); } string[] rev = transformSummaryInfo.RevisionNumber.Split(new char[] { ';' }, 3); string targetProductCode = rev[0].Substring(0, 38); string targetProductVersion = rev[0].Substring(38); string upgradeCode = rev[2]; string[] templ = transformSummaryInfo.Template.Split(new char[] { ';' }, 2); int targetProductLanguage = 0; if (templ.Length >= 2 && templ[1].Length > 0) { targetProductLanguage = Int32.Parse(templ[1], CultureInfo.InvariantCulture.NumberFormat); } int flags = transformSummaryInfo.CharacterCount; int validateFlags = flags >> 16; string thisProductCode = this.ExecutePropertyQuery("ProductCode"); string thisProductVersion = this.ExecutePropertyQuery("ProductVersion"); string thisUpgradeCode = this.ExecutePropertyQuery("UpgradeCode"); string thisProductLang = this.ExecutePropertyQuery("ProductLanguage"); int thisProductLanguage = 0; if (!String.IsNullOrEmpty(thisProductLang)) { thisProductLanguage = Int32.Parse(thisProductLang, CultureInfo.InvariantCulture.NumberFormat); } if ((validateFlags & (int) TransformValidations.Product) != 0 && thisProductCode != targetProductCode) { return false; } if ((validateFlags & (int) TransformValidations.UpgradeCode) != 0 && thisUpgradeCode != upgradeCode) { return false; } if ((validateFlags & (int) TransformValidations.Language) != 0 && targetProductLanguage != 0 && thisProductLanguage != targetProductLanguage) { return false; } Version thisProductVer = new Version(thisProductVersion); Version targetProductVer = new Version(targetProductVersion); if ((validateFlags & (int) TransformValidations.UpdateVersion) != 0) { if (thisProductVer.Major != targetProductVer.Major) return false; if (thisProductVer.Minor != targetProductVer.Minor) return false; if (thisProductVer.Build != targetProductVer.Build) return false; } else if ((validateFlags & (int) TransformValidations.MinorVersion) != 0) { if (thisProductVer.Major != targetProductVer.Major) return false; if (thisProductVer.Minor != targetProductVer.Minor) return false; } else if ((validateFlags & (int) TransformValidations.MajorVersion) != 0) { if (thisProductVer.Major != targetProductVer.Major) return false; } return true; }
/// <summary> /// Checks whether a transform is valid for this Database, according to its validation data and flags. /// </summary> /// <param name="transformFile">Path to the transform file</param> /// <returns>true if the transform can be validly applied to this Database; false otherwise</returns> /// <exception cref="InstallerException">the transform could not be applied</exception> /// <exception cref="InvalidHandleException">the Database handle is invalid</exception> public bool IsTransformValid(string transformFile) { if (String.IsNullOrEmpty(transformFile)) { throw new ArgumentNullException("transformFile"); } using (SummaryInfo transformSummInfo = new SummaryInfo(transformFile, false)) { return this.IsTransformValid(transformSummInfo); } }