├── WatchDog ├── watchdog.ico ├── packages.config ├── App.config ├── RebootForm.cs ├── GeneralSettingsForm.cs ├── Program.cs ├── NLogUtils.cs ├── LogForm.cs ├── Properties │ └── AssemblyInfo.cs ├── RebootFormVM.cs ├── NLog.config ├── GeneralSettingsFormVM.cs ├── Configuration.cs ├── ExceptionsManager.cs ├── EditForm.cs ├── MainForm.cs ├── NlogEvent.cs ├── LogForm.Designer.cs ├── Resources.Designer.cs ├── RegisterWatchdogTask.cs ├── GeneralSettingsForm.Designer.cs ├── RebootForm.resx └── Resources.resx ├── Screenshots ├── RebootMenu.png ├── TaskbarMenu.png ├── ConfigurationForm.png ├── GeneralSettingsMenu.png └── ApplicationSettingsMenu.png ├── WatchdogLib ├── packages.config ├── RebootHandler.cs ├── PipeExceptionEventHandler.cs ├── Properties │ └── AssemblyInfo.cs ├── Worker.cs ├── ApplicationWatcher.cs ├── Configuration.cs ├── IO │ ├── PipeStreamWriter.cs │ ├── PipeStreamReader.cs │ └── PipeStreamWrapper.cs ├── SleepDetector.cs └── WatchdogLib.csproj ├── Utilities ├── packages.config ├── Utilities.csproj.user ├── Controls │ ├── LineInputDialog.cs │ ├── ListInputDialog.cs │ ├── LoggingView.Designer.cs │ ├── LoggingView.cs │ ├── LineInputDialog.Designer.cs │ ├── ListInputDialog.Designer.cs │ ├── LineInputDialog.resx │ ├── ListInputDialog.resx │ └── LoggingView.resx ├── Properties │ └── AssemblyInfo.cs ├── ConfigurationSerializer.cs ├── NlogEvent.cs ├── EagerTimer.cs ├── EventWaiter.cs ├── Wildcard.cs ├── AsyncWorker.cs ├── Utilities.csproj └── StringUtils.cs ├── WatchdogClientLib ├── WatchdogClientLib.csproj.user ├── RequestKill.cs ├── Properties │ └── AssemblyInfo.cs ├── Worker.cs ├── WatchdogClientLib.csproj ├── IO │ ├── PipeStreamWriter.cs │ ├── PipeStreamReader.cs │ └── PipeStreamWrapper.cs └── Heartbeat.cs ├── MonitoredApplication ├── MonitoredApplication.csproj.user ├── Properties │ ├── Settings.settings │ ├── Settings.Designer.cs │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── App.config ├── Program.cs ├── Form1.cs ├── MonitoredApplication.csproj ├── Form1.resx └── Form1.Designer.cs ├── LICENSE ├── WatchDogClient.sln ├── WatchDogServer.sln └── README.md /WatchDog/watchdog.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thijse/Watchdog/HEAD/WatchDog/watchdog.ico -------------------------------------------------------------------------------- /Screenshots/RebootMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thijse/Watchdog/HEAD/Screenshots/RebootMenu.png -------------------------------------------------------------------------------- /Screenshots/TaskbarMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thijse/Watchdog/HEAD/Screenshots/TaskbarMenu.png -------------------------------------------------------------------------------- /Screenshots/ConfigurationForm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thijse/Watchdog/HEAD/Screenshots/ConfigurationForm.png -------------------------------------------------------------------------------- /Screenshots/GeneralSettingsMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thijse/Watchdog/HEAD/Screenshots/GeneralSettingsMenu.png -------------------------------------------------------------------------------- /Screenshots/ApplicationSettingsMenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thijse/Watchdog/HEAD/Screenshots/ApplicationSettingsMenu.png -------------------------------------------------------------------------------- /WatchdogLib/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /WatchDog/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Utilities/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Utilities/Utilities.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ShowAllFiles 5 | 6 | -------------------------------------------------------------------------------- /WatchdogClientLib/WatchdogClientLib.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ProjectFiles 5 | 6 | -------------------------------------------------------------------------------- /MonitoredApplication/MonitoredApplication.csproj.user: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ProjectFiles 5 | 6 | -------------------------------------------------------------------------------- /WatchdogLib/RebootHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace WatchdogLib 8 | { 9 | public class RebootHandler 10 | { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /MonitoredApplication/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WatchDog/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /MonitoredApplication/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /WatchdogLib/PipeExceptionEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace WatchdogLib 4 | { 5 | /// 6 | /// Handles exceptions thrown during a read or write operation on a named pipe. 7 | /// 8 | /// Exception that was thrown 9 | public delegate void PipeExceptionEventHandler(Exception exception); 10 | } -------------------------------------------------------------------------------- /WatchDog/RebootForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace WatchDog 12 | { 13 | public partial class RebootForm : Form 14 | { 15 | public RebootForm() 16 | { 17 | InitializeComponent(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /MonitoredApplication/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using System.Windows.Forms; 6 | 7 | namespace MonitoredApplication 8 | { 9 | static class Program 10 | { 11 | /// 12 | /// The main entry point for the application. 13 | /// 14 | [STAThread] 15 | static void Main() 16 | { 17 | Application.EnableVisualStyles(); 18 | Application.SetCompatibleTextRenderingDefault(false); 19 | Application.Run(new MonitoredApplicationForm()); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /WatchDog/GeneralSettingsForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | 11 | namespace WatchDog 12 | { 13 | public partial class GeneralSettingsForm : Form 14 | { 15 | public GeneralSettingsForm() 16 | { 17 | InitializeComponent(); 18 | } 19 | 20 | private void checkBoxRestartOnTask_CheckedChanged(object sender, EventArgs e) 21 | { 22 | 23 | } 24 | 25 | private void label5_Click(object sender, EventArgs e) 26 | { 27 | 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /WatchdogClientLib/RequestKill.cs: -------------------------------------------------------------------------------- 1 | namespace WatchdogClient 2 | { 3 | public class RequestKill 4 | { 5 | private readonly uint _killDelay; 6 | private readonly int _noAllowedErrors; 7 | private int _noErrors; 8 | 9 | public RequestKill(int noAllowedErrors, uint killDelay) 10 | { 11 | _noAllowedErrors = noAllowedErrors; 12 | _killDelay = killDelay; 13 | _noErrors = 0; 14 | } 15 | 16 | public void Reset() 17 | { 18 | _noErrors = 0; 19 | } 20 | 21 | public void Error() 22 | { 23 | _noErrors++; 24 | if (_noErrors == _noAllowedErrors) 25 | { 26 | Heartbeat.Instance.RequestKill(_killDelay); 27 | } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /WatchDog/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Diagnostics; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using WatchdogLib; 10 | using WatchDog.TrayIconTest; 11 | 12 | namespace WatchDog 13 | { 14 | 15 | using System.Windows.Forms; 16 | /// 17 | /// The Watchdog Application 18 | /// 19 | /// 20 | class Program 21 | { 22 | [STAThread] 23 | static void Main(string[] args) 24 | { 25 | ExceptionsManager.Logger = null; 26 | ExceptionsManager.TrayIcon = null; 27 | Application.EnableVisualStyles(); 28 | Application.SetCompatibleTextRenderingDefault(false); 29 | Application.Run(new TrayIcon()); 30 | 31 | 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /WatchDog/NLogUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Windows.Forms; 8 | using NLog; 9 | 10 | namespace WatchDog 11 | { 12 | class NLogUtils 13 | { 14 | private static Logger _namedLogger; 15 | 16 | 17 | public static Logger NamedLogger 18 | { 19 | get 20 | { 21 | if (_namedLogger == null) 22 | { 23 | var path = Path.GetDirectoryName(Application.ExecutablePath); 24 | //if (!string.IsNullOrEmpty(path) && Directory.Exists(path)) Directory.SetCurrentDirectory(path); 25 | 26 | _namedLogger = LogManager.GetLogger("WatchdogServer"); 27 | 28 | } 29 | return _namedLogger; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /WatchDog/LogForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using System.Windows.Forms; 10 | using Utilities.Controls; 11 | 12 | namespace WatchDog 13 | { 14 | public partial class LogForm : Form 15 | { 16 | public LoggingView LoggingView { get { return loggingView; } } 17 | 18 | public LogForm() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | private void LogFormFormClosing(object sender, FormClosingEventArgs e) 24 | { 25 | if (e.CloseReason == CloseReason.UserClosing) 26 | { 27 | e.Cancel = true; 28 | Hide(); 29 | } 30 | } 31 | 32 | private void LogFormResize(object sender, EventArgs e) 33 | { 34 | 35 | if (WindowState == FormWindowState.Minimized) 36 | { 37 | this.Hide(); 38 | } 39 | } 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019, 2020 Thijs Elenbaas 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MonitoredApplication/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MonitoredApplication.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.5.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Utilities/Controls/LineInputDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace Utilities.Controls 5 | { 6 | 7 | 8 | public partial class LineInputDialog : Form 9 | { 10 | public LineDialogResult LineDialogResult { get; set; } 11 | 12 | public static LineDialogResult Show(string text, string caption) 13 | { 14 | var dialog = new LineInputDialog 15 | { 16 | Name = caption, 17 | labelMessage = {Text = text}, 18 | }; 19 | dialog.ShowDialog(); 20 | return dialog.LineDialogResult; 21 | } 22 | 23 | public LineInputDialog() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | private void ButtonOkClick(object sender, EventArgs e) 29 | { 30 | LineDialogResult = new LineDialogResult() {Input = textBox1.Text, DialogResult = DialogResult.OK}; 31 | Close(); 32 | } 33 | 34 | private void ButtonCancelClick(object sender, EventArgs e) 35 | { 36 | LineDialogResult = new LineDialogResult() {Input = textBox1.Text, DialogResult = DialogResult.Cancel}; 37 | Close(); 38 | 39 | } 40 | } 41 | 42 | public class LineDialogResult 43 | { 44 | public DialogResult DialogResult { get; set; } 45 | public string Input { get; set; } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Utilities/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Utilities")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Utilities")] 13 | [assembly: AssemblyCopyright("Copyright © 2020")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b306adda-8617-4746-aba2-c36dea9b6145")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Utilities/Controls/ListInputDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace Utilities.Controls 5 | { 6 | 7 | 8 | public partial class ListInputDialog : Form 9 | { 10 | public ListDialogResult ListDialogResult { get; set; } 11 | 12 | public static ListDialogResult Show(string text, string caption) 13 | { 14 | var dialog = new ListInputDialog 15 | { 16 | Name = caption, 17 | labelMessage = {Text = text}, 18 | }; 19 | dialog.ShowDialog(); 20 | return dialog.ListDialogResult; 21 | } 22 | 23 | public ListInputDialog() 24 | { 25 | InitializeComponent(); 26 | } 27 | 28 | private void ButtonOkClick(object sender, EventArgs e) 29 | { 30 | ListDialogResult = new ListDialogResult() 31 | { 32 | //Input = textBox1.Text, 33 | Button = DialogResult.OK 34 | }; 35 | Close(); 36 | } 37 | 38 | private void ButtonCancelClick(object sender, EventArgs e) 39 | { 40 | ListDialogResult = new ListDialogResult() 41 | { 42 | //Input = textBox1.Text, 43 | Button = DialogResult.Cancel 44 | }; 45 | Close(); 46 | 47 | } 48 | } 49 | 50 | public class ListDialogResult 51 | { 52 | public DialogResult Button { get; set; } 53 | public string Input { get; set; } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /WatchDog/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WatchDog")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("WatchDog")] 13 | [assembly: AssemblyCopyright("Copyright © Thijs Elenbaas 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("74E898E8-9C2F-4EC7-A985-457B0A4FD546")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0")] 37 | -------------------------------------------------------------------------------- /WatchdogLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WatchdogLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("DevThread")] 12 | [assembly: AssemblyProduct("WatchdogLib")] 13 | [assembly: AssemblyCopyright("Copyright © DevThread 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("0db708a3-3121-42ca-8f29-df108ac5b1fd")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /MonitoredApplication/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("MonitoredApplication")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("MonitoredApplication")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("cc59b025-b383-4d28-9646-fcfc7fe86b06")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /WatchdogClientLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WatchdogClient")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("WatchdogClient")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("8668150c-c05f-43ca-9624-873ada5828f9")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /WatchDog/RebootFormVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using WatchdogLib; 7 | 8 | namespace WatchDog 9 | { 10 | public class RebootFormVM 11 | { 12 | private RebootForm _rebootForm; 13 | private RebootHandler _rebootHandler; 14 | private Configuration _configuration; 15 | 16 | public RebootFormVM(RebootForm rebootForm, RebootHandler rebootHandler, Configuration configuration) 17 | { 18 | _rebootForm = rebootForm; 19 | _rebootHandler = rebootHandler; 20 | _configuration = configuration; 21 | _rebootForm.comboBoxRebootMode.SelectedIndex = 0; 22 | _rebootForm.comboBoxRebootForce.SelectedIndex = 0; 23 | _rebootForm.comboBoxRebootAfterWindow.SelectedIndex = 0; 24 | } 25 | 26 | public void GetForm() 27 | { 28 | _configuration.PeriodicReboot = _rebootForm.checkBoxReboot.Checked; 29 | _configuration.RebootPeriod = int.Parse(_rebootForm.textBoxRebootAfterDays.Text); 30 | _configuration.RebootAfter = _rebootForm.dateTimePickerRebootAfter.Value.Date; 31 | _configuration.RebootBefore = _rebootForm.dateTimePickerRebootBefore.Value.Date; 32 | 33 | _configuration.RebootMode = (Configuration.RebootModes)_rebootForm.comboBoxRebootMode.SelectedIndex; 34 | _configuration.ForceMode = (Configuration.RebootModes)_rebootForm.comboBoxRebootForce.SelectedIndex; 35 | _configuration.RebootAfterTimeSlot = (Configuration.RebootAfterTimeSlotModes)_rebootForm.comboBoxRebootAfterWindow.SelectedIndex; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Utilities/Controls/LoggingView.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Utilities.Controls 2 | { 3 | partial class LoggingView 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.eagerTimer1 = new Utilities.EagerTimer(); 32 | ((System.ComponentModel.ISupportInitialize)(this.eagerTimer1)).BeginInit(); 33 | this.SuspendLayout(); 34 | // 35 | // eagerTimer1 36 | // 37 | this.eagerTimer1.AutoStart = false; 38 | this.eagerTimer1.Enabled = true; 39 | this.eagerTimer1.SynchronizingObject = this; 40 | ((System.ComponentModel.ISupportInitialize)(this.eagerTimer1)).EndInit(); 41 | this.ResumeLayout(false); 42 | 43 | } 44 | 45 | #endregion 46 | 47 | private EagerTimer eagerTimer1; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /WatchDog/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Utilities/ConfigurationSerializer.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Newtonsoft.Json; 3 | 4 | namespace Utilities 5 | { 6 | public class ConfigurationSerializer 7 | { 8 | private readonly string _fileName; 9 | private readonly JsonSerializer _serializer; 10 | 11 | public ConfigurationSerializer(string fileName, TConfig configuration) 12 | { 13 | _fileName = fileName; 14 | _serializer = new JsonSerializer 15 | { 16 | NullValueHandling = NullValueHandling.Ignore, 17 | Formatting = Formatting.Indented 18 | }; 19 | if (!File.Exists(_fileName)) 20 | { 21 | Serialize(configuration); 22 | } 23 | } 24 | 25 | public ConfigurationSerializer(string fileName) 26 | { 27 | _fileName = fileName; 28 | _serializer = new JsonSerializer 29 | { 30 | NullValueHandling = NullValueHandling.Include, 31 | Formatting = Formatting.Indented 32 | }; 33 | } 34 | public void Serialize(TConfig configuration) 35 | { 36 | using (var streamWriter = new StreamWriter(_fileName)) 37 | { 38 | _serializer.NullValueHandling = NullValueHandling.Ignore; 39 | _serializer.Serialize(streamWriter, configuration); 40 | } 41 | } 42 | 43 | public TConfig Deserialize() 44 | { 45 | 46 | using (var streamReader = new StreamReader(_fileName)) 47 | { 48 | return (TConfig)_serializer.Deserialize(streamReader, typeof(TConfig)); 49 | } 50 | } 51 | 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /WatchDog/GeneralSettingsFormVM.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using WatchdogLib; 3 | 4 | namespace WatchDog 5 | { 6 | public class GeneralSettingsFormVM 7 | { 8 | private readonly GeneralSettingsForm _generalSettingsForm; 9 | private readonly Configuration _configuration; 10 | 11 | public GeneralSettingsFormVM(GeneralSettingsForm generalSettingsForm, Configuration configuration) 12 | { 13 | _generalSettingsForm = generalSettingsForm; 14 | _configuration = configuration; 15 | 16 | _generalSettingsForm.buttonAcceptChanges.Click += ButtonAcceptChangesClicks; 17 | _generalSettingsForm.buttonCancel.Click += ButtonCancelClick; 18 | 19 | 20 | SetForm(); 21 | } 22 | 23 | 24 | private void ButtonCancelClick(object sender, EventArgs e) 25 | { 26 | _generalSettingsForm.Close(); 27 | } 28 | 29 | private void ButtonAcceptChangesClicks(object sender, EventArgs e) 30 | { 31 | GetForm(); 32 | RegisterWatchdogTask.SetTask(_configuration.RestartOnTask); 33 | Startup.SetStartup(_configuration.StartOnWindowsStart); 34 | _generalSettingsForm.Close(); 35 | } 36 | 37 | 38 | private void GetForm() 39 | { 40 | _configuration.RestartOnTask = _generalSettingsForm.checkBoxRestartOnTask.Checked; 41 | _configuration.StartOnWindowsStart = _generalSettingsForm.checkBoxStartOnWindowsStart.Checked; 42 | } 43 | 44 | private void SetForm() 45 | { 46 | _generalSettingsForm.checkBoxRestartOnTask.Checked = _configuration.RestartOnTask; 47 | _generalSettingsForm.checkBoxStartOnWindowsStart.Checked = _configuration.StartOnWindowsStart; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /WatchdogLib/Worker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace WatchdogLib 6 | { 7 | class Worker 8 | { 9 | private readonly TaskScheduler _callbackThread; 10 | 11 | private static TaskScheduler CurrentTaskScheduler 12 | { 13 | get 14 | { 15 | return (SynchronizationContext.Current != null 16 | ? TaskScheduler.FromCurrentSynchronizationContext() 17 | : TaskScheduler.Default); 18 | } 19 | } 20 | 21 | public event WorkerSucceededEventHandler Succeeded; 22 | public event WorkerExceptionEventHandler Error; 23 | 24 | public Worker() : this(CurrentTaskScheduler) 25 | { 26 | } 27 | 28 | public Worker(TaskScheduler callbackThread) 29 | { 30 | _callbackThread = callbackThread; 31 | } 32 | 33 | public void DoWork(Action action) 34 | { 35 | new Task(DoWorkImpl, action, CancellationToken.None, TaskCreationOptions.LongRunning).Start(); 36 | } 37 | 38 | private void DoWorkImpl(object oAction) 39 | { 40 | var action = (Action)oAction; 41 | try 42 | { 43 | action(); 44 | Callback(Succeed); 45 | } 46 | catch (Exception e) 47 | { 48 | Callback(() => Fail(e)); 49 | } 50 | } 51 | 52 | private void Succeed() 53 | { 54 | if (Succeeded != null) 55 | Succeeded(); 56 | } 57 | 58 | private void Fail(Exception exception) 59 | { 60 | if (Error != null) 61 | Error(exception); 62 | } 63 | 64 | private void Callback(Action action) 65 | { 66 | Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, _callbackThread); 67 | } 68 | } 69 | 70 | internal delegate void WorkerSucceededEventHandler(); 71 | internal delegate void WorkerExceptionEventHandler(Exception exception); 72 | } 73 | -------------------------------------------------------------------------------- /WatchdogClientLib/Worker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace WatchdogClient.Threading 6 | { 7 | class Worker 8 | { 9 | private readonly TaskScheduler _callbackThread; 10 | 11 | private static TaskScheduler CurrentTaskScheduler 12 | { 13 | get 14 | { 15 | return (SynchronizationContext.Current != null 16 | ? TaskScheduler.FromCurrentSynchronizationContext() 17 | : TaskScheduler.Default); 18 | } 19 | } 20 | 21 | public event WorkerSucceededEventHandler Succeeded; 22 | public event WorkerExceptionEventHandler Error; 23 | 24 | public Worker() : this(CurrentTaskScheduler) 25 | { 26 | } 27 | 28 | public Worker(TaskScheduler callbackThread) 29 | { 30 | _callbackThread = callbackThread; 31 | } 32 | 33 | public void DoWork(Action action) 34 | { 35 | new Task(DoWorkImpl, action, CancellationToken.None, TaskCreationOptions.LongRunning).Start(); 36 | } 37 | 38 | private void DoWorkImpl(object oAction) 39 | { 40 | var action = (Action) oAction; 41 | try 42 | { 43 | action(); 44 | Callback(Succeed); 45 | } 46 | catch (Exception e) 47 | { 48 | Callback(() => Fail(e)); 49 | } 50 | } 51 | 52 | private void Succeed() 53 | { 54 | if (Succeeded != null) 55 | Succeeded(); 56 | } 57 | 58 | private void Fail(Exception exception) 59 | { 60 | if (Error != null) 61 | Error(exception); 62 | } 63 | 64 | private void Callback(Action action) 65 | { 66 | Task.Factory.StartNew(action, CancellationToken.None, TaskCreationOptions.None, _callbackThread); 67 | } 68 | } 69 | 70 | internal delegate void WorkerSucceededEventHandler(); 71 | internal delegate void WorkerExceptionEventHandler(Exception exception); 72 | } 73 | -------------------------------------------------------------------------------- /WatchDog/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using WatchdogLib; 3 | 4 | namespace WatchDog 5 | { 6 | public class Configuration 7 | { 8 | public List ApplicationHandlersConfig { get; set; } 9 | public bool ShowTrayIcon { get; set; } 10 | 11 | public Configuration() 12 | { 13 | ApplicationHandlersConfig = new List(); 14 | ShowTrayIcon = true; 15 | 16 | var app = new ApplicationHandlerConfig() 17 | { 18 | ApplicationPath = @"D:\DevelPers\WatchDog\MonitoredApplication\bin\Release\MonitoredApplication.exe", 19 | ApplicationPath = "MonitoredApplication", 20 | Active = true 21 | }; 22 | //var applicationHandler = new ApplicationHandler("MonitoredApplication", @"D:\DevelPers\WatchDog\MonitoredApplication\bin\Release\MonitoredApplication.exe", 10, 10, 1, 1,false, true) {Active = true}; 23 | } 24 | 25 | } 26 | 27 | 28 | public class ApplicationHandlerConfig 29 | { 30 | public int NonResponsiveInterval { get; set; } 31 | public string ApplicationPath { get; set; } 32 | public string ApplicationName { get; set; } 33 | public bool UseHeartbeat { get; set; } 34 | public bool GrantKillRequest { get; set; } 35 | public uint HeartbeatInterval { get; set; } 36 | public int MaxProcesses { get; set; } 37 | public int MinProcesses { get; set; } 38 | public bool Active { get; set; } 39 | public bool KeepExistingNoProcesses { get; set; } 40 | 41 | public ApplicationHandlerConfig() 42 | { 43 | NonResponsiveInterval = 20; 44 | ApplicationPath = ""; 45 | ApplicationName = ""; 46 | UseHeartbeat = false; 47 | GrantKillRequest = true; 48 | HeartbeatInterval = 20; 49 | MinProcesses = 1; 50 | MaxProcesses = 10; 51 | Active = false; 52 | KeepExistingNoProcesses = true; 53 | } 54 | } 55 | 56 | 57 | } -------------------------------------------------------------------------------- /WatchDog/ExceptionsManager.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | using NLog; 4 | 5 | namespace WatchDog 6 | { 7 | class ExceptionsManager 8 | { 9 | static ExceptionsManager() 10 | { 11 | AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException; 12 | } 13 | 14 | public static NotifyIcon TrayIcon { get; set; } 15 | public static Logger Logger { get; set; } 16 | 17 | public static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) 18 | { 19 | var ex = (Exception)e.ExceptionObject; 20 | var message = (ex != null) ? ex.Message : "unknown error"; 21 | ServerCrash("Unhandled error in " + "Watchdog", "Unhandled error in watchdog server : " + message, true); 22 | Application.Exit(); 23 | } 24 | 25 | public static void ServerCrash(string title, string message, bool exit) 26 | { 27 | try 28 | { 29 | if (Logger != null) Logger.Fatal(message); 30 | } 31 | catch 32 | { 33 | // Do nothing 34 | } 35 | try 36 | { 37 | if (TrayIcon != null) 38 | { 39 | TrayIcon.BalloonTipIcon = ToolTipIcon.Error; 40 | TrayIcon.BalloonTipText = message; 41 | TrayIcon.BalloonTipTitle = title; 42 | TrayIcon.Text = "Watchdog server"; 43 | TrayIcon.ShowBalloonTip(1000); 44 | } 45 | else 46 | { 47 | MessageBox.Show( 48 | message, 49 | title, 50 | MessageBoxButtons.OK, 51 | MessageBoxIcon.Error, 52 | MessageBoxDefaultButton.Button1, 53 | MessageBoxOptions.RightAlign, 54 | true); 55 | } 56 | } 57 | catch 58 | { 59 | // Do nothing 60 | } 61 | finally 62 | { 63 | if (exit) Application.Exit(); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /WatchDog/EditForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | using Utilities; 12 | 13 | namespace WatchDog 14 | { 15 | public partial class EditForm : Form 16 | { 17 | public EventHandler ActivateEvent; 18 | public EditForm() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | private void ButtonSelectFileClick(object sender, EventArgs e) 24 | { 25 | 26 | var openFileDialog1 = new OpenFileDialog 27 | { 28 | InitialDirectory = "c:\\", 29 | Filter = "executable files |*.exe;*.com;*.bat|All files|*.*", 30 | 31 | RestoreDirectory = true 32 | }; 33 | 34 | 35 | if (openFileDialog1.ShowDialog() == DialogResult.OK) 36 | { 37 | try 38 | { 39 | var filenamePath = openFileDialog1.FileName; 40 | 41 | if (File.Exists(filenamePath)) 42 | { 43 | textBoxApplicationPath.Text = filenamePath; 44 | textBoxProcessName.Text = System.IO.Path.GetFileNameWithoutExtension(filenamePath);// FileUtils.GetBaseName(filenamePath) 45 | } 46 | } 47 | catch (Exception ex) 48 | { 49 | MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message); 50 | } 51 | } 52 | } 53 | 54 | private void MainFormFormClosing(object sender, FormClosingEventArgs e) 55 | { 56 | if (e.CloseReason == CloseReason.UserClosing) 57 | { 58 | e.Cancel = true; 59 | Hide(); 60 | } 61 | } 62 | 63 | //private void ButtonActivateClick(object sender, EventArgs e) 64 | //{ 65 | // if (ActivateEvent != null) ActivateEvent(this,null); 66 | //} 67 | 68 | //private void ButtonDeactivateClick(object sender, EventArgs e) 69 | //{ 70 | // if (DeactivateEvent != null) DeactivateEvent(this, null); 71 | //} 72 | 73 | //private void buttonAddProcess_Click(object sender, EventArgs e) 74 | //{ 75 | // if (AddEvent != null) DeactivateEvent(this, null); 76 | //} 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /WatchDog/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | using System.Windows.Forms; 11 | using Utilities; 12 | 13 | namespace WatchDog 14 | { 15 | public partial class MainForm : Form 16 | { 17 | public EventHandler ActivateEvent; 18 | public MainForm() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | private void ButtonSelectFileClick(object sender, EventArgs e) 24 | { 25 | 26 | var openFileDialog1 = new OpenFileDialog 27 | { 28 | InitialDirectory = "c:\\", 29 | Filter = "executable files |*.exe;*.com;*.bat|All files|*.*", 30 | 31 | RestoreDirectory = true 32 | }; 33 | 34 | 35 | if (openFileDialog1.ShowDialog() == DialogResult.OK) 36 | { 37 | try 38 | { 39 | var filenamePath = openFileDialog1.FileName; 40 | 41 | if (File.Exists(filenamePath)) 42 | { 43 | textBoxApplicationPath.Text = filenamePath; 44 | textBoxProcessName.Text = System.IO.Path.GetFileNameWithoutExtension(filenamePath);// FileUtils.GetBaseName(filenamePath) 45 | } 46 | } 47 | catch (Exception ex) 48 | { 49 | MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message); 50 | } 51 | } 52 | } 53 | 54 | private void MainFormFormClosing(object sender, FormClosingEventArgs e) 55 | { 56 | if (e.CloseReason == CloseReason.UserClosing) 57 | { 58 | e.Cancel = true; 59 | Hide(); 60 | } 61 | } 62 | 63 | //private void ButtonActivateClick(object sender, EventArgs e) 64 | //{ 65 | // if (ActivateEvent != null) ActivateEvent(this,null); 66 | //} 67 | 68 | //private void ButtonDeactivateClick(object sender, EventArgs e) 69 | //{ 70 | // if (DeactivateEvent != null) DeactivateEvent(this, null); 71 | //} 72 | 73 | //private void buttonAddProcess_Click(object sender, EventArgs e) 74 | //{ 75 | // if (AddEvent != null) DeactivateEvent(this, null); 76 | //} 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /WatchDogClient.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonitoredApplication", "MonitoredApplication\MonitoredApplication.csproj", "{BD78E5E6-40B6-4D02-8753-BB6AD04D48D0}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchdogClientLib", "WatchdogClientLib\WatchdogClientLib.csproj", "{8668150C-C05F-43CA-9624-873ADA5828F9}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {BD78E5E6-40B6-4D02-8753-BB6AD04D48D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {BD78E5E6-40B6-4D02-8753-BB6AD04D48D0}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {BD78E5E6-40B6-4D02-8753-BB6AD04D48D0}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {BD78E5E6-40B6-4D02-8753-BB6AD04D48D0}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {2530B029-8F53-4455-A8C9-127C9934A3AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {2530B029-8F53-4455-A8C9-127C9934A3AF}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {2530B029-8F53-4455-A8C9-127C9934A3AF}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {2530B029-8F53-4455-A8C9-127C9934A3AF}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {8668150C-C05F-43CA-9624-873ADA5828F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {8668150C-C05F-43CA-9624-873ADA5828F9}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {8668150C-C05F-43CA-9624-873ADA5828F9}.Release|Any CPU.ActiveCfg = Release|Any CPU 35 | {8668150C-C05F-43CA-9624-873ADA5828F9}.Release|Any CPU.Build.0 = Release|Any CPU 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /Utilities/NlogEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | 5 | using NLog; 6 | using NLog.Targets; 7 | using System.Timers; 8 | using NLog.Config; 9 | 10 | namespace Utilities 11 | { 12 | public class LogEventArgs : EventArgs 13 | { 14 | public List LogLines { get; private set; } 15 | 16 | public LogEventArgs(List logLines) 17 | { 18 | LogLines = logLines; 19 | } 20 | } 21 | 22 | [Target("NlogEvent")] 23 | public class NlogEventTarget : TargetWithLayout 24 | { 25 | public EventHandler OnLogEvent; 26 | private readonly ConcurrentQueue _logQueue; 27 | 28 | private static NlogEventTarget _instance; 29 | 30 | public static NlogEventTarget Instance 31 | { 32 | get 33 | { 34 | if (_instance == null) 35 | { 36 | _instance = new NlogEventTarget(); 37 | Register(_instance); 38 | } 39 | return _instance; 40 | } 41 | } 42 | 43 | public NlogEventTarget() 44 | { 45 | _logQueue = new ConcurrentQueue(); 46 | var timer = new Timer(100); 47 | timer.Elapsed += TimerElapsed; 48 | timer.Start(); 49 | } 50 | 51 | public static void Register(NlogEventTarget nlogEventTarget) 52 | { 53 | 54 | nlogEventTarget.Name = "event"; 55 | nlogEventTarget.Layout = "${longdate} ${uppercase:${level}} ${message}"; 56 | 57 | var config = LogManager.Configuration; 58 | config.AddTarget("nlogEvent", nlogEventTarget); 59 | var rule = new LoggingRule("*", LogLevel.Trace, nlogEventTarget); 60 | config.LoggingRules.Add(rule); 61 | 62 | LogManager.Configuration = config; 63 | LogManager.Configuration.Reload(); 64 | } 65 | 66 | private void TimerElapsed(object sender, ElapsedEventArgs e) 67 | { 68 | var logList = new List(); 69 | var localValue = ""; 70 | while (_logQueue.TryDequeue(out localValue)) logList.Add(localValue); 71 | 72 | if (logList.Count <= 0) return; 73 | if (OnLogEvent == null) return; 74 | var args = new LogEventArgs(logList); 75 | 76 | OnLogEvent(this, args); 77 | } 78 | 79 | protected override void Write(LogEventInfo logEvent) 80 | { 81 | var logMessage = this.Layout.Render(logEvent); 82 | _logQueue.Enqueue(logMessage); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /WatchDog/NlogEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Collections.Generic; 4 | 5 | using NLog; 6 | using NLog.Targets; 7 | using System.Timers; 8 | using NLog.Config; 9 | 10 | namespace WatchDog 11 | { 12 | public class LogEventArgs : EventArgs 13 | { 14 | public List LogLines { get; private set; } 15 | 16 | public LogEventArgs(List logLines) 17 | { 18 | LogLines = logLines; 19 | } 20 | } 21 | 22 | [Target("NlogEvent")] 23 | public sealed class NlogEventTarget : TargetWithLayout 24 | { 25 | public EventHandler OnLogEvent; 26 | private readonly ConcurrentQueue _logQueue; 27 | 28 | private static NlogEventTarget _instance; 29 | 30 | public static NlogEventTarget Instance 31 | { 32 | get 33 | { 34 | if (_instance == null) 35 | { 36 | _instance = new NlogEventTarget(); 37 | Register(_instance); 38 | } 39 | return _instance; 40 | } 41 | } 42 | 43 | public NlogEventTarget() 44 | { 45 | _logQueue = new ConcurrentQueue(); 46 | var timer = new Timer(100); 47 | timer.Elapsed += TimerElapsed; 48 | timer.Start(); 49 | } 50 | 51 | public static void Register(NlogEventTarget nlogEventTarget) 52 | { 53 | 54 | nlogEventTarget.Name = "event"; 55 | nlogEventTarget.Layout = "${longdate} ${uppercase:${level}} ${message}"; 56 | 57 | var config = LogManager.Configuration; 58 | config.AddTarget("nlogEvent", nlogEventTarget); 59 | var rule = new LoggingRule("*", LogLevel.Trace, nlogEventTarget); 60 | config.LoggingRules.Add(rule); 61 | 62 | LogManager.Configuration = config; 63 | LogManager.Configuration.Reload(); 64 | } 65 | 66 | private void TimerElapsed(object sender, ElapsedEventArgs e) 67 | { 68 | var logList = new List(); 69 | var localValue = ""; 70 | while (_logQueue.TryDequeue(out localValue)) logList.Add(localValue); 71 | 72 | if (logList.Count <= 0) return; 73 | if (OnLogEvent == null) return; 74 | var args = new LogEventArgs(logList); 75 | 76 | OnLogEvent(this, args); 77 | } 78 | 79 | protected override void Write(LogEventInfo logEvent) 80 | { 81 | var logMessage = this.Layout.Render(logEvent); 82 | _logQueue.Enqueue(logMessage); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /WatchDog/LogForm.Designer.cs: -------------------------------------------------------------------------------- 1 | using Utilities.Controls; 2 | 3 | namespace WatchDog 4 | { 5 | partial class LogForm 6 | { 7 | /// 8 | /// Required designer variable. 9 | /// 10 | private System.ComponentModel.IContainer components = null; 11 | 12 | 13 | 14 | /// 15 | /// Clean up any resources being used. 16 | /// 17 | /// true if managed resources should be disposed; otherwise, false. 18 | protected override void Dispose(bool disposing) 19 | { 20 | if (disposing && (components != null)) 21 | { 22 | components.Dispose(); 23 | } 24 | base.Dispose(disposing); 25 | } 26 | 27 | #region Windows Form Designer generated code 28 | 29 | /// 30 | /// Required method for Designer support - do not modify 31 | /// the contents of this method with the code editor. 32 | /// 33 | private void InitializeComponent() 34 | { 35 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LogForm)); 36 | this.loggingView = new Utilities.Controls.LoggingView(); 37 | this.SuspendLayout(); 38 | // 39 | // loggingView 40 | // 41 | this.loggingView.Dock = System.Windows.Forms.DockStyle.Fill; 42 | this.loggingView.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; 43 | this.loggingView.FollowLastItem = true; 44 | this.loggingView.FormattingEnabled = true; 45 | this.loggingView.Location = new System.Drawing.Point(0, 0); 46 | this.loggingView.MaxEntriesInListBox = 3000; 47 | this.loggingView.Name = "loggingView"; 48 | this.loggingView.Size = new System.Drawing.Size(500, 400); 49 | this.loggingView.TabIndex = 0; 50 | // 51 | // LogForm 52 | // 53 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 55 | this.ClientSize = new System.Drawing.Size(500, 400); 56 | this.Controls.Add(this.loggingView); 57 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 58 | this.Name = "LogForm"; 59 | this.Text = "Logging Watchdog"; 60 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.LogFormFormClosing); 61 | this.Resize += new System.EventHandler(this.LogFormResize); 62 | this.ResumeLayout(false); 63 | 64 | } 65 | 66 | #endregion 67 | 68 | private LoggingView loggingView; 69 | } 70 | } -------------------------------------------------------------------------------- /Utilities/EagerTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | using System.Timers; 4 | 5 | namespace Utilities 6 | { 7 | /// 8 | // EagerTimer is a simple wrapper around System.Timers.Timer that 9 | // provides "set up and immediately execute" functionality by adding a 10 | // new AutoStart property, and also provides the ability to manually 11 | // raise the Elapsed event with RaiseElapsed. 12 | /// 13 | public class EagerTimer : Timer 14 | { 15 | public EagerTimer(): base() { } 16 | 17 | public EagerTimer(double interval) : base(interval) { } 18 | 19 | // Need to hide this so we can use Elapsed.Invoke below 20 | // (otherwise the compiler complains) 21 | private event ElapsedEventHandler ElapsedHandler; 22 | public new event ElapsedEventHandler Elapsed 23 | { 24 | add { ElapsedHandler += value; base.Elapsed += value; } 25 | remove { ElapsedHandler -= value; base.Elapsed -= value; } 26 | } 27 | 28 | public new void Start() 29 | { 30 | // If AutoStart is enabled, we need to invoke the timer event manually 31 | if (AutoStart) 32 | { 33 | var onElapsedHandler = ElapsedHandler; 34 | if (onElapsedHandler != null) 35 | onElapsedHandler.BeginInvoke(this, null, AutoStartCallback, ElapsedHandler); // fire immediately 36 | } 37 | 38 | // Proceed as normal 39 | base.Start(); 40 | } 41 | 42 | public void Reset() 43 | { 44 | Stop(); 45 | Start(); 46 | } 47 | 48 | 49 | private void AutoStartCallback(IAsyncResult result) 50 | { 51 | 52 | try 53 | { 54 | var handler = result.AsyncState as ElapsedEventHandler; 55 | if (handler != null) handler.EndInvoke(result); 56 | } 57 | catch { } 58 | } 59 | 60 | // Summary: 61 | // Gets or sets a value indicating whether the EagerTimer should raise 62 | // the System.Timers.Timer.Elapsed event immediately when Start() is called, 63 | // or only after the first time it elapses. If AutoStart is false, EagerTimer behaves 64 | // identically to System.Timers.Timer. 65 | // 66 | // Returns: 67 | // true if the EagerTimer should raise the System.Timers.Timer.Elapsed 68 | // event immediately when Start() is called; false if it should raise the System.Timers.Timer.Elapsed 69 | // event only after the first time the interval elapses. The default is true. 70 | [Category("Behavior")] 71 | [DefaultValue(true)] 72 | [TimersDescription("TimerAutoStart")] 73 | public bool AutoStart { get; set; } 74 | 75 | /// 76 | /// Manually raises the Elapsed event of the System.Timers.Timer. 77 | /// 78 | public void RaiseElapsed() 79 | { 80 | if (ElapsedHandler != null) 81 | ElapsedHandler(this, null); 82 | } 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /WatchdogLib/ApplicationWatcher.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2015 All Rights Reserved 3 | // 4 | // Thijs Elenbaas 5 | // The ApplicationWatcher class implementation. This is the actual watchdog. 6 | 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Diagnostics; 10 | using System.IO; 11 | using System.Threading; 12 | using NLog; 13 | using Utilities; 14 | 15 | namespace WatchdogLib 16 | { 17 | public class ApplicationWatcher 18 | { 19 | private readonly Stopwatch _sleepStopwatch; 20 | private readonly Logger _logger; 21 | 22 | 23 | //public List ProcessHandlers { get; set; } 24 | public List ApplicationHandlers { get; set; } 25 | 26 | 27 | public ApplicationWatcher(Logger logger) 28 | { 29 | //ProcessHandlers= new List(); 30 | ApplicationHandlers = new List(); 31 | _sleepStopwatch = new Stopwatch(); 32 | var asyncWorkerMonitor = new AsyncWorker(MonitorJob) {Name = "ApplicationWatcher"}; 33 | asyncWorkerMonitor.Start(); 34 | _logger = logger; 35 | 36 | } 37 | 38 | private bool MonitorJob() 39 | { 40 | // Walk through list of applications to see which ones are running 41 | _sleepStopwatch.Restart(); 42 | foreach (var applicationHandler in ApplicationHandlers.ToArray()) 43 | { 44 | applicationHandler.Check(); 45 | } 46 | Thread.Sleep(Math.Max(0, 500 - (int)_sleepStopwatch.ElapsedMilliseconds)); 47 | return true; 48 | } 49 | 50 | 51 | 52 | public bool AddMonitoredApplication(string applicationName, string applicationPath, int nonResponsiveInterval, uint heartbeatInterval = 15, int minProcesses = 1, int maxProcesses = 1, bool keepExistingNoProcesses = false, bool useHeartbeat = false, bool grantKillRequest = true, bool active=false, uint startupMonitorDelay=20) 53 | { 54 | _logger.Trace("Registering {0} for monitoring", applicationName); 55 | ApplicationHandlers.Add(item: new ApplicationHandler(applicationName, applicationPath, nonResponsiveInterval, heartbeatInterval, minProcesses, maxProcesses, keepExistingNoProcesses, useHeartbeat, grantKillRequest, startupMonitorDelay) { Logger = _logger }) ; 56 | return true; // todo 57 | } 58 | 59 | 60 | public void Deserialize(Configuration configuration) 61 | { 62 | foreach (var applicationHandlerConfig in configuration.ApplicationHandlers) 63 | { 64 | var applicationHandler = new ApplicationHandler(applicationHandlerConfig); 65 | ApplicationHandlers.Add(applicationHandler); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /WatchdogClientLib/WatchdogClientLib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8668150C-C05F-43CA-9624-873ADA5828F9} 8 | Library 9 | Properties 10 | WatchdogClient 11 | WatchdogClient 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 62 | -------------------------------------------------------------------------------- /MonitoredApplication/Form1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using System.Diagnostics; 4 | using System.Timers; 5 | using System.Windows.Forms; 6 | using WatchdogClient; 7 | namespace MonitoredApplication 8 | { 9 | /// 10 | /// The Monitored Application 11 | /// 12 | public partial class MonitoredApplicationForm : Form 13 | { 14 | 15 | private System.Timers.Timer _timer; 16 | private Heartbeat _heartbeat; 17 | private int _heartbeatCount; 18 | public MonitoredApplicationForm() 19 | { 20 | InitializeComponent(); 21 | _heartbeat = new Heartbeat(); // initialize heartbeat 22 | 23 | _timer = new System.Timers.Timer(1000); 24 | _timer.Elapsed += OnTimedEvent; 25 | _timer.Enabled = true; 26 | 27 | #region WatchdogWatcher initialization 28 | 29 | int watchDogMonitorInterval = 5000; 30 | 31 | try 32 | { 33 | watchDogMonitorInterval = Convert.ToInt32(ConfigurationManager.AppSettings["WatchDogMonitorInterval"]); 34 | if (watchDogMonitorInterval != 0) 35 | { 36 | watchDogMonitorInterval = 5000; 37 | } 38 | } 39 | catch (Exception ex) 40 | { 41 | watchDogMonitorInterval = 5000; 42 | MessageBox.Show("Exception WatchdogMonitor : " + ex.StackTrace); 43 | } 44 | 45 | 46 | #endregion 47 | } 48 | 49 | private void OnTimedEvent(object sender, ElapsedEventArgs e) 50 | { 51 | // Invoke heartbeat on the main thread otherwise it will send even if the main thread is unresponsive 52 | Invoke(new MethodInvoker(delegate 53 | { 54 | _heartbeat.SendHeartbeat(); 55 | toolStripStatusLabelComments.Text = "Heartbeat " + _heartbeatCount++; 56 | Debug.WriteLine("Heartbeat " + _heartbeatCount); 57 | })); 58 | 59 | 60 | } 61 | 62 | /// 63 | /// Terminate the monitored application 64 | /// 65 | /// 66 | /// 67 | private void BtnTerminateClick(object sender, EventArgs e) 68 | { 69 | Process.GetCurrentProcess().Kill(); 70 | } 71 | 72 | 73 | private void button1_Click(object sender, EventArgs e) 74 | { 75 | while(true); 76 | } 77 | 78 | private void button2_Click(object sender, EventArgs e) 79 | { 80 | _timer.Stop(); 81 | } 82 | 83 | private void ButtonDirectKillClick(object sender, EventArgs e) 84 | { 85 | _heartbeat.RequestKill(); 86 | } 87 | 88 | private void button3_Click(object sender, EventArgs e) 89 | { 90 | _heartbeat.RequestKill(10); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /MonitoredApplication/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace MonitoredApplication.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MonitoredApplication.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /WatchdogLib/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace WatchdogLib 5 | { 6 | public class Configuration 7 | { 8 | public enum RebootModes 9 | { 10 | ShutDown, 11 | Reboot, 12 | PowerOff, 13 | HybridShutdown, 14 | }; 15 | 16 | 17 | public enum ForceModes 18 | { 19 | Normal, 20 | Force, 21 | ForceIfHung, 22 | }; 23 | 24 | public enum RebootAfterTimeSlotModes 25 | { 26 | FirstOccasion, 27 | TryNextDay 28 | }; 29 | 30 | 31 | public List ApplicationHandlers { get; set; } 32 | public bool ShowTrayIcon { get; set; } 33 | public bool PeriodicReboot { get; set; } 34 | public int RebootPeriod { get; set; } 35 | public DateTime RebootBefore { get; set; } 36 | public DateTime RebootAfter { get; set; } 37 | public RebootModes RebootMode { get; set; } 38 | public RebootModes ForceMode { get; set; } 39 | public RebootAfterTimeSlotModes RebootAfterTimeSlot { get; set; } 40 | 41 | public Configuration() 42 | { 43 | ApplicationHandlers = new List(); 44 | ShowTrayIcon = true; 45 | 46 | //var app = new ApplicationHandlerConfig() 47 | //{ 48 | // ApplicationPath = @"D:\DevelPers\WatchDog\MonitoredApplication\bin\Release\MonitoredApplication.exe", 49 | // ApplicationName = "MonitoredApplication", 50 | // Active = true 51 | //}; 52 | //ApplicationHandlers.Add(app); 53 | } 54 | 55 | } 56 | 57 | 58 | public class ApplicationHandlerConfig 59 | { 60 | public int NonResponsiveInterval { get; set; } 61 | public string ApplicationPath { get; set; } 62 | public string ApplicationName { get; set; } 63 | public bool UseHeartbeat { get; set; } 64 | public bool GrantKillRequest { get; set; } 65 | public uint HeartbeatInterval { get; set; } 66 | public int MaxProcesses { get; set; } 67 | public int MinProcesses { get; set; } 68 | public bool Active { get; set; } 69 | public bool KeepExistingNoProcesses { get; set; } 70 | 71 | public uint StartupMonitorDelay { get; set; } 72 | 73 | public ApplicationHandlerConfig() 74 | { 75 | NonResponsiveInterval = 20; 76 | ApplicationPath = ""; 77 | ApplicationName = ""; 78 | UseHeartbeat = false; 79 | GrantKillRequest = true; 80 | HeartbeatInterval = 20; 81 | MinProcesses = 1; 82 | MaxProcesses = 10; 83 | Active = false; 84 | KeepExistingNoProcesses = true; 85 | StartupMonitorDelay = 20; 86 | } 87 | } 88 | 89 | 90 | } -------------------------------------------------------------------------------- /WatchDogServer.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29806.167 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchDog", "WatchDog\WatchDog.csproj", "{FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WatchdogLib", "WatchdogLib\WatchdogLib.csproj", "{4BC93E50-963A-4471-922F-801810B9EFC2}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utilities", "Utilities\Utilities.csproj", "{B306ADDA-8617-4746-ABA2-C36DEA9B6145}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Release|Any CPU = Release|Any CPU 17 | Release|x64 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Debug|x64.ActiveCfg = Debug|Any CPU 23 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Debug|x64.Build.0 = Debug|Any CPU 24 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Release|x64.ActiveCfg = Release|Any CPU 27 | {FFDC0B09-1BC3-4C8E-9EFA-98A651428FD5}.Release|x64.Build.0 = Release|Any CPU 28 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 29 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Debug|Any CPU.Build.0 = Debug|Any CPU 30 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Debug|x64.ActiveCfg = Debug|Any CPU 31 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Debug|x64.Build.0 = Debug|Any CPU 32 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Release|x64.ActiveCfg = Release|Any CPU 35 | {4BC93E50-963A-4471-922F-801810B9EFC2}.Release|x64.Build.0 = Release|Any CPU 36 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Debug|x64.ActiveCfg = Debug|Any CPU 39 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Debug|x64.Build.0 = Debug|Any CPU 40 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Release|x64.ActiveCfg = Release|Any CPU 43 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145}.Release|x64.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {12F14A09-55B1-4428-86E0-1813C82429D0} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /WatchDog/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace WatchDog { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WatchDog.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon). 65 | /// 66 | internal static System.Drawing.Icon watchdog { 67 | get { 68 | object obj = ResourceManager.GetObject("watchdog", resourceCulture); 69 | return ((System.Drawing.Icon)(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /WatchdogLib/IO/PipeStreamWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Pipes; 4 | using System.Net; 5 | using System.Runtime.Serialization; 6 | using System.Runtime.Serialization.Formatters.Binary; 7 | 8 | namespace WatchdogLib.IO 9 | { 10 | /// 11 | /// Wraps a object and writes to it. Serializes .NET CLR objects specified by 12 | /// into binary form and sends them over the named pipe for a to read and deserialize. 13 | /// 14 | /// Reference type to serialize 15 | public class PipeStreamWriter where T : class 16 | { 17 | /// 18 | /// Gets the underlying PipeStream object. 19 | /// 20 | public PipeStream BaseStream { get; private set; } 21 | 22 | private readonly BinaryFormatter _binaryFormatter = new BinaryFormatter(); 23 | 24 | /// 25 | /// Constructs a new PipeStreamWriter object that writes to given . 26 | /// 27 | /// Pipe to write to 28 | public PipeStreamWriter(PipeStream stream) 29 | { 30 | BaseStream = stream; 31 | } 32 | 33 | #region Private stream writers 34 | 35 | /// An object in the graph of type parameter is not marked as serializable. 36 | private byte[] Serialize(T obj) 37 | { 38 | using (var memoryStream = new MemoryStream()) 39 | { 40 | _binaryFormatter.Serialize(memoryStream, obj); 41 | return memoryStream.ToArray(); 42 | } 43 | } 44 | 45 | private void WriteLength(int len) 46 | { 47 | var lenbuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(len)); 48 | BaseStream.Write(lenbuf, 0, lenbuf.Length); 49 | } 50 | 51 | private void WriteObject(byte[] data) 52 | { 53 | BaseStream.Write(data, 0, data.Length); 54 | } 55 | 56 | private void Flush() 57 | { 58 | BaseStream.Flush(); 59 | } 60 | 61 | #endregion 62 | 63 | /// 64 | /// Writes an object to the pipe. This method blocks until all data is sent. 65 | /// 66 | /// Object to write to the pipe 67 | /// An object in the graph of type parameter is not marked as serializable. 68 | public void WriteObject(T obj) 69 | { 70 | var data = Serialize(obj); 71 | WriteLength(data.Length); 72 | WriteObject(data); 73 | Flush(); 74 | } 75 | 76 | /// 77 | /// Waits for the other end of the pipe to read all sent bytes. 78 | /// 79 | /// The pipe is closed. 80 | /// The pipe does not support write operations. 81 | /// The pipe is broken or another I/O error occurred. 82 | public void WaitForPipeDrain() 83 | { 84 | BaseStream.WaitForPipeDrain(); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /WatchdogClientLib/IO/PipeStreamWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Pipes; 4 | using System.Net; 5 | using System.Runtime.Serialization; 6 | using System.Runtime.Serialization.Formatters.Binary; 7 | 8 | namespace WatchdogClient.IO 9 | { 10 | /// 11 | /// Wraps a object and writes to it. Serializes .NET CLR objects specified by 12 | /// into binary form and sends them over the named pipe for a to read and deserialize. 13 | /// 14 | /// Reference type to serialize 15 | public class PipeStreamWriter where T : class 16 | { 17 | /// 18 | /// Gets the underlying PipeStream object. 19 | /// 20 | public PipeStream BaseStream { get; private set; } 21 | 22 | private readonly BinaryFormatter _binaryFormatter = new BinaryFormatter(); 23 | 24 | /// 25 | /// Constructs a new PipeStreamWriter object that writes to given . 26 | /// 27 | /// Pipe to write to 28 | public PipeStreamWriter(PipeStream stream) 29 | { 30 | BaseStream = stream; 31 | } 32 | 33 | #region Private stream writers 34 | 35 | /// An object in the graph of type parameter is not marked as serializable. 36 | private byte[] Serialize(T obj) 37 | { 38 | using (var memoryStream = new MemoryStream()) 39 | { 40 | _binaryFormatter.Serialize(memoryStream, obj); 41 | return memoryStream.ToArray(); 42 | } 43 | } 44 | 45 | private void WriteLength(int len) 46 | { 47 | var lenbuf = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(len)); 48 | BaseStream.Write(lenbuf, 0, lenbuf.Length); 49 | } 50 | 51 | private void WriteObject(byte[] data) 52 | { 53 | BaseStream.Write(data, 0, data.Length); 54 | } 55 | 56 | private void Flush() 57 | { 58 | BaseStream.Flush(); 59 | } 60 | 61 | #endregion 62 | 63 | /// 64 | /// Writes an object to the pipe. This method blocks until all data is sent. 65 | /// 66 | /// Object to write to the pipe 67 | /// An object in the graph of type parameter is not marked as serializable. 68 | public void WriteObject(T obj) 69 | { 70 | var data = Serialize(obj); 71 | WriteLength(data.Length); 72 | WriteObject(data); 73 | Flush(); 74 | } 75 | 76 | /// 77 | /// Waits for the other end of the pipe to read all sent bytes. 78 | /// 79 | /// The pipe is closed. 80 | /// The pipe does not support write operations. 81 | /// The pipe is broken or another I/O error occurred. 82 | public void WaitForPipeDrain() 83 | { 84 | BaseStream.WaitForPipeDrain(); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /WatchdogLib/SleepDetector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Timers; 3 | using Microsoft.Win32; 4 | using NLog; 5 | 6 | namespace WatchdogLib 7 | { 8 | public class SleepDetector 9 | { 10 | 11 | private static SleepDetector _instance; 12 | private DateTime _lastTime; 13 | private DateTime _lastSleepTime; 14 | private readonly int _pollTimeOut; 15 | //private readonly int _sleepTimeOut; 16 | private readonly Timer _timer; 17 | private bool _elapsed; 18 | private Logger _logger; 19 | 20 | public int SleepTimeOut { get; set; } 21 | 22 | private bool JustSlept(int sleepTimeOut) 23 | { 24 | if ((DateTime.Now - _lastSleepTime) < TimeSpan.FromMilliseconds(sleepTimeOut)) 25 | { 26 | //_logger.Info("PC just slept"); 27 | return true; 28 | } else 29 | { 30 | // _logger.Info("PC did not sleep"); 31 | return false; 32 | } 33 | } 34 | 35 | public bool SleepTimeOutElapsed 36 | { 37 | get 38 | { 39 | if (JustSlept() || _elapsed) return false; 40 | _elapsed = true; 41 | return true; 42 | } 43 | } 44 | 45 | public TimeSpan SinceSleep() 46 | { 47 | return DateTime.Now - _lastSleepTime; 48 | } 49 | 50 | public DateTime LastSleep() 51 | { 52 | return _lastSleepTime; 53 | } 54 | 55 | public bool JustSlept() 56 | { 57 | return JustSlept(SleepTimeOut); 58 | } 59 | 60 | public static SleepDetector Instance 61 | { 62 | get { return _instance ?? (_instance = new SleepDetector()); } 63 | } 64 | 65 | private SleepDetector() 66 | { 67 | _logger = LogManager.GetLogger("WatchdogServer"); 68 | SleepTimeOut = 10*1000; 69 | _pollTimeOut = 100; 70 | _lastSleepTime = DateTime.MinValue; 71 | _lastTime = DateTime.Now; 72 | _timer = new Timer(_pollTimeOut); 73 | _timer.Elapsed += TimerElapsed; 74 | _timer.AutoReset = false; 75 | SystemEvents.PowerModeChanged += OnPowerChange; 76 | } 77 | 78 | private void TimerElapsed(object sender, ElapsedEventArgs e) 79 | { 80 | if ((DateTime.Now - _lastTime) > TimeSpan.FromMilliseconds(2*_pollTimeOut)) 81 | { 82 | _lastSleepTime = DateTime.Now; 83 | _elapsed = false; 84 | } 85 | _lastTime = DateTime.Now; 86 | _timer.Start(); 87 | } 88 | 89 | private void OnPowerChange(object sender, PowerModeChangedEventArgs e) 90 | { 91 | switch ( e.Mode ) 92 | { 93 | case PowerModes.Resume: 94 | case PowerModes.Suspend: 95 | case PowerModes.StatusChange: 96 | _lastSleepTime = DateTime.Now; 97 | _elapsed = false; 98 | break; 99 | } 100 | } 101 | 102 | 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /WatchdogLib/IO/PipeStreamReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Pipes; 4 | using System.Net; 5 | using System.Runtime.Serialization; 6 | using System.Runtime.Serialization.Formatters.Binary; 7 | 8 | namespace WatchdogLib.IO 9 | { 10 | /// 11 | /// Wraps a object and reads from it. Deserializes binary data sent by a 12 | /// into a .NET CLR object specified by . 13 | /// 14 | /// Reference type to deserialize data to 15 | public class PipeStreamReader where T : class 16 | { 17 | /// 18 | /// Gets the underlying PipeStream object. 19 | /// 20 | public PipeStream BaseStream { get; } 21 | 22 | /// 23 | /// Gets a value indicating whether the pipe is connected or not. 24 | /// 25 | public bool IsConnected { get; private set; } 26 | 27 | private readonly BinaryFormatter _binaryFormatter = new BinaryFormatter(); 28 | 29 | /// 30 | /// Constructs a new PipeStreamReader object that reads data from the given . 31 | /// 32 | /// Pipe to read from 33 | public PipeStreamReader(PipeStream stream) 34 | { 35 | BaseStream = stream; 36 | IsConnected = stream.IsConnected; 37 | } 38 | 39 | #region Private stream readers 40 | 41 | /// 42 | /// Reads the length of the next message (in bytes) from the client. 43 | /// 44 | /// Number of bytes of data the client will be sending. 45 | /// The pipe is disconnected, waiting to connect, or the handle has not been set. 46 | /// Any I/O error occurred. 47 | private int ReadLength() 48 | { 49 | const int lensize = sizeof (int); 50 | var lenbuf = new byte[lensize]; 51 | var bytesRead = BaseStream.Read(lenbuf, 0, lensize); 52 | if (bytesRead == 0) 53 | { 54 | IsConnected = false; 55 | return 0; 56 | } 57 | if (bytesRead != lensize) 58 | throw new IOException(string.Format("Expected {0} bytes but read {1}", lensize, bytesRead)); 59 | return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(lenbuf, 0)); 60 | } 61 | 62 | /// An object in the graph of type parameter is not marked as serializable. 63 | private T ReadObject(int len) 64 | { 65 | var data = new byte[len]; 66 | BaseStream.Read(data, 0, len); 67 | using (var memoryStream = new MemoryStream(data)) 68 | { 69 | return (T) _binaryFormatter.Deserialize(memoryStream); 70 | } 71 | } 72 | 73 | #endregion 74 | 75 | /// 76 | /// Reads the next object from the pipe. This method blocks until an object is sent 77 | /// or the pipe is disconnected. 78 | /// 79 | /// The next object read from the pipe, or null if the pipe disconnected. 80 | /// An object in the graph of type parameter is not marked as serializable. 81 | public T ReadObject() 82 | { 83 | var len = ReadLength(); 84 | return len == 0 ? default(T) : ReadObject(len); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /WatchdogClientLib/IO/PipeStreamReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Pipes; 4 | using System.Net; 5 | using System.Runtime.Serialization; 6 | using System.Runtime.Serialization.Formatters.Binary; 7 | 8 | namespace WatchdogClient.IO 9 | { 10 | /// 11 | /// Wraps a object and reads from it. Deserializes binary data sent by a 12 | /// into a .NET CLR object specified by . 13 | /// 14 | /// Reference type to deserialize data to 15 | public class PipeStreamReader where T : class 16 | { 17 | /// 18 | /// Gets the underlying PipeStream object. 19 | /// 20 | public PipeStream BaseStream { get; } 21 | 22 | /// 23 | /// Gets a value indicating whether the pipe is connected or not. 24 | /// 25 | public bool IsConnected { get; private set; } 26 | 27 | private readonly BinaryFormatter _binaryFormatter = new BinaryFormatter(); 28 | 29 | /// 30 | /// Constructs a new PipeStreamReader object that reads data from the given . 31 | /// 32 | /// Pipe to read from 33 | public PipeStreamReader(PipeStream stream) 34 | { 35 | BaseStream = stream; 36 | IsConnected = stream.IsConnected; 37 | } 38 | 39 | #region Private stream readers 40 | 41 | /// 42 | /// Reads the length of the next message (in bytes) from the client. 43 | /// 44 | /// Number of bytes of data the client will be sending. 45 | /// The pipe is disconnected, waiting to connect, or the handle has not been set. 46 | /// Any I/O error occurred. 47 | private int ReadLength() 48 | { 49 | const int lensize = sizeof (int); 50 | var lenbuf = new byte[lensize]; 51 | var bytesRead = BaseStream.Read(lenbuf, 0, lensize); 52 | if (bytesRead == 0) 53 | { 54 | IsConnected = false; 55 | return 0; 56 | } 57 | if (bytesRead != lensize) 58 | throw new IOException(string.Format("Expected {0} bytes but read {1}", lensize, bytesRead)); 59 | return IPAddress.NetworkToHostOrder(BitConverter.ToInt32(lenbuf, 0)); 60 | } 61 | 62 | /// An object in the graph of type parameter is not marked as serializable. 63 | private T ReadObject(int len) 64 | { 65 | var data = new byte[len]; 66 | BaseStream.Read(data, 0, len); 67 | using (var memoryStream = new MemoryStream(data)) 68 | { 69 | return (T) _binaryFormatter.Deserialize(memoryStream); 70 | } 71 | } 72 | 73 | #endregion 74 | 75 | /// 76 | /// Reads the next object from the pipe. This method blocks until an object is sent 77 | /// or the pipe is disconnected. 78 | /// 79 | /// The next object read from the pipe, or null if the pipe disconnected. 80 | /// An object in the graph of type parameter is not marked as serializable. 81 | public T ReadObject() 82 | { 83 | var len = ReadLength(); 84 | return len == 0 ? default(T) : ReadObject(len); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /WatchdogLib/WatchdogLib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {4BC93E50-963A-4471-922F-801810B9EFC2} 8 | Library 9 | Properties 10 | WatchdogLib 11 | WatchdogLib 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\NLog.4.3.7\lib\net45\NLog.dll 36 | True 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | {b306adda-8617-4746-aba2-c36dea9b6145} 70 | Utilities 71 | 72 | 73 | 74 | 81 | -------------------------------------------------------------------------------- /Utilities/EventWaiter.cs: -------------------------------------------------------------------------------- 1 | #region CmdMessenger - MIT - (c) 2014 Thijs Elenbaas. 2 | /* 3 | CmdMessenger - library that provides command based messaging 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | Copyright 2014 - Thijs Elenbaas 17 | */ 18 | 19 | #endregion 20 | 21 | using System.Threading; 22 | 23 | namespace Utilities 24 | { 25 | // Functionality comparable to AutoResetEvent (http://www.albahari.com/threading/part2.aspx#_AutoResetEvent) 26 | // but implemented using the monitor class: not inter processs, but ought to be more efficient. 27 | public class EventWaiter 28 | { 29 | public enum WaitState 30 | { 31 | TimeOut, 32 | Normal 33 | } 34 | 35 | private readonly object _key = new object(); 36 | private bool _block; 37 | 38 | /// 39 | /// start blocked (waiting for signal) 40 | /// 41 | public EventWaiter() 42 | { 43 | lock (_key) 44 | { 45 | _block = true; 46 | Monitor.Pulse(_key); 47 | } 48 | } 49 | 50 | /// 51 | /// start blocked or signalled. 52 | /// 53 | /// If true, first Wait will directly continue 54 | public EventWaiter(bool set) 55 | { 56 | lock (_key) 57 | { 58 | _block = !set; 59 | Monitor.Pulse(_key); 60 | } 61 | } 62 | 63 | /// 64 | /// Wait function. Blocks until signal is set or time-out 65 | /// 66 | /// time-out in ms 67 | /// 68 | public WaitState WaitOne(int timeOut) 69 | { 70 | lock (_key) 71 | { 72 | // Check if signal has already been raised before the wait function is entered 73 | if (!_block) 74 | { 75 | // If so, reset event for next time and exit wait loop 76 | _block = true; 77 | return WaitState.Normal; 78 | } 79 | 80 | // Wait under conditions 81 | bool noTimeOut = true; 82 | while (noTimeOut && _block) 83 | { 84 | noTimeOut = Monitor.Wait(_key, timeOut); 85 | } 86 | 87 | // Block Wait for next entry 88 | _block = true; 89 | 90 | // Return whether the Wait function was quit because of an Set event or timeout 91 | return noTimeOut ? WaitState.Normal : WaitState.TimeOut; 92 | } 93 | } 94 | 95 | /// 96 | /// Sets signal, will unblock thread in Wait function 97 | /// 98 | public void Set() 99 | { 100 | lock (_key) 101 | { 102 | _block = false; 103 | Monitor.Pulse(_key); 104 | } 105 | } 106 | 107 | /// 108 | /// Resets signal, will block threads entering Wait function 109 | /// 110 | public void Reset() 111 | { 112 | lock (_key) 113 | { 114 | _block = true; 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Utilities/Controls/LoggingView.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows.Forms; 3 | 4 | namespace Utilities.Controls 5 | { 6 | public partial class LoggingView : ListBox 7 | { 8 | public LoggingView() 9 | { 10 | InitializeComponent(); 11 | SetStyle( 12 | ControlStyles.OptimizedDoubleBuffer | 13 | ControlStyles.ResizeRedraw | 14 | ControlStyles.UserPaint, 15 | true); 16 | DrawMode = DrawMode.OwnerDrawFixed; 17 | FollowLastItem = true; 18 | MaxEntriesInListBox = 3000; 19 | } 20 | 21 | public bool FollowLastItem{ get; set; } 22 | public int MaxEntriesInListBox { get; set; } 23 | 24 | 25 | public void AddEntry(object item) 26 | { 27 | 28 | if (InvokeRequired) 29 | { 30 | Invoke(new MethodInvoker( delegate { AddEntry(item); })); 31 | return; 32 | } 33 | BeginUpdate(); 34 | Items.Add(item); 35 | 36 | if (Items.Count > MaxEntriesInListBox) 37 | { 38 | Items.RemoveAt(0); 39 | } 40 | 41 | if (FollowLastItem) TopIndex = Items.Count - 1; 42 | EndUpdate(); 43 | } 44 | 45 | public void AddEntry(string[] items) 46 | { 47 | if (InvokeRequired) 48 | { 49 | Invoke(new MethodInvoker(delegate { AddEntry(items); })); 50 | return; 51 | } 52 | BeginUpdate(); 53 | foreach (var item in items) 54 | { 55 | Items.Add(item); 56 | 57 | if (Items.Count > MaxEntriesInListBox) 58 | { 59 | Items.RemoveAt(0); 60 | } 61 | } 62 | 63 | if (FollowLastItem) TopIndex = Items.Count - 1; 64 | EndUpdate(); 65 | } 66 | 67 | protected override void OnDrawItem(DrawItemEventArgs e) 68 | { 69 | if (Items.Count > 0) 70 | { 71 | e.DrawBackground(); 72 | e.Graphics.DrawString(Items[e.Index].ToString(), e.Font, new SolidBrush(ForeColor), new PointF(e.Bounds.X, e.Bounds.Y)); 73 | } 74 | base.OnDrawItem(e); 75 | } 76 | protected override void OnPaint(PaintEventArgs e) 77 | { 78 | var iRegion = new Region(e.ClipRectangle); 79 | e.Graphics.FillRegion(new SolidBrush(BackColor), iRegion); 80 | if (Items.Count > 0) 81 | { 82 | for (int i = 0; i < Items.Count; ++i) 83 | { 84 | var irect = GetItemRectangle(i); 85 | if (e.ClipRectangle.IntersectsWith(irect)) 86 | { 87 | if ((SelectionMode == SelectionMode.One && SelectedIndex == i) 88 | || (SelectionMode == SelectionMode.MultiSimple && SelectedIndices.Contains(i)) 89 | || (SelectionMode == SelectionMode.MultiExtended && SelectedIndices.Contains(i))) 90 | { 91 | OnDrawItem(new DrawItemEventArgs(e.Graphics, Font, 92 | irect, i, 93 | DrawItemState.Selected, ForeColor, 94 | BackColor)); 95 | } 96 | else 97 | { 98 | OnDrawItem(new DrawItemEventArgs(e.Graphics, Font, 99 | irect, i, 100 | DrawItemState.Default, ForeColor, 101 | BackColor)); 102 | } 103 | iRegion.Complement(irect); 104 | } 105 | } 106 | } 107 | base.OnPaint(e); 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /WatchdogClientLib/Heartbeat.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | 4 | namespace WatchdogClient 5 | { 6 | 7 | public class Heartbeat 8 | { 9 | private const string PipeName = "named_pipe_watchdog"; 10 | private readonly NamedPipeClient _client = new NamedPipeClient(PipeName); 11 | private readonly string _processName; 12 | private Stopwatch _stopwatchHeartBeat; 13 | public uint Timeout { get; private set; } 14 | public Heartbeat(string processName) 15 | { 16 | _processName = processName; 17 | Initialize(); 18 | } 19 | 20 | public Heartbeat() 21 | { 22 | _processName = Process.GetCurrentProcess().ProcessName; 23 | Initialize(); 24 | } 25 | 26 | private void Initialize() 27 | { 28 | Timeout = 5; 29 | _client.ServerMessage += OnServerMessage; 30 | _client.Disconnected += OnDisconnected; 31 | _client.Connected += OnConnected; 32 | _client.AutoReconnect = true; 33 | _client.Start(); 34 | _stopwatchHeartBeat = new Stopwatch(); 35 | _stopwatchHeartBeat.Start(); 36 | } 37 | 38 | private void OnServerMessage(NamedPipeConnection connection, string message) 39 | { 40 | var args = message.Split(','); 41 | if (args.Length ==0 ) return; 42 | uint command; if (!uint.TryParse(args[0], out command)) return; 43 | 44 | switch (command) 45 | { 46 | case (int) Commands.SetTimeOut: 47 | if (args.Length < 2) return; 48 | uint timeout; 49 | if (uint.TryParse(args[1], out timeout)) { Timeout = timeout; } 50 | break; 51 | } 52 | } 53 | 54 | public void SendHeartbeat() 55 | { 56 | 57 | if (_stopwatchHeartBeat.ElapsedMilliseconds > 25) 58 | { 59 | _stopwatchHeartBeat.Restart(); 60 | SendCommand(Commands.Heartbeat, _processName); 61 | } 62 | } 63 | 64 | public void RequestKill() 65 | { 66 | SendCommand(Commands.RequestKill, _processName); 67 | } 68 | 69 | public void RequestKill(uint sec) 70 | { 71 | SendCommand(Commands.RequestKill, _processName,sec); 72 | } 73 | 74 | public void RequestKill(TimeSpan time) 75 | { 76 | SendCommand(Commands.RequestKill, _processName,time.TotalSeconds); 77 | } 78 | 79 | 80 | private void OnDisconnected(NamedPipeConnection connection) 81 | { 82 | } 83 | 84 | private void OnConnected(NamedPipeConnection connection) 85 | { 86 | SendCommand(Commands.Heartbeat, _processName); 87 | } 88 | 89 | 90 | private enum Commands 91 | { 92 | SetTimeOut, 93 | Heartbeat, 94 | RequestKill, 95 | } 96 | 97 | //private void SendCommand(Commands command, string[] arguments) 98 | //{ 99 | // var commandString = new string[] { command.ToString(), ""}; 100 | // _client.PushMessage(command.ToString()+","+ string.Join(",", commandString)); 101 | //} 102 | 103 | //private void SendCommand(Commands command) 104 | //{ 105 | // _client.PushMessage(command.ToString()); 106 | //} 107 | private void SendCommand(Commands command, T argument) 108 | { 109 | _client.PushMessage(((int)command).ToString() + "," +argument.ToString()); 110 | } 111 | 112 | private void SendCommand(Commands command, T1 argument1, T2 argument2) 113 | { 114 | _client.PushMessage(((int)command).ToString() + "," + argument1.ToString() + "," + argument2.ToString()); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Watchdog 2 | ==================== 3 | [![License](https://img.shields.io/badge/license-MIT%20License-blue.svg)](http://doge.mit-license.org) 4 | 5 | *CSharp Watchdog application. It will monitor applications and restart if necessary.* 6 | 7 | Watchdog is an application that can monitor as many applications as you want from the system tray. If an application exits it can be restarted. The watchdog is very configurable, e.g. how often it is polled, how often it will try to restart etc. 8 | 9 | The watchdog also comes with a single client library that you can integrate in your own application. It implements a heartbeat system. This means if the application is not sending a heartbeat anymore, the Watchdog can restart on this. 10 | 11 | # Overview 12 | ## System tray 13 | The application lives in the system tray, where it can be enabled, disabled and configured. The application can be configured through Settings and stopped or exited. Note that if your exit the watchdog it may automatically respawn, based on the general settings. The watchdog can also be stopped using the global shortcut using [CTR][ALT][W]. This is useful if the application that is monitored blocks the watchdog UI. 14 | ![Watchdog in system tray](/Screenshots/TaskbarMenu.png) 15 | 16 | ## Selecting applications to be watched 17 | The application allows watching as many applications as you need. The Crashing Application demonstrates different manners in which an application can exit, crash or freeze. 18 | ![Watchdog application selection](/Screenshots/ConfigurationForm.png) 19 | 20 | ## Watchdog settings 21 | ![Watchdog application settings](/Screenshots/ApplicationSettingsMenu.png) 22 | Multiple watchdog parameters can be modified per application 23 | * Path - The path of the application. The working directory is also based on this path 24 | * Arguments - Startup arguments of the application 25 | * Process name - Name of the process when running. This is often the application name, but not always. It is used to monitor if the application (and how many) is running. 26 | * Start once - Allows you to test if the settings are correct and will indeed start up the application 27 | * Min number of processes - The minimal number of processes of the application that should be running, this is typically 1, but for some applications (like servers) you may want to run more 28 | * Max number of processes - If more than the indicated number of processes are running, processes will be killed 29 | * Use Heartbeat - This refers to the heartbeat library you can implement in your own application 30 | * Ignore Heartbeat if never acquired - This means that if your application will only be restarted if it had a heartbeat at some point but it stopped 31 | * Max interval heartbeats - Maximum time between hearbeats. If more time occurs between two heartbeats, the watchdog wil restart. Make sure your application sends a heartbeat more often (at least a factor 2) 32 | * Max unresponsive interval - Maximum time that the application may be unresponsive. 33 | * Startup monitor delay - the time between starting an application and the first time that polling occurs. It may take an application some time to start properly and become responsive 34 | * Time between retries - the time between restarting the application 35 | * Active / in active - monitoring starts when the application is set to "Active" (and the watchdog is running) 36 | 37 | ## Persistence 38 | The application can be configured to start at on startup and/or be periodically checked to be running 39 | ![Watchdog general settings, determine restart behaviour](/Screenshots/GeneralSettingsMenu.png) 40 | * Start Watchdog on Windows Startup - The application starts when the user logs in (the application does not run as a service) 41 | * Periodically check if Watchdog is running - If enabled the Task Scheduler will try to start the application every 5 minutes 42 | ## Automatic reboot 43 | The application allows automatic, periodic reboots This may be useful to keep the system and it's applications run reliably. 44 | ![Watchdog reboot menu](/Screenshots/RebootMenu.png) 45 | 46 | ## Copyright 47 | 48 | Watchdog is provided under MIT License. Copyright © 2018, 2019, 2020 49 | -------------------------------------------------------------------------------- /Utilities/Wildcard.cs: -------------------------------------------------------------------------------- 1 | using System.Text.RegularExpressions; 2 | 3 | namespace Utilities 4 | { 5 | /// 6 | /// Represents a wildcard running on the RegEx engine. 7 | /// 8 | public class Wildcard : Regex 9 | { 10 | /// 11 | /// Initializes a wildcard with the given search pattern. 12 | /// 13 | /// The wildcard pattern to match. 14 | public Wildcard(string pattern) 15 | : base(WildcardToRegex(pattern)) 16 | { 17 | } 18 | 19 | 20 | /// 21 | /// Initializes a wildcard with the given search pattern and options. 22 | /// 23 | /// The wildcard pattern to match. 24 | /// 25 | public Wildcard(string pattern, bool caseSensitive = false) 26 | : base(WildcardToRegex(pattern), caseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase) 27 | { 28 | } 29 | 30 | /// 31 | /// Initializes a wildcard with the given search pattern and options. 32 | /// 33 | /// The wildcard pattern to match. 34 | /// Regular expression option. 35 | public Wildcard(string pattern, RegexOptions options) 36 | : base(WildcardToRegex(pattern), options) 37 | { 38 | } 39 | 40 | /// 41 | /// Converts a wildcard to a regex. 42 | /// 43 | /// The wildcard pattern to convert. 44 | /// A regex equivalent of the given wildcard. 45 | public static string WildcardToRegex2(string pattern) 46 | { 47 | // match from beginning to end, greedy match 48 | return "^" + Escape(pattern). 49 | Replace("\\*", ".*"). 50 | Replace("\\?", ".") + "$"; 51 | } 52 | 53 | public static string WildcardToRegex3(string pattern) 54 | { 55 | // match inside of string. Non-greedy. No explicit escaping 56 | pattern = pattern.Replace(".", @"\."); // escaping 57 | pattern = pattern.Replace("?", "."); 58 | pattern = pattern.Replace("*", ".*?"); 59 | pattern = pattern.Replace(@"\", @"\\"); 60 | pattern = pattern.Replace(" ", @"\s"); 61 | return pattern; 62 | } 63 | 64 | public static string WildcardToRegex(string pattern) 65 | { 66 | // match inside of string. Non-greedy. Explicit escaping 67 | return 68 | Regex.Escape(pattern). 69 | Replace("\\*", ".*?"). 70 | Replace("\\?", ".");; 71 | } 72 | 73 | public new static Match Match(string input, string pattern, RegexOptions options) 74 | { 75 | string wildcardPattern = WildcardToRegex(pattern); 76 | return Regex.Match(input, wildcardPattern, options); 77 | } 78 | 79 | public new static Match Match(string input, string pattern) 80 | { 81 | return Match(input, pattern, RegexOptions.None); 82 | } 83 | 84 | public new static bool IsMatch(string input, string pattern, RegexOptions options) 85 | { 86 | string wildcardPattern = WildcardToRegex(pattern); 87 | return Regex.IsMatch(input, wildcardPattern, options); 88 | } 89 | 90 | public new static bool IsMatch(string input, string pattern) 91 | { 92 | return IsMatch(input, pattern, RegexOptions.None); 93 | } 94 | 95 | public new static MatchCollection Matches(string input, string pattern, RegexOptions options) 96 | { 97 | string wildcardPattern = WildcardToRegex(pattern); 98 | return Regex.Matches(input, wildcardPattern, options); 99 | } 100 | 101 | public new static MatchCollection Matches(string input, string pattern) 102 | { 103 | return Matches(input, pattern, RegexOptions.None); 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /WatchDog/RegisterWatchdogTask.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Drawing; 4 | using System.IO; 5 | using System.Windows.Forms; 6 | using Microsoft.Win32.TaskScheduler; 7 | using Utilities; 8 | 9 | namespace WatchDog 10 | { 11 | public class RegisterWatchdogTask 12 | { 13 | const string TaskName = "WatchdogStarter"; 14 | const string ExecutableName = "Watchdog.exe"; 15 | 16 | public static bool SetTask(bool setTask) 17 | { 18 | if (setTask) return CreateTask(); else return DisableTask(); 19 | } 20 | 21 | private static bool DisableTask() 22 | { 23 | try 24 | { 25 | 26 | using (var taskService = new TaskService()) 27 | { 28 | var task = taskService.FindTask(TaskName); 29 | if (task == null) return true; 30 | 31 | task.Enabled = false; 32 | taskService.RootFolder.DeleteTask(TaskName); 33 | return true; 34 | } 35 | } 36 | catch (Exception ex) 37 | { 38 | Debug.WriteLine(ex.Message); 39 | return false; 40 | 41 | } 42 | 43 | } 44 | 45 | public static bool CreateTask() 46 | { 47 | try 48 | { 49 | if (TaskExists()) return true; 50 | 51 | var path = Path.GetDirectoryName(Application.ExecutablePath); 52 | var fileName = FileUtils.Combine(path, ExecutableName); 53 | if (!File.Exists(fileName)) return false; 54 | 55 | 56 | using (var taskService = new TaskService()) 57 | { 58 | // Create a new task definition and assign properties 59 | var taskDefinition = taskService.NewTask(); 60 | taskDefinition.RegistrationInfo.Description = "Starts watchdog if not running"; 61 | taskDefinition.Principal.LogonType = TaskLogonType.InteractiveToken; 62 | try { taskDefinition.Settings.DisallowStartIfOnBatteries = false; } catch { } 63 | try { taskDefinition.Settings.StopIfGoingOnBatteries = false; } catch { } 64 | 65 | // Fire trigger every 5 minutes 66 | var trigger = new TimeTrigger 67 | { 68 | Repetition = 69 | { 70 | Interval = TimeSpan.FromMinutes(5), 71 | } 72 | }; 73 | taskDefinition.Triggers.Add(trigger); 74 | 75 | // Add an action that will launch Notepad whenever the trigger fires 76 | taskDefinition.Actions.Add(new ExecAction(fileName, "", null)); 77 | 78 | // Register the task in the root folder 79 | taskService.RootFolder.RegisterTaskDefinition(TaskName, taskDefinition); 80 | 81 | } 82 | } 83 | catch (Exception ex) 84 | { 85 | Debug.WriteLine(ex.Message); 86 | return false; 87 | 88 | } 89 | return true; 90 | } 91 | 92 | public static bool TaskExists() 93 | { 94 | var path = Path.GetDirectoryName(Application.ExecutablePath); 95 | var fileName = FileUtils.Combine(path, ExecutableName); 96 | using (var taskService = new TaskService()) 97 | { 98 | var task = taskService.FindTask(TaskName); 99 | if (task == null) return false; 100 | 101 | var action = (ExecAction) task.Definition.Actions[0]; 102 | var filePath = action.Path; 103 | if (filePath != fileName) 104 | { 105 | // Watchdog location changed, delete to be re-instantiated 106 | taskService.RootFolder.DeleteTask(TaskName); 107 | return false; 108 | } 109 | 110 | return true; 111 | } 112 | 113 | } 114 | 115 | } 116 | 117 | 118 | } 119 | -------------------------------------------------------------------------------- /MonitoredApplication/MonitoredApplication.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BD78E5E6-40B6-4D02-8753-BB6AD04D48D0} 8 | WinExe 9 | Properties 10 | MonitoredApplication 11 | MonitoredApplication 12 | v4.7.2 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Form 51 | 52 | 53 | Form1.cs 54 | 55 | 56 | 57 | 58 | Form1.cs 59 | 60 | 61 | ResXFileCodeGenerator 62 | Resources.Designer.cs 63 | Designer 64 | 65 | 66 | True 67 | Resources.resx 68 | True 69 | 70 | 71 | SettingsSingleFileGenerator 72 | Settings.Designer.cs 73 | 74 | 75 | True 76 | Settings.settings 77 | True 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | {8668150c-c05f-43ca-9624-873ada5828f9} 86 | WatchdogClientLib 87 | 88 | 89 | 90 | 97 | -------------------------------------------------------------------------------- /Utilities/AsyncWorker.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Utilities; 5 | 6 | namespace Utilities 7 | { 8 | public class AsyncWorker 9 | { 10 | public enum State 11 | { 12 | Stopped, 13 | Running, 14 | Suspended 15 | } 16 | 17 | /// 18 | /// Main worker method to do some work. 19 | /// 20 | /// true is there is more work to do, otherwise false and worker will wait until signaled with SignalWorker(). 21 | public delegate bool AsyncWorkerJob(); 22 | 23 | private volatile State _state = State.Stopped; 24 | private volatile State _requestedState = State.Stopped; 25 | 26 | private readonly object _lock = new object(); 27 | private readonly EventWaiter _eventWaiter = new EventWaiter(); 28 | 29 | private readonly AsyncWorkerJob _workerJob; 30 | 31 | private System.Threading.Tasks.Task _workerTask; 32 | 33 | public string Name { get; set; } 34 | 35 | public State WorkerState { get { return _state; } } 36 | 37 | public bool IsRunning { get { return _state == State.Running; } } 38 | public bool IsSuspended { get { return _state == State.Suspended; } } 39 | 40 | public AsyncWorker(AsyncWorkerJob workerJob) 41 | { 42 | if (workerJob == null) throw new ArgumentNullException("workerJob"); 43 | _workerJob = workerJob; 44 | } 45 | 46 | public void Start() 47 | { 48 | lock (_lock) 49 | { 50 | if (_state == State.Stopped) 51 | { 52 | _requestedState = _state = State.Running; 53 | _eventWaiter.Reset(); 54 | 55 | // http://blogs.msdn.com/b/pfxteam/archive/2010/06/13/10024153.aspx 56 | // prefer using Task.Factory.StartNew for .net 4.0. For .net 4.5 Task.Run is the better option. 57 | _workerTask = Task.Factory.StartNew(x => 58 | { 59 | while (true) 60 | { 61 | if (_state == State.Stopped) break; 62 | 63 | bool haveMoreWork = false; 64 | if (_state == State.Running) 65 | { 66 | haveMoreWork = _workerJob(); 67 | 68 | // Check if state has been changed in workerJob thread. 69 | if (_requestedState != _state && _requestedState == State.Stopped) 70 | { 71 | _state = _requestedState; 72 | break; 73 | } 74 | } 75 | 76 | if (!haveMoreWork || _state == State.Suspended) _eventWaiter.WaitOne(Timeout.Infinite); 77 | _state = _requestedState; 78 | } 79 | }, CancellationToken.None, TaskCreationOptions.LongRunning); 80 | 81 | SpinWait.SpinUntil(() => _workerTask.Status == TaskStatus.Running); 82 | } 83 | else 84 | { 85 | //throw new InvalidOperationException("The worker is already started."); 86 | } 87 | } 88 | } 89 | 90 | public void Stop() 91 | { 92 | lock (_lock) 93 | { 94 | if (_state == State.Running || _state == State.Suspended) 95 | { 96 | _requestedState = State.Stopped; 97 | 98 | // Prevent deadlock by checking is we stopping from worker task or not. 99 | if (Task.CurrentId != _workerTask.Id) 100 | { 101 | _eventWaiter.Set(); 102 | _workerTask.Wait(); 103 | 104 | // http://blogs.msdn.com/b/pfxteam/archive/2012/03/25/10287435.aspx 105 | // Actually it's not required to call dispose on task, but we will do this if possible. 106 | _workerTask.Dispose(); 107 | } 108 | } 109 | else 110 | { 111 | //throw new InvalidOperationException("The worker is already stopped."); 112 | } 113 | } 114 | } 115 | 116 | public void Suspend() 117 | { 118 | lock (_lock) 119 | { 120 | if (_state == State.Running) 121 | { 122 | _requestedState = State.Suspended; 123 | _eventWaiter.Set(); 124 | SpinWait.SpinUntil(() => _requestedState == _state); 125 | } 126 | else 127 | { 128 | // Perhaps this does not require an Exception 129 | //throw new InvalidOperationException("The worker is not running."); 130 | } 131 | } 132 | } 133 | 134 | public void Resume() 135 | { 136 | lock (_lock) 137 | { 138 | if (_state == State.Suspended) 139 | { 140 | _requestedState = State.Running; 141 | _eventWaiter.Set(); 142 | SpinWait.SpinUntil(() => _requestedState == _state); 143 | } 144 | else 145 | { 146 | // Perhaps this does not require an Exception 147 | //throw new InvalidOperationException("The worker is not in suspended state."); 148 | } 149 | } 150 | } 151 | 152 | /// 153 | /// Signal worker to continue processing. 154 | /// 155 | public void Signal() 156 | { 157 | if (IsRunning) _eventWaiter.Set(); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Utilities/Controls/LineInputDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Utilities.Controls 2 | { 3 | partial class LineInputDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.textBox1 = new System.Windows.Forms.TextBox(); 32 | this.labelMessage = new System.Windows.Forms.Label(); 33 | this.buttonOk = new System.Windows.Forms.Button(); 34 | this.buttonCancel = new System.Windows.Forms.Button(); 35 | this.SuspendLayout(); 36 | // 37 | // textBox1 38 | // 39 | this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 40 | | System.Windows.Forms.AnchorStyles.Right))); 41 | this.textBox1.Location = new System.Drawing.Point(12, 38); 42 | this.textBox1.Name = "textBox1"; 43 | this.textBox1.Size = new System.Drawing.Size(355, 20); 44 | this.textBox1.TabIndex = 0; 45 | // 46 | // labelMessage 47 | // 48 | this.labelMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 49 | | System.Windows.Forms.AnchorStyles.Right))); 50 | this.labelMessage.AutoSize = true; 51 | this.labelMessage.Location = new System.Drawing.Point(13, 13); 52 | this.labelMessage.Name = "labelMessage"; 53 | this.labelMessage.Size = new System.Drawing.Size(49, 13); 54 | this.labelMessage.TabIndex = 1; 55 | this.labelMessage.Text = "message"; 56 | // 57 | // buttonOk 58 | // 59 | this.buttonOk.Location = new System.Drawing.Point(281, 74); 60 | this.buttonOk.Name = "buttonOk"; 61 | this.buttonOk.Size = new System.Drawing.Size(87, 26); 62 | this.buttonOk.TabIndex = 2; 63 | this.buttonOk.Text = "Ok"; 64 | this.buttonOk.UseVisualStyleBackColor = true; 65 | this.buttonOk.Click += new System.EventHandler(this.ButtonOkClick); 66 | // 67 | // buttonCancel 68 | // 69 | this.buttonCancel.Location = new System.Drawing.Point(188, 74); 70 | this.buttonCancel.Name = "buttonCancel"; 71 | this.buttonCancel.Size = new System.Drawing.Size(87, 26); 72 | this.buttonCancel.TabIndex = 3; 73 | this.buttonCancel.Text = "Cancel"; 74 | this.buttonCancel.UseVisualStyleBackColor = true; 75 | this.buttonCancel.Click += new System.EventHandler(this.ButtonCancelClick); 76 | // 77 | // LineInputDialog 78 | // 79 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 80 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 81 | this.AutoSize = true; 82 | this.ClientSize = new System.Drawing.Size(380, 115); 83 | this.Controls.Add(this.buttonCancel); 84 | this.Controls.Add(this.buttonOk); 85 | this.Controls.Add(this.labelMessage); 86 | this.Controls.Add(this.textBox1); 87 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 88 | this.Name = "LineInputDialog"; 89 | this.Text = "Form1"; 90 | this.ResumeLayout(false); 91 | this.PerformLayout(); 92 | 93 | } 94 | 95 | #endregion 96 | 97 | private System.Windows.Forms.TextBox textBox1; 98 | private System.Windows.Forms.Label labelMessage; 99 | private System.Windows.Forms.Button buttonOk; 100 | private System.Windows.Forms.Button buttonCancel; 101 | } 102 | } -------------------------------------------------------------------------------- /Utilities/Utilities.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B306ADDA-8617-4746-ABA2-C36DEA9B6145} 8 | Library 9 | Properties 10 | Utilities 11 | Utilities 12 | v4.7.2 13 | 512 14 | true 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Newtonsoft.Json.12.0.3\lib\net45\Newtonsoft.Json.dll 36 | 37 | 38 | ..\packages\NLog.4.7.2\lib\net45\NLog.dll 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Form 61 | 62 | 63 | LineInputDialog.cs 64 | 65 | 66 | Form 67 | 68 | 69 | ListInputDialog.cs 70 | 71 | 72 | Component 73 | 74 | 75 | LoggingView.cs 76 | 77 | 78 | Component 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | LineInputDialog.cs 92 | 93 | 94 | ListInputDialog.cs 95 | 96 | 97 | LoggingView.cs 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Utilities/Controls/ListInputDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Utilities.Controls 2 | { 3 | partial class ListInputDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.labelMessage = new System.Windows.Forms.Label(); 32 | this.buttonOk = new System.Windows.Forms.Button(); 33 | this.buttonCancel = new System.Windows.Forms.Button(); 34 | this.listBox1 = new System.Windows.Forms.ListBox(); 35 | this.SuspendLayout(); 36 | // 37 | // labelMessage 38 | // 39 | this.labelMessage.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 40 | | System.Windows.Forms.AnchorStyles.Right))); 41 | this.labelMessage.AutoSize = true; 42 | this.labelMessage.Location = new System.Drawing.Point(13, 13); 43 | this.labelMessage.Name = "labelMessage"; 44 | this.labelMessage.Size = new System.Drawing.Size(49, 13); 45 | this.labelMessage.TabIndex = 1; 46 | this.labelMessage.Text = "message"; 47 | // 48 | // buttonOk 49 | // 50 | this.buttonOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 51 | this.buttonOk.Location = new System.Drawing.Point(264, 221); 52 | this.buttonOk.Name = "buttonOk"; 53 | this.buttonOk.Size = new System.Drawing.Size(87, 26); 54 | this.buttonOk.TabIndex = 2; 55 | this.buttonOk.Text = "Ok"; 56 | this.buttonOk.UseVisualStyleBackColor = true; 57 | this.buttonOk.Click += new System.EventHandler(this.ButtonOkClick); 58 | // 59 | // buttonCancel 60 | // 61 | this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 62 | this.buttonCancel.Location = new System.Drawing.Point(171, 221); 63 | this.buttonCancel.Name = "buttonCancel"; 64 | this.buttonCancel.Size = new System.Drawing.Size(87, 26); 65 | this.buttonCancel.TabIndex = 3; 66 | this.buttonCancel.Text = "Cancel"; 67 | this.buttonCancel.UseVisualStyleBackColor = true; 68 | this.buttonCancel.Click += new System.EventHandler(this.ButtonCancelClick); 69 | // 70 | // listBox1 71 | // 72 | this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 73 | | System.Windows.Forms.AnchorStyles.Left) 74 | | System.Windows.Forms.AnchorStyles.Right))); 75 | this.listBox1.FormattingEnabled = true; 76 | this.listBox1.Location = new System.Drawing.Point(12, 44); 77 | this.listBox1.Name = "listBox1"; 78 | this.listBox1.Size = new System.Drawing.Size(339, 160); 79 | this.listBox1.TabIndex = 4; 80 | // 81 | // ListInputDialog 82 | // 83 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 84 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 85 | this.AutoSize = true; 86 | this.ClientSize = new System.Drawing.Size(363, 259); 87 | this.Controls.Add(this.listBox1); 88 | this.Controls.Add(this.buttonCancel); 89 | this.Controls.Add(this.buttonOk); 90 | this.Controls.Add(this.labelMessage); 91 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 92 | this.Name = "ListInputDialog"; 93 | this.Text = "Form1"; 94 | this.ResumeLayout(false); 95 | this.PerformLayout(); 96 | 97 | } 98 | 99 | #endregion 100 | private System.Windows.Forms.Label labelMessage; 101 | private System.Windows.Forms.Button buttonOk; 102 | private System.Windows.Forms.Button buttonCancel; 103 | private System.Windows.Forms.ListBox listBox1; 104 | } 105 | } -------------------------------------------------------------------------------- /WatchdogLib/IO/PipeStreamWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Pipes; 4 | using System.Runtime.Serialization; 5 | 6 | namespace WatchdogLib.IO 7 | { 8 | /// 9 | /// Wraps a object to read and write .NET CLR objects. 10 | /// 11 | /// Reference type to read from and write to the pipe 12 | public class PipeStreamWrapper : PipeStreamWrapper 13 | where TReadWrite : class 14 | { 15 | /// 16 | /// Constructs a new PipeStreamWrapper object that reads from and writes to the given . 17 | /// 18 | /// Stream to read from and write to 19 | public PipeStreamWrapper(PipeStream stream) : base(stream) 20 | { 21 | } 22 | } 23 | 24 | /// 25 | /// Wraps a object to read and write .NET CLR objects. 26 | /// 27 | /// Reference type to read from the pipe 28 | /// Reference type to write to the pipe 29 | public class PipeStreamWrapper 30 | where TRead : class 31 | where TWrite : class 32 | { 33 | /// 34 | /// Gets the underlying PipeStream object. 35 | /// 36 | public PipeStream BaseStream { get; private set; } 37 | 38 | /// 39 | /// Gets a value indicating whether the object is connected or not. 40 | /// 41 | /// 42 | /// true if the object is connected; otherwise, false. 43 | /// 44 | public bool IsConnected 45 | { 46 | get { return BaseStream.IsConnected && _reader.IsConnected; } 47 | } 48 | 49 | /// 50 | /// Gets a value indicating whether the current stream supports read operations. 51 | /// 52 | /// 53 | /// true if the stream supports read operations; otherwise, false. 54 | /// 55 | public bool CanRead 56 | { 57 | get { return BaseStream.CanRead; } 58 | } 59 | 60 | /// 61 | /// Gets a value indicating whether the current stream supports write operations. 62 | /// 63 | /// 64 | /// true if the stream supports write operations; otherwise, false. 65 | /// 66 | public bool CanWrite 67 | { 68 | get { return BaseStream.CanWrite; } 69 | } 70 | 71 | private readonly PipeStreamReader _reader; 72 | private readonly PipeStreamWriter _writer; 73 | 74 | /// 75 | /// Constructs a new PipeStreamWrapper object that reads from and writes to the given . 76 | /// 77 | /// Stream to read from and write to 78 | public PipeStreamWrapper(PipeStream stream) 79 | { 80 | BaseStream = stream; 81 | _reader = new PipeStreamReader(BaseStream); 82 | _writer = new PipeStreamWriter(BaseStream); 83 | } 84 | 85 | /// 86 | /// Reads the next object from the pipe. This method blocks until an object is sent 87 | /// or the pipe is disconnected. 88 | /// 89 | /// The next object read from the pipe, or null if the pipe disconnected. 90 | /// An object in the graph of type parameter is not marked as serializable. 91 | public TRead ReadObject() 92 | { 93 | return _reader.ReadObject(); 94 | } 95 | 96 | /// 97 | /// Writes an object to the pipe. This method blocks until all data is sent. 98 | /// 99 | /// Object to write to the pipe 100 | /// An object in the graph of type parameter is not marked as serializable. 101 | public void WriteObject(TWrite obj) 102 | { 103 | _writer.WriteObject(obj); 104 | } 105 | 106 | /// 107 | /// Waits for the other end of the pipe to read all sent bytes. 108 | /// 109 | /// The pipe is closed. 110 | /// The pipe does not support write operations. 111 | /// The pipe is broken or another I/O error occurred. 112 | public void WaitForPipeDrain() 113 | { 114 | _writer.WaitForPipeDrain(); 115 | } 116 | 117 | /// 118 | /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. 119 | /// 120 | public void Close() 121 | { 122 | BaseStream.Close(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /WatchdogClientLib/IO/PipeStreamWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.IO.Pipes; 4 | using System.Runtime.Serialization; 5 | 6 | namespace WatchdogClient.IO 7 | { 8 | /// 9 | /// Wraps a object to read and write .NET CLR objects. 10 | /// 11 | /// Reference type to read from and write to the pipe 12 | public class PipeStreamWrapper : PipeStreamWrapper 13 | where TReadWrite : class 14 | { 15 | /// 16 | /// Constructs a new PipeStreamWrapper object that reads from and writes to the given . 17 | /// 18 | /// Stream to read from and write to 19 | public PipeStreamWrapper(PipeStream stream) : base(stream) 20 | { 21 | } 22 | } 23 | 24 | /// 25 | /// Wraps a object to read and write .NET CLR objects. 26 | /// 27 | /// Reference type to read from the pipe 28 | /// Reference type to write to the pipe 29 | public class PipeStreamWrapper 30 | where TRead : class 31 | where TWrite : class 32 | { 33 | /// 34 | /// Gets the underlying PipeStream object. 35 | /// 36 | public PipeStream BaseStream { get; private set; } 37 | 38 | /// 39 | /// Gets a value indicating whether the object is connected or not. 40 | /// 41 | /// 42 | /// true if the object is connected; otherwise, false. 43 | /// 44 | public bool IsConnected 45 | { 46 | get { return BaseStream.IsConnected && _reader.IsConnected; } 47 | } 48 | 49 | /// 50 | /// Gets a value indicating whether the current stream supports read operations. 51 | /// 52 | /// 53 | /// true if the stream supports read operations; otherwise, false. 54 | /// 55 | public bool CanRead 56 | { 57 | get { return BaseStream.CanRead; } 58 | } 59 | 60 | /// 61 | /// Gets a value indicating whether the current stream supports write operations. 62 | /// 63 | /// 64 | /// true if the stream supports write operations; otherwise, false. 65 | /// 66 | public bool CanWrite 67 | { 68 | get { return BaseStream.CanWrite; } 69 | } 70 | 71 | private readonly PipeStreamReader _reader; 72 | private readonly PipeStreamWriter _writer; 73 | 74 | /// 75 | /// Constructs a new PipeStreamWrapper object that reads from and writes to the given . 76 | /// 77 | /// Stream to read from and write to 78 | public PipeStreamWrapper(PipeStream stream) 79 | { 80 | BaseStream = stream; 81 | _reader = new PipeStreamReader(BaseStream); 82 | _writer = new PipeStreamWriter(BaseStream); 83 | } 84 | 85 | /// 86 | /// Reads the next object from the pipe. This method blocks until an object is sent 87 | /// or the pipe is disconnected. 88 | /// 89 | /// The next object read from the pipe, or null if the pipe disconnected. 90 | /// An object in the graph of type parameter is not marked as serializable. 91 | public TRead ReadObject() 92 | { 93 | return _reader.ReadObject(); 94 | } 95 | 96 | /// 97 | /// Writes an object to the pipe. This method blocks until all data is sent. 98 | /// 99 | /// Object to write to the pipe 100 | /// An object in the graph of type parameter is not marked as serializable. 101 | public void WriteObject(TWrite obj) 102 | { 103 | _writer.WriteObject(obj); 104 | } 105 | 106 | /// 107 | /// Waits for the other end of the pipe to read all sent bytes. 108 | /// 109 | /// The pipe is closed. 110 | /// The pipe does not support write operations. 111 | /// The pipe is broken or another I/O error occurred. 112 | public void WaitForPipeDrain() 113 | { 114 | _writer.WaitForPipeDrain(); 115 | } 116 | 117 | /// 118 | /// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream. 119 | /// 120 | public void Close() 121 | { 122 | BaseStream.Close(); 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /MonitoredApplication/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /WatchDog/GeneralSettingsForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace WatchDog 2 | { 3 | partial class GeneralSettingsForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(GeneralSettingsForm)); 32 | this.checkBoxRestartOnTask = new System.Windows.Forms.CheckBox(); 33 | this.label5 = new System.Windows.Forms.Label(); 34 | this.buttonCancel = new System.Windows.Forms.Button(); 35 | this.buttonAcceptChanges = new System.Windows.Forms.Button(); 36 | this.checkBoxStartOnWindowsStart = new System.Windows.Forms.CheckBox(); 37 | this.label1 = new System.Windows.Forms.Label(); 38 | this.SuspendLayout(); 39 | // 40 | // checkBoxRestartOnTask 41 | // 42 | this.checkBoxRestartOnTask.AutoSize = true; 43 | this.checkBoxRestartOnTask.Location = new System.Drawing.Point(220, 32); 44 | this.checkBoxRestartOnTask.Name = "checkBoxRestartOnTask"; 45 | this.checkBoxRestartOnTask.Size = new System.Drawing.Size(15, 14); 46 | this.checkBoxRestartOnTask.TabIndex = 29; 47 | this.checkBoxRestartOnTask.UseVisualStyleBackColor = true; 48 | this.checkBoxRestartOnTask.CheckedChanged += new System.EventHandler(this.checkBoxRestartOnTask_CheckedChanged); 49 | // 50 | // label5 51 | // 52 | this.label5.AutoSize = true; 53 | this.label5.Location = new System.Drawing.Point(12, 33); 54 | this.label5.Name = "label5"; 55 | this.label5.Size = new System.Drawing.Size(202, 13); 56 | this.label5.TabIndex = 28; 57 | this.label5.Text = "Periodically check if Watchdog is running"; 58 | this.label5.Click += new System.EventHandler(this.label5_Click); 59 | // 60 | // buttonCancel 61 | // 62 | this.buttonCancel.Location = new System.Drawing.Point(78, 102); 63 | this.buttonCancel.Name = "buttonCancel"; 64 | this.buttonCancel.Size = new System.Drawing.Size(111, 28); 65 | this.buttonCancel.TabIndex = 31; 66 | this.buttonCancel.Text = "Cancel"; 67 | this.buttonCancel.UseVisualStyleBackColor = true; 68 | // 69 | // buttonAcceptChanges 70 | // 71 | this.buttonAcceptChanges.Location = new System.Drawing.Point(195, 102); 72 | this.buttonAcceptChanges.Name = "buttonAcceptChanges"; 73 | this.buttonAcceptChanges.Size = new System.Drawing.Size(111, 28); 74 | this.buttonAcceptChanges.TabIndex = 30; 75 | this.buttonAcceptChanges.Text = "Accept"; 76 | this.buttonAcceptChanges.UseVisualStyleBackColor = true; 77 | // 78 | // checkBoxStartOnWindowsStart 79 | // 80 | this.checkBoxStartOnWindowsStart.AutoSize = true; 81 | this.checkBoxStartOnWindowsStart.Location = new System.Drawing.Point(220, 8); 82 | this.checkBoxStartOnWindowsStart.Name = "checkBoxStartOnWindowsStart"; 83 | this.checkBoxStartOnWindowsStart.Size = new System.Drawing.Size(15, 14); 84 | this.checkBoxStartOnWindowsStart.TabIndex = 33; 85 | this.checkBoxStartOnWindowsStart.UseVisualStyleBackColor = true; 86 | // 87 | // label1 88 | // 89 | this.label1.AutoSize = true; 90 | this.label1.Location = new System.Drawing.Point(12, 9); 91 | this.label1.Name = "label1"; 92 | this.label1.Size = new System.Drawing.Size(179, 13); 93 | this.label1.TabIndex = 32; 94 | this.label1.Text = "Start Watchdog on Windows startup"; 95 | // 96 | // GeneralSettingsForm 97 | // 98 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 99 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 100 | this.ClientSize = new System.Drawing.Size(318, 142); 101 | this.Controls.Add(this.checkBoxStartOnWindowsStart); 102 | this.Controls.Add(this.label1); 103 | this.Controls.Add(this.buttonCancel); 104 | this.Controls.Add(this.buttonAcceptChanges); 105 | this.Controls.Add(this.checkBoxRestartOnTask); 106 | this.Controls.Add(this.label5); 107 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 108 | this.Name = "GeneralSettingsForm"; 109 | this.Text = "General Settings"; 110 | this.ResumeLayout(false); 111 | this.PerformLayout(); 112 | 113 | } 114 | 115 | #endregion 116 | 117 | public System.Windows.Forms.CheckBox checkBoxRestartOnTask; 118 | public System.Windows.Forms.Label label5; 119 | public System.Windows.Forms.Button buttonCancel; 120 | public System.Windows.Forms.Button buttonAcceptChanges; 121 | public System.Windows.Forms.CheckBox checkBoxStartOnWindowsStart; 122 | public System.Windows.Forms.Label label1; 123 | } 124 | } -------------------------------------------------------------------------------- /WatchDog/RebootForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Utilities/Controls/LineInputDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Utilities/Controls/ListInputDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Utilities/StringUtils.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.RegularExpressions; 6 | 7 | namespace Utilities 8 | { 9 | /// String utilities. 10 | public class StringUtils 11 | { 12 | /// Convert string from one codepage to another. 13 | /// The string. 14 | /// input encoding codepage. 15 | /// output encoding codepage. 16 | /// the encoded string. 17 | public static string ConvertEncoding(string input, Encoding fromEncoding, Encoding toEncoding) 18 | { 19 | var byteArray = fromEncoding.GetBytes(input); 20 | var asciiArray = Encoding.Convert(fromEncoding, toEncoding, byteArray); 21 | var finalString = toEncoding.GetString(asciiArray); 22 | return finalString; 23 | } 24 | public static string UniqueName(string baseName, string[] names) 25 | { 26 | baseName = baseName.TrimEnd(); 27 | baseName = Regex.Replace(baseName, @"\(\d+\)$",""); 28 | baseName = Regex.Replace(baseName, @"\d+\$",""); 29 | baseName = baseName.TrimEnd(); 30 | if (!names.Contains(baseName)) return baseName; 31 | var count = 1; 32 | while (true) 33 | { 34 | count++; 35 | var endName = string.Format("{0} ({1})", baseName, count); 36 | if (!names.Contains(endName)) return endName; 37 | } 38 | } 39 | } 40 | 41 | public static class StringExtensions 42 | { 43 | public static bool Contains(this string source, string toCheck, StringComparison comp) 44 | { 45 | return source.IndexOf(toCheck, comp) >= 0; 46 | } 47 | 48 | public static string TrimEnd(this string source, string value) 49 | { 50 | if (!source.EndsWith(value)) return source; 51 | return source.Remove(source.LastIndexOf(value, StringComparison.Ordinal)); 52 | } 53 | 54 | public static string TrimStart(this string source, string value) 55 | { 56 | if (!source.StartsWith(value)) return source; 57 | return source.Remove(source.IndexOf(value, StringComparison.Ordinal),value.Length); 58 | } 59 | 60 | /// 61 | /// Returns with the minimal concatenation of (starting from end) that 62 | /// results in satisfying .EndsWith(ending). 63 | /// 64 | /// "hel".WithEnding("llo") returns "hello", which is the result of "hel" + "lo". 65 | public static string WithEnding(this string str, string ending) 66 | { 67 | if (str == null) 68 | return ending; 69 | 70 | string result = str; 71 | 72 | // Right() is 1-indexed, so include these cases 73 | // * Append no characters 74 | // * Append up to N characters, where N is ending length 75 | for (int i = 0; i <= ending.Length; i++) 76 | { 77 | string tmp = result + ending.Right(i); 78 | if (tmp.EndsWith(ending)) 79 | return tmp; 80 | } 81 | 82 | return result; 83 | } 84 | 85 | /// Gets the rightmost characters from a string. 86 | /// The string to retrieve the substring from. 87 | /// The number of characters to retrieve. 88 | /// The substring. 89 | public static string Right(this string value, int length) 90 | { 91 | if (value == null) 92 | { 93 | throw new ArgumentNullException("value"); 94 | } 95 | if (length < 0) 96 | { 97 | throw new ArgumentOutOfRangeException("length", length, "Length is less than zero"); 98 | } 99 | 100 | return (length < value.Length) ? value.Substring(value.Length - length) : value; 101 | } 102 | 103 | public static string Remove(this string s, string substring) 104 | { 105 | return s.Replace(substring, ""); 106 | } 107 | 108 | public static IEnumerable SplitOnLength(this string s, int partLength) { 109 | if (s == null) 110 | throw new ArgumentNullException("s"); 111 | if (partLength <= 0) 112 | throw new ArgumentException("Part length has to be positive.", "partLength"); 113 | 114 | for (var i = 0; i < s.Length; i += partLength) 115 | yield return s.Substring(i, Math.Min(partLength, s.Length - i)); 116 | } 117 | 118 | public static string SplitOnLength(this string s, int partLength,string prepend="", string append="") { 119 | if (s == null) 120 | throw new ArgumentNullException("s"); 121 | if (partLength <= 0) 122 | throw new ArgumentException("Part length has to be positive.", "partLength"); 123 | 124 | var result = ""; 125 | for (var i = 0; i < s.Length; i += partLength) 126 | result += prepend+ s.Substring(i, Math.Min(partLength, s.Length - i)) + append+ ((i < s.Length-partLength)?Environment.NewLine:""); 127 | return result; 128 | } 129 | 130 | public static IEnumerable SplitOnNewLine(this string s) 131 | { 132 | string[] lines = s.Split( 133 | new[] { "\r\n", "\r", "\n" }, 134 | StringSplitOptions.None 135 | ); 136 | return lines; 137 | } 138 | 139 | public static string ToHex(this string s) 140 | { 141 | string hex = ""; 142 | foreach (char c in s) 143 | { 144 | hex += String.Format("{0:x2}", (uint)System.Convert.ToUInt32(((int)(c)).ToString())); 145 | } 146 | return hex; 147 | } 148 | 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /MonitoredApplication/Form1.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /WatchDog/Resources.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | watchdog.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | -------------------------------------------------------------------------------- /Utilities/Controls/LoggingView.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | 124 | False 125 | 126 | -------------------------------------------------------------------------------- /MonitoredApplication/Form1.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace MonitoredApplication 2 | { 3 | partial class MonitoredApplicationForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.btn_Terminate = new System.Windows.Forms.Button(); 32 | this.button1 = new System.Windows.Forms.Button(); 33 | this.button2 = new System.Windows.Forms.Button(); 34 | this.buttonDirectKill = new System.Windows.Forms.Button(); 35 | this.button3 = new System.Windows.Forms.Button(); 36 | this.statusStrip1 = new System.Windows.Forms.StatusStrip(); 37 | this.toolStripStatusLabelComments = new System.Windows.Forms.ToolStripStatusLabel(); 38 | this.statusStrip1.SuspendLayout(); 39 | this.SuspendLayout(); 40 | // 41 | // btn_Terminate 42 | // 43 | this.btn_Terminate.Location = new System.Drawing.Point(215, 12); 44 | this.btn_Terminate.Name = "btn_Terminate"; 45 | this.btn_Terminate.Size = new System.Drawing.Size(75, 23); 46 | this.btn_Terminate.TabIndex = 1; 47 | this.btn_Terminate.Text = "Terminate"; 48 | this.btn_Terminate.UseVisualStyleBackColor = true; 49 | this.btn_Terminate.Click += new System.EventHandler(this.BtnTerminateClick); 50 | // 51 | // button1 52 | // 53 | this.button1.Location = new System.Drawing.Point(12, 12); 54 | this.button1.Name = "button1"; 55 | this.button1.Size = new System.Drawing.Size(143, 23); 56 | this.button1.TabIndex = 2; 57 | this.button1.Text = "Become Unresponsive"; 58 | this.button1.UseVisualStyleBackColor = true; 59 | this.button1.Click += new System.EventHandler(this.button1_Click); 60 | // 61 | // button2 62 | // 63 | this.button2.Location = new System.Drawing.Point(317, 12); 64 | this.button2.Name = "button2"; 65 | this.button2.Size = new System.Drawing.Size(139, 23); 66 | this.button2.TabIndex = 3; 67 | this.button2.Text = "Stop heartbeat"; 68 | this.button2.UseVisualStyleBackColor = true; 69 | this.button2.Click += new System.EventHandler(this.button2_Click); 70 | // 71 | // buttonDirectKill 72 | // 73 | this.buttonDirectKill.Location = new System.Drawing.Point(16, 55); 74 | this.buttonDirectKill.Name = "buttonDirectKill"; 75 | this.buttonDirectKill.Size = new System.Drawing.Size(139, 23); 76 | this.buttonDirectKill.TabIndex = 4; 77 | this.buttonDirectKill.Text = "Request direct kill"; 78 | this.buttonDirectKill.UseVisualStyleBackColor = true; 79 | this.buttonDirectKill.Click += new System.EventHandler(this.ButtonDirectKillClick); 80 | // 81 | // button3 82 | // 83 | this.button3.Location = new System.Drawing.Point(197, 53); 84 | this.button3.Name = "button3"; 85 | this.button3.Size = new System.Drawing.Size(139, 23); 86 | this.button3.TabIndex = 5; 87 | this.button3.Text = "Request kill in 10 sec"; 88 | this.button3.UseVisualStyleBackColor = true; 89 | this.button3.Click += new System.EventHandler(this.button3_Click); 90 | // 91 | // statusStrip1 92 | // 93 | this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { 94 | this.toolStripStatusLabelComments}); 95 | this.statusStrip1.Location = new System.Drawing.Point(0, 107); 96 | this.statusStrip1.Name = "statusStrip1"; 97 | this.statusStrip1.Size = new System.Drawing.Size(533, 22); 98 | this.statusStrip1.TabIndex = 6; 99 | this.statusStrip1.Text = "statusStrip1"; 100 | // 101 | // toolStripStatusLabelComments 102 | // 103 | this.toolStripStatusLabelComments.Name = "toolStripStatusLabelComments"; 104 | this.toolStripStatusLabelComments.Size = new System.Drawing.Size(0, 17); 105 | // 106 | // MonitoredApplicationForm 107 | // 108 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 109 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 110 | this.ClientSize = new System.Drawing.Size(533, 129); 111 | this.Controls.Add(this.statusStrip1); 112 | this.Controls.Add(this.button3); 113 | this.Controls.Add(this.buttonDirectKill); 114 | this.Controls.Add(this.button2); 115 | this.Controls.Add(this.button1); 116 | this.Controls.Add(this.btn_Terminate); 117 | this.Name = "MonitoredApplicationForm"; 118 | this.Text = "Monitored Application"; 119 | this.statusStrip1.ResumeLayout(false); 120 | this.statusStrip1.PerformLayout(); 121 | this.ResumeLayout(false); 122 | this.PerformLayout(); 123 | 124 | } 125 | 126 | #endregion 127 | private System.Windows.Forms.Button btn_Terminate; 128 | private System.Windows.Forms.Button button1; 129 | private System.Windows.Forms.Button button2; 130 | private System.Windows.Forms.Button buttonDirectKill; 131 | private System.Windows.Forms.Button button3; 132 | private System.Windows.Forms.StatusStrip statusStrip1; 133 | private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabelComments; 134 | } 135 | } 136 | 137 | --------------------------------------------------------------------------------