Beispiel #1
0
        void BlockLogOff(bool block)
        {
            logOffBlocked = block;

            if (block)
            {
                // prevent shutdown
                if (VistaTools.AtLeastVista())
                {
                    ShutdownBlockReasonCreate(Handle, clientLang.LogOffError);
                }

                // prevent the computer from going to sleep
                SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS | EXECUTION_STATE.ES_SYSTEM_REQUIRED);
            }
            else
            {
                // allow shutdown
                if (VistaTools.AtLeastVista())
                {
                    ShutdownBlockReasonDestroy(Handle);
                }

                // allow the computer to go to sleep
                SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
            }
        }
Beispiel #2
0
 public frmFilesInUse(ClientLanguage cLang, string filename)
 {
     InitializeComponent();
     clientLang     = cLang;
     Text           = clientLang.FilesInUseDialog.Title;
     btnCancel.Text = clientLang.CancelUpdate;
     FilenameInUse  = filename;
     txtFile.Text   = filename;
     if (VistaTools.AtLeastVista())
     {
         try
         {
             runningProcesses = GetProcessesUsingFiles(new string[1]
             {
                 filename
             });
         }
         catch
         {
         }
         if (runningProcesses != null && runningProcesses.Count > 0)
         {
             UpdateList();
             lblProc.Text         = clientLang.FilesInUseDialog.SubTitle;
             btnCloseProc.Text    = clientLang.ClosePrc;
             btnCloseAll.Text     = clientLang.CloseAllPrc;
             lblProc.Visible      = true;
             listProc.Visible     = true;
             btnCloseAll.Visible  = true;
             btnCloseProc.Visible = true;
             showingProcesses     = true;
             chkProc = new Timer
             {
                 Enabled  = true,
                 Interval = 2000
             };
             chkProc.Tick += chkProc_Tick;
             bw            = new BackgroundWorker
             {
                 WorkerSupportsCancellation = true
             };
             bw.DoWork             += bw_DoWork;
             bw.RunWorkerCompleted += bw_RunWorkerCompleted;
             bw.RunWorkerAsync();
         }
     }
     SetStyle(ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, value: true);
     UpdateSizes();
 }
Beispiel #3
0
        bool NeedElevationToUpdate()
        {
            // if only updating local user files, no elevation is needed
            if (IsAdmin || OnlyUpdatingLocalUser())
            {
                return(false);
            }

            // UAC Shield on next button for Windows Vista+
            if (VistaTools.AtLeastVista())
            {
                VistaTools.SetButtonShield(btnNext, true);
            }

            return(true);
        }
Beispiel #4
0
        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 });
            }
        }
