void bw_DoWorkPreExecute(object sender, DoWorkEventArgs e) { // simply update the progress bar to show the 3rd step is entirely complete bw.ReportProgress(0, new object[] { GetRelativeProgess(3, 0), 0, string.Empty, ProgressStatus.None, null }); List <UninstallFileInfo> rollbackCOM = new List <UninstallFileInfo>(); Exception except = null; for (int i = 0; i < UpdtDetails.UpdateFiles.Count; i++) { bool unregister = (UpdtDetails.UpdateFiles[i].RegisterCOMDll & (COMRegistration.UnRegister | COMRegistration.PreviouslyRegistered)) != 0; // skip non-executing files, skip execute "after" updates if ((!UpdtDetails.UpdateFiles[i].Execute || !UpdtDetails.UpdateFiles[i].ExBeforeUpdate) && !unregister) { continue; } // form the absolute path of the file to execute or unregister string fullFile = FixUpdateDetailsPaths(UpdtDetails.UpdateFiles[i].RelativePath); if (string.IsNullOrEmpty(fullFile)) { continue; } if (!unregister) { try { // we only support starting non-elevated on Vista+ // And the user must be an admin (otherwise starting as the same elevation as wyUpdate is ample) if (UpdtDetails.UpdateFiles[i].ElevationType == ElevationType.NotElevated && IsAdmin && VistaTools.AtLeastVista()) { int exitCode = (int)LimitedProcess.Start(fullFile, string.IsNullOrEmpty(UpdtDetails.UpdateFiles[i].CommandLineArgs) ? null : ParseText(UpdtDetails.UpdateFiles[i].CommandLineArgs), false, UpdtDetails.UpdateFiles[i].WaitForExecution, UpdtDetails.UpdateFiles[i].ProcessWindowStyle); // if we're rolling back on non-zero return codes, the return code is non-zero, and it's not in the exception list if (UpdtDetails.UpdateFiles[i].RollbackOnNonZeroRet && exitCode != 0 && (UpdtDetails.UpdateFiles[i].RetExceptions == null || !UpdtDetails.UpdateFiles[i].RetExceptions.Contains(exitCode))) { except = new Exception("\"" + fullFile + "\" returned " + exitCode + "."); break; } } else // Same as wyUpdate or elevated { ProcessStartInfo psi = new ProcessStartInfo { FileName = fullFile, WindowStyle = UpdtDetails.UpdateFiles[i].ProcessWindowStyle }; // command line arguments if (!string.IsNullOrEmpty(UpdtDetails.UpdateFiles[i].CommandLineArgs)) { psi.Arguments = ParseText(UpdtDetails.UpdateFiles[i].CommandLineArgs); } // only elevate if the current process isn't already elevated if (!IsAdmin && UpdtDetails.UpdateFiles[i].ElevationType == ElevationType.Elevated) { psi.Verb = "runas"; psi.ErrorDialog = true; psi.ErrorDialogParentHandle = MainWindowHandle; } //start the process Process p = Process.Start(psi); if (UpdtDetails.UpdateFiles[i].WaitForExecution && p != null) { p.WaitForExit(); // if we're rolling back on non-zero return codes, the return code is non-zero, and it's not in the exception list if (UpdtDetails.UpdateFiles[i].RollbackOnNonZeroRet && p.ExitCode != 0 && (UpdtDetails.UpdateFiles[i].RetExceptions == null || !UpdtDetails.UpdateFiles[i].RetExceptions.Contains(p.ExitCode))) { except = new Exception("\"" + psi.FileName + "\" returned " + p.ExitCode + "."); break; } } } } catch (Exception ex) { // failure when executing the file except = new Exception("Failed to execute the file \"" + fullFile + "\": " + ex.Message, ex); break; } } else // unregistering DLL { try { RegisterDllServer(fullFile, true); // add to the rollback list rollbackCOM.Add(new UninstallFileInfo { Path = fullFile, RegisterCOMDll = COMRegistration.Register }); } catch (Exception ex) { except = ex; break; } } } // save rollback info RollbackUpdate.WriteRollbackCOM(Path.Combine(TempDirectory, "backup\\unreggedComList.bak"), rollbackCOM); if (IsCancelled() || except != null) { // rollback unregged COM bw.ReportProgress(1, false); RollbackUpdate.RollbackUnregedCOM(TempDirectory); // rollback stopped services RollbackUpdate.RollbackStoppedServices(TempDirectory); bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Failure, except }); } else { // registry modification completed sucessfully bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Success, null }); } }
void ShowFrame(Frame frameNum) { frameOn = frameNum; switch (frameNum) { case Frame.Checking: //Update checking screen panelDisplaying.ChangePanel(FrameType.Update, clientLang.Checking.Title, clientLang.Checking.SubTitle, clientLang.Checking.Content, String.Empty); btnNext.Enabled = false; if (!isAutoUpdateMode) { CheckForUpdate(); } break; case Frame.UpdateInfo: //Update Info Screen panelDisplaying.ChangePanel(FrameType.TextInfo, clientLang.UpdateInfo.Title, clientLang.UpdateInfo.SubTitle, clientLang.UpdateInfo.Content, clientLang.UpdateBottom); // check if elevation is needed needElevation = NeedElevationToUpdate(); btnNext.Enabled = true; btnNext.Text = clientLang.UpdateButton; if (QuickCheck) { // return 2 if we're just checking if (QuickCheckJustCheck) { if (OutputInfo == string.Empty) { // output the changelog Console.WriteLine(ServerFile.NewVersion); Console.WriteLine(panelDisplaying.GetChanges(false)); } else if (OutputInfo != null) { try { using (StreamWriter outfile = new StreamWriter(OutputInfo)) { outfile.WriteLine(ServerFile.NewVersion); outfile.WriteLine(panelDisplaying.GetChanges(false)); } } catch { } } ReturnCode = 2; Close(); return; } ShowInTaskbar = true; WindowState = FormWindowState.Normal; TopMost = true; TopMost = false; QuickCheck = false; } else if (isAutoUpdateMode) { // save the automatic updater file SaveAutoUpdateData(UpdateStepOn.UpdateAvailable); updateHelper.SendSuccess(ServerFile.NewVersion, panelDisplaying.GetChanges(true), true); } break; case Frame.InstallUpdates: //Download and Install Updates panelDisplaying.ShowChecklist = true; panelDisplaying.ChangePanel(FrameType.Update, clientLang.DownInstall.Title, clientLang.DownInstall.SubTitle, clientLang.DownInstall.Content, String.Empty); if (SelfUpdateState == SelfUpdateState.FullUpdate) { //show status for downloading self SetStepStatus(0, clientLang.DownloadingSelfUpdate); } else { //show status for the downloading update SetStepStatus(0, clientLang.Download); } if (!isAutoUpdateMode) { DownloadUpdate(); } btnNext.Enabled = false; break; case Frame.UpdatedSuccessfully: //Display Congrats Window panelDisplaying.ChangePanel(FrameType.WelcomeFinish, clientLang.SuccessUpdate.Title, clientLang.SuccessUpdate.Content, String.Empty, clientLang.FinishBottom); btnNext.Enabled = true; btnCancel.Visible = false; btnNext.Text = clientLang.FinishButton; break; case Frame.AlreadyUpToDate: //Your Product is already up to date screen panelDisplaying.ChangePanel(FrameType.WelcomeFinish, clientLang.AlreadyLatest.Title, clientLang.AlreadyLatest.Content, String.Empty, clientLang.FinishBottom); btnNext.Enabled = true; btnCancel.Visible = false; btnNext.Text = clientLang.FinishButton; break; case Frame.NoUpdatePathAvailable: //No update to the latest version is available if (!string.IsNullOrEmpty(ServerFile.NoUpdateToLatestLinkText)) { panelDisplaying.SetNoUpdateAvailableLink(ServerFile.NoUpdateToLatestLinkText, ServerFile.NoUpdateToLatestLinkURL); } panelDisplaying.ChangePanel(FrameType.WelcomeFinish, clientLang.NoUpdateToLatest.Title, clientLang.NoUpdateToLatest.Content, String.Empty, clientLang.FinishBottom); btnNext.Enabled = true; btnCancel.Visible = false; btnNext.Text = clientLang.FinishButton; break; case Frame.Uninstall: //Uninstall screen panelDisplaying.ShowChecklist = true; panelDisplaying.ChangePanel(FrameType.Update, clientLang.Uninstall.Title, clientLang.Uninstall.SubTitle, clientLang.Uninstall.Content, String.Empty); //Show uninstalling status SetStepStatus(0, clientLang.UninstallFiles); btnNext.Enabled = false; InstallUpdates(UpdateOn.Uninstalling); break; case Frame.Error: //Display error screen //TODO: make the return codes error specific ReturnCode = 1; // show details button to hide all the complex crap from users panelDisplaying.ErrorDetails = errorDetails; panelDisplaying.SetUpErrorDetails(clientLang.ShowDetails); panelDisplaying.ChangePanel(FrameType.WelcomeFinish, clientLang.UpdateError.Title, error, "", clientLang.FinishBottom); btnNext.Enabled = true; btnCancel.Visible = false; btnNext.Text = clientLang.FinishButton; // show wyUpdate if if (QuickCheck && !QuickCheckNoErr) { ShowInTaskbar = true; WindowState = FormWindowState.Normal; TopMost = true; TopMost = false; QuickCheck = false; } break; } // handle all success / error cases if (FrameIs.ErrorFinish(frameNum)) { // allow the user to forcefuly exit BlockLogOff(false); EnableCancel(); // allow the user to exit by pressing ESC CancelButton = btnNext; // set the error return code (1) or success (0) ReturnCode = frameNum == Frame.Error ? 1 : 0; if (QuickCheck) { if (frameNum == Frame.Error && !QuickCheckNoErr) { Visible = true; TopMost = true; TopMost = false; } else { if (frameNum == Frame.Error) { if (OutputInfo == string.Empty) { // output the error Console.WriteLine(error + "\r\n"); Console.WriteLine(errorDetails); } else if (OutputInfo != null) { try { using (StreamWriter outfile = new StreamWriter(OutputInfo)) { outfile.WriteLine(error); outfile.WriteLine(errorDetails); } } catch { } } // If we're starting a process on error, then start it if (StartOnErr != null) { try { LimitedProcess.Start(StartOnErr, StartOnErrArgs); } catch { } } } WindowState = FormWindowState.Minimized; ShowInTaskbar = false; Visible = true; Close(); return; } } else if (isAutoUpdateMode) { // if it's reasonable to expect a client to be waiting for an error // that is, if we haven't already started the update process // then send all waiting processes the error message if (update.CurrentlyUpdating < UpdateOn.ClosingProcesses) { // wait for any clients to connect if (!updateHelper.RunningServer) { StartQuickAndDirtyAutoUpdateMode(); } // send the error to any running "client" processes updateHelper.SendFailed(error, errorDetails, autoUpdateStepProcessing); } if (frameNum == Frame.UpdatedSuccessfully || frameNum == Frame.Error) { // save whether an update succeeded or failed AutoUpdaterInfo auInfo; if (frameNum == Frame.Error) { auInfo = new AutoUpdaterInfo(updateHelper.AutoUpdateID, oldAUTempFolder) { AutoUpdaterStatus = AutoUpdaterStatus.UpdateFailed, ErrorTitle = error, ErrorMessage = errorDetails }; } else { auInfo = new AutoUpdaterInfo(updateHelper.AutoUpdateID, oldAUTempFolder) { AutoUpdaterStatus = AutoUpdaterStatus.UpdateSucceeded, UpdateVersion = ServerFile.NewVersion, ChangesInLatestVersion = panelDisplaying.GetChanges(true), ChangesIsRTF = true }; } auInfo.Save(); try { if (updateHelper.IsAService) { using (ServiceController srvc = new ServiceController(updateHelper.FileOrServiceToExecuteAfterUpdate)) { if (updateHelper.ExecutionArguments != null) { string[] args = CmdLineToArgvW.SplitArgs(updateHelper.ExecutionArguments); // start the windows service srvc.Start(args); } else // start the windows service (without args) { srvc.Start(); } } } else { // start the updated program as a limited user LimitedProcess.Start(updateHelper.FileOrServiceToExecuteAfterUpdate, updateHelper.ExecutionArguments); } } catch { } //TODO: if the service fails to start then log the error -- if the app fails to start, no big deal } // we're no longer in autoupdate mode - cleanup temp files on close isAutoUpdateMode = false; Close(); return; } else if (UpdatingFromService || (update.CloseOnSuccess && frameNum == Frame.UpdatedSuccessfully) || (StartOnErr != null && frameNum == Frame.Error)) { // If we're updating from a service (i.e. no-ui), then close on *either* success or failure. // If we're in normal mode but the user has specified they want "CloseOnSuccess", then do it. if (log != null) { if (frameNum == Frame.UpdatedSuccessfully) { log.Write("Updated successfully."); } else { log.Write(error + " - " + errorDetails); } } // If we're starting a process on error, then start it if (StartOnErr != null && frameNum == Frame.Error) { // if the "failure" process fails to start then show // the error screen. try { LimitedProcess.Start(StartOnErr, StartOnErrArgs); } catch { return; } } Close(); return; } } try { // so the user doesn't accidentally cancel update. btnNext.Focus(); } catch { } // if silent & if on one of the user interaction screens, then click next if (isSilent && (FrameIs.Interaction(frameOn))) { btnNext_Click(null, EventArgs.Empty); return; } }
void bw_DoWorkOptimizeExecute(object sender, DoWorkEventArgs e) { // simply update the progress bar to show the 6th step is entirely complete bw.ReportProgress(0, new object[] { GetRelativeProgess(6, 0), 0, string.Empty, ProgressStatus.None, null }); List <UninstallFileInfo> rollbackCOM = new List <UninstallFileInfo>(); List <string> startedServices = new List <string>(); Exception except = null; //optimize everything but "temp" files for (int i = 0; i < UpdtDetails.UpdateFiles.Count; i++) { if (UpdtDetails.UpdateFiles[i].IsNETAssembly || (UpdtDetails.UpdateFiles[i].RegisterCOMDll & COMRegistration.Register) == COMRegistration.Register) { if (IsCancelled()) { break; } //if not a temp file if (UpdtDetails.UpdateFiles[i].RelativePath.Length >= 4 && UpdtDetails.UpdateFiles[i].RelativePath.Substring(0, 4) != "temp") { //optimize (ngen) the file string filename = FixUpdateDetailsPaths(UpdtDetails.UpdateFiles[i].RelativePath); if (UpdtDetails.UpdateFiles[i].IsNETAssembly) { //TODO: add proper rolling back of newly NGENed files if (!string.IsNullOrEmpty(filename)) { NGenInstall(filename, UpdtDetails.UpdateFiles[i]); //optimize the file } } else { try { RegisterDllServer(filename, false); // add to the rollback list rollbackCOM.Add(new UninstallFileInfo { Path = filename, RegisterCOMDll = COMRegistration.UnRegister }); } catch (Exception ex) { except = ex; break; } } } } } RollbackUpdate.WriteRollbackCOM(Path.Combine(TempDirectory, "backup\\reggedComList.bak"), rollbackCOM); bw.ReportProgress(0, new object[] { GetRelativeProgess(6, 50), 50, string.Empty, ProgressStatus.None, null }); if (!IsCancelled() && except == null) { // execute files for (int i = 0; i < UpdtDetails.UpdateFiles.Count; i++) { // skip non-executing files, skip execute "before" updates if (!UpdtDetails.UpdateFiles[i].Execute || UpdtDetails.UpdateFiles[i].ExBeforeUpdate) { continue; } // form the absolute path of the file to execute string fileToExec = FixUpdateDetailsPaths(UpdtDetails.UpdateFiles[i].RelativePath); if (string.IsNullOrEmpty(fileToExec)) { continue; } try { // we only support starting non-elevated on Vista+ // And the user must be an admin (otherwise starting as the same elevation as wyUpdate is ample) if (UpdtDetails.UpdateFiles[i].ElevationType == ElevationType.NotElevated && IsAdmin && VistaTools.AtLeastVista()) { int exitCode = (int)LimitedProcess.Start(fileToExec, string.IsNullOrEmpty(UpdtDetails.UpdateFiles[i].CommandLineArgs) ? null : ParseText(UpdtDetails.UpdateFiles[i].CommandLineArgs), false, UpdtDetails.UpdateFiles[i].WaitForExecution, UpdtDetails.UpdateFiles[i].ProcessWindowStyle); // if we're rolling back on non-zero return codes, the return code is non-zero, and it's not in the exception list if (UpdtDetails.UpdateFiles[i].RollbackOnNonZeroRet && exitCode != 0 && (UpdtDetails.UpdateFiles[i].RetExceptions == null || !UpdtDetails.UpdateFiles[i].RetExceptions.Contains(exitCode))) { except = new Exception("\"" + fileToExec + "\" returned " + exitCode + "."); break; } } else { ProcessStartInfo psi = new ProcessStartInfo { FileName = fileToExec, WindowStyle = UpdtDetails.UpdateFiles[i].ProcessWindowStyle }; // command line arguments if (!string.IsNullOrEmpty(UpdtDetails.UpdateFiles[i].CommandLineArgs)) { psi.Arguments = ParseText(UpdtDetails.UpdateFiles[i].CommandLineArgs); } // only elevate if the current process isn't already elevated if (!IsAdmin && UpdtDetails.UpdateFiles[i].ElevationType == ElevationType.Elevated) { psi.Verb = "runas"; psi.ErrorDialog = true; psi.ErrorDialogParentHandle = MainWindowHandle; } // start the process Process p = Process.Start(psi); if (UpdtDetails.UpdateFiles[i].WaitForExecution && p != null) { p.WaitForExit(); // if we're rolling back on non-zero return codes, the return code is non-zero, and it's not in the exception list if (UpdtDetails.UpdateFiles[i].RollbackOnNonZeroRet && p.ExitCode != 0 && (UpdtDetails.UpdateFiles[i].RetExceptions == null || !UpdtDetails.UpdateFiles[i].RetExceptions.Contains(p.ExitCode))) { except = new Exception("\"" + psi.FileName + "\" returned " + p.ExitCode + "."); break; } } } } catch (Exception ex) { // failure when executing the file except = new Exception("Failed to execute the file \"" + fileToExec + "\": " + ex.Message, ex); break; } } } if (!IsCancelled() && except == null) { try { // try to start services foreach (StartService service in UpdtDetails.ServicesToStart) { // skip the start service if it will be started as part of the auto-update process if (SkipStartService != null && string.Compare(SkipStartService, service.Name, StringComparison.OrdinalIgnoreCase) == 0) { continue; } using (ServiceController srvc = new ServiceController(service.Name)) { ServiceControllerStatus status = srvc.Status; if (status != ServiceControllerStatus.Running) { if (service.Arguments != null) { // parse the arguments for variables for (int i = 0; i < service.Arguments.Length; i++) { service.Arguments[i] = ParseText(service.Arguments[i]); } // start the service with the arguments srvc.Start(service.Arguments); } else // no arguments { srvc.Start(); } // report that we're waiting for the service to start so the user knows what's going on bw.ReportProgress(0, new object[] { GetRelativeProgess(6, 50), 50, "Waiting for service to start: " + srvc.DisplayName, ProgressStatus.None, null }); //TODO: periodically check if the user has cancelled -- for services that fail to start //srvc.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(5)); srvc.WaitForStatus(ServiceControllerStatus.Running); startedServices.Add(service.Name); } } } } catch (Exception ex) { except = ex; } // save rollback info RollbackUpdate.WriteRollbackServices(Path.Combine(TempDirectory, "backup\\startedServices.bak"), startedServices); } if (IsCancelled() || except != null) { // tell the main window we're rolling back registry bw.ReportProgress(1, true); // rollback started services RollbackUpdate.RollbackStartedServices(TempDirectory); // rollback newly regged COM dlls RollbackUpdate.RollbackRegedCOM(TempDirectory); // rollback the registry RollbackUpdate.RollbackRegistry(TempDirectory); //rollback files bw.ReportProgress(1, false); RollbackUpdate.RollbackFiles(TempDirectory, ProgramDirectory); // rollback unregged COM RollbackUpdate.RollbackUnregedCOM(TempDirectory); // rollback stopped services RollbackUpdate.RollbackStoppedServices(TempDirectory); bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Failure, except }); } else { bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Success, null }); } }