Simply create a watchdog program using C#

Simply create a watchdog program using C#

In some special projects, the software may be unattended. If the program hangs for some reason or the process is killed, it is very necessary to develop a watchdog program at this time

最后更新 11/11/2022 11:20 AM
傲慢与偏见
预计阅读 6 分钟
分类
.NET
标签
.NET C#

This article was submitted by netizens.

Author: Pride and Prejudice

Original title: Simply create a watchdog program using C#

Original link: www.cnblogs.com/chonglu/p/16913746.html

First of all, thank you to the netizens for their support:

Netizens are welcome to submit technical articles. The subject matter is unlimited and there is no contribution fee...

abstract

In some special projects, the software may be unattended. If the program hangs for some reason or the process is killed, etc., it is very necessary to develop a watchdog program. It is like an invincible cockroach. As long as the program exits abnormally, it can immediately start the program under care again.

code implementation

Tips: There is a complete source code at the end of the article, so I won't write it step by step.

  1. Create a Dog class, mainly used to periodically scan whether the caretaker program is still running

开了个定时器,每 5 秒去检查 1 次,如果没有找到进程则使用Process启动程序

public class Dog
{
    private Timer timer = new Timer();
    private string processName ;
    private string filePath;//要监控的程序的路径
    public Dog()
    {
        timer.Interval = 5000;
        timer.Tick += timer_Tick;
    }

    public void Start(string filePath)
    {
        this.filePath = filePath;
        this.processName = Path.GetFileNameWithoutExtension(filePath);
        timer.Enabled = true;
    }

    /// <summary>
    /// 定时检测系统是否在运行
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void timer_Tick(object sender, EventArgs e)
    {
        try
        {
            Process[] myproc = Process.GetProcessesByName(processName);
            if (myproc.Length == 0)
            {
                Log.Info("检测到看护程序已退出,开始重新激活程序,程序路径:{0}",filePath);
                ProcessStartInfo info = new ProcessStartInfo
                {
                    WorkingDirectory = Path.GetDirectoryName(filePath),
                    FileName = filePath,
                    UseShellExecute = true
                };
                Process.Start(info);
                Log.Info("看护程序已启动");
            }
        }
        catch (Exception)
        {

        }

    }
}

2、在程序入口接收被看护程序的路径,启动Dog扫描

static class Program
{
    static NotifyIcon icon = new NotifyIcon();
    private static Dog dog = new Dog();
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main(string[] args)
    {
        if (args == null || args.Length == 0)
        {
            MessageBox.Show("启动参数异常", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

        string filePath = args[0];
        if(!File.Exists(filePath))
        {
            MessageBox.Show("启动参数异常", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }
        Process current = Process.GetCurrentProcess();
        Process[] processes = Process.GetProcessesByName(current.ProcessName);
        //遍历与当前进程名称相同的进程列表
        foreach (Process process in processes)
        {
            //如果实例已经存在则忽略当前进程
            if (process.Id != current.Id)
            {
                //保证要打开的进程同已经存在的进程来自同一文件路径
                if (process.MainModule.FileName.Equals(current.MainModule.FileName))
                {
                    //已经存在的进程
                    return;
                }
                else
                {
                    process.Kill();
                    process.WaitForExit(3000);
                }
            }
        }
        icon.Text = "看门狗";
        icon.Visible = true;
        Log.Info("启动看门狗,看护程序:{0}",filePath);
        dog.Start(filePath);
        Application.Run();
    }

}
  1. Simply implement a logger (you can also use a third-party library, but it is recommended that the caretaker should not have any dependencies), or you can directly use the one below me. It is very simple and has no dependencies.
public class Log
{
    //读写锁,当资源处于写入模式时,其他线程写入需要等待本次写入结束之后才能继续写入
    private static ReaderWriterLockSlim LogWriteLock = new ReaderWriterLockSlim();
    //日志文件路径
    public static string logPath = "logs\\dog.txt";

    //静态方法todo:在处理话类型之前自动调用,去检查日志文件是否存在
    static Log()
    {
        //创建文件夹
        if (!Directory.Exists("logs"))
        {
            Directory.CreateDirectory("logs");
        }
    }

    /// <summary>
    /// 写入日志.
    /// </summary>
    public static void Info(string format, params object[] args)
    {
        try
        {
            LogWriteLock.EnterWriteLock();
            string msg = args.Length > 0 ? string.Format(format, args) : format;
            using (FileStream stream = new FileStream(logPath, FileMode.Append))
            {
                StreamWriter write = new StreamWriter(stream);
                string content = String.Format("{0} {1}",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),msg);
                write.WriteLine(content);
                //关闭并销毁流写入文件
                write.Close();
                write.Dispose();
            }
        }
        catch (Exception e)
        {

        }
        finally
        {
            LogWriteLock.ExitWriteLock();
        }
    }
}

At this point, the nursing process has been completed. Then encapsulate a start-stop class in the main program (caretaker program)

  1. The main program encapsulates the watchdog start-stop class
 public static class WatchDog
{
    private static string processName = "WatchDog";  //看护程序进程名(注意这里不是被看护程序名,你可以试一下换成主程序名字会使什么效果)
    private static string appPath = AppDomain.CurrentDomain.BaseDirectory;	//系统启动目录
    /// <summary>
    /// 启动看门狗
    /// </summary>
    public static void Start()
    {
        try
        {
            string program = string.Format("{0}{1}.exe", appPath, processName);
            ProcessStartInfo info = new ProcessStartInfo
            {
                WorkingDirectory = appPath,
                FileName = program,
                CreateNoWindow = true,
                UseShellExecute = true,
                Arguments = Process.GetCurrentProcess().MainModule.FileName  //被看护程序的完整路径
            };
            Process.Start(info);
        }
        catch (Exception)
        {
        }
    }

    /// <summary>
    /// 停用看门狗
    /// </summary>
    public static void Stop()
    {
        Process[] myproc = Process.GetProcessesByName(processName);
        foreach (Process pro in myproc)
        {
            pro.Kill();
            pro.WaitForExit(3000);
        }
    }
}

The principle is also very simple, and there are two points to note:

  • processName字段表示看护程序,不是被看护程序,如果写反了,嗯...(你可以试下效果)
  • Arguments参数是被看护程序的完整路径,因为一般情况下,是由被看护程序启动看护程序,所以我们可以直接使用Process.GetCurrentProcess().MainModule.FileName获取到被看护程序的完整路径
  1. Start the watchdog at the main program entry point
public partial class App : Application
{
    [STAThread]
    static void Main()
    {
        //程序启动前调用看护程序
        WatchDog.Start();
        Application app = new Application();
        MainWindow mainWindow = new MainWindow();
        app.Run(mainWindow);
    }
}

Entry points such as Winform, ordinary WPF, and Prism are all different, and you can handle them flexibly according to the actual situation of the project.

Finally, stop the watchdog program where you need to exit the program normally (i.e., the main program close button or other place where you want to exit the program normally)

effect

source code

https://github.com/luchong0813/WatchDogDemo

Keep Exploring

延伸阅读

更多文章
同分类 / 同标签 4/22/2026

Support for. NET by operating system versions (250707 update)

Use virtual machines and test machines to test the support of each version of the operating system for. NET. After installing the operating system, it is passed by measuring the corresponding running time of the installation and being able to run the Stardust Agent.

继续阅读
同分类 / 同标签 2/7/2026

Summary of experience in using AOT

From the very beginning of project creation, you should develop a good habit of conducting AOT release testing in a timely manner whenever new features are added or newer syntax is used.

继续阅读