/// <summary> /// Run the uninstaller on a new thread. /// </summary> internal void RunUninstaller(RunUninstallerOptions options) { lock (_operationLock) { if (Finished || IsRunning || CurrentStatus != UninstallStatus.Waiting) { return; } if ((UninstallerEntry.IsRegistered && !UninstallerEntry.RegKeyStillExists()) || (UninstallerEntry.UninstallerKind == UninstallerType.Msiexec && MsiTools.MsiEnumProducts().All(g => !g.Equals(UninstallerEntry.BundleProviderKey)))) { CurrentStatus = UninstallStatus.Completed; Finished = true; return; } CurrentStatus = UninstallStatus.Uninstalling; IsRunning = true; } var worker = new Thread(UninstallThread) { Name = "RunBulkUninstall_Worker" }; worker.Start(options); }
private void UninstallThread(object parameters) { var options = parameters as RunUninstallerOptions; Debug.Assert(options != null, "options != null"); Exception error = null; var retry = false; try { using (var uninstaller = UninstallerEntry.RunUninstaller(options.PreferQuiet, options.Simulate)) { // Can be null during simulation if (uninstaller != null) { if (options.PreferQuiet && UninstallerEntry.QuietUninstallPossible) { uninstaller.PriorityClass = ProcessPriorityClass.BelowNormal; } var checkCounters = options.PreferQuiet && options.AutoKillStuckQuiet && UninstallerEntry.QuietUninstallPossible; List <Process> childProcesses; var idleCounter = 0; do { if (_skipLevel == SkipCurrentLevel.Skip) { break; } childProcesses = uninstaller.GetChildProcesses().Where( p => !p.ProcessName.Contains("explorer", StringComparison.InvariantCultureIgnoreCase)) .ToList(); if (!uninstaller.HasExited) { childProcesses.Add(uninstaller); } if (checkCounters) { if (TestUninstallerForStalls(childProcesses)) { idleCounter++; } // Kill the uninstaller (and children) if they were idle/stalled for too long if (idleCounter > 40) { uninstaller.Kill(true); throw new IOException(Localisation.UninstallError_UninstallerTimedOut); } } else { Thread.Sleep(1000); } // Kill the uninstaller (and children) if user told us to or if it was idle for too long if (_skipLevel == SkipCurrentLevel.Terminate) { uninstaller.Kill(true); if (UninstallerEntry.UninstallerKind == UninstallerType.Msiexec) { foreach (var process in Process.GetProcessesByName("Msiexec")) { try { process.Kill(); } catch (InvalidOperationException) { } catch (Win32Exception) { } catch (NotSupportedException) { } } } break; } } while (!uninstaller.HasExited || childProcesses.Any(p => !p.HasExited)); if (_skipLevel == SkipCurrentLevel.None) { var exitVar = uninstaller.ExitCode; if (exitVar != 0) { if (UninstallerEntry.UninstallerKind == UninstallerType.Msiexec && exitVar == 1602) { // 1602 ERROR_INSTALL_USEREXIT - The user has cancelled the installation. _skipLevel = SkipCurrentLevel.Skip; } else if (exitVar == -1073741510) { /* 3221225786 / 0xC000013A / -1073741510 * The application terminated as a result of a CTRL+C. * Indicates that the application has been terminated either by user's * keyboard input CTRL+C or CTRL+Break or closing command prompt window. */ _skipLevel = SkipCurrentLevel.Terminate; } else { switch (exitVar) { // The system cannot find the file specified. Indicates that the file can not be found in specified location. case 2: // The system cannot find the path specified. Indicates that the specified path can not be found. case 3: // Access is denied. Indicates that user has no access right to specified resource. case 5: // Program is not recognized as an internal or external command, operable program or batch file. case 9009: break; default: if (options.RetryFailedQuiet) { retry = true; } break; } throw new IOException(Localisation.UninstallError_UninstallerReturnedCode + exitVar); } } } } } } catch (Exception ex) { error = ex; } // Take care of the aftermath if (_skipLevel != SkipCurrentLevel.None) { _skipLevel = SkipCurrentLevel.None; CurrentStatus = UninstallStatus.Skipped; CurrentError = new OperationCanceledException(Localisation.ManagerError_Skipped); } else if (error != null) { //Localisation.ManagerError_PrematureWorkerStop is unused CurrentStatus = UninstallStatus.Failed; CurrentError = error; } else { CurrentStatus = UninstallStatus.Completed; } if (retry && _canRetry) { CurrentStatus = UninstallStatus.Waiting; _canRetry = false; } else { Finished = true; } IsRunning = false; }