// 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.Globalization; using System.Runtime.InteropServices; /// /// Provides access to summary information of a Windows Installer database. /// public class SummaryInfo : InstallerHandle { internal const int MAX_PROPERTIES = 20; /// /// Gets a SummaryInfo object that can be used to examine, update, and add /// properties to the summary information stream of a package or transform. /// /// Path to the package (database) or transform /// True to reserve resources for writing summary information properties. /// the package does not exist or could not be read /// the package is an invalid format ///

/// The SummaryInfo 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: /// MsiGetSummaryInformation ///

public SummaryInfo(string packagePath, bool enableWrite) : base((IntPtr) SummaryInfo.OpenSummaryInfo(packagePath, enableWrite), true) { } internal SummaryInfo(IntPtr handle, bool ownsHandle) : base(handle, ownsHandle) { } /// Gets or sets the Title summary information property. ///

/// The Title summary information property briefly describes the type of installer package. Phrases /// such as "Installation Database" or "Transform" or "Patch" may be used for this property. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string Title { get { return this[2]; } set { this[2] = value; } } /// Gets or sets the Subject summary information property. ///

/// The Subject summary information property conveys to a file browser the product that can be installed using /// the logic and data in this installer database. For example, the value of the summary property for /// Microsoft Office 97 would be "Microsoft Office 97 Professional". This value is typically set from the /// installer property ProductName. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string Subject { get { return this[3]; } set { this[3] = value; } } /// Gets or sets the Author summary information property. ///

/// The Author summary information property conveys to a file browser the manufacturer of the installation /// database. This value is typically set from the installer property Manufacturer. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string Author { get { return this[4]; } set { this[4] = value; } } /// Gets or sets the Keywords summary information property. ///

/// The Keywords summary information property is used by file browsers to hold keywords that permit the /// database file to be found in a keyword search. The set of keywords typically includes "Installer" as /// well as product-specific keywords, and may be localized. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string Keywords { get { return this[5]; } set { this[5] = value; } } /// Gets or sets the Comments summary information property. ///

/// The Comments summary information property conveys the general purpose of the installer database. By convention, /// the value for this summary property is set to the following: ///

/// "This installer database contains the logic and data required to install <product name>." ///

/// where <product name> is the name of the product being installed. In general the value for this summary /// property only changes in the product name, nothing else. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string Comments { get { return this[6]; } set { this[6] = value; } } /// Gets or sets the Template summary information property. ///

/// The Template summary information propery indicates the platform and language versions supported by the database. ///

/// The syntax of the Template Summary property information is: /// [platform property][,platform property][,...];[language id][,language id][,...] ///

/// For example, the following are all valid values for the Template Summary property: /// /// Intel;1033 /// Intel64;1033 /// ;1033 /// ; /// Intel ;1033,2046 /// Intel64;1033,2046 /// Intel;0 /// ///

/// If this is a 64-bit Windows Installer, enter Intel64 in the Template summary information property. Note that an /// installation package cannot have both the Intel and Intel64 properties set. ///

/// If the current platform does not match one of the platforms specified then the installer will not process the /// package. Not specifying a platform implies that the package is platform-independent. ///

/// Entering 0 in the language ID field of the Template summary information property, or leaving this field empty, /// indicates that the package is language neutral. ///

/// There are variations of this property depending on whether it is in a source installer database or a transform. ///

/// Source Installer Database - Only one language can be specified in a source installer database. Merge Modules are /// the only packages that may have multiple languages. For more information, see Multiple Language Merge Modules. ///

/// Transform - In a transform file, only one language may be specified. The specified platform and language determine /// whether a transform can be applied to a particular database. The platform property and the language property can /// be left blank if no transform restriction relies on them to validate the transform. ///

/// This summary property is REQUIRED. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string Template { get { return this[7]; } set { this[7] = value; } } /// Gets or sets the LastSavedBy summary information property. ///

/// The installer sets the Last Saved By summary information property to the value of the LogonUser property during /// an administrative installation. The installer never uses this property and a user never needs to modify it. /// Developers of a database editing tool may use this property to track the last person to modify the database. /// This property should be left set to null in a final shipping database. ///

/// In a transform, this summary property contains the platform and language ID(s) that a database should have /// after it has been transformed. The property specifies to what the Template should be set in the new database. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string LastSavedBy { get { return this[8]; } set { this[8] = value; } } /// Gets or sets the RevisionNumber summary information property. ///

/// The Revision Number summary information property contains the package code for the installer package. The /// package code is a unique identifier of the installer package. ///

/// The Revision Number summary information property of a patch package specifies the GUID patch code for /// the patch. This is followed by a list of patch code GUIDs for obsolete patches that are removed when this /// patch is applied. The patch codes are concatenated with no delimiters separating GUIDs in the list. ///

/// The Revision Number summary information property of a transform package lists the product code GUIDs /// and version of the new and original products and the upgrade code GUID. The list is separated with /// semicolons as follows. ///