Beispiel #5
0
        public frmMain(string[] args)
        {
            //sets to SegoeUI on Vista
            Font = SystemFonts.MessageBoxFont;

            // check if user is an admin for windows 2000+
            IsAdmin = VistaTools.IsUserAnAdmin();

            InitializeComponent();

            //enable Lazy SSL for all downloads
            FileDownloader.SetupSaneDownloadOptions();

            //resize the client so its client region = 500x360
            if (ClientRectangle.Width != 500)
            {
                Width = (Width - ClientRectangle.Width) + 500;
            }

            if (ClientRectangle.Height != 360)
            {
                Height = (Height - ClientRectangle.Height) + 360;
            }

            //add the panelDisplaying to form
            panelDisplaying.TabIndex = 0;
            Controls.Add(panelDisplaying);

            try
            {
                //process commandline argument
                Arguments commands = new Arguments(args);
                ProcessArguments(commands);

                // load the self update information
                if (!string.IsNullOrEmpty(selfUpdateFileLoc))
                {
                    //Note: always load the selfupdate data before the automatic update data
                    LoadSelfUpdateData(selfUpdateFileLoc);
                    ConfigureProxySettings();

                    //TODO: wyUp 3.0: excise this hack
                    //if the loaded file is from RC1, then update self and bail out
                    if (selfUpdateFromRC1)
                    {
                        //install the new client, and relaunch it to continue the update
                        if (needElevation && NeedElevationToUpdate())
                        {
                            //the user "elevated" as a non-admin user
                            //warn the user of their idiocy
                            error = clientLang.AdminError;

                            //set to false so new client won't be launched in frmMain_Load()
                            selfUpdateFromRC1 = false;

                            ShowFrame(Frame.Error);
                        }
                        else
                        {
                            needElevation = false;

                            FileAttributes atr             = File.GetAttributes(oldSelfLocation);
                            bool           resetAttributes = (atr & FileAttributes.Hidden) != 0 || (atr & FileAttributes.ReadOnly) != 0 || (atr & FileAttributes.System) != 0;

                            // remove the ReadOnly & Hidden atributes temporarily
                            if (resetAttributes)
                            {
                                File.SetAttributes(oldSelfLocation, FileAttributes.Normal);
                            }

                            //Install the new client
                            File.Copy(newSelfLocation, oldSelfLocation, true);

                            if (resetAttributes)
                            {
                                File.SetAttributes(oldSelfLocation, atr);
                            }

                            //Relaunch self in OnLoad()
                        }

                        //bail out
                        return;
                    }
                }
                else // not self-updating
                {
                    ConfigureProxySettings();
                }

                //Load the client information
                if (clientFileType == ClientFileType.PreRC2)
                {
                    //TODO: wyUp 3.0: stop supporting old client files (barely anyone uses RC2).
                    update.OpenObsoleteClientFile(clientFileLoc);
                }
                else
                {
                    update.OpenClientFile(clientFileLoc, clientLang, forcedLanguageCulture, updatePathVar, customUrlArgs);
                }

                clientLang.SetVariables(update.ProductName, update.InstalledVersion);
            }
            catch (Exception ex)
            {
                clientLang.SetVariables(update.ProductName, update.InstalledVersion);

                error        = "Client file failed to load. The client.wyc file might be corrupt.";
                errorDetails = ex.Message;

                ShowFrame(Frame.Error);
                return;
            }

            //sets up Next & Cancel buttons
            SetButtonText();

            //set header alignment, etc.
            panelDisplaying.HeaderImageAlign = update.HeaderImageAlign;

            if (update.HeaderTextIndent >= 0)
            {
                panelDisplaying.HeaderIndent = update.HeaderTextIndent;
            }

            panelDisplaying.HideHeaderDivider = update.HideHeaderDivider;

            // set the
            if (update.CustomWyUpdateTitle != null)
            {
                Text = update.CustomWyUpdateTitle;
            }

            try
            {
                if (!string.IsNullOrEmpty(update.HeaderTextColorName))
                {
                    panelDisplaying.HeaderTextColor = Color.FromName(update.HeaderTextColorName);
                }
            }
            catch { }

            //load the Side/Top images
            panelDisplaying.TopImage  = update.TopImage;
            panelDisplaying.SideImage = update.SideImage;

            if (isAutoUpdateMode)
            {
                try
                {
                    // create the temp folder where we'll store the updates long term
                    if (tempDirectory == null)
                    {
                        tempDirectory = CreateAutoUpdateTempFolder();
                    }
                }
                catch (Exception ex)
                {
                    error        = clientLang.GeneralUpdateError;
                    errorDetails = "Failed to create the automatic updater temp folder: " + ex.Message;

                    ShowFrame(Frame.Error);
                    return;
                }

                try
                {
                    // load the previous auto update state from "autoupdate"
                    LoadAutoUpdateData();
                    ConfigureProxySettings();
                }
                catch
                {
                    startStep = UpdateStepOn.Checking;
                }
            }
            else if (SelfUpdateState == SelfUpdateState.FullUpdate)
            {
                try
                {
                    // load the server file for MinClient needed details (i.e. failure case)
                    ServerFile = ServerFile.Load(serverFileLoc, updatePathVar, customUrlArgs);

                    //load the self-update server file
                    LoadClientServerFile();
                    clientLang.NewVersion = SelfServerFile.NewVersion;
                }
                catch (Exception ex)
                {
                    error        = clientLang.ServerError;
                    errorDetails = ex.Message;

                    ShowFrame(Frame.Error);
                    return;
                }

                if (needElevation && NeedElevationToUpdate())
                {
                    //the user "elevated" as a non-admin user
                    //warn the user of their idiocy
                    error = clientLang.AdminError;
                    ShowFrame(Frame.Error);
                }
                else
                {
                    needElevation = false;

                    //begin updating the product
                    ShowFrame(Frame.InstallUpdates);
                }
            }
            //continuing from elevation or self update (or both)
            else if (SelfUpdateState == SelfUpdateState.ContinuingRegularUpdate)
            {
                try
                {
                    //load the server file (without filling the 'changes' box & without downloading the wyUpdate Server file)
                    LoadServerFile(false);
                }
                catch (Exception ex)
                {
                    error        = clientLang.ServerError;
                    errorDetails = ex.Message;

                    ShowFrame(Frame.Error);
                    return;
                }

                if (needElevation && NeedElevationToUpdate())
                {
                    // the user "elevated" as a non-admin user
                    // warn the user of their idiocy
                    error = clientLang.AdminError;

                    ShowFrame(Frame.Error);
                }
                else
                {
                    needElevation = false;

                    //begin updating the product
                    ShowFrame(Frame.InstallUpdates);
                }
            }
            else if (!uninstalling)
            {
                startStep = UpdateStepOn.Checking;
            }
        }
