/// <summary> /// Check if a file is in the queue, if not add it to the queue. /// This function does NOT take a lock on the queue before modifying it. This function is not thread safe /// </summary> /// <param name="filePath">Filename to check and add</param> /// <param name="monitorTask">Name of the monitor task adding the file, blank if manually added</param> /// <param name="manualFile">True is it's added manually to the queue</param> private void CheckAndAddFile(string filePath, MonitorJobOptions monitorTask, bool manualFile) { Ini iniHistory = new Ini(GlobalDefs.HistoryFile); if (!QueueContains(filePath)) { if (!Util.FileIO.FileLocked(filePath)) { string historyRec = iniHistory.ReadString(filePath, "Status", ""); // If it's an output file (you can skip output file reconversion by setting SkipReconversion in Conversion Task Settings) if ((monitorTask != null) && monitorTask.monitorConvertedFiles) if (Core.ConvertedFileStatuses.Any(x => x.Equals(historyRec))) historyRec = ""; // This is a converted file and we have been asked to process converted files also // Are we asked to reconvert recorded files if ((monitorTask != null) && monitorTask.reMonitorRecordedFiles) if (Core.SourceFileStatuses.Any(x => x.Equals(historyRec))) // Check if the status matches any of the source file status historyRec = ""; if (historyRec == "" || manualFile) // Either the file has not been processed (Status is missing) or readded manually (Status is blank) { if (File.Exists(filePath)) { if (manualFile) { AddJobs(filePath, monitorTask, true); //add manual jobs for conversion at the head of queue (after the last currently active job) } else { // Check to see if the age of the file is old enough DateTime timeStamp = Util.FileIO.GetFileModifiedTime(filePath); if (timeStamp.AddHours(_minimumAge) < DateTime.Now) { AddJobs(filePath, monitorTask, false); // Added by a monitor task } } } else if (manualFile) //delete only if a manual entry is made { Log.AppLog.WriteEntry(this, "Unable to queue file for conversion - file not found " + filePath + "\r\n", Log.LogEntryType.Warning); Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile); iniManualQueue.DeleteKey("ManualQueue", filePath); } } else { if (!_processedFiles.Contains(filePath)) // Keep a track of processed file so we don't overload the mcebuddy.log file { _processedFiles.Add(filePath); // to the list of processed file so we don't end up doing it again Log.AppLog.WriteEntry(this, "File " + filePath + " already converted with status " + historyRec + "\r\n", Log.LogEntryType.Debug); } // Manual file entry may have been readded multiple times, each time we log it and remove it from the ini file if (manualFile) // Delete the manual entry { Log.AppLog.WriteEntry(this, "Manual file " + filePath + " already converted with status " + historyRec + "\r\n", Log.LogEntryType.Debug); Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile); iniManualQueue.DeleteKey("ManualQueue", filePath); } } } else { if (!_processedFiles.Contains(filePath)) // Keep a track of processed file so we don't overload the mcebuddy.log file { _processedFiles.Add(filePath); // to the list of processed file so we don't end up doing it again Log.AppLog.WriteEntry(this, "Unable to queue file for conversion - file inaccessible/locked by another process " + filePath + "\r\n", Log.LogEntryType.Debug); } // Manual file entry may have been readded multiple times, each time we log it and remove it from the ini file if (manualFile) // Delete the manual entry { Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile); iniManualQueue.DeleteKey("ManualQueue", filePath); Log.AppLog.WriteEntry(this, "Unable to queue manual file for conversion - file inaccessible/locked by another process " + filePath + "\r\n", Log.LogEntryType.Debug); } } } }
public void CancelJob(int[] jobList) { if (jobList == null) { Log.AppLog.WriteEntry(this, "Empty job list passed to cancel jobs", Log.LogEntryType.Error, true); return; } Monitor.Enter(monitorLock); // Need to ensure when this function is called, the Engine is not in Starting or stopping mode Monitor.Enter(_queueManager.Queue); try { List<ConversionJob> convJob = new List<ConversionJob>(); for (int i = 0; i < jobList.Length; i++) { //Build the list of conversion jobs to cancel, don't use job numbers since they will change once removed from the queue if ((jobList[i] >= 0) && (jobList[i] < _queueManager.Queue.Count)) convJob.Add(_queueManager.Queue[jobList[i]]); } foreach (ConversionJob cj in convJob) { if (cj != null) { if (cj.Active) // if job is active, remove from manual queue and mark it cancelled for monitor thread to process { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Active job signalled cancellation for") + " " + cj.OriginalFileName, Log.LogEntryType.Information, true); cj.Status.Cancelled = true; } else { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Inactive job cancelled") + " " + cj.OriginalFileName, Log.LogEntryType.Information, true); cj.Status.Cancelled = true; // mark the job as cancelled (for write history and tracking) // First delete the job from the manual file entry while the ref is active, if this is the last task for the job if (_queueManager.JobCount(cj.OriginalFileName) <= 1) { Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile); iniManualQueue.DeleteKey("ManualQueue", cj.Status.SourceFile); } WriteHistory(cj); // Write to history file (it will check for last task for job) _queueManager.Queue.Remove(cj); // now remove the job from the queue } } } } catch (Exception e) { Log.AppLog.WriteEntry(this, "Unable to cancel jobs. JobList = " + string.Join(",", jobList.Select(x => x.ToString()).ToArray()) + " MaxJobs = " + _maxConcurrentJobs.ToString() + " Conversion Jobs Initialized = " + _conversionJobs.Length.ToString(), Log.LogEntryType.Error, true); Log.AppLog.WriteEntry(this, "Error -> " + e.ToString(), Log.LogEntryType.Error, true); } Monitor.Exit(_queueManager.Queue); Monitor.Exit(monitorLock); // Need to ensure when this function is called, the Engine is not in Starting or stopping mode }
/// <summary> /// Adds a conversion job to the queue /// This function does NOT take a lock on the queue before modifying it. This function is not thread safe /// </summary> /// <param name="filePath">File to add</param> /// <param name="monitorTask">Monitor task name which found the file</param> /// <param name="manual">True if this is a manuall added entry, false if it's added by a monitor task</param> private void AddJobs(string filePath, MonitorJobOptions monitorTask, bool manual) { bool filterMatchSuccessful = false; // Check if the file has already been processed in the past if so skip if (_conversionTaskFilterMismatchFiles.Contains(filePath)) return; // foreach (ConversionJobOptions conversionTask in MCEBuddyConf.GlobalMCEConfig.AllConversionTasks) { // Check if the task is disabled, which case skip if (!conversionTask.enabled) { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Conversion Task") + " " + conversionTask.taskName + " " + Localise.GetPhrase("disabled, skipping file") + " " + filePath, Log.LogEntryType.Debug, true); continue; } conversionTask.sourceVideo = filePath; // Monitor Task name matching if not empty if ((monitorTask != null) && !String.IsNullOrWhiteSpace(monitorTask.taskName) && (conversionTask.monitorTaskNames != null)) { bool foundMatch = false; foreach (string matchMonitorTaskName in conversionTask.monitorTaskNames) { if (monitorTask.taskName.ToLower().Trim() != matchMonitorTaskName.ToLower().Trim()) // match the list of a name continue; // move onto next monitor task name else { foundMatch = true; break; } } if (!foundMatch) { Log.AppLog.WriteEntry(this, "Skipping Conversion task " + conversionTask.taskName + " for file " + filePath + " since Monitor task " + monitorTask.taskName + " does not match the list of monitor tasks in the conversion task.", Log.LogEntryType.Debug, true); continue; // move into next conversion task } } // Metadata extract and pattern match from conversion task VideoMetaData metaData = MetadataMatchFilters(conversionTask); if (metaData != null) // We got a match - process the file { // Calculate where to add the job in the queue int idx; if (manual || conversionTask.insertQueueTop) // Manual jobs to the head of the queue, just after the current active job, or check if the conversion task is asking to add the job at the head of the queue { for (idx = 0; idx < _jobQueue.Count; idx++) { if (!_jobQueue[idx].Active) break; } } else idx = _jobQueue.Count; // Add the job to the end of the active queue // If it's a manual entry then we need to convert, reset the skip reconverting flag if it's set if (manual && conversionTask.skipReprocessing) { conversionTask.skipReprocessing = conversionTask.checkReprocessingHistory = false; // We can make a direct change since this is a copy object Log.AppLog.WriteEntry(this, "Manually added file, resetting the skip reprocessing option, the file will converted even if it has been processed before", Log.LogEntryType.Debug, true); } Log.AppLog.WriteEntry(this, Localise.GetPhrase("Added new job to queue for") + " " + filePath, Log.LogEntryType.Information, true); ConversionJob job = new ConversionJob(conversionTask, metaData); _jobQueue.Insert(idx, job); filterMatchSuccessful = true; // we cleared filters and processed the file // Send an eMail if required GeneralOptions go = MCEBuddyConf.GlobalMCEConfig.GeneralOptions; bool sendEMail = go.sendEmail; // do we need to send an eMail after adding a job to the queue bool sendQueue = go.eMailSettings.queueEvent; string sendQueueSubject = go.eMailSettings.queueSubject; bool skipBody = go.eMailSettings.skipBody; if (sendEMail && sendQueue) { string subject = Localise.GetPhrase("MCEBuddy added a video conversion to the queue"); string message = Localise.GetPhrase("Source Video") + " -> " + job.OriginalFileName + "\r\n"; message += Localise.GetPhrase("Profile") + " -> " + job.Profile + "\r\n"; message += Localise.GetPhrase("Conversion Task") + " -> " + job.TaskName + "\r\n"; // Check for custom subject and process if (!String.IsNullOrWhiteSpace(sendQueueSubject)) subject = UserCustomParams.CustomParamsReplace(sendQueueSubject, job.WorkingPath, "", "", job.OriginalFileName, "", "", "", job.Profile, job.TaskName, metaData.MetaData, Log.AppLog); eMailSendEngine.AddEmailToSendQueue(subject, (skipBody ? "" : message)); // Send the eMail through the eMail engine } } else if (manual) // Delete manual file entry if we didn't create a conversion job, otherwise the engine will clear it on completion { // Manual files may be added multiple times and the filter may already have it from the last time, so be safe and delete it Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile); // Delete the entry from the manual queue iniManualQueue.DeleteKey("ManualQueue", filePath); } } // If we have been through all the conversion tasks and not a single task has processed this file, hence we add it to the filter mismatch list so it won't be processed in future (MetadataExtract is very intensive and also prevent overburdening the log file) if (!filterMatchSuccessful) _conversionTaskFilterMismatchFiles.Add(filePath); }
/// <summary> /// Main CORE engine thread of MCEBuddy which runs in the background to check for new jobs, scans for new files, checks for updates to MCEBuddy etc /// </summary> private void MonitorThread() // Background thread that check for job starting, additions and completion { Thread updateCheckThread = null, scanThread = null, syncThread = null; try { DateTime lastUpdateCheck = DateTime.Now.AddDays(-1); DateTime lastPollCheck = DateTime.Now.AddSeconds(-_pollPeriod); GlobalDefs.Shutdown = false; while (!GlobalDefs.Shutdown) { // Check for updated version and messages if (DateTime.Now > lastUpdateCheck.AddHours(GlobalDefs.random.Next(12, 25))) { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Checking for new version of MCEBuddy"), Log.LogEntryType.Information); lastUpdateCheck = DateTime.Now; if ((updateCheckThread != null) && updateCheckThread.IsAlive) continue; // Don't start another one yet updateCheckThread = new Thread(new ThreadStart(_updateCheck.Check)); updateCheckThread.SetApartmentState(ApartmentState.STA); updateCheckThread.CurrentCulture = updateCheckThread.CurrentUICulture = Localise.MCEBuddyCulture; updateCheckThread.IsBackground = true; // Kill the thread if the process exits updateCheckThread.Start(); } //Check for new files and clean up log files if ((DateTime.Now > lastPollCheck.AddSeconds(_pollPeriod)) || (_rescan)) { _rescan = false; lastPollCheck = DateTime.Now; // Check for new files in the monitor folders - run as thread to keep it responsive if ((scanThread != null) && scanThread.IsAlive) continue; // Don't start another one yet scanThread = new Thread(() => _queueManager.ScanForFiles()); scanThread.CurrentCulture = scanThread.CurrentUICulture = Localise.MCEBuddyCulture; scanThread.IsBackground = true; // Kill the thread if the process exits scanThread.Start(); // check if converted files need to kept in sync with source files (deleted) - run as thread to keep it responsive if (MCEBuddyConf.GlobalMCEConfig.GeneralOptions.deleteConverted) { if ((syncThread != null) && syncThread.IsAlive) continue; // Don't start another one yet syncThread = new Thread(() => _queueManager.SyncConvertedFiles(_useRecycleBin)); // Check for new files in the monitor folders syncThread.CurrentCulture = syncThread.CurrentUICulture = Localise.MCEBuddyCulture; syncThread.IsBackground = true; // Kill the thread if the process exits syncThread.Start(); } // check for log files clean up CleanLogFiles(); } // Resume jobs if we are within the conversion time if (CheckIfWithinConversionTime()) // Call the internal function, cannot take a lock { // We are within the conversion time, if the engine has not auto resumed, then resume it if (_autoPause) // If we are auto paused, then resume it since we are within the conversion time _autoPause = GlobalDefs.Pause = false; // Resume it } else { // We are outside the conversion time, if the engine has not auto paused, then pause it if (!_autoPause) // If we are not paused, then pause it since we are outside the conversion time _autoPause = GlobalDefs.Pause = true; // Pause it } //Check the status of the jobs and start new ones bool SomeRunning = false; for (int i = 0; i < _conversionJobs.Length; i++) { if (_conversionJobs[i] != null) { // Check for running and clean up completed jobs if (_conversionJobs[i].Completed) { Monitor.Enter(_queueManager.Queue); //the lock is always on the jobQueue Log.AppLog.WriteEntry(this, Localise.GetPhrase("Job for") + " " + _conversionJobs[i].OriginalFileName + " " + Localise.GetPhrase("completed"), Log.LogEntryType.Information, true); // Now delete the job from the manual file entry, if it has succeeded great, if it has failed we don't want an endless loop of conversion if ((_queueManager.JobCount(_conversionJobs[i].OriginalFileName) <= 1)) // Whether it is cancelled of finished delete from the manual queue either way { Ini iniManualQueue = new Ini(GlobalDefs.ManualQueueFile); iniManualQueue.DeleteKey("ManualQueue", _conversionJobs[i].OriginalFileName); } if ((_archiveOriginal) && (_conversionJobs[i].Status.SuccessfulConversion) && (_queueManager.JobCount(_conversionJobs[i].OriginalFileName) <= 1) && (String.Compare(_conversionJobs[i].OriginalFileName, _conversionJobs[i].ConvertedFile, true) != 0)) { string pathName = Path.GetDirectoryName(_conversionJobs[i].OriginalFileName); //get the directory name if (!pathName.ToLower().Contains((string.IsNullOrEmpty(MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archivePath) ? GlobalDefs.MCEBUDDY_ARCHIVE.ToLower() : MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archivePath.ToLower()))) //check if we are currently operating from the archive folder (manual queue), in which case don't archive { string archivePath = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.archivePath; // use the specified archive path if (archivePath == "") // Default archive location to be used archivePath = Path.Combine(pathName, GlobalDefs.MCEBUDDY_ARCHIVE); //update the path name for a new sub-directory called Archive Util.FilePaths.CreateDir(archivePath); //create the sub-directory if required string newFilePath = Path.Combine(archivePath, Path.GetFileName(_conversionJobs[i].OriginalFileName)); Log.AppLog.WriteEntry(this, "Archiving original file " + _conversionJobs[i].OriginalFileName + " to Archive folder " + archivePath, Log.LogEntryType.Debug); try { // Archive the EDL, SRT, XML, NFO etc files also along with the original file if present foreach (string supportFileExt in GlobalDefs.supportFilesExt) { string extFile = Path.Combine(Path.GetDirectoryName(_conversionJobs[i].OriginalFileName), Path.GetFileNameWithoutExtension(_conversionJobs[i].OriginalFileName) + supportFileExt); // Saved support file if (File.Exists(extFile)) File.Move(extFile, Path.Combine(archivePath, Path.GetFileName(extFile))); } // Last file to move File.Move(_conversionJobs[i].OriginalFileName, newFilePath); //move the file into the archive folder } catch (Exception e) { Log.AppLog.WriteEntry(this, "Unable to move original file " + _conversionJobs[i].OriginalFileName + " to Archive folder " + archivePath, Log.LogEntryType.Error); Log.AppLog.WriteEntry(this, "Error : " + e.ToString(), Log.LogEntryType.Error); } } } // Delete/archive only if the conversion was successful and original marked for deletion and it is the last task for the job and the original file and converted file don't have the same name+path (since it's been replaced already) else if ((_deleteOriginal) && (_conversionJobs[i].Status.SuccessfulConversion) && (_queueManager.JobCount(_conversionJobs[i].OriginalFileName) <= 1) && (String.Compare(_conversionJobs[i].OriginalFileName, _conversionJobs[i].ConvertedFile, true) != 0)) { // Delete the EDL, SRT, XML, NFO etc files also along with the original file if present foreach (string supportFileExt in GlobalDefs.supportFilesExt) { string extFile = Path.Combine(Path.GetDirectoryName(_conversionJobs[i].OriginalFileName), Path.GetFileNameWithoutExtension(_conversionJobs[i].OriginalFileName) + supportFileExt); // support file Util.FileIO.TryFileDelete(extFile, _useRecycleBin); // Delete support file } Util.FileIO.TryFileDelete(_conversionJobs[i].OriginalFileName, _useRecycleBin); // delete original file Log.AppLog.WriteEntry(this, "Deleting original file " + _conversionJobs[i].OriginalFileName, Log.LogEntryType.Debug, true); } // Check of it's a failure and the original file needs to be moved if ((_failedMoveOriginal) && (_conversionJobs[i].Status.Error) && (_queueManager.JobCount(_conversionJobs[i].OriginalFileName) <= 1)) { string pathName = Path.GetDirectoryName(_conversionJobs[i].OriginalFileName); //get the directory name string failedPath = MCEBuddyConf.GlobalMCEConfig.GeneralOptions.failedPath; // use the specified path to move the file conversion original file Util.FilePaths.CreateDir(failedPath); //create the sub-directory if required string newFilePath = Path.Combine(failedPath, Path.GetFileName(_conversionJobs[i].OriginalFileName)); Log.AppLog.WriteEntry(this, "Moving original file " + _conversionJobs[i].OriginalFileName + " to Failed conversion folder " + failedPath, Log.LogEntryType.Debug); try { File.Move(_conversionJobs[i].OriginalFileName, newFilePath); //move the file into the archive folder } catch (Exception e) { Log.AppLog.WriteEntry(this, "Unable to move original file " + _conversionJobs[i].OriginalFileName + " to Failed conversion folder " + failedPath, Log.LogEntryType.Error); Log.AppLog.WriteEntry(this, "Error : " + e.ToString(), Log.LogEntryType.Error); } } //First write the history and finish the job, then remove from the queue WriteHistory(_conversionJobs[i]); _queueManager.Queue.Remove(_conversionJobs[i]); _conversionJobs[i] = null; Monitor.Exit(_queueManager.Queue); } else { SomeRunning = true; } } else { // Start new jobs if conversions are not paused if (!GlobalDefs.Pause) { Monitor.Enter(_queueManager.Queue); for (int j = 0; j < _queueManager.Queue.Count; j++) { if ((!_queueManager.Queue[j].Completed) && (!_queueManager.Queue[j].Active)) { _conversionJobs[i] = _queueManager.Queue[j]; // Checking for a custom temp working path for conversion (other drives/locations) if (String.IsNullOrWhiteSpace(_conversionJobs[i].WorkingPath)) // Local temp folder takes precedence _conversionJobs[i].WorkingPath = Path.Combine((String.IsNullOrEmpty(MCEBuddyConf.GlobalMCEConfig.GeneralOptions.tempWorkingPath) ? GlobalDefs.AppPath : MCEBuddyConf.GlobalMCEConfig.GeneralOptions.tempWorkingPath), "working" + i.ToString(System.Globalization.CultureInfo.InvariantCulture)); // Start the conversion _conversionJobs[i].StartConversionThread(); SomeRunning = true; // Update status // Send an eMail if required GeneralOptions go = MCEBuddyConf.GlobalMCEConfig.GeneralOptions; bool sendEMail = go.sendEmail; // do we need to send an eMail after each job bool sendStart = go.eMailSettings.startEvent; string sendStartSubject = go.eMailSettings.startSubject; bool skipBody = go.eMailSettings.skipBody; if (sendEMail && sendStart) { string subject = Localise.GetPhrase("MCEBuddy started a video conversion"); string message = Localise.GetPhrase("Source Video") + " -> " + _conversionJobs[i].OriginalFileName + "\r\n"; message += Localise.GetPhrase("Profile") + " -> " + _conversionJobs[i].Profile + "\r\n"; message += Localise.GetPhrase("Conversion Task") + " -> " + _conversionJobs[i].TaskName + "\r\n"; message += Localise.GetPhrase("Conversion Started At") + " -> " + DateTime.Now.ToString("s", System.Globalization.CultureInfo.InvariantCulture) + "\r\n"; // Check for custom subject and process if (!String.IsNullOrWhiteSpace(sendStartSubject)) subject = UserCustomParams.CustomParamsReplace(sendStartSubject, _conversionJobs[i].WorkingPath, "", _conversionJobs[i].ConvertedFile, _conversionJobs[i].OriginalFileName, "", "", "", _conversionJobs[i].Profile, _conversionJobs[i].TaskName, _conversionJobs[i].MetaData, Log.AppLog); eMailSendEngine.AddEmailToSendQueue(subject, (skipBody ? "" : message)); // Send the eMail through the eMail engine } Log.AppLog.WriteEntry(this, "Job for " + _conversionJobs[i].OriginalFileName + " started using Conversion Task " + _conversionJobs[i].TaskName + " and Profile " + _conversionJobs[i].Profile, Log.LogEntryType.Information, true); Log.AppLog.WriteEntry(this, "Temp working path is " + _conversionJobs[i].WorkingPath, Log.LogEntryType.Debug, true); break; } } Monitor.Exit(_queueManager.Queue); } } } if ((GlobalDefs.Active) && !SomeRunning) // Was running jobs earlier, no active jobs now { Log.AppLog.WriteEntry(this, Localise.GetPhrase("No conversions running , allowing system sleep"), Log.LogEntryType.Debug, true); Util.PowerManagement.AllowSleep(); _allowSleep = true; } else if ((!GlobalDefs.Active) && SomeRunning) // Wasn't running jobs earlier, has new active jobs now { if (_userAllowSleep) // User allows sleep while converting { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Starting new conversions, allowing system sleep"), Log.LogEntryType.Debug, true); Util.PowerManagement.AllowSleep(); _allowSleep = true; } else { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Starting new conversions, preventing system sleep"), Log.LogEntryType.Debug, true); Util.PowerManagement.PreventSleep(); _allowSleep = false; } } // Check if the conversion is paused while the job is active, if so allow sleep if (GlobalDefs.Pause && SomeRunning && !_allowSleep) { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Active jobs paused, allowing system sleep"), Log.LogEntryType.Debug, true); Util.PowerManagement.AllowSleep(); _allowSleep = true; } else if (!GlobalDefs.Pause && SomeRunning && !_userAllowSleep && _allowSleep) // disable sleep once the job has been resumed and user does not allow sleeping while converting { Log.AppLog.WriteEntry(this, Localise.GetPhrase("Active jobs resumed, user does not allow sleep while converting, preventing system sleep"), Log.LogEntryType.Debug, true); Util.PowerManagement.PreventSleep(); _allowSleep = false; } GlobalDefs.Active = SomeRunning; _engineCrashed = false; // we've reached here so, reset it // Sleep then shutdown check Thread.Sleep(GlobalDefs.ENGINE_CORE_SLEEP_PERIOD); } // Shutdown support threads if ((syncThread != null) && syncThread.IsAlive) syncThread.Abort(); if ((scanThread != null) && scanThread.IsAlive) scanThread.Abort(); if ((updateCheckThread != null) && updateCheckThread.IsAlive) updateCheckThread.Abort(); // Shut down the conversion threads Monitor.Enter(_queueManager.Queue); for (int i = 0; i < _conversionJobs.Length; i++) { if (_conversionJobs[i] != null) { _conversionJobs[i].StopConversionThread(); _conversionJobs[i] = null; } } _queueManager.Queue.Clear(); // Clear the entire queue Monitor.Exit(_queueManager.Queue); Util.PowerManagement.AllowSleep(); //reset to default _allowSleep = true; GlobalDefs.Active = false; _monitorThread = null; // this thread is done } catch (Exception e) { _autoPause = GlobalDefs.Pause = false; // Reset suspension state GlobalDefs.Shutdown = true; // Terminate everything since we had a major crash // Shutdown support threads if ((syncThread != null) && syncThread.IsAlive) syncThread.Abort(); if ((scanThread != null) && scanThread.IsAlive) scanThread.Abort(); if ((updateCheckThread != null) && updateCheckThread.IsAlive) updateCheckThread.Abort(); // Release the queue lock if taken try { Monitor.Exit(_queueManager.Queue); } // Incase it's taken release it, if not taken it will throw an exception catch { } Util.PowerManagement.AllowSleep(); //reset to default _allowSleep = true; GlobalDefs.Active = false; _engineCrashed = true; GeneralOptions go = MCEBuddyConf.GlobalMCEConfig.GeneralOptions; go.engineRunning = false; MCEBuddyConf.GlobalMCEConfig.UpdateGeneralOptions(go, true); // Write the stop engine settings, since it crashed Log.AppLog.WriteEntry(this, "MCEBuddy Monitor Thread Crashed. Error: " + e.ToString(), Log.LogEntryType.Error, true); // This may or may not work depending upon whether the llog has been initialized otherwise it goes into NULL log Log.WriteSystemEventLog("MCEBuddy Monitor Thread Crashed. Error: " + e.ToString(), EventLogEntryType.Error); _monitorThread = null; // this thread is done } }