// 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.Text; using System.Collections; using System.Collections.Generic; /// /// Accessor for information about components within the context of an installation session. /// public sealed class ComponentInfoCollection : ICollection { private Session session; internal ComponentInfoCollection(Session session) { this.session = session; } /// /// Gets information about a component within the context of an installation session. /// /// name of the component /// component object public ComponentInfo this[string component] { get { return new ComponentInfo(this.session, component); } } void ICollection.Add(ComponentInfo item) { throw new InvalidOperationException(); } void ICollection.Clear() { throw new InvalidOperationException(); } /// /// Checks if the collection contains a component. /// /// name of the component /// true if the component is in the collection, else false public bool Contains(string component) { return this.session.Database.CountRows( "Component", "`Component` = '" + component + "'") == 1; } bool ICollection.Contains(ComponentInfo item) { return item != null && this.Contains(item.Name); } /// /// Copies the features into an array. /// /// array that receives the features /// offset into the array public void CopyTo(ComponentInfo[] array, int arrayIndex) { foreach (ComponentInfo component in this) { array[arrayIndex++] = component; } } /// /// Gets the number of components defined for the product. /// public int Count { get { return this.session.Database.CountRows("Component"); } } bool ICollection.IsReadOnly { get { return true; } } bool ICollection.Remove(ComponentInfo item) { throw new InvalidOperationException(); } /// /// Enumerates the components in the collection. /// /// an enumerator over all features in the collection public IEnumerator GetEnumerator() { using (View compView = this.session.Database.OpenView( "SELECT `Component` FROM `Component`")) { compView.Execute(); foreach (Record compRec in compView) using (compRec) { string comp = compRec.GetString(1); yield return new ComponentInfo(this.session, comp); } } } IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } } /// /// Provides access to information about a component within the context of an installation session. /// public class ComponentInfo { private Session session; private string name; internal ComponentInfo(Session session, string name) { this.session = session; this.name = name; } /// /// Gets the name of the component (primary key in the Component table). /// public string Name { get { return this.name; } } /// /// Gets the current install state of the designated Component. /// /// the Session handle is invalid /// an unknown Component was requested ///

/// Win32 MSI API: /// MsiGetComponentState ///

public InstallState CurrentState { get { int installedState, actionState; uint ret = RemotableNativeMethods.MsiGetComponentState((int) this.session.Handle, this.name, out installedState, out actionState); if (ret != 0) { if (ret == (uint) NativeMethods.Error.UNKNOWN_COMPONENT) { throw InstallerException.ExceptionFromReturnCode(ret, this.name); } else { throw InstallerException.ExceptionFromReturnCode(ret); } } return (InstallState) installedState; } } /// /// Gets or sets the action state of the designated Component. /// /// the Session handle is invalid /// an unknown Component was requested /// the user exited the installation ///

/// Win32 MSI APIs: /// MsiGetComponentState, /// MsiSetComponentState ///

public InstallState RequestState { get { int installedState, actionState; uint ret = RemotableNativeMethods.MsiGetComponentState((int) this.session.Handle, this.name, out installedState, out actionState); if (ret != 0) { if (ret == (uint) NativeMethods.Error.UNKNOWN_COMPONENT) { throw InstallerException.ExceptionFromReturnCode(ret, this.name); } else { throw InstallerException.ExceptionFromReturnCode(ret); } } return (InstallState) actionState; } set { uint ret = RemotableNativeMethods.MsiSetComponentState((int) this.session.Handle, this.name, (int) value); if (ret != 0) { if (ret == (uint) NativeMethods.Error.UNKNOWN_COMPONENT) { throw InstallerException.ExceptionFromReturnCode(ret, this.name); } else { throw InstallerException.ExceptionFromReturnCode(ret); } } } } /// /// Gets disk space per drive required to install a component. /// /// Requested component state /// A list of InstallCost structures, specifying the cost for each drive for the component ///

/// Win32 MSI API: /// MsiEnumComponentCosts ///

public IList GetCost(InstallState installState) { IList costs = new List(); StringBuilder driveBuf = new StringBuilder(20); for (uint i = 0; true; i++) { int cost, tempCost; uint driveBufSize = (uint) driveBuf.Capacity; uint ret = RemotableNativeMethods.MsiEnumComponentCosts( (int) this.session.Handle, this.name, i, (int) installState, driveBuf, ref driveBufSize, out cost, out tempCost); if (ret == (uint) NativeMethods.Error.NO_MORE_ITEMS) break; if (ret == (uint) NativeMethods.Error.MORE_DATA) { driveBuf.Capacity = (int) ++driveBufSize; ret = RemotableNativeMethods.MsiEnumComponentCosts( (int) this.session.Handle, this.name, i, (int) installState, driveBuf, ref driveBufSize, out cost, out tempCost); } if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } costs.Add(new InstallCost(driveBuf.ToString(), cost * 512L, tempCost * 512L)); } return costs; } } }