Beispiel #6
0
        void StartSelfElevated()
        {
            ProcessStartInfo psi = new ProcessStartInfo
            {
                ErrorDialog             = true,
                ErrorDialogParentHandle = Handle
            };

            if (SelfUpdateState == SelfUpdateState.WillUpdate)
            {
                //create the filename for the newly copied client
                psi.FileName = Path.Combine(tempDirectory, Path.GetFileName(VersionTools.SelfLocation));

                //copy self to the temp folder
                File.Copy(VersionTools.SelfLocation, psi.FileName, true);
            }
            else if (SelfUpdateState == SelfUpdateState.FullUpdate)
            {
                //launch the newly updated self
                psi.FileName = oldSelfLocation;
            }
            else if (isAutoUpdateMode)
            {
                psi.FileName = IsNewSelf ? newSelfLocation : oldSelfLocation;

                // oldSelfLocation is null when elevation is needed, but no self update is taking place
                if (string.IsNullOrEmpty(psi.FileName))
                {
                    psi.FileName = VersionTools.SelfLocation;
                }
            }
            else
            {
                psi.FileName = VersionTools.SelfLocation;
            }

            if (needElevation)
            {
                // elevate to administrator
                psi.Verb = "runas";

                // check if UAC is enabled on the computer, if not throw an error
                bool canUAC = false;

                try
                {
                    if (VistaTools.AtLeastVista())
                    {
                        using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"))
                        {
                            // see if UAC is enabled
                            if (key != null)
                            {
                                canUAC = (int)key.GetValue("EnableLUA", null) != 0;
                            }
                        }
                    }
                    else
                    {
                        // Assume XP / 2000 limited user can use the RunAs box
                        // this may or may not be true.

                        //TODO: make this more robust
                        // see: http://www.windowsnetworking.com/kbase/WindowsTips/Windows2003/AdminTips/Admin/DisablingtheRunAsCommand.html
                        canUAC = true;
                    }
                }
                catch { }

                if (!canUAC)
                {
                    //TODO: use a more specific error to tell the user
                    // to re-enable UAC on their computer.
                    error = clientLang.AdminError;
                    ShowFrame(Frame.Error);
                    return;
                }
            }

            try
            {
                string selfUpdatePath = Path.Combine(tempDirectory, "selfUpdate.sup");

                // write necessary info (base/temp dirs, new client files, etc.) to a file
                SaveSelfUpdateData(selfUpdatePath);

                psi.Arguments = "-supdf:\"" + selfUpdatePath + "\"";

                if (IsNewSelf)
                {
                    psi.Arguments += " /ns";
                }

                Process.Start(psi);
                Close();
            }
            catch (Exception ex)
            {
                // the process couldn't be started. This happens for 1 of 3 reasons:

                // 1. The user cancelled the UAC box
                // 2. The limited user tried to elevate to an Admin that has a blank password
                // 3. The limited user tries to elevate as a Guest account
                error        = clientLang.AdminError;
                errorDetails = ex.Message;

                ShowFrame(Frame.Error);
            }
        }
Beispiel #7
0
        public frmFilesInUse(ClientLanguage cLang, string filename)
        {
            InitializeComponent();

            clientLang = cLang;

            // translate the buttons & text
            Text           = clientLang.FilesInUseDialog.Title;
            btnCancel.Text = clientLang.CancelUpdate;

            FilenameInUse = filename;
            txtFile.Text  = filename;

            if (VistaTools.AtLeastVista())
            {
                // get the list of processes using the file

                try
                {
                    runningProcesses = GetProcessesUsingFiles(new[] { filename });
                }
                catch { }

                if (runningProcesses != null && runningProcesses.Count > 0)
                {
                    UpdateList();

                    // translate the items
                    lblProc.Text      = clientLang.FilesInUseDialog.SubTitle;
                    btnCloseProc.Text = clientLang.ClosePrc;
                    btnCloseAll.Text  = clientLang.CloseAllPrc;

                    // show the list box of the running processes
                    lblProc.Visible      = true;
                    listProc.Visible     = true;
                    btnCloseAll.Visible  = true;
                    btnCloseProc.Visible = true;

                    showingProcesses = true;

                    chkProc = new Timer {
                        Enabled = true, Interval = 2000
                    };
                    chkProc.Tick += chkProc_Tick;

                    bw = new BackgroundWorker {
                        WorkerSupportsCancellation = true
                    };
                    bw.DoWork             += bw_DoWork;
                    bw.RunWorkerCompleted += bw_RunWorkerCompleted;

                    //begin checking the for the filenames
                    bw.RunWorkerAsync();
                }
            }

            SetStyle(ControlStyles.AllPaintingInWmPaint
                     | ControlStyles.OptimizedDoubleBuffer
                     | ControlStyles.ResizeRedraw
                     | ControlStyles.UserPaint, true);

            // position all the components
            UpdateSizes();
        }
        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 });
            }
        }