/// <summary> /// Installs files that are unexpectedly missing. /// </summary> /// <param name="product">Product code for the product that owns the component to be installed</param> /// <param name="component">Component to be installed</param> /// <param name="installState">Specifies the way the component should be installed.</param> /// <exception cref="InstallCanceledException">the user exited the installation</exception> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiinstallmissingcomponent.asp">MsiInstallMissingComponent</a> /// </p></remarks> 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); } }
/// <summary> /// Formats and writes the previously stored properties into the standard summary information stream. /// </summary> /// <exception cref="InstallerException">The stream cannot be successfully written.</exception> /// <remarks><p> /// 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. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisummaryinfopersist.asp">MsiSummaryInfoPersist</a> /// </p></remarks> public void Persist() { uint ret = NativeMethods.MsiSummaryInfoPersist((int)this.Handle); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Sets all fields in a record to null. /// </summary> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msirecordcleardata.asp">MsiRecordClearData</a> /// </p></remarks> public void Clear() { uint ret = RemotableNativeMethods.MsiRecordClearData((int)this.Handle); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Sets a record stream field from a Stream object. Stream data cannot be inserted into temporary fields. /// </summary> /// <param name="field">Specifies the field of the Record to set.</param> /// <param name="stream">Specifies the stream data.</param> /// <exception cref="ArgumentOutOfRangeException">The field is less than 0 or greater than the /// number of fields in the Record.</exception> /// <remarks><p> /// The stream persists if the Record is inserted into the Database and the Database is committed. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msirecordsetstream.asp">MsiRecordsetStream</a> /// </p></remarks> public void SetStream(int field, Stream stream) { this.CheckRange(field); if (stream == null) { uint ret = RemotableNativeMethods.MsiRecordSetStream((int)this.Handle, (uint)field, null); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } } else { Stream writeStream = null; string tempPath = Path.GetTempFileName(); try { writeStream = new FileStream(tempPath, FileMode.Truncate, FileAccess.Write); byte[] buf = new byte[512]; int count; while ((count = stream.Read(buf, 0, buf.Length)) > 0) { writeStream.Write(buf, 0, count); } writeStream.Close(); writeStream = null; uint ret = RemotableNativeMethods.MsiRecordSetStream((int)this.Handle, (uint)field, tempPath); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } } finally { if (writeStream != null) { writeStream.Close(); } if (File.Exists(tempPath)) { try { File.Delete(tempPath); } catch (IOException) { if (this.view != null) { this.view.Database.DeleteOnClose(tempPath); } } } } } }
/// <summary> /// [MSI 3.1] Migrates a user's application configuration data to a new SID. /// </summary> /// <param name="oldSid">Previous user SID that data is to be migrated from</param> /// <param name="newSid">New user SID that data is to be migrated to</param> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msinotifysidchange.asp">MsiNotifySidChange</a> /// </p></remarks> public static void NotifySidChange(string oldSid, string newSid) { uint ret = NativeMethods.MsiNotifySidChange(oldSid, newSid); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Reinstalls a product. /// </summary> /// <param name="product">Product code for the product to be reinstalled</param> /// <param name="reinstallModes">Reinstall modes</param> /// <exception cref="InstallCanceledException">the user exited the installation</exception> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msireinstallproduct.asp">MsiReinstallProduct</a> /// </p></remarks> public static void ReinstallProduct(string product, ReinstallModes reinstallModes) { uint ret = NativeMethods.MsiReinstallProduct(product, (uint)reinstallModes); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Installs files that are unexpectedly missing. /// </summary> /// <param name="product">Product code for the product that owns the file to be installed</param> /// <param name="file">File to be installed</param> /// <exception cref="InstallCanceledException">the user exited the installation</exception> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiinstallmissingfile.asp">MsiInstallMissingFile</a> /// </p></remarks> public static void InstallMissingFile(string product, string file) { uint ret = NativeMethods.MsiInstallMissingFile(product, file); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
private void End(bool commit) { uint ret = NativeMethods.MsiEndTransaction(commit ? 1 : 0); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Enables logging of the selected message type for all subsequent install sessions in /// the current process space. /// </summary> /// <param name="logModes">One or more mode flags specifying the type of messages to log</param> /// <param name="logFile">Full path to the log file. A null path disables logging, /// in which case the logModes paraneter is ignored.</param> /// <param name="append">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.</param> /// <param name="flushEveryLine">If true, the log will be flushed after every line. /// If false, the log will be flushed every 20 lines. The default is true.</param> /// <exception cref="ArgumentException">an invalid log mode was specified</exception> /// <remarks><p> /// This method takes effect on any new installation processes. Calling this /// method from within a custom action will not start logging for that installation. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msienablelog.asp">MsiEnableLog</a> /// </p></remarks> 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); } }
/// <summary> /// Sets the install level for the current installation to a specified value and /// recalculates the Select and Installed states for all features in the Feature /// table. Also sets the Action state of each component in the Component table based /// on the new level. /// </summary> /// <param name="installLevel">New install level</param> /// <exception cref="InvalidHandleException">the Session handle is invalid</exception> /// <remarks><p> /// The SetInstallLevel method sets the following:<list type="bullet"> /// <item><description>The installation level for the current installation to a specified value</description></item> /// <item><description>The Select and Installed states for all features in the Feature table</description></item> /// <item><description>The Action state of each component in the Component table, based on the new level</description></item> /// </list> /// If 0 or a negative number is passed in the ilnstallLevel parameter, /// the current installation level does not change, but all features are still /// updated based on the current installation level. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetinstalllevel.asp">MsiSetInstallLevel</a> /// </p></remarks> public void SetInstallLevel(int installLevel) { this.ValidateSessionAccess(); uint ret = RemotableNativeMethods.MsiSetInstallLevel((int)this.Handle, installLevel); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Opens an installer package for use with functions that access the product database and install engine, /// returning an Session object. /// </summary> /// <param name="packagePath">Path to the package</param> /// <param name="ignoreMachineState">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.</param> /// <returns>A Session object allowing access to the product database and install engine</returns> /// <exception cref="InstallerException">The product could not be opened</exception> /// <exception cref="InstallerException">The installer configuration data is corrupt</exception> /// <remarks><p> /// 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. /// </p><p> /// A "safe" Session object ignores the current computer state when opening the package and prevents /// changes to the current computer state. /// </p><p> /// The Session 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 APIs: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenpackage.asp">MsiOpenPackage</a>, /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiopenpackageex.asp">MsiOpenPackageEx</a> /// </p></remarks> 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)); }
/// <summary> /// Sets the value of a field to an integer. /// </summary> /// <param name="field">Specifies the field to set.</param> /// <param name="value">new value of the field</param> /// <exception cref="ArgumentOutOfRangeException">The field is less than 0 or greater than the /// number of fields in the Record.</exception> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msirecordsetinteger.asp">MsiRecordSetInteger</a> /// </p></remarks> /// <seealso cref="SetNullableInteger(int,int?)"/> public void SetInteger(int field, int value) { this.CheckRange(field); uint ret = RemotableNativeMethods.MsiRecordSetInteger((int)this.Handle, (uint)field, value); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Obtains and stores the user information and product ID from an installation wizard. /// </summary> /// <remarks><p> /// This method is typically called by an application during the first run of the application. The application /// first gets the <see cref="ProductInstallation.ProductId"/> or <see cref="ProductInstallation.RegOwner"/>. /// If those properties are missing, the application calls CollectUserInfo. /// CollectUserInfo opens the product's installation package and invokes a wizard sequence that collects /// user information. Upon completion of the sequence, user information is registered. Since this API requires /// an authored user interface, the user interface level should be set to full by calling /// <see cref="Installer.SetInternalUI(InstallUIOptions)"/> as <see cref="InstallUIOptions.Full"/>. /// </p><p> /// The CollectUserInfo method invokes a FirstRun dialog from the product installation database. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msicollectuserinfo.asp">MsiCollectUserInfo</a> /// </p></remarks> public void CollectUserInfo() { if (this.properties == null) { uint ret = NativeMethods.MsiCollectUserInfo(this.InstallationCode); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } } }
/// <summary> /// Enumerates the source media in the source list of the patch or product installation. /// </summary> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistenummediadisks.asp">MsiSourceListEnumMediaDisks</a> /// </p></remarks> public IEnumerator <MediaDisk> GetEnumerator() { uint diskId; StringBuilder volumeBuf = new StringBuilder(40); uint volumeBufSize = (uint)volumeBuf.Capacity; StringBuilder promptBuf = new StringBuilder(80); uint promptBufSize = (uint)promptBuf.Capacity; for (uint i = 0; true; i++) { uint ret = NativeMethods.MsiSourceListEnumMediaDisks( this.installation.InstallationCode, this.installation.UserSid, this.installation.Context, (uint)this.installation.InstallationType, i, out diskId, volumeBuf, ref volumeBufSize, promptBuf, ref promptBufSize); if (ret == (uint)NativeMethods.Error.MORE_DATA) { volumeBuf.Capacity = (int)++volumeBufSize; promptBuf.Capacity = (int)++promptBufSize; ret = NativeMethods.MsiSourceListEnumMediaDisks( this.installation.InstallationCode, this.installation.UserSid, this.installation.Context, (uint)this.installation.InstallationType, i, out diskId, volumeBuf, ref volumeBufSize, promptBuf, ref promptBufSize); } if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS) { break; } if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } yield return(new MediaDisk((int)diskId, volumeBuf.ToString(), promptBuf.ToString())); } }
/// <summary> /// Gets or sets the string value of a named installer property, as maintained by the /// Session object in the in-memory Property table, or, if it is prefixed with a percent /// sign (%), the value of a system environment variable for the current process. /// </summary> /// <exception cref="InvalidHandleException">the Session handle is invalid</exception> /// <remarks><p> /// Win32 MSI APIs: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msigetproperty.asp">MsiGetProperty</a>, /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetproperty.asp">MsiSetProperty</a> /// </p></remarks> public string this[string property] { get { if (String.IsNullOrEmpty(property)) { throw new ArgumentNullException("property"); } if (!this.sessionAccessValidated && !Session.NonImmediatePropertyNames.Contains(property)) { this.ValidateSessionAccess(); } StringBuilder buf = new StringBuilder(); uint bufSize = 0; uint ret = RemotableNativeMethods.MsiGetProperty((int)this.Handle, property, buf, ref bufSize); if (ret == (uint)NativeMethods.Error.MORE_DATA) { buf.Capacity = (int)++bufSize; ret = RemotableNativeMethods.MsiGetProperty((int)this.Handle, property, buf, ref bufSize); } if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } return(buf.ToString()); } set { if (String.IsNullOrEmpty(property)) { throw new ArgumentNullException("property"); } this.ValidateSessionAccess(); if (value == null) { value = String.Empty; } uint ret = RemotableNativeMethods.MsiSetProperty((int)this.Handle, property, value); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } } }
private static IntPtr[] Begin(string transactionName, TransactionAttributes attributes) { int hTransaction; IntPtr hChangeOfOwnerEvent; uint ret = NativeMethods.MsiBeginTransaction(transactionName, (int)attributes, out hTransaction, out hChangeOfOwnerEvent); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } return(new IntPtr[] { (IntPtr)hTransaction, hChangeOfOwnerEvent }); }
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); } }
/// <summary> /// Removes all source media from the list. /// </summary> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistclearallex.asp">MsiSourceListClearAllEx</a> /// </p></remarks> public void Clear() { uint ret = NativeMethods.MsiSourceListClearAllEx( this.installation.InstallationCode, this.installation.UserSid, this.installation.Context, (uint)NativeMethods.SourceType.Media | (uint)this.installation.InstallationType); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Forces the installer to search the source list for a valid /// source the next time a source is required. For example, when the /// installer performs an installation or reinstallation, or when it /// requires the path for a component that is set to run from source. /// </summary> /// <remarks><p> /// Win32 MSI APIs: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistforceresolution.asp">MsiSourceListForceResolution</a>, /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistforceresolutionex.asp">MsiSourceListForceResolutionEx</a> /// </p></remarks> public void ForceResolution() { uint ret = NativeMethods.MsiSourceListForceResolutionEx( this.installation.InstallationCode, this.installation.UserSid, this.installation.Context, (uint)this.installation.InstallationType); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Apply a transform to the database, specifying error conditions to suppress. /// </summary> /// <param name="transformFile">Path to the transform file</param> /// <param name="errorConditionsToSuppress">Error conditions that are to be suppressed</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, TransformErrors errorConditionsToSuppress) { if (String.IsNullOrEmpty(transformFile)) { throw new ArgumentNullException("transformFile"); } uint ret = NativeMethods.MsiDatabaseApplyTransform((int)this.Handle, transformFile, (int)errorConditionsToSuppress); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Enumerates product installations based on certain criteria. /// </summary> /// <param name="productCode">ProductCode (GUID) of the product instances to be enumerated. Only /// instances of products within the scope of the context specified by the /// <paramref name="userSid"/> and <paramref name="context"/> parameters will be /// enumerated. This parameter may be set to null to enumerate all products in the specified /// context.</param> /// <param name="userSid">Specifies a security identifier (SID) that restricts the context /// of enumeration. A SID value other than s-1-1-0 is considered a user SID and restricts /// enumeration to the current user or any user in the system. The special SID string /// s-1-1-0 (Everyone) specifies enumeration across all users in the system. This parameter /// can be set to null to restrict the enumeration scope to the current user. When /// <paramref name="context"/> is set to the machine context only, /// <paramref name="userSid"/> must be null.</param> /// <param name="context">Specifies the user context.</param> /// <returns>An enumeration of product objects for enumerated product instances.</returns> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msienumproductsex.asp">MsiEnumProductsEx</a> /// </p></remarks> public static IEnumerable <ProductInstallation> GetProducts( string productCode, string userSid, UserContexts context) { StringBuilder buf = new StringBuilder(40); UserContexts targetContext; StringBuilder targetSidBuf = new StringBuilder(40); for (uint i = 0; ; i++) { uint targetSidBufSize = (uint)targetSidBuf.Capacity; uint ret = NativeMethods.MsiEnumProductsEx( productCode, userSid, context, i, buf, out targetContext, targetSidBuf, ref targetSidBufSize); if (ret == (uint)NativeMethods.Error.MORE_DATA) { targetSidBuf.Capacity = (int)++targetSidBufSize; ret = NativeMethods.MsiEnumProductsEx( productCode, userSid, context, i, buf, out targetContext, targetSidBuf, ref targetSidBufSize); } if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS) { break; } if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } yield return(new ProductInstallation( buf.ToString(), targetSidBuf.ToString(), targetContext)); } }
public void Execute(Record executeParams) { uint ret = RemotableNativeMethods.MsiViewExecute( (int)this.Handle, (executeParams != null ? (int)executeParams.Handle : 0)); if (ret == (uint)NativeMethods.Error.BAD_QUERY_SYNTAX) { throw new BadQuerySyntaxException(this.sql); } else if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <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> /// Gets the count of all rows in the table that satisfy a given condition. /// </summary> /// <param name="table">Name of the table whose rows are to be counted</param> /// <param name="where">Conditional expression, such as could be placed on the end of a SQL WHERE clause</param> /// <returns>The count of all rows in the table satisfying the condition</returns> /// <exception cref="BadQuerySyntaxException">the SQL WHERE syntax is invalid</exception> /// <exception cref="InstallerException">the View could not be executed</exception> /// <exception cref="InvalidHandleException">the Database handle is invalid</exception> public int CountRows(string table, string where) { if (String.IsNullOrEmpty(table)) { throw new ArgumentNullException("table"); } // to support temporary tables like _Streams, run the query even if the table isn't persistent TableInfo tableInfo = this.Tables[table]; string primaryKeys = tableInfo == null ? "*" : String.Concat("`", tableInfo.PrimaryKeys[0], "`"); int count; try { using (View view = this.OpenView( "SELECT {0} FROM `{1}`{2}", primaryKeys, table, (where != null && where.Length != 0 ? " WHERE " + where : ""))) { view.Execute(); for (count = 0; ; count++) { // Avoid creating unnecessary Record objects by not calling View.Fetch(). int recordHandle; uint ret = RemotableNativeMethods.MsiViewFetch((int)view.Handle, out recordHandle); if (ret == (uint)NativeMethods.Error.NO_MORE_ITEMS) { break; } if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } RemotableNativeMethods.MsiCloseHandle(recordHandle); } } } catch (BadQuerySyntaxException) { // table was missing count = 0; } return(count); }
/// <summary> /// Makes the current process the owner of the multi-package installation transaction. /// </summary> /// <param name="attributes">Select optional behavior when joining the transaction.</param> /// <exception cref="InvalidHandleException">The transaction handle is not valid.</exception> /// <exception cref="InstallerException">The transaction could not be joined.</exception> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msijointransaction.asp">MsiJoinTransaction</a> /// </p></remarks> public void Join(TransactionAttributes attributes) { IntPtr hChangeOfOwnerEvent; uint ret = NativeMethods.MsiJoinTransaction((int)this.Handle, (int)attributes, out hChangeOfOwnerEvent); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } this.ownerChangeEvent = hChangeOfOwnerEvent; if (this.ownerChangeEvent != IntPtr.Zero && this.ownerChangeListeners.Count >= 1) { new Thread(this.WaitForOwnerChange).Start(); } }
/// <summary> /// Executes an action sequence described in the specified table. /// </summary> /// <param name="sequenceTable">Name of the table containing the action sequence.</param> /// <exception cref="InvalidHandleException">the Session handle is invalid</exception> /// <exception cref="InstallCanceledException">the user exited the installation</exception> /// <remarks><p> /// This method queries the specified table, ordering the actions by the numbers in the Sequence column. /// For each row retrieved, an action is executed, provided that any supplied condition expression does /// not evaluate to FALSE. /// </p><p> /// An action sequence containing any actions that update the system, such as the InstallFiles and /// WriteRegistryValues actions, cannot be run by calling DoActionSequence. The exception to this rule is if /// DoActionSequence is called from a custom action that is scheduled in the InstallExecuteSequence table /// between the InstallInitialize and InstallFinalize actions. Actions that do not update the system, such /// as AppSearch or CostInitialize, can be called. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisequence.asp">MsiSequence</a> /// </p></remarks> public void DoActionSequence(string sequenceTable) { if (String.IsNullOrEmpty(sequenceTable)) { throw new ArgumentNullException("sequenceTable"); } this.ValidateSessionAccess(); uint ret = RemotableNativeMethods.MsiSequence((int)this.Handle, sequenceTable, 0); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Adds or updates a disk of the media source for the product or patch. /// </summary> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistaddmediadisk.asp">MsiSourceListAddMediaDisk</a> /// </p></remarks> public void Add(MediaDisk item) { uint ret = NativeMethods.MsiSourceListAddMediaDisk( this.installation.InstallationCode, this.installation.UserSid, this.installation.Context, (uint)this.installation.InstallationType, (uint)item.DiskId, item.VolumeLabel, item.DiskPrompt); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }
/// <summary> /// Checks to see if sufficient disk space is present for the current installation. /// </summary> /// <returns>True if there is sufficient disk space; false otherwise.</returns> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msiverifydiskspace.asp">MsiVerifyDiskSpace</a> /// </p></remarks> public bool VerifyDiskSpace() { this.ValidateSessionAccess(); uint ret = RemotableNativeMethods.MsiVerifyDiskSpace((int)this.Handle); if (ret == (uint)NativeMethods.Error.DISK_FULL) { return(false); } else if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } return(true); }
/// <summary> /// Removes a specified disk from the set of registered disks. /// </summary> /// <param name="diskId">ID of the disk to remove</param> /// <remarks><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisourcelistclearmediadisk.asp">MsiSourceListClearMediaDisk</a> /// </p></remarks> public bool Remove(int diskId) { uint ret = NativeMethods.MsiSourceListClearMediaDisk( this.installation.InstallationCode, this.installation.UserSid, this.installation.Context, (uint)this.installation.InstallationType, (uint)diskId); if (ret != 0) { // TODO: Figure out when to return false. throw InstallerException.ExceptionFromReturnCode(ret); } return(true); }
/// <summary> /// Sets a record stream field from a file. Stream data cannot be inserted into temporary fields. /// </summary> /// <param name="field">Specifies the field of the Record to set.</param> /// <param name="filePath">Specifies the path to the file containing the stream.</param> /// <exception cref="ArgumentOutOfRangeException">The field is less than 0 or greater than the /// number of fields in the Record.</exception> /// <remarks><p> /// The contents of the specified file are read into a stream object. The stream persists if /// the Record is inserted into the Database and the Database is committed. /// </p><p> /// To reset the stream to its beginning you must pass in null for filePath. /// Do not pass an empty string, "", to reset the stream. /// </p><p> /// Setting a stream with this method is more efficient than setting a field to a /// FileStream object. /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msirecordsetstream.asp">MsiRecordsetStream</a> /// </p></remarks> public void SetStream(int field, string filePath) { this.CheckRange(field); if (String.IsNullOrEmpty(filePath)) { throw new ArgumentNullException("filePath"); } uint ret = RemotableNativeMethods.MsiRecordSetStream((int)this.Handle, (uint)field, filePath); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } }