栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

C#实现定时检测软件运行状态

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C#实现定时检测软件运行状态

一、需求

windows程序,定时监测某软件是否启动状态,并通过redis发送监测数据。

二、开发前梳理

通过vs2019进行代码编写,使用隐藏的winform实现,定时任务通过.net自带的System.Timers工具,redis工具使用ServiceStack.Redis,任务主要通过System.Diagnostics

工具获取程序进程,并定时获取其状态,最后使用wix打包工具,将程序打包程MSI,以供客户机安装。安装后自启,并且程序需要可以实现开机自启,通过添加RegistryKey注册表实现。

三、实现

首先新建一个winform程序,向窗体中添加notifyicon和contextmenustrip,这两个控件的组合是实现将程序运行时图标显示在任务栏里。可以选中notifyicon1在右侧属性栏的Icon属性添加显示图标,也可以在代码中添加,后面又需求根据被检测软件运行状态而变换图标颜色的需求,所以在代码中会有所体现。

单击选中contextMenuStrip1,添加一个按钮“退出”,用来执行退出程序操作。

单击选中退出按钮,在右侧属性栏的事件属性列表中添加clicks事件

至此,简单的winform前端完成,接下来实现代码部分。

转到窗体的代码部分,

    public partial class IconForm : Form
    {
        public IconForm()
        {
            InitializeComponent();
        }
        //log4n用于输出打印日志
        ILog _log = LogManager.GetLogger(typeof(IconForm));
        //服务程序的主体类
        CheckService checkService = new CheckService();
        //程序任务栏托管的显示图标
        string iconY = ConfigurationManager.AppSettings["IconY"].Trim();
        string iconN = ConfigurationManager.AppSettings["IconN"].Trim(); 
        bool check = false;//开机自启标志

        #region 窗体单例模式
        //使用单例模式是为了在后续改变显示图标时不新建窗体,而是同一个窗体
        public static IconForm instance;
        public static IconForm CreateForm()
        {
            if (instance == null || instance.IsDisposed)
            {
                instance = new IconForm();
            }
            return instance;
        }
        #endregion

        #region 载入
        private void IconForm_Load(object sender, EventArgs e)
        {
            //检查是否开机自启
            RegistryKey r_local = Registry.CurrentUser;
            RegistryKey r_run = r_local.OpenSubKey(@"SOFTWAREMicrosoftWindowsCurrentVersionRun", false);
            if (r_run.GetValue("CheckService") == null)
            {
                check = true;
            }
            r_run.Close();
            r_local.Close();
            CheckedChanged(check);
            checkService.Start();
        }
        #endregion

        #region 画面及控件隐藏
        private void IconForm_SizeChanged(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.Hide(); //或者是this.Visible = false;
                this.notifyIcon1.Visible = true;
            }
        }
        #endregion

        #region 小图标右键退出按钮
        private void exitMenuItem_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show("您确定要退出程序吗?", "确认", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.OK)
            {
                notifyIcon1.Visible = false;
                checkService.Stop();
                this.Close();
                this.Dispose();
                Application.Exit();
            }
        }
        #endregion

        #region 设置开机自启
        private void CheckedChanged(bool check)
        {
            try
            {
                if (check == true)
                {
                    string path = Application.ExecutablePath;
                    RegistryKey rk = Registry.CurrentUser;//RegistryKey rk = Registry.CurrentUser;
                    RegistryKey rk2 = rk.CreateSubKey(@"SOFTWAREMicrosoftWindowsCurrentVersionRun");
                    rk2.SetValue("CheckService", path);
                    rk2.Close();
                    rk.Close();
                }
            }
            catch (Exception ex)
            {
                _log.Error(ex.Message.ToString()+"设置开机自启失败");
            }
        }
        #endregion 

    }

因为设置了单例模式启动窗体,故程序的入口处启动窗体的方式需要修改

class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(IconForm.CreateForm());
        }
    }

下面实现服务部分的代码

