private ExternalUIHandler CreateProgressHandler(Request request) { var currentTotalTicks = -1; var currentProgress = 0; var progressDirection = 1; var actualPercent = 0; ExternalUIHandler handler = (type, message, buttons, icon, button) => { if (request.IsCanceled) { return MessageResult.Cancel; } switch (type) { case InstallMessage.Progress: if (message.Length >= 2) { var msg = message.Split(": ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).Select(m => m.ToInt32(0)).ToArray(); switch (msg[1]) { // http://msdn.microsoft.com/en-us/library/aa370354(v=VS.85).aspx case 0: //Resets progress bar and sets the expected total number of ticks in the bar. currentTotalTicks = msg[3]; currentProgress = 0; if (msg.Length >= 6) { progressDirection = msg[5] == 0 ? 1 : -1; } break; case 1: //Provides information related to progress messages to be sent by the current action. break; case 2: //Increments the progress bar. if (currentTotalTicks == -1) { break; } currentProgress += msg[3]*progressDirection; break; case 3: //Enables an action (such as CustomAction) to add ticks to the expected total number of progress of the progress bar. break; } } if (currentTotalTicks > 0) { var newPercent = (currentProgress*100/currentTotalTicks); if (actualPercent < newPercent) { actualPercent = newPercent; // request.Debug("Progress : {0}", newPercent); request.Progress(_progressId, actualPercent, "installing..."); } } break; } return MessageResult.OK; }; return handler; }
/// <summary> /// Enables an external user-interface handler. This external UI handler is called before the /// normal internal user-interface handler. The external UI handler has the option to suppress /// the internal UI by returning a non-zero value to indicate that it has handled the messages. /// </summary> /// <param name="uiHandler">A callback delegate that handles the UI messages</param> /// <param name="messageFilter">Specifies which messages to handle using the external message handler. /// If the external handler returns a non-zero result, then that message will not be sent to the UI, /// instead the message will be logged if logging has been enabled.</param> /// <returns>The previously set external handler, or null if there was no previously set handler</returns> /// <remarks><p> /// To restore the previous UI handler, a second call is made to SetExternalUI using the /// ExternalUIHandler returned by the first call to SetExternalUI and specifying /// <see cref="InstallLogModes.None"/> as the message filter. /// </p><p> /// The external user interface handler does not have full control over the external user /// interface unless <see cref="SetInternalUI(InstallUIOptions)"/> is called with the uiLevel parameter set to /// <see cref="InstallUIOptions.Silent"/>. If SetInternalUI is not called, the internal user /// interface level defaults to <see cref="InstallUIOptions.Basic"/>. As a result, any message not /// handled by the external user interface handler is handled by Windows Installer. The initial /// "Preparing to install..." dialog always appears even if the external user interface /// handler handles all messages. /// </p><p> /// SetExternalUI should only be called from a bootstrapping application. You cannot call /// it from a custom action /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetexternalui.asp">MsiSetExternalUI</a> /// </p></remarks> public static ExternalUIHandler SetExternalUI(ExternalUIHandler uiHandler, InstallLogModes messageFilter) { NativeExternalUIHandler nativeHandler = null; if (uiHandler != null) { nativeHandler = new ExternalUIProxy(uiHandler).ProxyHandler; Installer.externalUIHandlers.Add(nativeHandler); } NativeExternalUIHandler oldNativeHandler = NativeMethods.MsiSetExternalUI(nativeHandler, (uint) messageFilter, IntPtr.Zero); if (oldNativeHandler != null && oldNativeHandler.Target is ExternalUIProxy) { Installer.externalUIHandlers.Remove(oldNativeHandler); return ((ExternalUIProxy) oldNativeHandler.Target).Handler; } else { return null; } }
/// <summary> /// Enables an external user-interface handler. This external UI handler is called before the /// normal internal user-interface handler. The external UI handler has the option to suppress /// the internal UI by returning a non-zero value to indicate that it has handled the messages. /// </summary> /// <param name="uiHandler">A callback delegate that handles the UI messages</param> /// <param name="messageFilter">Specifies which messages to handle using the external message handler. /// If the external handler returns a non-zero result, then that message will not be sent to the UI, /// instead the message will be logged if logging has been enabled.</param> /// <returns>The previously set external handler, or null if there was no previously set handler</returns> /// <remarks><p> /// To restore the previous UI handler, a second call is made to SetExternalUI using the /// ExternalUIHandler returned by the first call to SetExternalUI and specifying /// <see cref="InstallLogModes.None"/> as the message filter. /// </p><p> /// The external user interface handler does not have full control over the external user /// interface unless <see cref="SetInternalUI(InstallUIOptions)"/> is called with the uiLevel parameter set to /// <see cref="InstallUIOptions.Silent"/>. If SetInternalUI is not called, the internal user /// interface level defaults to <see cref="InstallUIOptions.Basic"/>. As a result, any message not /// handled by the external user interface handler is handled by Windows Installer. The initial /// "Preparing to install..." dialog always appears even if the external user interface /// handler handles all messages. /// </p><p> /// SetExternalUI should only be called from a bootstrapping application. You cannot call /// it from a custom action /// </p><p> /// Win32 MSI API: /// <a href="http://msdn.microsoft.com/library/en-us/msi/setup/msisetexternalui.asp">MsiSetExternalUI</a> /// </p></remarks> public static ExternalUIHandler SetExternalUI(ExternalUIHandler uiHandler, InstallLogModes messageFilter) { NativeExternalUIHandler nativeHandler = null; if (uiHandler != null) { nativeHandler = new ExternalUIProxy(uiHandler).ProxyHandler; Installer.externalUIHandlers.Add(nativeHandler); } NativeExternalUIHandler oldNativeHandler = NativeMethods.MsiSetExternalUI(nativeHandler, (uint)messageFilter, IntPtr.Zero); if (oldNativeHandler != null && oldNativeHandler.Target is ExternalUIProxy) { Installer.externalUIHandlers.Remove(oldNativeHandler); return(((ExternalUIProxy)oldNativeHandler.Target).Handler); } else { return(null); } }
internal ExternalUIProxy(ExternalUIHandler handler) { this.handler = handler; }
public void CustomActionTest1() { InstallLogModes logEverything = InstallLogModes.FatalExit | InstallLogModes.Error | InstallLogModes.Warning | InstallLogModes.User | InstallLogModes.Info | InstallLogModes.ResolveSource | InstallLogModes.OutOfDiskSpace | InstallLogModes.ActionStart | InstallLogModes.ActionData | InstallLogModes.CommonData | InstallLogModes.Progress | InstallLogModes.Initialize | InstallLogModes.Terminate | InstallLogModes.ShowDialog; Installer.SetInternalUI(InstallUIOptions.Silent); ExternalUIHandler prevHandler = Installer.SetExternalUI( WindowsInstallerTest.ExternalUILogger, logEverything); try { string[] customActions = new string[] { "SampleCA1", "SampleCA2" }; #if DEBUG string caDir = @"..\..\..\..\..\build\debug\x86\"; #else string caDir = @"..\..\..\..\..\build\ship\x86\"; #endif caDir = Path.GetFullPath(caDir); string caFile = "WixToolset.Dtf.Samples.ManagedCA.dll"; string caProduct = "CustomActionTest.msi"; this.CreateCustomActionProduct(caProduct, caDir + caFile, customActions, false); Exception caughtEx = null; try { Installer.InstallProduct(caProduct, String.Empty); } catch (Exception ex) { caughtEx = ex; } Assert.IsInstanceOfType(caughtEx, typeof(InstallCanceledException), "Exception thrown while installing product: " + caughtEx); string arch = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE"); string arch2 = Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"); if (arch == "AMD64" || arch2 == "AMD64") { caDir = caDir.Replace("x86", "x64"); this.CreateCustomActionProduct(caProduct, caDir + caFile, customActions, true); caughtEx = null; try { Installer.InstallProduct(caProduct, String.Empty); } catch (Exception ex) { caughtEx = ex; } Assert.IsInstanceOfType(caughtEx, typeof(InstallCanceledException), "Exception thrown while installing 64bit product: " + caughtEx); } } finally { Installer.SetExternalUI(prevHandler, InstallLogModes.None); } }
[Ignore] // Requires elevation. public void InstallerTransactTwoProducts() { string dbFile1 = "InstallerTransactProduct1.msi"; string dbFile2 = "InstallerTransactProduct2.msi"; string productCode1; string productCode2; using (Database db1 = new Database(dbFile1, DatabaseOpenMode.CreateDirect)) { WindowsInstallerUtils.InitializeProductDatabase(db1); WindowsInstallerUtils.CreateTestProduct(db1); productCode1 = db1.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0]; db1.Commit(); } using (Database db2 = new Database(dbFile2, DatabaseOpenMode.CreateDirect)) { WindowsInstallerUtils.InitializeProductDatabase(db2); WindowsInstallerUtils.CreateTestProduct(db2); productCode2 = db2.ExecuteStringQuery("SELECT `Value` FROM `Property` WHERE `Property` = 'ProductCode'")[0]; db2.Commit(); } ProductInstallation installation1 = new ProductInstallation(productCode1); ProductInstallation installation2 = new ProductInstallation(productCode2); Assert.IsFalse(installation1.IsInstalled, "Checking that product 1 is not installed before starting."); Assert.IsFalse(installation2.IsInstalled, "Checking that product 2 is not installed before starting."); Installer.SetInternalUI(InstallUIOptions.Silent); ExternalUIHandler prevHandler = Installer.SetExternalUI(WindowsInstallerTest.ExternalUILogger, InstallLogModes.FatalExit | InstallLogModes.Error | InstallLogModes.Warning | InstallLogModes.User | InstallLogModes.Info | InstallLogModes.ResolveSource | InstallLogModes.OutOfDiskSpace | InstallLogModes.ActionStart | InstallLogModes.ActionData | InstallLogModes.CommonData | InstallLogModes.Progress | InstallLogModes.Initialize | InstallLogModes.Terminate | InstallLogModes.ShowDialog); Assert.IsNull(prevHandler, "Checking that returned previous UI handler is null."); Transaction transaction = new Transaction("TestInstallTransaction", TransactionAttributes.None); Exception caughtEx = null; try { Installer.InstallProduct(dbFile1, String.Empty); } catch (Exception ex) { caughtEx = ex; } Assert.IsNull(caughtEx, "Exception thrown while installing product 1: " + caughtEx); Console.WriteLine(); Console.WriteLine("==================================================================="); Console.WriteLine(); try { Installer.InstallProduct(dbFile2, String.Empty); } catch (Exception ex) { caughtEx = ex; } Assert.IsNull(caughtEx, "Exception thrown while installing product 2: " + caughtEx); transaction.Commit(); transaction.Close(); prevHandler = Installer.SetExternalUI(prevHandler, InstallLogModes.None); Assert.AreEqual <ExternalUIHandler>(WindowsInstallerTest.ExternalUILogger, prevHandler, "Checking that previously-set UI handler is returned."); Assert.IsTrue(installation1.IsInstalled, "Checking that product 1 is installed."); Assert.IsTrue(installation2.IsInstalled, "Checking that product 2 is installed."); Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); Console.WriteLine("==================================================================="); Console.WriteLine("==================================================================="); Console.WriteLine(); Console.WriteLine(); Console.WriteLine(); ExternalUIRecordHandler prevRecHandler = Installer.SetExternalUI(WindowsInstallerTest.ExternalUIRecordLogger, InstallLogModes.FatalExit | InstallLogModes.Error | InstallLogModes.Warning | InstallLogModes.User | InstallLogModes.Info | InstallLogModes.ResolveSource | InstallLogModes.OutOfDiskSpace | InstallLogModes.ActionStart | InstallLogModes.ActionData | InstallLogModes.CommonData | InstallLogModes.Progress | InstallLogModes.Initialize | InstallLogModes.Terminate | InstallLogModes.ShowDialog); Assert.IsNull(prevRecHandler, "Checking that returned previous UI record handler is null."); transaction = new Transaction("TestUninstallTransaction", TransactionAttributes.None); try { Installer.InstallProduct(dbFile1, "REMOVE=All"); } catch (Exception ex) { caughtEx = ex; } Assert.IsNull(caughtEx, "Exception thrown while removing product 1: " + caughtEx); try { Installer.InstallProduct(dbFile2, "REMOVE=All"); } catch (Exception ex) { caughtEx = ex; } Assert.IsNull(caughtEx, "Exception thrown while removing product 2: " + caughtEx); transaction.Commit(); transaction.Close(); Assert.IsFalse(installation1.IsInstalled, "Checking that product 1 is not installed after removing."); Assert.IsFalse(installation2.IsInstalled, "Checking that product 2 is not installed after removing."); prevRecHandler = Installer.SetExternalUI(prevRecHandler, InstallLogModes.None); Assert.AreEqual <ExternalUIRecordHandler>(WindowsInstallerTest.ExternalUIRecordLogger, prevRecHandler, "Checking that previously-set UI record handler is returned."); }