/// Original-Product-Code Original-Product-Version ; New-Product Code New-Product-Version; Upgrade-Code ///

/// This summary property is REQUIRED. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string RevisionNumber { get { return this[9]; } set { this[9] = value; } } /// Gets or sets the CreatingApp summary information property. ///

/// The CreatingApp summary information property conveys which application created the installer database. /// In general the value for this summary property is the name of the software used to author this database. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public string CreatingApp { get { return this[18]; } set { this[18] = value; } } /// Gets or sets the LastPrintTime summary information property. ///

/// The LastPrintTime summary information property can be set to the date and time during an administrative /// installation to record when the administrative image was created. For non-administrative installations /// this property is the same as the CreateTime summary information property. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public DateTime LastPrintTime { get { return (DateTime) this[11, typeof(DateTime)]; } set { this[11, typeof(DateTime)] = value; } } /// Gets or sets the CreateTime summary information property. ///

/// The CreateTime summary information property conveys when the installer database was created. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public DateTime CreateTime { get { return (DateTime) this[12, typeof(DateTime)]; } set { this[12, typeof(DateTime)] = value; } } /// Gets or sets the LastSaveTime summary information property. ///

/// The LastSaveTime summary information property conveys when the last time the installer database was /// modified. Each time a user changes an installation the value for this summary property is updated to /// the current system time/date at the time the installer database was saved. Initially the value for /// this summary property is set to null to indicate that no changes have yet been made. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public DateTime LastSaveTime { get { return (DateTime) this[13, typeof(DateTime)]; } set { this[13, typeof(DateTime)] = value; } } /// Gets or sets the CodePage summary information property. ///

/// The Codepage summary information property is the numeric value of the ANSI code page used for any /// strings that are stored in the summary information. Note that this is not the same code page for /// strings in the installation database. The Codepage summary information property is used to translate /// the strings in the summary information into Unicode when calling the Unicode API functions. The /// Codepage summary information property must be set before any string properties are set in the /// summary information. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public short CodePage { get { return (short) this[1, typeof(short)]; } set { this[1, typeof(short)] = value; } } /// Gets or sets the PageCount summary information property. ///

/// For an installation package, the PageCount summary information property contains the minimum /// installer version required. For Windows Installer version 1.0, this property must be set to the /// integer 100. For 64-bit Windows Installer Packages, this property must be set to the integer 200. ///

/// For a transform package, the PageCount summary information property contains minimum installer /// version required to process the transform. Set to the greater of the two PageCount summary information /// property values belonging to the databases used to generate the transform. ///

/// The PageCount summary information property is set to null in patch packages. ///

/// This summary property is REQUIRED. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public int PageCount { get { return (int) this[14, typeof(int)]; } set { this[14, typeof(int)] = value; } } /// Gets or sets the WordCount summary information property. ///

/// The WordCount summary information property indicates the type of source file image. If this property is /// not present, it defaults to 0. Note that this property is stored in place of the standard Count property. ///

/// This property is a bit field. New bits may be added in the future. At present the following bits are /// available: /// /// Bit 0: 0 = long file names, 1 = short file names /// Bit 1: 0 = source is uncompressed, 1 = source is compressed /// Bit 2: 0 = source is original media, 1 = source is administrative installation /// [MSI 4.0] Bit 3: 0 = elevated privileges can be required to install, 1 = elevated privileges are not required to install /// ///

/// These are combined to give the WordCount summary information property one of the following values /// indicating a type of source file image: /// /// 0 - Original source using long file names. Matches tree in Directory table. /// 1 - Original source using short file names. Matches tree in Directory table. /// 2 - Compressed source files using long file names. Matches cabinets and files in the Media table. /// 3 - Compressed source files using short file names. Matches cabinets and files in the Media table. /// 4 - Administrative image using long file names. Matches tree in Directory table. /// 5 - Administrative image using short file names. Matches tree in Directory table. /// ///

/// Note that if the package is marked as compressed (bit 1 is set), the installer only installs files /// located at the root of the source. In this case, even files marked as uncompressed in the File table must /// be located at the root to be installed. To specify a source image that has both a cabinet file (compressed /// files) and uncompressed files that match the tree in the Directory table, mark the package as uncompressed /// by leaving bit 1 unset (value=0) in the WordCount summary information property and set /// (value=16384) in the Attributes column of the File table /// for each file in the cabinet. ///

/// For a patch package, the WordCount summary information property specifies the patch engine that was used /// to create the patch files. The default value is 1 and indicates that MSPATCH was used to create the patch /// A value of "2" means that the patch is using smaller, optimized, files available only with Windows Installer /// version 1.2 or later. A patch with a WordCount of "2" fails immediately if used with a Windows Installer /// version earlier than 1.2. A patch with a WordCount of "3" fails immediately if used with a Windows Installer /// version earlier than 2.0. ///

