zoukankan      html  css  js  c++  java
  • 【C#】WinForm 之 SQL Server 服务监控器(避免开机启动服务)

        

    由于刚刚开始写博客加上最近人又懒,很多过去的项目都没时间去整理,先把以前写过的一个小工具发上来吧。


    关于MS-SQL服务优化

    安装过MS-SQL Server的人应该知道,系统会因此多出4、5项新的服务

    • SQL Active Directory Helper 服务
    • SQL Server (SQLEXPRESS)  这个是Visual Studio自带的,单独安装过数据库管理工具的数据库名字会不同
    • SQL Server Browser
    • SQL Server VSS Writer
    • SQL Server 代理 (SQLEXPRESS)  SQLEXPRESS数据库为Visual Studio平台自带

    记得当初学习数据库这门课的时候,小伙伴们为了安装一个Microsoft SQL Server 2008可谓是历尽磨难。然而除了平白占用几个G的磁盘空间外,最最不能让人接受的就是多出的这一串服务,以致开机时间立马翻了一番。

    为了优化开机服务,我尝试着讲这些服务一一禁用,最后得出

    • 如果需要连接至数据库, SQL Server (SQLEXPRESS) 服务必须开启;
    • 如果不知道本地服务器名与数据库连接地址时,保持SQL Server Browser 服务开启可以让VS平台自动列举,方便手动绑定。

    因此本着尽可能加快开机速度并消除DBMS带来的负面影响,我只保留了唯一的服务SQL Server ,禁用了其余服务项。

    然而一次无意中连接失败让我发现了其中存在的巨大安全隐患。当时我在查看日志文件(可以参考这个路径 C:Program FilesMicrosoft SQL ServerMSSQL10.SQLEXPRESSMSSQLLog),发现其中2Mb多的错误警告文件里密密麻麻的异地IP登陆失败记录,而我的数据库只是用于本地的SQL学习完全不可能有远程访问,也就是说在开启服务期间电脑曾经被攻击!!而我们要知道的是在windows的环境下整个操作系统也是数据库的一部分,遭遇入侵不只是自己建立的数据库,攻击者甚至可以通过登陆服务器控制整个主机。当时自己才意识到网络攻击原来离自己那么近,曾经信誓旦旦的去跟踪那些非法IP,不过这里就不扯远了(关于网络安全问题今后有时间再进行整理吧)。

    自从那次经历后,自己也再不敢放着SQL服务长期开启了,而这个小工具也就是那时候写出来的。目的是为了随时启动与关闭SQL服务,避免了每次从任务管理器密密麻麻的服务中寻找这个服务,方便在学习完毕后及时将其关闭。看起来,我还是一如既往的懒哈吐舌笑脸


    功能

    言归正传,为了能监控指定的系统服务,并且还要能将服务开启与关闭,C#自然是首选(没办法,我用的是人家windows的系统嘛)。

    C# 可以提供 ManagementClass来对机器的信息进行管理,可以通过设定不同的管理类来获得机器的基本信息;

    结合 ManagementObjectCollection (用于存储管理对象的集合)、ManagementObject (单个管理对象),我们很快能获得系统的服务并对其进行操作。

    此外,为了方便监控,考虑最小化到通知栏进行显示,即使用 System.Windows.Forms.NotifyIcon 控件。


    相关代码与界面:

    CO}OYA}J[QT~K3V%BS9IRD2

    using System;
    using System.Management;
    using System.Windows.Forms;
    
    
    namespace Watch
    {
        public partial class Form1 : Form
        {
            //创建通知栏点击后的菜单
            ContextMenu notifyContextMenu = new ContextMenu();
            
            private ManagementClass mc = new ManagementClass("Win32_Service"); //系统管理类里选择Win32服务(不区分64位)
            private ManagementObjectCollection moc; //用于存储系统中的所有服务
            private ManagementObject myService;  //用于选择单个管理对象,即单个服务
    
            MenuItem m_open; //三个菜单项
            MenuItem m_close;
            MenuItem m_exit;        
    
            public Form1()
            {            
                System.Diagnostics.Process.GetCurrentProcess().MaxWorkingSet = (IntPtr)500000;
    
                InitializeComponent();
                this.notifyIcon1.Text = "正在监控服务...";
                this.textBox1.Text = "MSSQL$SQLEXPRESS";
    
                m_open = new MenuItem();
                m_close = new MenuItem();
                m_exit = new MenuItem();
    
                m_open.Text = "启动服务";
                m_close.Text = "停止服务";
                m_exit.Text = "退出";
                m_open.Click += new EventHandler(m_open_Click);
                m_close.Click += new EventHandler(m_close_Click);
                m_exit.Click += new EventHandler(m_exit_Click);
    
                notifyContextMenu.MenuItems.Add(m_open);
                notifyContextMenu.MenuItems.Add(m_close);
                notifyContextMenu.MenuItems.Add(m_exit);
                notifyIcon1.ContextMenu = notifyContextMenu;
    
                getState();
            }
    
            //关闭指定服务
            void m_close_Click(object sender, EventArgs e)
            {
                if ((bool)myService["AcceptStop"])
                {
                    myService.InvokeMethod("StopService", null);
                    this.notifyIcon1.Icon = Properties.Resources.close;
                }
                getState();
            }
    
            //启动指定服务
            void m_open_Click(object sender, EventArgs e) 
            {
                if ((string)myService["State"] == "Stopped")
                {
                    myService.InvokeMethod("StartService", null);
                }
                else if ((string)myService["State"] == "Paused")
                {
                    myService.InvokeMethod("ResumeService", null);
                }
                getState();
            }
    
            //退出程序
            void m_exit_Click(object sender, EventArgs e)
            {
                this.Dispose();  //释放内存,比第一个好。
                Application.Exit();
            }
    
            //双击通知栏图标后显示主窗口
            private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
            {
                getState();
                if (this.Visible == true)
                {
                    this.Hide();
                }
                else
                {
                    this.Show();
                    this.Activate();
                }
            }
    
            //获取即时的系统服务信息
            private void getState()
            {
                if (moc != null) //清空历史服务信息
                    moc.Dispose();
                moc = mc.GetInstances(); //获取服务列表
                foreach (ManagementObject mo in moc) //查找指定服务
                {
                    if ((string)mo["Name"] == this.textBox1.Text)
                    {
                        myService = mo;
                        break;
                    }
                }
    
                if ((string)myService["StartMode"] == "Disabled") //判断服务是否被禁用
                {
                    this.label1.Text = "Disabled";
                    this.notifyIcon1.Icon = Properties.Resources.disabled;
                }
                else if ((string)myService["State"] == "Running") //判断服务是否在运行
                {
                    this.notifyIcon1.Icon = Properties.Resources.open;
                    m_close.Checked = false;
                    m_open.Checked = true;
                    this.label1.Text = "Running";
                }
                else if ((string)myService["State"] == "Stopped") //判断服务是否已停止
                {
                    this.notifyIcon1.Icon = Properties.Resources.close;
                    m_close.Checked = true;
                    m_open.Checked = false;
                    this.label1.Text = "Stopped";
                }
                else //如果处于中间状态,间隔一段时间后重新获取服务状态
                {
                    this.label1.Text = (string)myService["State"];
                    System.Threading.Thread.Sleep(500);
                    getState();
                }
            }
    
            //重载系统默认的关闭事件,即点击主窗口的关闭叉叉时不退出程序,仅隐藏窗口(变相实现了最小化到通知栏)
            protected override void WndProc(ref Message m)
            {
                const int WM_SYSCOMMAND = 0x0112;
                const int SC_CLOSE = 0xF060;
    
                if (m.Msg == WM_SYSCOMMAND && (int)m.WParam == SC_CLOSE)
                {
                    // 屏蔽传入的消息事件 
                    this.Hide();
                    return;
                }
                base.WndProc(ref m);
            }
    
            //为了学习拖动事件,这里增加了一个隐藏的小功能:鼠标在标签处按下时能拖动标签
            private void label2_MouseDown(object sender, MouseEventArgs e)
            {
                this.label2.DoDragDrop(this.label2, DragDropEffects.Move);
            }
            
            private void textBox1_DragEnter(object sender, DragEventArgs e) //当标签拖入到输入框后鼠标出现拖动标志
            {
                e.Effect = DragDropEffects.Move;
            }
    
            private void textBox1_DragDrop(object sender, DragEventArgs e) //当拖入的标签在输入框释放后恢复默认的服务名字
            {
                this.textBox1.Text = "MSSQL$SQLEXPRESS";
            }
        }
    }

     

    关于“最小化到通知栏”

    许多有通知栏图标的应用在关闭主窗口后并没有退出程序,而仅仅是“最小化到通知栏”。

    之前代码中就利用重载关闭消息 protected override void WndProc(ref Message m) 实现了这一点。

    重写WndProc函数,可以捕捉所有窗口发生的消息。这样,我们就可以"篡改"传入的消息,而人为的让窗口改变行为。

    这里再补充一些Windows中常见的消息类型,如下只为部分:

    • WM_NULL = $0000;
    • WM_CREATE = $0001;
      应用程序创建一个窗口
    • WM_DESTROY = $0002;
      一个窗口被销毁
    • WM_MOVE = $0003;
      移动一个窗口
    • WM_SIZE = $0005;
      改变一个窗口的大小
    • WM_ACTIVATE = $0006;
      一个窗口被激活或失去激活状态;
    • WM_SETFOCUS = $0007;
      获得焦点后
    • WM_KILLFOCUS = $0008;
      失去焦点
    • WM_ENABLE = $000A;
      改变enable状态
    • WM_SETREDRAW = $000B;
      设置窗口是否能重画
    • WM_SETTEXT = $000C;
      应用程序发送此消息来设置一个窗口的文本
    • WM_GETTEXT = $000D;
      应用程序发送此消息来复制对应窗口的文本到缓冲区
    • WM_GETTEXTLENGTH = $000E;
      得到与一个窗口有关的文本的长度(不包含空字符)
    • WM_PAINT = $000F;
      要求一个窗口重画自己
    • WM_CLOSE = $0010;
      当一个窗口或应用程序要关闭时发送一个信号
    • WM_QUERYENDSESSION = $0011;
      当用户选择结束对话框或程序自己调用ExitWindows函数
    • WM_QUIT = $0012;
      用来结束程序运行或当程序调用postquitmessage函数
    • WM_QUERYOPEN = $0013;
      当用户窗口恢复以前的大小位置时,把此消息发送给某个图标
    • WM_ERASEBKGND = $0014;
      当窗口背景必须被擦除时(例在窗口改变大小时)
    • WM_SYSCOLORCHANGE = $0015;
      当系统颜色改变时,发送此消息给所有顶级窗口
    • WM_ENDSESSION = $0016;
      当系统进程发出WM_QUERYENDSESSION消息后,此消息发送给应用程序,通知它对话是否结束

    完整的消息类型代码见:http://www.cnblogs.com/KC-Mei/p/4334177.html

  • 相关阅读:
    疲劳原理
    golang中的 time 常用操作
    access与excel
    数据结构正式篇!初探!!
    数据结构复习之C语言malloc()动态分配内存概述
    C语言字符数组与字符串
    数据结构复习之C语言指针与结构体
    c语言数组
    数据结构
    C语言腾讯课堂(一)
  • 原文地址:https://www.cnblogs.com/KC-Mei/p/4334179.html
Copyright © 2011-2022 走看看