public class CheckService
    {
        ILog _log = LogManager.GetLogger(typeof(CheckService));
        //自带定时器类
        Timer timer = new Timer();
        //功能实现类
        MonitorController moni = new MonitorController();
        public void Start()
        {
            log4net.Config.XmlConfigurator.Configure();
            //string cron = ConfigurationManager.AppSettings["GetTime"].Trim();
            _log.Debug("start Wrap Service!");
            moni.GetInformation();
            //设置定时任务执行时间
            timer.Enabled = true;
            timer.Interval = 60000; //执行间隔时间,单位为毫秒; 这里实际间隔为1分钟  
            timer.Start();
            timer.Elapsed += new System.Timers.ElapsedEventHandler(TimeJob);
        }
        //任务停止
        public void Stop()
        {
            timer.Stop();
            _log.Debug("Stop Wrap Service!");
        }
        //设置定时任务内容
        public void TimeJob(object source, ElapsedEventArgs e)
        {
            moni.GetInformation();
        }
    }

进入功能实现代码部分

public class MonitorController
    {
        static bool processCheck = true;
        public void GetInformation()
        {
            log4net.Config.XmlConfigurator.Configure();
            ILog _log = LogManager.GetLogger(typeof(MonitorController));
            //获取用户信息实现类
            UserLoginServiceImpl userLoginServiceImpl = new UserLoginServiceImpl();
            //获取进程信息实现类
            ProcessOnServiceImpl processOnServiceImpl = new ProcessOnServiceImpl();
            //获取IP信息实现类
            NetHelperIn netHelper = new NetHelperImpl();
            try
            {
                //写入数据
                _log.Debug("start Wrap GetInformation!");
                List ipcollection = netHelper.GetAllIP();
                string account = userLoginServiceImpl.GetAccount().ToLower();
                bool encryp_process = processOnServiceImpl.GetProcess();
                if (processCheck != encryp_process)
                {
                    //反射获取类及方法调用,调用更换显示图标的类方法
                    //加载程序集
                    Assembly assembly = Assembly.Load("ProcessMonitor");
                    //获取程序集中需要的类
                    Type t = assembly.GetType("ProcessMonitor.ProcessCheck");
                    object obj = Activator.CreateInstance(t);
                    //获取类中指定的方法
                    MethodInfo mi = t.GetMethod("ProcessChange");
                    //传入参数,调用方法
                    object[] param = new object[] { encryp_process.ToString() };
                    mi.Invoke(obj, param);

                    processCheck = encryp_process;
                }
                
                string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                //向所有redis发送所有IP为KEY的数据
                foreach (string ip in ipcollection)
                {
                    string redis_key = ip + "_ep";
                    string[] rediscolle = ConfigurationManager.AppSettings.AllKeys;
                    foreach (string redisPath in rediscolle)
                    {
                        if (redisPath.Contains("RedisPath"))
                        {
                            try
                            {
                                string path = ConfigurationManager.AppSettings[redisPath].Trim();
                                //获取Redis操作接口
                                RedisClient Redis = new RedisClient(path, 6379);
                                Redis.Set(redis_key, new UserLogin(account, encryp_process, time), new TimeSpan(0, 10, 0));
                                //保存到硬盘
                                Redis.Save();
                                //释放内存
                                Redis.Dispose();
                                _log.Info("取出刚才存进去的数据 " + Redis.Get(redis_key) + "n 存入服务器:" + path);
                            }
                            catch (Exception ex)
                            {
                                _log.Error(ex.Message.ToString() + "Redis path:" + ConfigurationManager.AppSettings[redisPath].Trim());
                            }
                        }
                    }
                }
            }
            catch (TimeoutException ex)
            {
                _log.Error(ex.Message.ToString()+"连接Redis超时");
            }
        }
    }

通过反射调用的类

public class ProcessCheck
    {
        public void ProcessChange(string statu)
        {
            IconForm form = IconForm.CreateForm(); 
            form.IconChange(statu);
        }
    }

转到窗体实现部分实现图标转变

 #region 图片改变
        public void IconChange(string statu)
        {
            try
            {
                if (statu == "True")
                {
                    this.notifyIcon1.Icon = new System.Drawing.Icon(iconY);
                }
                else if (statu == "False")
                {
                    this.notifyIcon1.Icon = new System.Drawing.Icon(iconN);
                }
                else
                    _log.Error("IconChange()进程状态获取失败" + statu);
            }
            catch (Exception ex)
            { 
                    _log.Error("报错:" + ex.Message);
            }
            
        }
        #endregion

获取本机所有IPv4 IP类

class NetHelperImpl : NetHelperIn
    {
        public List GetAllIP()
        {
            IPAddress[] IPs = Dns.GetHostAddresses(Dns.GetHostName());
            List ipList = new List();
            foreach (IPAddress ip in IPs)
            {
                if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                    ipList.Add(ip.ToString());
            }
            return ipList;
        }
    }

获取用户信息类

class UserLoginServiceImpl : UserLoginServiceIn
    {
        //public string GetAccount()
        //{
        //    return WindowsIdentity.GetCurrent().Name;
        //}
        
        [DllImport("Wtsapi32.dll")]
        protected static extern void WTSFreeMemory(IntPtr pointer);

        [DllImport("Wtsapi32.dll")]
        protected static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTSInfoClass wtsInfoClass, out IntPtr ppBuffer, out uint pBytesReturned);
        public enum WTSInfoClass
        {
            WTSInitialProgram,
            WTSApplicationName,
            WTSWorkingDirectory,
            WTSOEMId,
            WTSSessionId,
            WTSUserName,
            WTSWinStationName,
            WTSDomainName,
            WTSConnectState,
            WTSClientBuildNumber,
            WTSClientName,
            WTSClientDirectory,
            WTSClientProductId,
            WTSClientHardwareId,
            WTSClientAddress,
            WTSClientDisplay,
            WTSClientProtocolType
        }
        public string GetAccount()
        {
            IntPtr buffer;
            uint strLen; 
            int cur_session = Process.GetCurrentProcess().SessionId;
            var username = "SYSTEM"; // assume SYSTEM as this will return "" below
            if (WTSQuerySessionInformation(IntPtr.Zero, cur_session, WTSInfoClass.WTSUserName, out buffer, out strLen) && strLen > 1)
            {
                username = Marshal.PtrToStringAnsi(buffer); // don't need length as these are null terminated strings
                //WTSFreeMemory(buffer);
                //if (WTSQuerySessionInformation(IntPtr.Zero, cur_session, WTSInfoClass.WTSDomainName, out buffer, out strLen) && strLen > 1)
                //{
                //    username = Marshal.PtrToStringAnsi(buffer) + "\" + username; // prepend domain name
                //    WTSFreeMemory(buffer);
                //}
            }
            return username;
        }
    }

获取进程信息类

class ProcessOnServiceImpl : ProcessOnServiceIn
    {
        public bool GetProcess()
        {
            Process[] pro = Process.GetProcesses();//获取已开启的所有进程
            string myPro = ConfigurationManager.AppSettings["ProcessName"].Trim();
            //遍历所有查找到的进程

            for (int i = 0; i < pro.Length; i++)
            {

                //判断此进程是否是要查找的进程
                if (pro[i].ProcessName.ToString() == myPro)
                {
                    return true;
                }
            }
            return false;
        }
    }

至此,基础功能实现完成。

四、使用打包工具打包

这里使用wix进行打包配置,新建一个wix setup项目(需要先去官网下载响应的安装包安装)

引用文件较多时可以使用heat命令进行生成

heat.exe dir "C:projectmyappbinRelease" -dr INSTALLFOLDER -cg ProductComponent -gg -scom -sreg -sfrag -out "C:projectmySetupProjectmyapp.wxs"

最终生成文件结构如下

安装主体代码:



	
		
		
    
    
		
			
				
				
					
				
			
			
				
				
				
			
		
		
		
		
		
			
			
			
			
				
			
			
				
			
		
		 
			
		
		
		
		
			Not Installed
		
		
		
		
	
	
		
			
				
				
				
				
			
		
		
			
				
				
			
		
	

五、问题

1、程序本计划使用服务的方式在后台运行,但是使用服务时,在用户为管理员身份的情况下无法获取正确的用户名~故采用现在winform程序的方式,各路大神若有好的解决方法,也请不吝赐教~

2、本程序安装时需要管理员权限,wix已经配置了以管理员权限安装,但是似乎没有效果;运行时如果不以管理员身份则不输出日志,以管理员身份运行程序时才会输出日志,也是没找到原因。各路大神若有好的解决方法,也请不吝赐教~

3、程序中还有很多不足,因为还不是很熟悉,只能先以实现功能为主,.各路大神若有好的解决方法,也请不吝赐教~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/984631.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号