c#遊戲進程殺手
我認為寫博客還是比較重要的,特別是短時間寫出一個含有新知識點的軟件。這樣總結下這次編程經驗和再捋順一下這次編程思路。首先來談談為什麽想做這個小程序,一是感覺自己太貪玩想控制一下,二是也鍛煉下自己的編程。好,話不多說進入正題吧。
文件源代碼在這個https://i.cnblogs.com/Files.aspx?order=1下面。名字是ApplicationControl。不過使用的時候你還是要到子窗體中設置你的遊戲庫,我這裏只有WeGame、LOL登陸程序的進程名稱。源碼有點亂,見諒。如需改進,請多指教。
首先給大家展示一下程序結果圖:
這裏的原理很簡單,就是寫一個監視進程的函數如果發現進程列表中有相同名字的進程則調用process類中的kill方法殺死進程,再設置一個計時器來循環調用該函數即可。
首先我們窗體加載函數中調用一個初始化函數。
Initial函數:
1 public void Initial() 2 { 3 timer1.Enabled = false; 4 for (int i = 0; i < 24; i++) 5 { 6 Hour.Items.Add(i); //combox控件名稱 7 } 8 Hour.SelectedIndex = 0; 9 for (inti = 0; i < 60; i++) 10 { 11 Minute.Items.Add(i); 12 Sceond.Items.Add(i); 13 } 14 Minute.SelectedIndex = 0; 15 Sceond.SelectedIndex = 0; 16 LoadTime(); //後面解釋說明 17 string fileName = @"\gamelist.txt"; //後面解釋說明 首次加載程序 18 string dirpath = System.Environment.CurrentDirectory; 19 string path = dirpath + fileName;
20 if (File.Exists(path)) 21 { 22 try 23 { 24 StreamReader sr = new StreamReader(path, Encoding.UTF8); 25 string line; 26 while ((line = sr.ReadLine()) != null) 27 { 28 gamename.Add(line); 29 textBox1.AppendText(line + "\r\n"); 30 } 31 sr.Dispose(); 32 } 33 catch { }; 34 } 35 36 }
其中Hour、Minute、sceond(秒翻譯錯了,應該是second,哈哈)分別是Combox控件的名稱。計時器控件則是Timer1。
之後就可以為啟動button寫函數了。
1 private void button3_Click(object sender, EventArgs e) 2 { 3 flag = 1; 4 timer1.Enabled = true; 5 timer1.Interval = 500; 6 h = Convert.ToInt32(Hour.SelectedItem); //用戶選擇的時間 7 m = Convert.ToInt32(Minute.SelectedItem); 8 s = Convert.ToInt32(Sceond.SelectedItem); 9 TS = new TimeSpan(h, m, s); //設置一個TimeSpan對象來存放時間 10 }
點擊按鈕,告訴計時器開始工作,並把用戶選擇的時間存儲起來。
1 //計時器函數。 2 private void timer1_Tick(object sender, EventArgs e) 3 { 4 if (timer1.Enabled == true) 5 { 6 GameControl();//調用進程檢查函數,如果存在則查殺 7 string str1 = TS.Hours.ToString() + ":" + TS.Minutes.ToString() + ":" + TS.Seconds.ToString(); 8 time.Text = str1; //設置時間標簽 9 string str2 = TSsum.Hours.ToString() + ":" + TSsum.Minutes.ToString() + ":" + TSsum.Seconds.ToString(); 10 label8.Text = str2; //總時間顯示標簽 11 TS = TS.Subtract(new TimeSpan(0, 0, 1)); //TS 每隔一秒設置時間減一倒計時效果 12 TSsum = TSsum.Add(new TimeSpan(0, 0, 1)); //TSsum 每隔一秒總時間加一 13 if (TS.TotalSeconds < 0.0) //倒計時完畢 14 { 15 timer1.Enabled = false; 16 MessageBox.Show("你離成功又進了一步"); 17 flag = 0; 18 flagtime = 1; 19 LoadTime(); //另外說明 20 } 21 } 22 }
每次調用GameControl去查殺進程。
1 public void GameControl() 2 { 3 List<Process[]> pro = new List<Process[]>(); //進程的泛型集合 因為可能對多個進程進行監視 可以理解為裝箱 4 Process[] gameProcess =Process.GetProcessesByName("Taskmgr"); //防止用任務管理器關閉這個程序 5 pro.Add(gameProcess); 6 //gamename是所有遊戲進程名字的泛型集合。 7 for (int i = 0; i < gamename.Count; i++) 8 { 9 gameProcess = Process.GetProcessesByName(gamename[i].Replace(".exe", "").Trim()); 10 pro.Add(gameProcess); 11 } 12 try 13 { 14 for (int i = 0; i < pro.Count;i++ ) 15 { 16 Process[] game = pro[i]; //可以理解為拆箱 17 foreach (Process p in game) 18 { 19 p.Kill(); 20 } 21 } 22 } 23 catch (Exception e) 24 { 25 26 } 27 }
這裏用一個trycatch防止程序拋異常。
這樣連任務管理器都關不了的程序,怎麽辦呢,我們還是比較人性化設置一個結束button來提前結束這個程序。只是有很多彈出框。~嘿嘿!
1 //結束按鈕 2 private void shutdown_Click(object sender, EventArgs e) 3 { 4 Thread th = new Thread(ShutDown); //開啟一個新線程運行 5 th.Start(); 6 } 7 public void ShutDown() 8 { 9 if (flag == 1) //flag 標識程序是否跑起來了 0--否 1--是 跑起來才有作用 10 { 11 DialogResult re = MessageBox.Show("能不能再堅持一會兒?", "提示", MessageBoxButtons.YesNo); 12 if (re == DialogResult.No) 13 { 14 Thread.Sleep(5000); //選擇一次否,休眠5s(給你時間冷靜下沖動的大腦) 15 re = MessageBox.Show("堅持就是勝利,不要放棄!", "提示", MessageBoxButtons.YesNo); 16 if (re == DialogResult.No) 17 { 18 Thread.Sleep(5000); 19 re = MessageBox.Show("你離成功就差一步了!", "提示", MessageBoxButtons.YesNo); 20 if (re == DialogResult.No) 21 { 22 Thread.Sleep(5000); 23 re = MessageBox.Show("想一想自己還有沒有其他更重要的事做沒做!", "提示", MessageBoxButtons.YesNo); 24 if (re == DialogResult.No) 25 { 26 Thread.Sleep(5000); 27 re = MessageBox.Show("比你牛逼的人還在努力!", "提示", MessageBoxButtons.YesNo); 28 timer1.Enabled = false; //關閉計時器 29 flagtime = 1; 30 flag = 0; //設置程序狀態--關閉 31 LoadTime(); //將這段時間加到總時間上 32 } 33 } 34 } 35 } 36 } 37 }
這裏開啟一個新線程運行這個函數是為了防止我們我們主線程休眠。如果不開,就整個程序休眠5s。開了就相當於這個函數休眠5s。
當然呢,任務管理器關不掉那我們可以點擊窗口關閉按鈕啦(不過NO way~)
1 //窗體關閉時發生 2 private void ApplicationControl_FormClosing(object sender, FormClosingEventArgs e) 3 { 4 if (flag != 0) //判斷程序是否運行 5 { 6 e.Cancel = true;//取消這個動作 7 } 8 }
到這裏我們基本已經將這個程序的主要功能做出來了。那我們再做點東西來潤色、潤色。別看看它只是修飾功能,它的難度一點都不比我們主要功能小。
首先我們不是有個叫“控制總時長”的標簽嗎:這個是記錄我們每次設置時間到結束的總時長。它的原理就是本次程序結束後,生成一個txt文件將這個時間記錄時間,如果存在這個文件則覆蓋上去,就實現了時間的刷新。當然了,我們每次首先需要在程序加載時,把這個時間讀取出來。
1 //加載、更新總時間 2 public void LoadTime() 3 { 4 string fileName = @"\sumtime.txt"; //生成一個名字為sumtime的文本文件 5 string str = System.Environment.CurrentDirectory; //程序所在路徑 6 string path = str + fileName; //路徑拼接 7 FileStream fs; 8 if (!File.Exists(path)) //如果不存在此文件(首次運行該程序) 9 { 10 fs = new FileStream(path, FileMode.Create); 11 } 12 else if (flagtime == 0) //讀取時間 窗體加載時完成 13 { 14 try 15 { 16 StreamReader sr = new StreamReader(path, Encoding.UTF8); 17 DateTime line; 18 line = Convert.ToDateTime(sr.ReadLine()); 19 hsum = line.Hour; 20 msum = line.Minute; 21 ssum = line.Second; 22 TSsum = new TimeSpan(hsum, msum, ssum); //記錄讀取的總時間 23 label8.Text = line.Hour.ToString() + ":" + line.Minute.ToString() + ":" + line.Second.ToString(); 24 sr.Dispose(); 25 } 26 catch { }; 27 }
你能看到這個函數有兩個功能,一個讀取時間、一個寫入時間,所以這個函數有兩個地方被調用到。
讀取:初始化程序時調用了(Initial());
寫入:當計時器為0時調用(timer);
當點擊結束按鈕時,設置時間並未到0(相當於強制關閉)用到了。
好了,這個功能做了。那麽我們還有一個功能沒做,那就是添加遊戲名稱到我們gamename泛型集合中,當然你可以手動gamename.add("遊戲名稱");但是我們能不能更人性化、智能化一點呢,答案肯定是可以的。
那我們要做的就是點擊“掃描全盤按鈕”。它的原理是點擊後開啟一個新窗體(子窗體)選擇要搜索的分區,如果找到了與我們遊戲庫(這也是一個泛型集合)中名稱相同的就記錄返回到我們主窗體中的gamename集合中。
先上圖
3個checkbox根據選擇狀態,返回一個值(C、D、E),點擊確定開始搜索。搜索完畢,返回找到的遊戲名稱。
這裏特別說一下checkbox的size要重新設置下,我原來以為它的大小就是那個小方框。其實它要大的多,如果間距設小了,其他的checkbox就被擋住了(效果就是只有一個),我當時做的時候卡在這裏半天,我還以為出現了靈異事件,最後問了下老師才知道。
那麽有人要問了為什麽會是C、D、E,我有F盤呢?別急。我們首先在初始化窗體時遍歷一遍盤符、統計。
1 List<string> gameBase = new List<string>(); //我們的遊戲庫 2 //窗體加載 3 private void ChooseArea_Load(object sender, EventArgs e) 4 { 5 int drivesCount = System.IO.Directory.GetLogicalDrives().Length;//獲取盤符數 6 CheckBox[] box=new CheckBox[drivesCount]; 7 int x = 110; 8 for (int i = 0; i < drivesCount;i++ ) 9 { 10 box[i] = new CheckBox(); 11 char abc =Convert.ToChar(‘C‘+i); //從C開始+1,轉成(D、E...) 12 box[i].Text = abc+ "盤"; //checkbox空間名稱 生成 13 box[i].Name=abc.ToString(); 14 box[i].Size = new Size(50,50); 15 box[i].Location = new Point(x,80); 16 groupBox1.Controls.Add(box[i]); 17 x += 55;//3個box的橫軸間距 18 } 19 gameBase.Add("tgp_daemon.exe"); //添加遊戲進程名稱 20 gameBase.Add("Client.exe"); 21 }
這樣就能生成相應的checkbox數量了。
然後點擊確定button,返回有哪些盤被選中再構建路徑去磁盤裏搜索。
1 //確定按鈕 2 private void button1_Click(object sender, EventArgs e) 3 { 4 List<string> check = new List<string>();//存儲選中狀態下的checkbox值(C盤、D盤、...) 5 foreach (Control c in groupBox1.Controls)// 遍歷groupbox容器裏的控件 6 { 7 if (c is CheckBox) //如果類型為Checkbox 8 { 9 if (((CheckBox)c).Checked == true) //判斷是否為選中狀態 10 { 11 check.Add(((CheckBox)c).Text); 12 } 13 } 14 } 15 for (int i = 0; i < check.Count; i++) 16 { 17 //構建尋找路徑(C:\\、D:\\...) 18 string path = check[0].Substring(0, 1)+":\\"; 19 FindFiles(path); //開始搜索 20 this.Close(); //搜索完畢後,自動關閉子窗口 21 } 22 }
其中最重要的一環就是FindFiles(path)函數了。我們怎樣將子窗口的搜索到的值返回給我們主窗體呢,那麽委托和事件就登場了。
public delegate void GameListDelegate(string str);//聲明委托 public event GameListDelegate GameNameUpdate;//聲明事件 public void FindFiles(string subpath) { FindFile ff = new FindFile(); //新建一個FindFile類 for (int i = 0; i < gameBase.Count; i++) { ff.getFile(subpath, gameBase[i]); //調用getFile函數,結果會存儲在lis集合裏。 textBox1.AppendText(ff.lst[i].ToString() + "\r\n");//顯示 } if (GameNameUpdate != null) //判斷事件是否被註冊 { GameNameUpdate(textBox1.Text.ToString()); } }
然後GameNameUpdate這個事件在主窗體‘掃描全盤遊戲’按鈕點擊事件裏被註冊上LoadGame;
1 private void addGame_Click(object sender, EventArgs e) 2 { 3 chooseArea ca = new chooseArea(); //實例化子窗體 4 ca.GameNameUpdate += LoadGame; //註冊LoadGame事件 5 //ca.GameNameUpdate+=new chooseArea.GameListDelegate(LoadGame); 6 ca.Show(); 7 } 8 //LoadGame函數 9 public void LoadGame(string str) 10 { 11 string fileName = @"\gamelist.txt"; 12 string dirpath = System.Environment.CurrentDirectory; 13 string path = dirpath + fileName; 14 FileStream fs; 15 if (!File.Exists(path)) 16 { 17 try 18 { 19 textBox1.Text = str; 20 Regex regex = new Regex("\r\n"); //因為子窗體傳過來的值有換行符"\r\n";這裏實例化一個正則表達式 regex類的對象來以字符串"\r\n"的形式進行分割 21 string[] name = regex.Split(str); 22 for (int i = 0; i < name.Length-1; i++)//因為分割後或多出一個""變量;所以長度-1 23 { 24 gamename.Add(name[i]); //導入gamename集合中 去查殺 25 } 26 fs = new FileStream(path, FileMode.Create); 27 StreamWriter sw = new StreamWriter(fs); 28 for (int i = 0; i < gamename.Count; i++) 29 { 30 sw.WriteLine(gamename[i]); 31 } 32 sw.Flush(); 33 sw.Close(); 34 } 35 catch { }; 36 } 37 else 38 { 39 try 40 { 41 StreamReader sr = new StreamReader(path, Encoding.UTF8); 42 string line; 43 while ((line=sr.ReadLine()) != null) 44 { 45 gamename.Add(line); 46 textBox1.AppendText(line + "\r\n"); 47 } 48 sr.Dispose(); 49 } 50 catch { }; 51 } 52 }
同樣的生成一個文本文件,下次進入程序如果有就不用再掃描全盤了。
再返回我們的子窗體中的FindFiles函數中的FindFile類,它是我們搜索文件的關鍵。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.IO; 7 namespace ChooseArea 8 { 9 class FindFile 10 { 11 public List<FileInfo> lst = new List<FileInfo>(); 12 public List<FileInfo> getFile(string path, string extName)//創建一個List<FileInfo>類型的函數 13 { 14 getdir(path, extName);//傳入路徑、文件名 15 return lst; 16 } 17 18 private void getdir(string path, string extName) 19 { 20 try 21 { 22 //獲取文件夾列表 23 string[] dirs = Directory.GetDirectories(path); 24 DirectoryInfo fdir = new DirectoryInfo(path); 25 FileInfo[] file = fdir.GetFiles(); 26 27 //當前目錄文件或目錄不為空 28 if (file.Length != 0 || dirs.Length != 0) 29 { 30 foreach (FileInfo f in file) 31 { 32 if (extName.ToLower().IndexOf(f.Name.ToLower()) >= 0) //匹配上 33 { 34 lst.Add(f); 35 } 36 } 37 foreach (string d in dirs) 38 { 39 getdir(d, extName);//遞歸 40 } 41 } 42 } 43 catch 44 { 45 46 } 47 } 48 49 } 50 }
好,這樣一個程序就做成功了。呱唧,呱唧。
c#遊戲進程殺手