void bw_DoWorkRegistry(object sender, DoWorkEventArgs e)
        {
            List <RegChange> rollbackRegistry = new List <RegChange>();

            //parse variables in the regChanges
            for (int i = 0; i < UpdtDetails.RegistryModifications.Count; i++)
            {
                UpdtDetails.RegistryModifications[i] = ParseRegChange(UpdtDetails.RegistryModifications[i]);
            }

            Exception except = null;

            try
            {
                UpdateRegistry(rollbackRegistry);
            }
            catch (Exception ex)
            {
                except = ex;
            }

            RollbackUpdate.WriteRollbackRegistry(Path.Combine(TempDirectory, "backup\\regList.bak"), rollbackRegistry);

            if (IsCancelled() || except != null)
            {
                // rollback the registry
                bw.ReportProgress(1, true);
                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
            {
                // registry modification completed sucessfully
                bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Success, null });
            }
        }
        void bw_DoWorkProcessesCheck(object sender, DoWorkEventArgs e)
        {
            // processes
            List <FileInfo> files      = null;
            List <Process>  rProcesses = null;

            // rollback list for stopped services
            List <string> stoppedServices = new List <string>();
            Exception     except          = null; // store any errors

            // create the backup folder
            Directory.CreateDirectory(Path.Combine(TempDirectory, "backup"));

            try
            {
                // if we're AutoUpdating the service has been shutdown by the AutomaticUpdaterBackend
                // and we should wait for the service to complete shutting down
                if (SkipStartService != null)
                {
                    using (ServiceController srvc = new ServiceController(SkipStartService))
                    {
                        if (srvc.Status != ServiceControllerStatus.Stopped)
                        {
                            srvc.WaitForStatus(ServiceControllerStatus.Stopped);
                        }
                    }
                }

                // first try to stop services
                foreach (string service in UpdtDetails.ServicesToStop)
                {
                    using (ServiceController srvc = new ServiceController(service))
                    {
                        ServiceControllerStatus status = ServiceControllerStatus.Stopped;

                        try
                        {
                            // non-existent services throw an exception on queries
                            status = srvc.Status;
                        }
                        catch { }

                        if (status == ServiceControllerStatus.Running)
                        {
                            try
                            {
                                srvc.Stop();
                            }
                            catch (Exception)
                            {
                                // get the latest status of the service -- it might have crashed close
                                srvc.Refresh();
                                if (srvc.Status != ServiceControllerStatus.Stopped)
                                {
                                    throw;
                                }
                            }

                            // report that we're waiting for the service to stop so the user knows what's going on
                            bw.ReportProgress(0, new object[] { -1, -1, "Waiting for service to stop: " + srvc.DisplayName, ProgressStatus.None, null });

                            srvc.WaitForStatus(ServiceControllerStatus.Stopped);

                            stoppedServices.Add(service);
                        }
                    }
                }

                files = new List <FileInfo>(new DirectoryInfo(ProgramDirectory).GetFiles("*.exe", SearchOption.AllDirectories));

                RemoveSelfFromProcesses(files);

                //check for (and delete) a newer client if it exists
                DeleteClientInPath(ProgramDirectory, Path.Combine(TempDirectory, "base"));

                rProcesses = ProcessesNeedClosing(files);

                if (rProcesses.Count == 0)
                {
                    // no processes need closing, all done
                    files      = null;
                    rProcesses = null;
                }
                else if (SkipUIReporting) // and rProcesses.Count > 0
                {
                    // check every second for 20 seconds.
                    for (int i = 0; i < 20; ++i)
                    {
                        // sleep for 1 second
                        Thread.Sleep(1000);

                        rProcesses = ProcessesNeedClosing(files);

                        if (rProcesses.Count == 0)
                        {
                            break;
                        }
                    }

                    if (rProcesses.Count != 0)
                    {
                        StringBuilder sb = new StringBuilder();

                        sb.AppendLine(rProcesses.Count + " processes are running:\r\n");

                        foreach (Process proc in rProcesses)
                        {
                            sb.AppendLine(proc.MainWindowTitle + " (" + proc.ProcessName + ".exe)");
                        }

                        // tell the user about the open processes
                        throw new Exception(sb.ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                except = ex;
            }

            // save rollback info
            RollbackUpdate.WriteRollbackServices(Path.Combine(TempDirectory, "backup\\stoppedServices.bak"), stoppedServices);

            if (IsCancelled() || except != null)
            {
                bw.ReportProgress(1, false);

                // rollback stopped services
                RollbackUpdate.RollbackStoppedServices(TempDirectory);

                bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Failure, except });
            }
            else // completed successfully
            {
                bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Success, new object[] { files, rProcesses } });
            }
        }
        void bw_DoWorkClientData(object sender, DoWorkEventArgs e)
        {
            Exception except = null;

            try
            {
                OutputDirectory = Path.Combine(TempDirectory, "ClientData");
                Directory.CreateDirectory(OutputDirectory);

                string oldClientFile = null;

                // see if a 1.1+ client file exists (client.wyc)
                if (ClientFileType != ClientFileType.Final &&
                    File.Exists(Path.Combine(Path.GetDirectoryName(Filename), "client.wyc")))
                {
                    oldClientFile  = Filename;
                    Filename       = Path.Combine(Path.GetDirectoryName(Filename), "client.wyc");
                    ClientFileType = ClientFileType.Final;
                }


                if (ClientFileType == ClientFileType.PreRC2)
                {
                    //convert pre-RC2 client file by saving images to disk
                    string tempImageFilename;

                    //create the top image
                    if (ClientFile.TopImage != null)
                    {
                        ClientFile.TopImageFilename = "t.png";

                        tempImageFilename = Path.Combine(OutputDirectory, "t.png");
                        ClientFile.TopImage.Save(tempImageFilename, System.Drawing.Imaging.ImageFormat.Png);
                    }

                    //create the side image
                    if (ClientFile.SideImage != null)
                    {
                        ClientFile.SideImageFilename = "s.png";

                        tempImageFilename = Path.Combine(OutputDirectory, "s.png");
                        ClientFile.SideImage.Save(tempImageFilename, System.Drawing.Imaging.ImageFormat.Png);
                    }
                }
                else
                {
                    //Extract the contents of the client data file
                    ExtractUpdateFile();

                    if (File.Exists(Path.Combine(OutputDirectory, "iuclient.iuc")))
                    {
                        // load and merge the existing file

                        ClientFile tempClientFile = new ClientFile();
                        tempClientFile.LoadClientData(Path.Combine(OutputDirectory, "iuclient.iuc"));
                        tempClientFile.InstalledVersion = ClientFile.InstalledVersion;
                        ClientFile = tempClientFile;

                        File.Delete(Path.Combine(OutputDirectory, "iuclient.iuc"));
                    }
                }

                List <UpdateFile> updateDetailsFiles = UpdtDetails.UpdateFiles;

                FixUpdateFilesPaths(updateDetailsFiles);


                //write the uninstall file
                RollbackUpdate.WriteUninstallFile(TempDirectory, Path.Combine(OutputDirectory, "uninstall.dat"), updateDetailsFiles);

                List <UpdateFile> files = new List <UpdateFile>();

                //add all the files in the outputDirectory
                AddFiles(OutputDirectory.Length + 1, OutputDirectory, files);

                //recompress all the client data files
                string tempClient = Path.Combine(TempDirectory, "client.file");
                ClientFile.SaveClientFile(files, tempClient);

                // overrite existing client.wyc, while keeping the file attributes

                FileAttributes atr = FileAttributes.Normal;

                if (File.Exists(Filename))
                {
                    atr = File.GetAttributes(Filename);
                }

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

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

                //replace the original
                File.Copy(tempClient, Filename, true);

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


                if (oldClientFile != null)
                {
                    // delete the old client file
                    File.Delete(oldClientFile);
                }
            }
            catch (Exception ex)
            {
                // handle failed to write to client file
                except = ex;
            }

            if (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 });
            }
        }