/// This summary property is REQUIRED. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public int WordCount { get { return (int) this[15, typeof(int)]; } set { this[15, typeof(int)] = value; } } /// Gets or sets the CharacterCount summary information property. ///

/// The CharacterCount summary information property is only used in transforms. This part of the summary /// information stream is divided into two 16-bit words. The upper word contains the transform validation /// flags. The lower word contains the transform error condition flags. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public int CharacterCount { get { return (int) this[16, typeof(int)]; } set { this[16, typeof(int)] = value; } } /// Gets or sets the Security summary information property. ///

/// The Security summary information property conveys whether the package should be opened as read-only. The database /// editing tool should not modify a read-only enforced database and should issue a warning at attempts to modify a /// read-only recommended database. The following values of this property are applicable to Windows Installer files: /// /// 0 - no restriction /// 2 - read only recommended /// 4 - read only enforced /// ///

/// This property should be set to read-only recommended (2) for an installation database and to read-only /// enforced (4) for a transform or patch. ///

/// Win32 MSI APIs: /// MsiSummaryInfoGetProperty, /// MsiSummaryInfoSetProperty ///

public int Security { get { return (int) this[19, typeof(int)]; } set { this[19, typeof(int)] = value; } } private object this[uint property, Type type] { get { uint dataType; StringBuilder stringValue = new StringBuilder(""); uint bufSize = 0; int intValue; long timeValue = 0; uint ret = RemotableNativeMethods.MsiSummaryInfoGetProperty( (int) this.Handle, property, out dataType, out intValue, ref timeValue, stringValue, ref bufSize); if (ret != 0 && dataType != (uint) VarEnum.VT_LPSTR) { throw InstallerException.ExceptionFromReturnCode(ret); } switch ((VarEnum) dataType) { case VarEnum.VT_EMPTY: { if (type == typeof(DateTime)) { return DateTime.MinValue; } else if (type == typeof(string)) { return String.Empty; } else if (type == typeof(short)) { return (short) 0; } else { return (int) 0; } } case VarEnum.VT_LPSTR: { if (ret == (uint) NativeMethods.Error.MORE_DATA) { stringValue.Capacity = (int) ++bufSize; ret = RemotableNativeMethods.MsiSummaryInfoGetProperty( (int) this.Handle, property, out dataType, out intValue, ref timeValue, stringValue, ref bufSize); } if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } return stringValue.ToString(); } case VarEnum.VT_I2: case VarEnum.VT_I4: { if (type == typeof(string)) { return intValue.ToString(CultureInfo.InvariantCulture); } else if (type == typeof(short)) { return (short) intValue; } else { return intValue; } } case VarEnum.VT_FILETIME: { if (type == typeof(string)) { return DateTime.FromFileTime(timeValue).ToString(CultureInfo.InvariantCulture); } else { return DateTime.FromFileTime(timeValue); } } default: { throw new InstallerException(); } } } set { uint dataType = (uint) VarEnum.VT_NULL; string stringValue = ""; int intValue = 0; long timeValue = 0; if (type == typeof(short)) { dataType = (uint) VarEnum.VT_I2; intValue = (int)(short) value; // Double cast because value is a *boxed* short. } else if (type == typeof(int)) { dataType = (uint) VarEnum.VT_I4; intValue = (int) value; } else if (type == typeof(string)) { dataType = (uint) VarEnum.VT_LPSTR; stringValue = (string) value; } else // (type == typeof(DateTime)) { dataType = (uint) VarEnum.VT_FILETIME; timeValue = ((DateTime) value).ToFileTime(); } uint ret = NativeMethods.MsiSummaryInfoSetProperty( (int) this.Handle, property, dataType, intValue, ref timeValue, stringValue); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } } } private string this[uint property] { get { return (string) this[property, typeof(string)]; } set { this[property, typeof(string)] = value; } } /// /// Formats and writes the previously stored properties into the standard summary information stream. /// /// The stream cannot be successfully written. ///

/// This method may only be called once after all the property values have been set. Properties may /// still be read after the stream is written. ///

/// Win32 MSI API: /// MsiSummaryInfoPersist ///

public void Persist() { uint ret = NativeMethods.MsiSummaryInfoPersist((int) this.Handle); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } } private static int OpenSummaryInfo(string packagePath, bool enableWrite) { int summaryInfoHandle; int maxProperties = !enableWrite ? 0 : SummaryInfo.MAX_PROPERTIES; uint ret = RemotableNativeMethods.MsiGetSummaryInformation( 0, packagePath, (uint) maxProperties, out summaryInfoHandle); if (ret != 0) { if (ret == (uint) NativeMethods.Error.FILE_NOT_FOUND || ret == (uint) NativeMethods.Error.ACCESS_DENIED) { throw new FileNotFoundException(null, packagePath); } else { throw InstallerException.ExceptionFromReturnCode(ret); } } return summaryInfoHandle; } } }