1457 lines
79 KiB
C#
1457 lines
79 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Windows;
|
|
using System.Windows.Controls;
|
|
using System.Windows.Data;
|
|
using System.Windows.Documents;
|
|
using System.Windows.Input;
|
|
using System.Windows.Media;
|
|
using System.Windows.Media.Imaging;
|
|
using System.Windows.Navigation;
|
|
using System.Windows.Shapes;
|
|
using WatchdogLib.WPF;
|
|
using WatchdogLib.Thread;
|
|
using System.Timers;
|
|
using Watchdog.WatchdogLib.Process;
|
|
using System.Diagnostics;
|
|
using WatchdogLib.File;
|
|
using WatchdogLib.Tools;
|
|
using Watchdog.WatchdogLib.File;
|
|
using Watchdog.WatchdogLib.Registry;
|
|
using Watchdog.WatchdogLib.Assembly;
|
|
using System.Windows.Threading;
|
|
using Watchdog.WatchdogLib.Other;
|
|
using Watchdog.WPFWindows;
|
|
using Watchdog.WatchdogLib.Monitor;
|
|
using Watchdog.WatchdogLib.Net;
|
|
using Watchdog.WatchdogLib.Win32;
|
|
|
|
namespace Watchdog
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for MainWindow.xaml
|
|
/// </summary>
|
|
public partial class HiddenMainWindow : Window
|
|
{
|
|
#region Private Statics
|
|
|
|
// Core Timers * And HiddenWindow Var *
|
|
private static KeepHidden _HiddenWindow = null;
|
|
private static TTimer _timer = new TTimer(TTimer_ElapsedEventHandler, 1523, false, false); // Kicks in every ~1.5 Seconds
|
|
private static TTimer _timerScheduler = new TTimer(TTimer_ElapsedEventHandlerScheduler, 61491, false, false); // Kicks in every ~1 Minute
|
|
private static TTimer _timerSchedulerBackup = new TTimer(TTimer_ElapsedEventHandlerSchedulerBackup, 99986, false, false); // Kicks in every 1.665 Minutes (uneven so timers have the highest chance of not overlapping)
|
|
|
|
// In case an unexpected process shutdown occurs, let's try to do more clean-up
|
|
private static bool s_WindowCloseGotCalled = false;
|
|
|
|
// to makes sure we have a clean shut down * Prev State Tracking *
|
|
private static bool s_bIsTimerRunning = false;
|
|
private static bool s_bIsSchedulerTimerRunning = false;
|
|
private static bool s_bIsSchedulerBackupTimerRunning = false;
|
|
|
|
// Start/Stop Timers *While shuting down _timer can be null* calling These functions and ignore any errors,
|
|
// Functions return the * previous state before calling * so if the previous state was 'Off' then it returns false, previous state was 'On' it returns true;
|
|
private static bool StartTimer() { lock (_HiddenWindow) { bool bPrevState = s_bIsTimerRunning; try { _timer.Start(); s_bIsTimerRunning = true; } catch (Exception) { /* ignore */ } return bPrevState; } }
|
|
private static bool StopTimer() { lock (_HiddenWindow) { bool bPrevState = s_bIsTimerRunning; try { _timer.Stop(); s_bIsTimerRunning = false; } catch (Exception) { /* ignore */ } return bPrevState; } }
|
|
private static bool StartSchedulerTimer() { lock (_HiddenWindow) { bool bPrevState = s_bIsSchedulerTimerRunning; try { _timerScheduler.Start(); s_bIsSchedulerTimerRunning = true; } catch (Exception) { /* ignore */ } return bPrevState; } }
|
|
private static bool StopSchedulerTimer() { lock (_HiddenWindow) { bool bPrevState = s_bIsSchedulerTimerRunning; try { _timerScheduler.Stop(); s_bIsSchedulerTimerRunning = false; } catch (Exception) { /* ignore */ } return bPrevState; } }
|
|
//private static bool StartSchedulerBackupTimer(uint IntervalInMiliseconds = 99986) { lock (_HiddenWindow) { bool bPrevState = s_bIsSchedulerBackupTimerRunning; try { _timerSchedulerBackup.Start(IntervalInMiliseconds); s_bIsSchedulerBackupTimerRunning = true; } catch (Exception) { /* ignore */ } return bPrevState; } }
|
|
private static bool StartSchedulerBackupTimer(uint IntervalInMiliseconds) { lock (_HiddenWindow) { bool bPrevState = s_bIsSchedulerBackupTimerRunning; try { _timerSchedulerBackup.Start(IntervalInMiliseconds); s_bIsSchedulerBackupTimerRunning = true; } catch (Exception) { /* ignore */ } return bPrevState; } }
|
|
private static bool StopSchedulerBackupTimer() { lock (_HiddenWindow) { bool bPrevState = s_bIsSchedulerBackupTimerRunning; try { _timerSchedulerBackup.Stop(); s_bIsSchedulerBackupTimerRunning = false; } catch (Exception) { /* ignore */ } return bPrevState; } }
|
|
|
|
#endregion
|
|
|
|
#region Internal Statics * (Monitor API) *
|
|
|
|
/// <summary>
|
|
/// Use this to Start the Process Monitor * Also Called by Scheduler and Scheduler Backup *
|
|
/// </summary>
|
|
/// <param name="bReloadConfigurationData">true to force a one-time refresh of XML DS Data, false otherwise</param>
|
|
/// <param name="bShowUserPopup">true to interact with desktop, false otherwise</param>
|
|
//internal static void StartMonitoring(bool bReloadConfigurationData = false, bool bShowUserPopup = true)
|
|
internal static void StartMonitoring(bool bReloadConfigurationData, bool bShowUserPopup)
|
|
{
|
|
// If the Monitor was Paused Prior? - restart the Timers
|
|
if (App.State_IsMonitorPaused())
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Set to Running
|
|
App.State_MonitorStarted();
|
|
|
|
// Re-start Timers
|
|
StartTimer();
|
|
StartScheduler();
|
|
StartSchedulerBackup(99986);
|
|
|
|
// Log and Inform the User
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_MONITOR_STARTED_FROM_PAUSE", App.APPLICATION_NAME_SHORT, false));
|
|
if(bShowUserPopup && !App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_START_SUCCESS", App.APPLICATION_NAME_SHORT, App.APP_XML_DS_FILENAME));
|
|
|
|
// * Set the System Tray Icon According to Running State *
|
|
if(!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.SetSysTrayIconAccordingToRunningState(App.State_GetSystemState());
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Is the Monitor already running?
|
|
if (App.State_MonitorIsInRunningState())
|
|
return;
|
|
|
|
// Set to Running
|
|
App.State_MonitorStarted();
|
|
|
|
// Let's get Started
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Reset the Last Scheduler Run Time
|
|
if (!App.State_IsSchedulerExecuting())
|
|
App.setting.LastSchedulerRun = DateTime.MinValue;
|
|
|
|
// Reset the Last Scheduler Backup Run Time
|
|
if (!App.State_IsSchedulerBackupExecuting())
|
|
App.setting.LastSchedulerBackupRun = DateTime.MinValue;
|
|
|
|
// Reset Error State * But Only if we are NOT being Called by the Scheduler *
|
|
if (!App.State_IsSchedulerExecuting())
|
|
App.State_Error_ResetErrorState();
|
|
|
|
// Log Start of monitoring
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_MONITOR_STARTED", App.APPLICATION_NAME_SHORT, bReloadConfigurationData ? "True" : "False"));
|
|
|
|
// * Set the System Tray Icon According to Running State *
|
|
if(!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.SetSysTrayIconAccordingToRunningState(App.State_GetSystemState());
|
|
|
|
// Popup Std Start Monitoring Message
|
|
if (bShowUserPopup && !App.State_SpecialMode_IsRunAsServiceSet())
|
|
{
|
|
if (App.State_IsSchedulerExecuting())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_STARTSTOP", App.APPLICATION_NAME_SHORT, App.APP_XML_DS_FILENAME));
|
|
else if (App.State_IsSchedulerBackupExecuting())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_BACKUP_STARTSTOP_DISPLAY2", App.APPLICATION_NAME_SHORT));
|
|
else
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_START_SUCCESS", App.APPLICATION_NAME_SHORT, App.APP_XML_DS_FILENAME));
|
|
}
|
|
|
|
// Reload Configuration, if neccessary
|
|
App.xmlfile.ForceRefreshOnNext_ReadData = bReloadConfigurationData;
|
|
if (!bReloadConfigurationData)
|
|
{
|
|
// make sure that at least all the process/service info is cleared
|
|
App.xmlfile.ReadData(false).ClearAllStartNFailTimes();
|
|
// also clear PID information
|
|
App.xmlfile.ReadData(false).MonitoredProcesses.ClearPidInformation();
|
|
}
|
|
|
|
// Let the Schedulers Handle the starting of the Timers,
|
|
// * don't start anything if it is already executing - concurrency *
|
|
if (!App.State_IsSchedulerExecuting() && !App.State_IsSchedulerBackupExecuting())
|
|
{
|
|
if(App.setting.SchedulerSettingsExist || App.setting.SchedulerBackupSettingsExist)
|
|
{
|
|
// When we StartMonitoring, we should delay start the Scheduler,
|
|
// to give the timer a change to start all processes. 10 Seconds should do.
|
|
ElapsedEventHandler timedStart = delegate(object sender, ElapsedEventArgs e)
|
|
{
|
|
Timer timer = (Timer)sender;
|
|
timer.Stop();
|
|
StartScheduler(); // * Start the Scheduler, if it is set *
|
|
StartSchedulerBackup(99986); // * Start the Scheduler Backup, if it is set *
|
|
timer.Dispose();
|
|
timer = null;
|
|
};
|
|
TTimer delayStartScheduler = new TTimer(timedStart, 5000, true, true);
|
|
}
|
|
}
|
|
|
|
// Allow Scheduler to manage this timer
|
|
if(!App.State_IsSchedulerExecuting())
|
|
StartTimer();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Pause the Monitor * Also Called by Scheduler Backup *
|
|
/// </summary>
|
|
/// <param name="bShowUserPopup">true to interact with desktop, false otherwise</param>
|
|
//internal static void PauseMonitoring(bool bShowUserPopup = true)
|
|
internal static void PauseMonitoring(bool bShowUserPopup)
|
|
{
|
|
if (App.State_IsMonitorPaused() || !App.State_MonitorIsInRunningState())
|
|
return;
|
|
|
|
App.log.Info("PauseMonitoring Called");
|
|
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Stop Both Timers, inside a Lock,
|
|
// should do the trick * Neither should execute *
|
|
StopTimer();
|
|
StopScheduler();
|
|
if (!App.State_IsSchedulerBackupExecuting())
|
|
StopSchedulerBackup();
|
|
|
|
// Mark the System as a Paused State
|
|
App.State_MonitorPaused();
|
|
|
|
// Log Pause of monitoring
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_MONITOR_PAUSED", App.APPLICATION_NAME_SHORT));
|
|
if (bShowUserPopup && !App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_MONITOR_PAUSED", App.APPLICATION_NAME_SHORT));
|
|
|
|
// * Set the System Tray Icon According to Current State *
|
|
if(!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.SetSysTrayIconAccordingToRunningState(App.State_GetSystemState());
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restarts the Monitor * Also Called by Scheduler *
|
|
/// </summary>
|
|
/// <param name="nWaitBeforeStartSeconds">Time in seconds to wait before starting (after stopping)</param>
|
|
/// <param name="bShowUserPopup">true to interact with desktop, false otherwise</param>
|
|
//internal static void RestartMonitoring(uint nWaitBeforeStartSeconds = 4, bool bShowUserPopup = true)
|
|
internal static void RestartMonitoring(uint nWaitBeforeStartSeconds, bool bShowUserPopup)
|
|
{
|
|
App.log.Info("RestartMonitoring Called");
|
|
|
|
// Stop the Monitor
|
|
StopMonitoring(bShowUserPopup, false);
|
|
|
|
// Sleep, for a little while,...
|
|
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(nWaitBeforeStartSeconds));
|
|
|
|
// Now Start again...
|
|
StartMonitoring(!App.State_IsSchedulerExecuting(), bShowUserPopup);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restarts the Monitor, including all services
|
|
/// </summary>
|
|
/// <param name="nWaitBeforeStartSeconds">Time in seconds to wait before starting (after stopping)</param>
|
|
/// <param name="bShowUserPopup">true to interact with desktop, false otherwise</param>
|
|
//internal static void RestartAllMonitoring(uint nWaitBeforeStartSeconds = 4, bool bShowUserPopup = true)
|
|
internal static void RestartAllMonitoring(uint nWaitBeforeStartSeconds, bool bShowUserPopup)
|
|
{
|
|
App.log.Info("RestartAllMonitoring Called");
|
|
|
|
// Stop the Monitor
|
|
StopMonitoring(bShowUserPopup, true);
|
|
|
|
// Sleep, for a little while,...
|
|
System.Threading.Thread.Sleep(TimeSpan.FromSeconds(nWaitBeforeStartSeconds));
|
|
|
|
// Now Start again...
|
|
StartMonitoring(!App.State_IsSchedulerExecuting(), bShowUserPopup);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stops Monitoring, including all Services
|
|
/// </summary>
|
|
/// <param name="bShowUserPopup">true to interact with desktop, false otherwise</param>
|
|
//internal static void StopAllMonitoring(bool bShowUserPopup = true)
|
|
internal static void StopAllMonitoring(bool bShowUserPopup)
|
|
{
|
|
App.log.Info("StopAllMonitoring Called");
|
|
StopMonitoring(bShowUserPopup, true);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this to Stop the Process Monitor * Also Called by Scheduler and Scheduler Backup *
|
|
/// </summary>
|
|
//internal static void StopMonitoring(bool bShowUserPopup = true, bool bForceShutdownOfServices = false)
|
|
internal static void StopMonitoring(bool bShowUserPopup, bool bForceShutdownOfServices)
|
|
{
|
|
// Is the Monitor even running?
|
|
if (!App.State_MonitorIsInRunningState())
|
|
return;
|
|
|
|
// Set to Stopped
|
|
App.State_MonitorStopped();
|
|
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Reset Error State * But Only if we are NOT being Called by the Scheduler *
|
|
if (!App.State_IsSchedulerExecuting() && !App.State_IsSchedulerBackupExecuting())
|
|
App.State_Error_ResetErrorState();
|
|
|
|
// Log Stop of monitoring
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_MONITOR_STOPPED", App.APPLICATION_NAME_SHORT));
|
|
|
|
// Stop the Internal Timers * Always do this * just in case
|
|
StopTimer();
|
|
StopSchedulerTimer();
|
|
if (!App.State_IsSchedulerBackupExecuting())
|
|
StopSchedulerBackupTimer();
|
|
|
|
// Read the config
|
|
WatchdogConfiguration config = App.xmlfile.ReadData(false);
|
|
|
|
// * Set the System Tray Icon According to Running State *
|
|
if(!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.SetSysTrayIconAccordingToRunningState(App.State_GetSystemState());
|
|
|
|
// Popup Std Stop Monitoring Message * But Only if Scheduler && Scheduler Backup is NOT running *
|
|
if (bShowUserPopup && !App.State_SpecialMode_IsRunAsServiceSet())
|
|
{
|
|
if(App.State_IsSchedulerExecuting())
|
|
{
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_STARTSTOP_DISPLAY1", App.APPLICATION_NAME_SHORT));
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_STARTSTOP_DISPLAY1", App.APPLICATION_NAME_SHORT));
|
|
}
|
|
else if (App.State_IsSchedulerBackupExecuting())
|
|
{
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_BACKUP_STARTSTOP_DISPLAY1", App.APPLICATION_NAME_SHORT));
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_BACKUP_STARTSTOP_DISPLAY1", App.APPLICATION_NAME_SHORT));
|
|
}
|
|
else
|
|
{
|
|
if (config.ConfiguredHasAny)
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_STOP_SUCCESS", App.APPLICATION_NAME_SHORT, App.APP_XML_DS_FILENAME, bForceShutdownOfServices));
|
|
else
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_NO_CONFIGURATION_FOUND", App.APP_XML_DS_FILENAME));
|
|
}
|
|
|
|
if (config.ConfiguredHasAny)
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_STOP_SUCCESS", App.APPLICATION_NAME_SHORT, App.APP_XML_DS_FILENAME, bForceShutdownOfServices));
|
|
else
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_NO_CONFIGURATION_FOUND", App.APP_XML_DS_FILENAME));
|
|
}
|
|
|
|
// Shutdown any of our Running Processes
|
|
TraceM.TraceBegin();
|
|
bool bKillApplications = !(App.State_SpecialCircum_ShouldWeNotCloseApplicationsOnExit() && s_WindowCloseGotCalled);
|
|
if(bKillApplications)
|
|
ProcessKillAllMonitoredProcessesIfAny(config);
|
|
TraceM.TraceEnd("Killing Running Applications");
|
|
|
|
// Shutdown any of our Running Services
|
|
TraceM.TraceBegin();
|
|
ServicesKillAllMonitoredServicesIfAny(config, bForceShutdownOfServices);
|
|
TraceM.TraceEnd("Killing Running Services");
|
|
|
|
// Try Reclaim memory by running the Garbage Collector
|
|
// * Really appears to not be doing much *
|
|
if (!App.State_IsSchedulerExecuting() && !App.State_IsSchedulerBackupExecuting())
|
|
{
|
|
TraceM.TraceBegin();
|
|
GC.Collect();
|
|
GC.WaitForPendingFinalizers();
|
|
GC.Collect();
|
|
TraceM.TraceEnd("Garbage Collector Called");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this to Start the Scheduler
|
|
/// </summary>
|
|
internal static void StartScheduler()
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Start the Scheduler Only if there is any Scheduler Information (and the Settings Window
|
|
// isn't currently being shown - Settings window disables/enables Scheduler on it's own *
|
|
if (!App.State_IsSchedulerExecuting() && App.setting.SchedulerSettingsExist &&
|
|
!WPFWindowMaker.IsWindowOfTypeWPFWindowShowing_WithinLock(WPFWindow.Settings_Window))
|
|
StartSchedulerTimer();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this to Stop the Scheduler
|
|
/// </summary>
|
|
internal static void StopScheduler()
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
StopSchedulerTimer();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this to Start the Scheduler Backup
|
|
/// </summary>
|
|
//internal static void StartSchedulerBackup(uint IntervalInMiliseconds = 99986)
|
|
internal static void StartSchedulerBackup(uint IntervalInMiliseconds)
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Start the Scheduler Backup Only if there is any Scheduler Backup Information (and the Settings Window
|
|
// isn't currently being shown - Settings window disables/enables Scheduler Backup on it's own *
|
|
if (!App.State_IsSchedulerBackupExecuting() && App.setting.SchedulerBackupSettingsExist &&
|
|
!WPFWindowMaker.IsWindowOfTypeWPFWindowShowing_WithinLock(WPFWindow.Settings_Window))
|
|
StartSchedulerBackupTimer(IntervalInMiliseconds);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use this to Stop the Scheduler Backup
|
|
/// </summary>
|
|
internal static void StopSchedulerBackup()
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
StopSchedulerBackupTimer();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Construction
|
|
|
|
/// <summary>
|
|
/// Constructor
|
|
/// </summary>
|
|
public HiddenMainWindow()
|
|
{
|
|
InitializeComponent();
|
|
|
|
// Only continue, if no fatal application error occured
|
|
if (!App.s_FatalErrorOccured)
|
|
{
|
|
// * Force this window to remain hidden indefinitly*
|
|
_HiddenWindow = new KeepHidden(this);
|
|
|
|
// Assign ProcessExit Event to Handle more specialized Cleanup
|
|
AppDomain.CurrentDomain.ProcessExit += new EventHandler(CurrentDomain_ProcessExit);
|
|
|
|
// We DON'T NEED TO SHOW THE HIDDEN WINDOW * Triggering OnLoad(), if we are
|
|
// being launched via the Command-Line.
|
|
if (App.State_SpecialMode_IsCommandLineSet())
|
|
{
|
|
// If we are in Command-Line Mode * Then Hidden Window should never be shown *
|
|
// in fact we'll enter into a whole new entry point * CommandLine MODE
|
|
ElapsedEventHandler EnterCommandLineMode = delegate(object sender, ElapsedEventArgs e)
|
|
{
|
|
Timer timer = (Timer)sender;
|
|
timer.Stop();
|
|
|
|
// * Enter CommandLine Mode *
|
|
CMDlineHandler.EnterCommandLineMode();
|
|
|
|
timer.Dispose();
|
|
timer = null;
|
|
|
|
// Done Here, shut down the app
|
|
App.Current.Shutdown();
|
|
};
|
|
TTimer timerEnterCommandLineMode = new TTimer(EnterCommandLineMode, 500, true, true);
|
|
}
|
|
else
|
|
{
|
|
// Calling Show() directly in the Constructor causes a .Net Run-time Crash
|
|
// upon first launch only. Calling it .5 seconds later does the trick of avoiding that error,
|
|
// because by then the object is fully constructed
|
|
ElapsedEventHandler DelayShowHiddenWindow = delegate(object sender, ElapsedEventArgs e)
|
|
{
|
|
Timer timer = (Timer)sender;
|
|
timer.Stop();
|
|
|
|
// * Show the Hidden Window *
|
|
_HiddenWindow.Show();
|
|
|
|
timer.Dispose();
|
|
timer = null;
|
|
};
|
|
TTimer timerDelayShowHiddenWindow = new TTimer(DelayShowHiddenWindow, 500, true, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Process Monitor / Service Monitor * CORE LOGIC *
|
|
|
|
/// <summary>
|
|
/// Called every Nth Interval, does the grunt of the work for this whole
|
|
/// Application. It checks the processes, and if they are running, etc...
|
|
/// * Core Business Logic *
|
|
/// </summary>
|
|
private static void TTimer_ElapsedEventHandler(object sender, ElapsedEventArgs e)
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Stop the timer to prevent multiple call-Ins, while work is still being done
|
|
StopTimer();
|
|
|
|
// Everything is Good, Monitor the Processes / Services Start any processes / Services that aren't available
|
|
if (App.State_MonitorIsInRunningState() && !App.State_IsMonitorPaused())
|
|
{
|
|
// Get the Configuration
|
|
WatchdogConfiguration config = App.xmlfile.ReadData(false);
|
|
|
|
// * NO CONFIGURATION * Stop! - Nothing to monitor
|
|
if (!config.ConfiguredHasAny)
|
|
{
|
|
StopMonitoring(true, false);
|
|
return;
|
|
}
|
|
|
|
// * Read the Ini Configuration Settings *
|
|
TraceM.TraceBegin();
|
|
uint nMaxFailureCount = App.setting.MaxFailureCount;
|
|
uint nMaxFailureCountHour = App.setting.MaxFailureCountHour;
|
|
TraceM.TraceEnd("Monitor - Reading in INI Configuration");
|
|
|
|
// * SERVICE MONITORING *
|
|
TraceM.TraceBegin();
|
|
bool bErrorThrownInServicesMonitor = !ServiceMonitor(config, nMaxFailureCount, nMaxFailureCountHour);
|
|
TraceM.TraceEnd("* Service Monitoring *");
|
|
|
|
// * PROCESS MONITORING *
|
|
TraceM.TraceBegin();
|
|
bool bErrorThrownInProcessMonitor = !ProcessMonitor(config, nMaxFailureCount, nMaxFailureCountHour);
|
|
TraceM.TraceEnd("* Process Monitoring *");
|
|
|
|
// If Any Unknown Errors were Thrown! Stop the Monitor
|
|
if (bErrorThrownInServicesMonitor || bErrorThrownInProcessMonitor)
|
|
{
|
|
StopMonitoring(true, false);
|
|
|
|
////
|
|
// An Error Occured with the Application * Better Notify User, if specified *
|
|
////
|
|
if (App.setting.EmailNotificationEnabled && App.setting.EmailSettingsValid)
|
|
{
|
|
bool bIsSend = Emailer.SendEmail(App.setting.EmailStmpServer, App.setting.EmailSenderEmail, App.APPLICATION_NAME_SHORT,
|
|
App.setting.EmailReceiverEmail, AppResx.GetStringFormated("ERROR_EMAIL_SUBJECT", App.APPLICATION_NAME_SHORT),
|
|
AppResx.GetStringFormated("ERROR_EMAIL_BODY", App.APPLICATION_NAME_SHORT, App.setting.EmailCustomMessageText),
|
|
App.setting.EmailSmtpPort, String.Empty, App.setting.EmailStmpServerRequiresAuth, App.setting.EmailSmtpUsername, App.setting.EmailSmtpPassword,
|
|
App.setting.EmailStmpServerRequiresSSL, 30);
|
|
if (!bIsSend)
|
|
App.log.Error("Failed to Send ERROR_EMAIL");
|
|
else
|
|
App.log.Info(String.Format("Email (ERROR_EMAIL) Notification send to {0}", App.setting.EmailReceiverEmail));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (!App.State_IsMonitorPaused()) // If the System Is Paused, no need to start the Timer again
|
|
{
|
|
// Re-Start the timer, if all went well
|
|
// * At the end of each Cycle, Set the System Tray Icon Accordingly * Keep track when we were last run
|
|
if(!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.SetSysTrayIconAccordingToRunningState(App.State_GetSystemState());
|
|
StartTimer(); // Everything went well, continue...
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Used by the Scheduler Timer to determine if a restart is to occur
|
|
/// </summary>
|
|
/// <param name="now">now datetime stamp</param>
|
|
/// <param name="start">scheduler start datetime stamp</param>
|
|
/// <param name="LastRun">datetime when last run occured</param>
|
|
/// <param name="nHoursOrMinutes">numeric value indicating hours or minutes</param>
|
|
/// <param name="bIsHours">true if hours, false if minutes</param>
|
|
/// <returns>true if we want the Scheduler to Restart, false otherwise</returns>
|
|
private static bool PerformRestartTimeSchedulerTriggered(DateTime now, DateTime start, DateTime LastRun, uint nHoursOrMinutes, bool bIsHours)
|
|
{
|
|
// * OLD CALCULATION * OLD SCHOOL * Make sure enough time has passed since last run, otherwise no need to continue
|
|
//TimeSpan tsLastRun = now - LastRun;
|
|
//bool bEnoughTimeSinceLastRunHasPassed = bIsHours ? (((double)(tsLastRun.TotalMinutes / 60)) >= ((double)nHoursOrMinutes)) : (tsLastRun.TotalMinutes >= ((double)nHoursOrMinutes));
|
|
//return bEnoughTimeSinceLastRunHasPassed;
|
|
|
|
// If the current time is within 2 minutes of last run, there is no need to continue
|
|
TimeSpan tsDiffBetweenNowAndLastRun = (now - LastRun);
|
|
bool bIsWithin2MinutesOfLastRun = (tsDiffBetweenNowAndLastRun.TotalMinutes >= 0) && (tsDiffBetweenNowAndLastRun.TotalMinutes <= 2.9997);
|
|
if (bIsWithin2MinutesOfLastRun)
|
|
return false;
|
|
|
|
// Check the start time * if we are near the start time and a last run hasn't occured, then yes, run this *
|
|
TimeSpan tsDiffBetweenNowAndStart = (now - start);
|
|
bool bIsWithin2MinutesOfScheduledStartTime = (tsDiffBetweenNowAndStart.TotalMinutes >= 0) && (tsDiffBetweenNowAndStart.TotalMinutes <= 2.9997);
|
|
if (bIsWithin2MinutesOfScheduledStartTime)
|
|
return true;
|
|
|
|
// Perform Cycle Calculation
|
|
double durationInMinutes = bIsHours ? nHoursOrMinutes * 60 : nHoursOrMinutes;
|
|
double remCycle = tsDiffBetweenNowAndStart.TotalMinutes % durationInMinutes;
|
|
bool bIsWithin2MinutesOfRemCycle = (remCycle >= 0) && (remCycle <= 2.9997);
|
|
return bIsWithin2MinutesOfRemCycle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called every Nth Interval, does the grunt of the work for the Scheduler
|
|
/// * Core Business Logic *
|
|
/// </summary>
|
|
private static void TTimer_ElapsedEventHandlerScheduler(object sender, ElapsedEventArgs e)
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
// *imp * stop the process/services monitor (so that while
|
|
// this timer occurs it won't conflict with what happens here
|
|
bool bPrevStateTimer = StopTimer();
|
|
|
|
// Stop the Scheduler timer to prevent multiple call-Ins, while work is still being done
|
|
StopSchedulerTimer();
|
|
|
|
// Everything is Good,
|
|
if (App.State_MonitorIsInRunningState() && !App.State_IsSchedulerExecuting() && !App.State_IsMonitorPaused())
|
|
{
|
|
// Set the Scheduler State
|
|
App.State_SchedulerExecution_Started();
|
|
|
|
// Fetch scheduler settings
|
|
bool bFoundSchedulerSettings = false;
|
|
DateTime dtStart = DateTime.MinValue;
|
|
DateTime dtLastRun = DateTime.MinValue;
|
|
uint nHoursOrMinutes = 0;
|
|
bool bIsHours = true;
|
|
|
|
// Only Do something if there are any settings
|
|
bFoundSchedulerSettings = App.setting.GetSchedulerSettings(out dtStart, out dtLastRun, out nHoursOrMinutes, out bIsHours);
|
|
if (!bFoundSchedulerSettings)
|
|
return; // No Scheduler Settings, no need to continue
|
|
|
|
// Get the Now Time
|
|
DateTime dtNow = DateTime.Now;
|
|
|
|
// Make sure we've reached the Start Time, else there is no need to continue
|
|
if (dtNow >= dtStart && PerformRestartTimeSchedulerTriggered(dtNow, dtStart, dtLastRun, nHoursOrMinutes, bIsHours))
|
|
{
|
|
// Log the fact that Scheduler is about to stop / start
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_STARTSTOP", App.APPLICATION_NAME_SHORT, App.APP_XML_DS_FILENAME));
|
|
|
|
// * Perform Restart *
|
|
RestartMonitoring(4, true);
|
|
|
|
// Set Last Run
|
|
App.setting.LastSchedulerRun = dtNow;
|
|
}
|
|
|
|
// Reset the Scheduler State
|
|
App.State_SchedulerExecution_Stopped();
|
|
}
|
|
|
|
if (!App.State_IsMonitorPaused()) // If the System Is Paused, no need to start the Timers again
|
|
{
|
|
// Re-Start the Scheduler timer * Everything went well s *
|
|
StartScheduler();
|
|
|
|
// Now it should be save to start the Main Monitor Timer
|
|
if (bPrevStateTimer)
|
|
StartTimer();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Integrity - When we fire a start Trigger with SchedulerBackupTriggerOccured(), in case another call in occurs,
|
|
/// we know to ignore it
|
|
/// </summary>
|
|
private static DateTime _LastStartTriggerFired = DateTime.MinValue;
|
|
|
|
/// <summary>
|
|
/// Integrity - When we fire a end Trigger with SchedulerBackupTriggerOccured(), in case another call in occurs,
|
|
/// we know to ignore it
|
|
/// </summary>
|
|
private static DateTime _LastEndTriggerFired = DateTime.MinValue;
|
|
|
|
/// <summary>
|
|
/// Deterimes the State of the Scheduler Backup and what action to take
|
|
/// </summary>
|
|
/// <param name="dtNow">The Now DateTime</param>
|
|
/// <param name="dtScheduledStartDT">Scheduled Start DateTime</param>
|
|
/// <param name="dtLastRun">Last Run, should be set when the first start occured and passed into here for checking</param>
|
|
/// <param name="tsDuration">the duration from start to end</param>
|
|
/// <returns>we want to perform the following action * Trigger Occured *, 0 = None, 1 = Start, 2 = End</returns>
|
|
private static uint SchedulerBackupTriggerOccured (DateTime dtNow, DateTime dtScheduledStartDT, DateTime dtLastRun, TimeSpan tsDuration)
|
|
{
|
|
// Time Of Day Vars
|
|
TimeSpan TimeOfDayNow = dtNow.TimeOfDay;
|
|
TimeSpan TimeOfDayScheduled = dtScheduledStartDT.TimeOfDay;
|
|
|
|
// Debug
|
|
//dtNow = DateTime.Parse("8/13/2011 01:57:29 AM");
|
|
//TimeOfDayNow = new TimeSpan(1, 57, 29);
|
|
//TimeOfDayScheduled = new TimeSpan(1, 56, 11);
|
|
//tsDuration = new TimeSpan(4, 0, 0);
|
|
//dtLastRun = DateTime.Parse("1/1/0001 12:00:00 AM");
|
|
|
|
// Time of Day Within Time Calc;
|
|
TimeSpan tsDiffBetweenNowAndScheduled = (TimeOfDayNow - TimeOfDayScheduled);
|
|
bool bIsWithin2MinutesOfScheduledTime = (tsDiffBetweenNowAndScheduled.TotalMinutes > 0) && (tsDiffBetweenNowAndScheduled.TotalMinutes <= 2.9997);
|
|
TimeSpan tsDiffBetweenNowAndScheduledDurationEnd = TimeOfDayNow - (TimeOfDayScheduled + tsDuration);
|
|
if(tsDiffBetweenNowAndScheduledDurationEnd.TotalMinutes < 0) // A Day must have passed
|
|
tsDiffBetweenNowAndScheduledDurationEnd = tsDiffBetweenNowAndScheduledDurationEnd + new TimeSpan(24, 00, 00);
|
|
bool bIsWithin2MinutesOfScheduledTimeDurationEnd = (tsDiffBetweenNowAndScheduledDurationEnd.TotalMinutes <= 2.9997);
|
|
|
|
// Last Run Calculations * make sure to see if it was started prior
|
|
// ~Last Run allows us to determine if there exists a start for an end,
|
|
// we only check the end event to see if a start occured
|
|
if (bIsWithin2MinutesOfScheduledTimeDurationEnd)
|
|
{
|
|
TimeSpan tsDiffBetweenNowAndLastRun = dtNow - dtLastRun;
|
|
TimeSpan tsDiffInDuration = tsDiffBetweenNowAndLastRun - tsDuration;
|
|
|
|
// In the event the Monitor App got started somewhere in between times,
|
|
// and we trigger the end event (because time was reached), we
|
|
// are checking last run, to see if it coincides with this end event,
|
|
// if it doesn't (as in it is way too long ago ~here anything above 10 minutes out
|
|
// of bounds from the duration), we won't trigger the end event, assuming
|
|
// that it never started in this cycle to begin with, waiting for the next cycle
|
|
bool bIsLastRunOutOfBounce = (tsDiffInDuration.TotalMinutes > 0) && (tsDiffInDuration.TotalMinutes >= 10);
|
|
if (bIsLastRunOutOfBounce)
|
|
return 0;
|
|
}
|
|
|
|
// Integrity Check * prevent multiple callins within time boundary 2.9997, * or actually
|
|
// within the same day * may as well, we only allow 1 start/end trigger per day
|
|
if (bIsWithin2MinutesOfScheduledTime)
|
|
{
|
|
TimeSpan ts = dtNow - _LastStartTriggerFired;
|
|
if ((ts.TotalMinutes > 0) && (ts.TotalMinutes > 1000)) // we should only be firing on start trigger per day aka 1440, but 1000 is a good check (even)
|
|
_LastStartTriggerFired = dtNow;
|
|
else
|
|
bIsWithin2MinutesOfScheduledTime = false;
|
|
}
|
|
else if (bIsWithin2MinutesOfScheduledTimeDurationEnd)
|
|
{
|
|
TimeSpan ts = dtNow - _LastEndTriggerFired;
|
|
if ((ts.TotalMinutes > 0) && (ts.TotalMinutes > 1000)) // we should only be firing on end trigger per day aka 1440, but 1000 is a good check (even)
|
|
_LastStartTriggerFired = dtNow;
|
|
else
|
|
bIsWithin2MinutesOfScheduledTime = false;
|
|
}
|
|
|
|
// Trigger Start / Stop / Or Nothing
|
|
if (bIsWithin2MinutesOfScheduledTime)
|
|
return 1;
|
|
else if (bIsWithin2MinutesOfScheduledTimeDurationEnd)
|
|
return 2;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called every Nth Interval, does the grunt of the work for the Scheduler Backup
|
|
/// * Core Business Logic *
|
|
/// </summary>
|
|
private static void TTimer_ElapsedEventHandlerSchedulerBackup(object sender, ElapsedEventArgs e)
|
|
{
|
|
lock (_HiddenWindow)
|
|
{
|
|
// Stop the Scheduler Backup timer to prevent multiple call-Ins, while work is still being done
|
|
StopSchedulerBackupTimer();
|
|
|
|
// Everything is Good,
|
|
//if (App.State_MonitorIsInRunningState() && !App.State_IsSchedulerBackupExecuting()) // BUG
|
|
if (!App.State_IsSchedulerBackupExecuting())
|
|
{
|
|
// Set the Scheduler State
|
|
App.State_SchedulerBackupExecution_Started();
|
|
|
|
// Fetch scheduler Backup settings
|
|
bool bFoundSchedulerBackupSettings = false;
|
|
DateTime dtStart = DateTime.MinValue;
|
|
DateTime dtLastRun = DateTime.MinValue;
|
|
uint nHoursOrMinutes = 0;
|
|
bool bIsHours = true;
|
|
|
|
// Only Do something if there are any settings
|
|
bFoundSchedulerBackupSettings = App.setting.GetSchedulerBackupSettings(out dtStart, out dtLastRun, out nHoursOrMinutes, out bIsHours);
|
|
if (!bFoundSchedulerBackupSettings)
|
|
return; // No Scheduler Backup Settings, no need to continue
|
|
|
|
// Get the Now Time
|
|
DateTime dtNow = DateTime.Now;
|
|
|
|
// Make sure we've reached the Start Time, else there is no need to continue
|
|
if (dtNow >= dtStart)
|
|
{
|
|
// Get the Duration
|
|
TimeSpan tsDuration = bIsHours ? TimeSpan.FromHours(nHoursOrMinutes) : TimeSpan.FromMinutes(nHoursOrMinutes);
|
|
|
|
// Determine the State of the Scheduler Backup an the Action To Take
|
|
uint nTriggerResult = SchedulerBackupTriggerOccured(dtNow, dtStart, dtLastRun, tsDuration);
|
|
|
|
bool bPerformAnAction = (nTriggerResult == 1) || (nTriggerResult == 2);
|
|
if (bPerformAnAction)
|
|
{
|
|
// Get Current State
|
|
App.StateSystem state = App.State_GetSystemState();
|
|
bool bStopInsteadOfPause = App.setting.SchedulerBackupStopInsteadOfPause;
|
|
bool bStopServices = App.setting.SchedulerBackupStopServices;
|
|
|
|
// Log the fact that Scheduler Backup is about to pause / stop / start
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_SCHEDULER_BACKUP_STARTSTOP", App.APPLICATION_NAME_SHORT, (state == App.StateSystem.Paused)));
|
|
|
|
// * Perform System Pause * or
|
|
// * Perform System Start *, or * System Stop *, depending on system state and Settings
|
|
switch (nTriggerResult)
|
|
{
|
|
case 1: // Duration Start
|
|
{
|
|
// We are in a wrong state to perform a start
|
|
if (state != App.StateSystem.Error &&
|
|
state != App.StateSystem.Running)
|
|
{
|
|
App.log.Error(String.Format("SchedulerBackup Wrong State for Action 'Duration Start' for State {0}. SchedulerBackup Trigger Ignored", Enum.GetName(typeof(App.StateSystem), state)));
|
|
}
|
|
else
|
|
{
|
|
// Perform Action
|
|
if (bStopInsteadOfPause)
|
|
StopMonitoring(true, bStopServices);
|
|
else
|
|
PauseMonitoring(true);
|
|
|
|
// Mark Scheduler Backup as Started
|
|
App.setting.LastSchedulerBackupRun = dtNow;
|
|
}
|
|
break;
|
|
}
|
|
case 2: // Duration End
|
|
{
|
|
// We are in a wrong state to perform a start
|
|
if (state != App.StateSystem.Paused &&
|
|
state != App.StateSystem.Stopped)
|
|
{
|
|
App.log.Error(String.Format("SchedulerBackup Wrong State for Action 'Duration End' for State {0}. SchedulerBackup Trigger Ignored", Enum.GetName(typeof(App.StateSystem), state)));
|
|
}
|
|
else
|
|
{
|
|
// Perform Action
|
|
StartMonitoring(false, true);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset the Scheduler Backup State
|
|
App.State_SchedulerBackupExecution_Stopped();
|
|
}
|
|
|
|
// Re-Start the Scheduler Backup timer * Waiting for the next iteration *
|
|
StartSchedulerBackup(99986);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// * Core Logic * Monitor Processes from the Configuration. Start Any Processes that are Ok to
|
|
/// be started (ProcessOkToBeStarted_Check) that are currently not running
|
|
/// </summary>
|
|
/// <param name="config">Monitor Configuration</param>
|
|
/// <param name="nMaxFailureCount">Max Failure Count</param>
|
|
/// <param name="nMaxFailureCountHour">Max Failure Count in given Hour Timespan</param>
|
|
/// <returns>true if successfull, false if ProcessMonitor Threw an Error</returns>
|
|
private static bool ProcessMonitor(WatchdogConfiguration config, uint nMaxFailureCount, uint nMaxFailureCountHour)
|
|
{
|
|
// * PROCESS MONITORING *
|
|
if (config.ConfiguredHasAnyProcesses)
|
|
{
|
|
try
|
|
{
|
|
// Start Any Processes that are NOT Running
|
|
uint uProcessStartSuccessCount = 0;
|
|
uint uProcessStarFailCount = 0;
|
|
List<WatchdogConfiguration.ProcessExe> nonRunningProcesses = Processes_ThatNeedToBeStarted_Check(config);
|
|
if (nonRunningProcesses.Count > 0)
|
|
{
|
|
// Iterate each non-running Process and try to Start it
|
|
foreach (WatchdogConfiguration.ProcessExe mProcess in nonRunningProcesses)
|
|
{
|
|
// Check that the Process can be started
|
|
if (!ProcessOkToBeStarted_Check(mProcess, nMaxFailureCount, nMaxFailureCountHour))
|
|
continue;
|
|
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_ABOUT_TO_START_PROCESS", mProcess.ProcessExeFileNameNPath, mProcess.CommandLinePrms), -1);
|
|
uint PID = PStarter.StartProcess(PStartInfo.CreateProcess(mProcess.ProcessExeFileNameNPath, mProcess.CommandLinePrms, mProcess.WorkingDirectory, false, ProcessWindowStyle.Normal, true), false, false);
|
|
if (PID > 0)
|
|
{
|
|
// Add to Start Attempt, Set the PID, log, and incr. Counter
|
|
mProcess.AddStartTime(DateTime.Now, (int)(nMaxFailureCount + 2)); // *Always* Keep the List 2 bigger than nMaxFailureCount, this way we can track up to nMaxFailure
|
|
mProcess.PID = PID;
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_START_PROCESS_SUCCESS", mProcess.ProcessExeFileNameNPath, mProcess.CommandLinePrms), -1);
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_START_PROCESS_SUCCESS2", mProcess.ProcessExeFileNameNPath, mProcess.CommandLinePrms, mProcess.GetStartTimesInGivenTimeSpan(TimeSpan.FromHours(nMaxFailureCountHour)), nMaxFailureCountHour), -1);
|
|
uProcessStartSuccessCount++;
|
|
}
|
|
else
|
|
{
|
|
// Add to Failure, Reset the PID, log, and incr. Counter
|
|
mProcess.AddFailTime(DateTime.Now, (int)(nMaxFailureCount + 2)); // *Always* Keep the List 2 bigger than nMaxFailureCount, this way we can track up to nMaxFailure
|
|
mProcess.PID = 0;
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED", mProcess.ProcessExeFileNameNPath, mProcess.CommandLinePrms), -1);
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED2", mProcess.ProcessExeFileNameNPath, mProcess.CommandLinePrms, mProcess.GetFailTimesInGivenTimeSpan(TimeSpan.FromHours(nMaxFailureCountHour)), nMaxFailureCountHour), -1);
|
|
uProcessStarFailCount++;
|
|
}
|
|
}
|
|
|
|
// Imp! - Let the User know Visually that Processes were started or failed to start
|
|
if (uProcessStartSuccessCount > 0 && uProcessStarFailCount == 0)
|
|
{
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_PROCESS_N_SUCCESS_COUNT", uProcessStartSuccessCount));
|
|
if(!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_PROCESS_N_SUCCESS_COUNT", (int)uProcessStartSuccessCount));
|
|
}
|
|
else if (uProcessStartSuccessCount == 0 && uProcessStarFailCount > 0)
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_PROCESS_N_FAIL_COUNT", uProcessStarFailCount));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_PROCESS_N_FAIL_COUNT", (int)uProcessStarFailCount));
|
|
}
|
|
else if (uProcessStartSuccessCount > 0 && uProcessStarFailCount > 0)
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_PROCESS_N_SUCCESS_AND_N_FAIL_COUNT", uProcessStartSuccessCount, uProcessStarFailCount));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_PROCESS_N_SUCCESS_AND_N_FAIL_COUNT", (int)uProcessStartSuccessCount, (int)uProcessStarFailCount));
|
|
}
|
|
|
|
// If any Process Changes occured * Refresh the System Tray Notification Area *
|
|
if (uProcessStartSuccessCount > 0 || uProcessStarFailCount > 0)
|
|
{
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
Watchdog.WatchdogLib.Win32.Functions.RefreshTaskbarNotificationArea();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We are in a * good State * No Configuration was found that isn't running,
|
|
// use this time to make sure that our StartedPID Table is in sync * Perform general internal DS Cleanup *
|
|
PStarter.PerformGeneralCleanupOfAllStartedProcessIDs(config.MonitoredProcesses.QueryAllPidInfo(false, true));
|
|
}
|
|
}
|
|
catch (Exception ex) { App.log.Error("Process Monitor Running Error Thrown", ex); return false; }
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if the process is Ok to be Started. Checks error state as well as timeout values
|
|
/// </summary>
|
|
/// <param name="processExe">a valid process exe, that is going to be started</param>
|
|
/// <param name="nMaxFailureCount">Max Failure Count</param>
|
|
/// <param name="nMaxFailureCountHour">Max Failure Count in given Hour Timespan</param>
|
|
/// <returns>true if it is ok to start, false otherwise</returns>
|
|
private static bool ProcessOkToBeStarted_Check(WatchdogConfiguration.ProcessExe processExe, uint nMaxFailureCount, uint nMaxFailureCountHour)
|
|
{
|
|
if (processExe == null)
|
|
return false;
|
|
|
|
// * Ignore any process marked as errored *
|
|
if (processExe.InErrorState)
|
|
return false;
|
|
|
|
// If there was a failure starting the process before,... check
|
|
// the last failed time flag, we don't want to try over and over again, every second,
|
|
// but we'll give it a try every minute
|
|
if (!processExe.LastFailTimeTimeoutExceeded(TimeSpan.FromMinutes(1)))
|
|
{
|
|
return false;
|
|
}
|
|
else if (processExe.GetFailTimesInGivenTimeSpanMaxTryExceeded(new TimeSpan((int)nMaxFailureCountHour, 0, 0), nMaxFailureCount))
|
|
{
|
|
// We are now officially in an error state
|
|
App.State_Error_SetErrorState(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED_ERROR_STATE", processExe.ProcessExeFileNameNPath, processExe.CommandLinePrms));
|
|
processExe.InErrorState = true;
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED_ERROR_STATE", processExe.ProcessExeFileNameNPath, processExe.CommandLinePrms));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED_ERROR_STATE", processExe.ProcessExeFileNameNPath, processExe.CommandLinePrms));
|
|
return false; // skip Starting of this Process; Start Failure Count too High
|
|
}
|
|
|
|
// If the process started correctly, but then failed shortly thereafter,
|
|
// then we want to keep track of it and make sure that don't try to continue starting it
|
|
if (!processExe.LastStartTimeTimeoutExceeded(TimeSpan.FromMinutes(1)))
|
|
{
|
|
return false;
|
|
}
|
|
else if (processExe.GetStartTimesInGivenTimeSpanMaxTryExceeded(new TimeSpan((int)nMaxFailureCountHour, 0, 0), nMaxFailureCount))
|
|
{
|
|
// We are now officially in an error state
|
|
App.State_Error_SetErrorState(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED_ERROR_STATE", processExe.ProcessExeFileNameNPath, processExe.CommandLinePrms));
|
|
processExe.InErrorState = true;
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED_ERROR_STATE", processExe.ProcessExeFileNameNPath, processExe.CommandLinePrms));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_START_PROCESS_FAILED_ERROR_STATE", processExe.ProcessExeFileNameNPath, processExe.CommandLinePrms));
|
|
return false; // skip Starting of this Process; Start Count too High
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Static variable * For Performance * used by Processes_ThatNeedToBeStarted_Check()
|
|
/// </summary>
|
|
private static List<WatchdogConfiguration.ProcessExe> s_nonRunningProcesses = new List<WatchdogConfiguration.ProcessExe>();
|
|
|
|
/// <summary>
|
|
/// Goes thru the configuration and returns back a list of all processes that need to be started
|
|
/// </summary>
|
|
/// <param name="config">Monitor Configuration</param>
|
|
/// <returns>List of all processes currently not running that require a new start, empty list if none found</returns>
|
|
private static List<WatchdogConfiguration.ProcessExe> Processes_ThatNeedToBeStarted_Check(WatchdogConfiguration config)
|
|
{
|
|
// Clear Non-Running List
|
|
s_nonRunningProcesses.Clear();
|
|
|
|
// We don't want to run thru all command-line parameters all the time * Time-Hog *
|
|
// ~instead we want to check our run-time configuration to see if we have any start/fail information,
|
|
// if we don't, then we MUST run thru everything, because this means our PID info will be out of date
|
|
// ~If we are in an Error state, don't perform in-depth search, otherwise once the error state is reached
|
|
// we'll always fail here and always perform the in-depth search pointlessly since we'll never launch that process
|
|
bool bPerformInDepthProcessSearch = config.MonitoredProcesses.HasIncompletePidInformation() && (App.State_GetSystemState() != App.StateSystem.Error);
|
|
if (bPerformInDepthProcessSearch)
|
|
{
|
|
// Cache Process Lookups * for performance *
|
|
ProcessW.ClearProcessObjsGetterCache();
|
|
foreach (WatchdogConfiguration.ProcessExe mProcess in config.MonitoredProcesses.ProcessExes)
|
|
{
|
|
// Immediatly Cache the Process Getter Calls * Better Performance *
|
|
Process[] RunningProcessesOfExe = ProcessW.AllRunningProcessesOf(mProcess.ProcessName, true, true);
|
|
|
|
// Perform ExactProcessExeNCommandLinePrms Matching
|
|
Process rProcess = null;
|
|
int nProcessIndex = -1;
|
|
TraceM.TraceBegin();
|
|
bool bFoundMatch = ProcessW.FoundExactProcessExeNCommandLinePrmsInRunningProcesses(RunningProcessesOfExe, mProcess.ProcessExeFileNameNPath, mProcess.CommandLinePrms, (int)mProcess.PID, out rProcess, out nProcessIndex);
|
|
TraceM.TraceEnd("Calling FoundExactProcessExeNCommandLinePrmsInRunningProcessess");
|
|
|
|
// If no Match was found in the Running Processes, add to the list
|
|
if (!bFoundMatch)
|
|
{
|
|
s_nonRunningProcesses.Add(mProcess);
|
|
}
|
|
else if(rProcess != null) // we found a match * update the configuration *
|
|
{
|
|
// Update the Pid in our configuration
|
|
mProcess.PID = (uint)rProcess.Id;
|
|
rProcess = null;
|
|
}
|
|
}
|
|
}
|
|
else // Quick Search * Better Performances *
|
|
{
|
|
// Fastest way to check for PID changes is to retrieve
|
|
// all Pids on the system once and then do everything in memory
|
|
TraceM.TraceBegin();
|
|
List<uint> AllComputerPIDs = ProcessW.AllRunningPids();
|
|
foreach (uint pid in config.MonitoredProcesses.QueryAllPidInfo(false, true))
|
|
{
|
|
if (!AllComputerPIDs.Contains(pid))
|
|
{
|
|
WatchdogConfiguration.ProcessExe p = config.MonitoredProcesses.GetProcessExeForPid(pid);
|
|
if(p != null)
|
|
s_nonRunningProcesses.Add(p);
|
|
}
|
|
}
|
|
TraceM.TraceEnd("Going Thru Applications Pid-by-Pid");
|
|
}
|
|
|
|
// Return all Processes that aren't running
|
|
return s_nonRunningProcesses;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Iterates thru the Configured Processes and Try's to Kill Any Processes that
|
|
/// are running.
|
|
/// </summary>
|
|
private static void ProcessKillAllMonitoredProcessesIfAny(WatchdogConfiguration config)
|
|
{
|
|
// Kill all Processes that exist in our configuration
|
|
uint nAssumedRunningProcesses = 0;
|
|
uint nErroredProcesses = 0;
|
|
uint nProcessesKilled = 0;
|
|
|
|
// Allow the User to not kill certain processes via the Restart Scheduler
|
|
bool bIncludeNonRestartProcesses = !App.State_IsSchedulerExecuting();
|
|
|
|
// Check Configuration
|
|
if (config.ConfiguredHasAnyProcesses)
|
|
{
|
|
nErroredProcesses = config.MonitoredProcesses.NumberOfPidsInErrorState();
|
|
if (nErroredProcesses > 0)
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_NPROCESSES_IN_AN_ERROR_STATE", App.APPLICATION_NAME_SHORT, nErroredProcesses));
|
|
|
|
nAssumedRunningProcesses = (uint)config.MonitoredProcesses.QueryAllPidInfo(false, bIncludeNonRestartProcesses).Length;
|
|
if (nAssumedRunningProcesses > 0)
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_ABOUT_TO_CLOSE_N_PROCESSES", App.APPLICATION_NAME_SHORT, nAssumedRunningProcesses));
|
|
|
|
if (nAssumedRunningProcesses <= 0) // nothing to do here
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
return; // nothing to do here
|
|
}
|
|
|
|
// Iterate the Configuration * Use the PIDs whe have stored *
|
|
foreach (uint pid in config.MonitoredProcesses.QueryAllPidInfo(false, bIncludeNonRestartProcesses))
|
|
{
|
|
WatchdogConfiguration.ProcessExe p = config.MonitoredProcesses.GetProcessExeForPid(pid);
|
|
bool bSuccess = PStarter.KillProcess(pid, false, 1, true, 2);
|
|
if (bSuccess)
|
|
{
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_CLOSE_PID_SUCCESS", pid, p.ProcessExeFileNameNPath, p.CommandLinePrms), -1);
|
|
nProcessesKilled++;
|
|
}
|
|
else
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_CLOSE_PID_FAILURE", pid, p.ProcessExeFileNameNPath, p.CommandLinePrms), -1);
|
|
}
|
|
}
|
|
|
|
// Refresh the taskbar, after killing all the processes
|
|
if(nProcessesKilled > 0 && !App.State_SpecialMode_IsRunAsServiceSet())
|
|
Watchdog.WatchdogLib.Win32.Functions.RefreshTaskbarNotificationArea();
|
|
|
|
// Let the User know that errors occured
|
|
if (App.State_GetSystemState() != App.StateSystem.Error) /* if We already are in an error state, no need to pop-up a message again */
|
|
{
|
|
if (nProcessesKilled != nAssumedRunningProcesses)
|
|
{
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_ABOUT_CLOSE_N_PROCESSES_FAILURE", (int)(nAssumedRunningProcesses - nProcessesKilled)));
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_ABOUT_CLOSE_N_PROCESSES_FAILURE", (config.MonitoredProcesses.ProcessExes.Length - nProcessesKilled)));
|
|
}
|
|
else
|
|
{
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_ABOUT_CLOSE_N_PROCESSES_SUCCESS", nProcessesKilled));
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_ABOUT_CLOSE_N_PROCESSES_SUCCESS", nProcessesKilled));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// * Core Logic * Monitor Services from the Configuration. Start Any Services that are Ok to
|
|
/// be started (ServiceOkToBeStarted_Check) that are currently not running
|
|
/// </summary>
|
|
/// <param name="config">Monitor Configuration</param>
|
|
/// <param name="nMaxFailureCount">Max Failure Count</param>
|
|
/// <param name="nMaxFailureCountHour">Max Failure Count in given Hour Timespan</param>
|
|
/// <returns>true if successfull, false if ServiceMonitor Threw an Error</returns>
|
|
private static bool ServiceMonitor(WatchdogConfiguration config, uint nMaxFailureCount, uint nMaxFailureCountHour)
|
|
{
|
|
// * SERVICE MONITORING *
|
|
if (config.ConfiguredHasAnyServices)
|
|
{
|
|
try
|
|
{
|
|
// Check To see if the Service is up and running, if it isn't, restart it * simple stuff *
|
|
uint uServiceStartSuccessCount = 0;
|
|
uint uServiceStartFailCount = 0;
|
|
foreach (WatchdogConfiguration.ServiceExe s in config.MonitoredServices.ServiceExes)
|
|
{
|
|
// Start the Service up to Five Times * Simplified way of doing this *
|
|
TraceM.TraceBegin();
|
|
bool bIsServiceRunning = ServiceW.IsServiceRunning(s.Name);
|
|
TraceM.TraceEnd("Checking Service is Running");
|
|
|
|
if (!bIsServiceRunning)
|
|
{
|
|
// Check that the Service can be started
|
|
if (!ServiceOkToBeStarted_Check(s, nMaxFailureCount, nMaxFailureCountHour))
|
|
continue;
|
|
|
|
// * Try to Restart the Service *
|
|
TraceM.TraceBegin();
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_ABOUT_TO_RESTART_SERVICE", s.Name), -1);
|
|
bool bRestartOk = ServiceW.RestartService(s.Name, true, 240 , 2);
|
|
TraceM.TraceEnd("Restarting Service");
|
|
|
|
if (bRestartOk)
|
|
{
|
|
// Add to Start Attempt, Log the Successful Launch, incr. Start Service Counter
|
|
s.AddStartTime(DateTime.Now, (int)(nMaxFailureCount + 2)); // *Always* Keep the List 2 bigger than nMaxFailureCount, this way we can track up to nMaxFailure
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_START_SERVICE_SUCCESS", s.Name, s.GetStartTimesInGivenTimeSpan(TimeSpan.FromHours(nMaxFailureCountHour)), nMaxFailureCountHour), -1);
|
|
uServiceStartSuccessCount++;
|
|
}
|
|
else
|
|
{
|
|
// Add to Failure, Log the Errored Launch, incr. Failed Service Counter
|
|
s.AddFailTime(DateTime.Now, (int)(nMaxFailureCount + 2)); // *Always* Keep the List 2 bigger than nMaxFailureCount, this way we can track up to nMaxFailure
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_START_SERVICE_FAILED", s.Name, s.GetFailTimesInGivenTimeSpan(TimeSpan.FromHours(nMaxFailureCountHour)), nMaxFailureCountHour), -1);
|
|
uServiceStartFailCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Imp! - Let the User know Visually that Processes were started or failed to start
|
|
if (uServiceStartSuccessCount > 0 && uServiceStartFailCount == 0)
|
|
{
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_SERVICE_N_SUCCESS_COUNT", uServiceStartSuccessCount));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_SERVICE_N_SUCCESS_COUNT", (int)uServiceStartSuccessCount));
|
|
}
|
|
else if (uServiceStartSuccessCount == 0 && uServiceStartFailCount > 0)
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_SERVICE_N_FAIL_COUNT", uServiceStartFailCount));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_SERVICE_N_FAIL_COUNT", (int)uServiceStartFailCount));
|
|
}
|
|
else if (uServiceStartSuccessCount > 0 && uServiceStartFailCount > 0)
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_SERVICE_N_SUCCESS_AND_N_FAIL_COUNT", uServiceStartSuccessCount, uServiceStartFailCount));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_SERVICE_N_SUCCESS_AND_N_FAIL_COUNT", (int)uServiceStartSuccessCount, (int)uServiceStartFailCount));
|
|
}
|
|
}
|
|
catch (Exception ex) { App.log.Error("Error Thrown in Service Monitor", ex); return false; };
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Checks to see if the service is Ok to be Started. Checks error state as well as timeout values
|
|
/// </summary>
|
|
/// <param name="serviceExe">a valid service exe, that is going to be started</param>
|
|
/// <param name="nMaxFailureCount">Max Failure Count</param>
|
|
/// <param name="nMaxFailureCountHour">Max Failure Count in given Hour Timespan</param>
|
|
/// <returns>true if it is ok to start, false otherwise</returns>
|
|
private static bool ServiceOkToBeStarted_Check(WatchdogConfiguration.ServiceExe serviceExe, uint nMaxFailureCount, uint nMaxFailureCountHour)
|
|
{
|
|
if (serviceExe == null)
|
|
return false;
|
|
|
|
// * Ignore any services marked as errored *
|
|
if (serviceExe.InErrorState)
|
|
return false;
|
|
|
|
// If there was a failure starting the Service before,... check
|
|
// the last failed time flag, we don't want to try over and over again, every second,
|
|
// but we'll give it a try every minute
|
|
if (!serviceExe.LastFailTimeTimeoutExceeded(TimeSpan.FromMinutes(1)))
|
|
{
|
|
return false;
|
|
}
|
|
else if (serviceExe.GetFailTimesInGivenTimeSpanMaxTryExceeded(new TimeSpan((int)nMaxFailureCountHour, 0, 0), nMaxFailureCount)) // Default 1 Hour
|
|
{
|
|
// We are now officially in an error state
|
|
App.State_Error_SetErrorState(AppResx.GetStringFormated("MESSAGE_START_SERVICE_FAILED_ERROR_STATE", serviceExe.Name));
|
|
serviceExe.InErrorState = true;
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_START_SERVICE_FAILED_ERROR_STATE", serviceExe.Name));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_START_SERVICE_FAILED_ERROR_STATE", serviceExe.Name));
|
|
return false; // skip Starting of this Service; Start Failure Count too High
|
|
}
|
|
|
|
// If the service started correctly, but then failed shortly thereafter,
|
|
// then we want to keep track of it and make sure that don't try to continue starting it
|
|
if (!serviceExe.LastStartTimeTimeoutExceeded(TimeSpan.FromMinutes(1)))
|
|
{
|
|
return false;
|
|
}
|
|
else if (serviceExe.GetStartTimesInGivenTimeSpanMaxTryExceeded(new TimeSpan((int)nMaxFailureCountHour, 0, 0), nMaxFailureCount)) // Default 1 Hour
|
|
{
|
|
// We are now officially in an error state
|
|
App.State_Error_SetErrorState(AppResx.GetStringFormated("MESSAGE_START_SERVICE_FAILED_ERROR_STATE", serviceExe.Name));
|
|
serviceExe.InErrorState = true;
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_START_SERVICE_FAILED_ERROR_STATE", serviceExe.Name));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_START_SERVICE_FAILED_ERROR_STATE", serviceExe.Name));
|
|
return false; // skip Starting of this Service; Start Count too High
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Iterates thru the Configured Processes and Try's to Kill Any Services that
|
|
/// are running and configured to be Stopped.
|
|
/// </summary>
|
|
/// <param name="bForceShutdownOfServices">Set to true to force shutting down of services, false otherwise</param>
|
|
//private static void ServicesKillAllMonitoredServicesIfAny(WatchdogConfiguration config, bool bForceShutdownOfServices = false)
|
|
private static void ServicesKillAllMonitoredServicesIfAny(WatchdogConfiguration config, bool bForceShutdownOfServices)
|
|
{
|
|
// Should we shutdown Services???
|
|
bool bRestartServices = bForceShutdownOfServices || (App.State_IsSchedulerExecuting() && App.setting.SchedulerRestartsServices);
|
|
if (bRestartServices)
|
|
{
|
|
int nServicesClosed = 0;
|
|
int nServicesNotClosed = 0;
|
|
|
|
// Allow the User to not kill certain services via the Restart Scheduler
|
|
bool bIncludeNonRestartServices = !App.State_IsSchedulerExecuting();
|
|
if (config.ConfiguredHasAnyServices)
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_ABOUT_TO_CLOSE_N_SERVICES", App.APPLICATION_NAME_SHORT, config.MonitoredServices.QueryAllServiceInfo(false, bIncludeNonRestartServices).Length));
|
|
|
|
foreach (string ServiceName in config.MonitoredServices.QueryAllServiceInfo(false, bIncludeNonRestartServices))
|
|
{
|
|
// This is only getting called when the scheduler is executing...
|
|
// the scheduler will be responsible for starting the monitor which in turn will start the services and keep track of all
|
|
// service starts, hence all we have to do here is shut down the services * they will automatically be restarted *
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_ABOUT_TO_CLOSE_SERVICE", ServiceName), -1);
|
|
bool bCloseServiceSuccess = ServiceW.StopService(ServiceName, true, 240);
|
|
if (bCloseServiceSuccess)
|
|
{
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_CLOSE_SERVICE_SUCCESS", ServiceName), -1);
|
|
nServicesClosed++;
|
|
}
|
|
else
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_CLOSE_SERVICE_FAILURE", ServiceName), -1);
|
|
nServicesNotClosed++;
|
|
}
|
|
}
|
|
|
|
// Imp! - Let the User know Visually that Services were Stopped
|
|
if (nServicesClosed > 0 && nServicesNotClosed == 0)
|
|
{
|
|
App.log.Info(AppResx.GetStringFormated("MESSAGE_STOPSERVICE_N_SUCCESS_COUNT", nServicesClosed));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_STOPSERVICE_N_SUCCESS_COUNT", nServicesClosed));
|
|
}
|
|
else if (nServicesClosed == 0 && nServicesNotClosed > 0)
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_STOPSERVICE_N_FAIL_COUNT", nServicesNotClosed));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_STOPSERVICE_N_FAIL_COUNT", nServicesNotClosed));
|
|
}
|
|
else if (nServicesClosed > 0 && nServicesNotClosed > 0)
|
|
{
|
|
App.log.Error(AppResx.GetStringFormated("MESSAGE_STOPSERVICE_N_SUCCESS_AND_N_FAIL_COUNT", nServicesClosed, nServicesNotClosed));
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
WatchdogSysTray.PopUpBallon_Error(AppResx.GetStringFormated("MESSAGE_STOPSERVICE_N_SUCCESS_AND_N_FAIL_COUNT", nServicesClosed, nServicesNotClosed));
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Loaded/Unloaded Event Handlers
|
|
|
|
/// <summary>
|
|
/// Handles the Main Window StartUp event.
|
|
/// </summary>
|
|
private void Window_Loaded(object sender, RoutedEventArgs e)
|
|
{
|
|
// * To make sure, we are not fatally closing *
|
|
if (App.s_FatalErrorOccured)
|
|
return;
|
|
|
|
// * To make sure, do nothing in command-line mode *
|
|
if (App.State_SpecialMode_IsCommandLineSet())
|
|
return;
|
|
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
{
|
|
// Performance Load WPF Windows
|
|
WPFWindows.WPFWindowMaker.PerformanceCache();
|
|
|
|
// Set Registry key to Start w. Windows, if specified
|
|
bool bStartWithWindows = App.setting.StartWithWindows;
|
|
App.log.Info(String.Format("Starting with Windows is set to: '{0}'", bStartWithWindows));
|
|
}
|
|
|
|
// Ensure proper existence of HardLink, if specified
|
|
bool bCreateHardLink = App.setting.CreateExeHardLinkInRootPath;
|
|
App.log.Info(String.Format("Creating .Exe HardLink in Root Path is set to: '{0}'", bCreateHardLink));
|
|
|
|
// If we are deployed by ClickOnce, let's modify the uninstall icon (Add/Remove) Programs
|
|
// ~there appears to be no better way than modifying the registry manually * Now Add/Remove will have a nice
|
|
// little App icon instead of the default ClickOnce Icon *
|
|
string strKeyFetched = RegKey.GetKey<string>("Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + App.APPLICATION_PRODUCT_CLICKONCE_ID, "DisplayIcon", "");
|
|
if(!String.IsNullOrEmpty(strKeyFetched))
|
|
RegKey.SetKey<string>("Microsoft\\Windows\\CurrentVersion\\Uninstall\\" + App.APPLICATION_PRODUCT_CLICKONCE_ID, "DisplayIcon", AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileNameNPath(AssemblyW.AssemblyST.Entry));
|
|
|
|
// Sleep a little before showing the System Tray
|
|
System.Threading.Thread.Sleep(250);
|
|
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
{
|
|
// Refresh the taskbar, when launching (maybe there are trailing instances)
|
|
Watchdog.WatchdogLib.Win32.Functions.RefreshTaskbarNotificationArea();
|
|
|
|
// Show the System Tray Icon/Menu
|
|
WatchdogSysTray.WatchdogSysTray_Show();
|
|
}
|
|
|
|
// Start Process Monitoring upon start? * Default is Yes *
|
|
if (App.setting.StartMonitorUponStart)
|
|
{
|
|
// We should only start the monitor, if there is any configuration
|
|
if (App.xmlfile.ReadData(false).ConfiguredHasAny)
|
|
{
|
|
StartMonitoring(false, true);
|
|
}
|
|
else if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
{
|
|
WatchdogSysTray.PopUpBallon_Info(AppResx.GetStringFormated("MESSAGE_NO_CONFIGURATION_FOUND", App.APP_XML_DS_FILENAME));
|
|
WPFWindows.WPFWindowMaker.CreateNShowWindow(WPFWindows.WPFWindow.Settings_Window);
|
|
}
|
|
else
|
|
{
|
|
// Nothing to do Here (we must be in Service Mode), without a configuration
|
|
App.FatalExceptionStopExecution("No Configuration Found in ServiceMode", false);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handles the Main Window Exit event.
|
|
/// </summary>
|
|
private void Window_Closed(object sender, EventArgs e)
|
|
{
|
|
// * To make sure, we are not fatally closing *
|
|
if (App.s_FatalErrorOccured)
|
|
return;
|
|
|
|
// * To make sure, do nothing in command-line mode *
|
|
if (App.State_SpecialMode_IsCommandLineSet())
|
|
return;
|
|
|
|
// for unexpected cleanup
|
|
s_WindowCloseGotCalled = true;
|
|
|
|
// Stop the Process Monitor
|
|
StopMonitoring(false, false);
|
|
|
|
// Make sure the latest DS is saved to file
|
|
App.xmlfile.SaveData();
|
|
|
|
if (!App.State_SpecialMode_IsRunAsServiceSet())
|
|
{
|
|
// Close the System Tray Icon/Menu
|
|
WatchdogSysTray.WatchdogSysTray_Hide();
|
|
|
|
// Unload All Windows (incl. Performance) * Close Log Tail if exists Prior *
|
|
LogViewerWindow.CloseFileTailBeforeExitIfExists();
|
|
WPFWindows.WPFWindowMaker.CloseAll();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Handle Specialized Cleanup
|
|
/// </summary>
|
|
void CurrentDomain_ProcessExit(object sender, EventArgs e)
|
|
{
|
|
try
|
|
{
|
|
// Stop Internal Timers
|
|
StopTimer();
|
|
StopSchedulerTimer();
|
|
StopSchedulerBackupTimer();
|
|
|
|
if (_timer != null)
|
|
_timer.Dispose();
|
|
|
|
if (_timerScheduler != null)
|
|
_timerScheduler.Dispose();
|
|
|
|
if (_timerSchedulerBackup != null)
|
|
_timerSchedulerBackup.Dispose();
|
|
|
|
// Make sure that the close get's called * Unexpected cleanup *
|
|
if (!s_WindowCloseGotCalled)
|
|
Window_Closed(null, null);
|
|
}
|
|
catch (Exception) { /* ignore */ }
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|