예제 #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 });
            }
        }
예제 #5
0
        void bw_DoWorkUpdateFiles(object sender, DoWorkEventArgs e)
        {
            //check if folders exist, and count files to be moved
            string backupFolder = Path.Combine(TempDirectory, "backup");

            string[] backupFolders = new string[13];

            //Note: InstallShortcuts() requires the position in array to remain constant
            string[] origFolders = { "base", "system", "64system", "root", "appdata", "lappdata", "comappdata", "comdesktop", "comstartmenu", "cp86", "cp64", "curdesk", "curstart" };
            string[] destFolders = { ProgramDirectory,
                                     SystemFolders.GetSystem32x86(),
                                     SystemFolders.GetSystem32x64(),
                                     SystemFolders.GetRootDrive(),
                                     SystemFolders.GetCurrentUserAppData(),
                                     SystemFolders.GetCurrentUserLocalAppData(),
                                     SystemFolders.GetCommonAppData(),
                                     SystemFolders.GetCommonDesktop(),
                                     SystemFolders.GetCommonProgramsStartMenu(),
                                     SystemFolders.GetCommonProgramFilesx86(),
                                     SystemFolders.GetCommonProgramFilesx64(),
                                     SystemFolders.GetCurrentUserDesktop(),
                                     SystemFolders.GetCurrentUserProgramsStartMenu() };

            List <FileFolder> rollbackList = new List <FileFolder>();
            int totalDone = 0;

            Exception except = null;

            try
            {
                int totalFiles = 0;

                // count the files and create backup folders
                for (int i = 0; i < origFolders.Length; i++)
                {
                    // does orig folder exist?
                    if (!Directory.Exists(Path.Combine(TempDirectory, origFolders[i])))
                    {
                        continue;
                    }

                    //orig folder exists, set backup & orig folder locations
                    backupFolders[i] = Path.Combine(backupFolder, origFolders[i]);
                    origFolders[i]   = Path.Combine(TempDirectory, origFolders[i]);
                    Directory.CreateDirectory(backupFolders[i]);

                    // delete "newer" client, if it will overwrite this client
                    DeleteClientInPath(destFolders[i], origFolders[i]);

                    // count the total files
                    totalFiles += new DirectoryInfo(origFolders[i]).GetFiles("*", SearchOption.AllDirectories).Length;
                }


                //run the backup & replace
                for (int i = 0; i < origFolders.Length; i++)
                {
                    if (IsCancelled())
                    {
                        break;
                    }

                    if (backupFolders[i] != null) //if the backup folder exists
                    {
                        UpdateFiles(origFolders[i], destFolders[i], backupFolders[i], rollbackList, ref totalDone, ref totalFiles);
                    }
                }

                DeleteFiles(backupFolder, rollbackList);

                InstallShortcuts(destFolders, backupFolder, rollbackList);
            }
            catch (Exception ex)
            {
                except = ex;
            }

            // write the list of newly created files and folders
            RollbackUpdate.WriteRollbackFiles(Path.Combine(backupFolder, "fileList.bak"), rollbackList);

            if (IsCancelled() || except != null)
            {
                // 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
            {
                // backup & replace was successful
                bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Success, null });
            }
        }
예제 #6
0
        void bw_DoWorkUninstall(object sender, DoWorkEventArgs e)
        {
            List <UninstallFileInfo> filesToUninstall = new List <UninstallFileInfo>();
            List <string>            foldersToDelete  = new List <string>();
            List <RegChange>         registryToDelete = new List <RegChange>();
            List <UninstallFileInfo> comDllsToUnreg   = new List <UninstallFileInfo>();
            List <string>            servicesToStop   = new List <string>();

            // Load the list of files, folders etc. from the client file (Filename)
            RollbackUpdate.ReadUninstallData(Filename, filesToUninstall, foldersToDelete, registryToDelete, comDllsToUnreg, servicesToStop);

            // stop the services
            foreach (string service in servicesToStop)
            {
                try
                {
                    // stop the service
                    using (ServiceController srvc = new ServiceController(service))
                    {
                        srvc.Stop();
                        srvc.WaitForStatus(ServiceControllerStatus.Stopped);
                    }
                }
                catch { }
            }

            // unregister COM files
            foreach (var uninstallFileInfo in comDllsToUnreg)
            {
                try
                {
                    RegisterDllServer(uninstallFileInfo.Path, true);
                }
                catch { }
            }

            // uninstall files
            foreach (UninstallFileInfo file in filesToUninstall)
            {
                try
                {
                    if (file.UnNGENFile)
                    {
                        NGenUninstall(file.Path, file);
                    }

                    if (file.DeleteFile)
                    {
                        File.Delete(file.Path);
                    }
                }
                catch { }
            }

            //uninstall folders
            for (int i = foldersToDelete.Count - 1; i >= 0; i--)
            {
                //delete the last folder first (this fixes the problem of nested folders)
                try
                {
                    //directory must be empty in order to delete it
                    Directory.Delete(foldersToDelete[i]);
                }
                catch { }
            }


            // tell the sender that we're uninstalling reg now:
            bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.None, null });

            //uninstall registry
            foreach (RegChange reg in registryToDelete)
            {
                try
                {
                    reg.ExecuteOperation();
                }
                catch { }
            }

            // All done
            bw.ReportProgress(0, new object[] { -1, -1, string.Empty, ProgressStatus.Success, null });
        }
        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 });
            }
        }