【原創】本身動手寫工具----簽到器[Beta 1.0]

寫在前面

最近公司沒有什麼項目,想經過項目練練手的機會也沒有,只能本身學習了,所以空下來的時間也挺多的,就打開網頁看看吧,哎,一打開就讓簽到(像什麼百度知道啊、百度雲盤啊之類的),我簽到的目的是獲取積分,便於下載資料^_^,真是煩的很,要是有個工具能幫助我全自動處理該有多好,想着想着大概的思路就出來了,無非就是開啓進程,傳入參數,肯定座標,點擊。OK啦啊哈哈~ 起來碼磚了……
好了,不閒聊了,幹活,先上效果圖。(我對win7的毛玻璃界面情有獨鍾……^_^)php

                      

功能概覽

整體來講,這款小工具就是打開IE瀏覽器,輸入地址,而後經過API給鼠標定位,在模擬鼠標點擊的過程。可是在寫代碼的過程當中,發現其實它不只僅能夠打開瀏覽器,還能夠打開各類Windows下的工具,可是相對於瀏覽器的簽到功能,仍是比較麻煩的,由於打開Windows下的工具後須要的操做比較複雜,而這個工具當初的定位也僅僅是簽到(點擊一下)。此外,這個小工具還能夠添加任務、批量執行任務,添加任務時,首先把中間的三個文本框填好,也就是任務名稱、進程名稱、進程參數,詳細的內容參考上面的截圖,除了這些參數,還須要肯定鼠標點擊的位置,在指定的位置點擊鼠標右鍵,就能夠將任務中須要點擊的位置存儲起來,每點擊一次,該座標都會更新一次。全部的參數都知足了以後,最後單擊「新增任務」,那麼一個任務就創建好了,之後就能夠經過簽到器來幫你實現了~~。另外,下面有兩個線程休眠時間,一個是任務與任務之間的,另外一個是單個任務以內的。在執行任務的過程當中,須要將指定的線程Sleep,不然程序執行太快,瀏覽器尚未打開,程序就結束了,豈不是很悲催~~~~因此這就須要設置線程內的休眠時間。那麼線程間的休眠呢,其實這個倒無所謂了,怎麼設置均可以,由於它不會影響任務的執行,不過爲了避免把個人簽到器累壞,仍是設置了2秒鐘~~~~~~~哈哈。另外,任務的存儲我是採用XML格式的文件進行存儲,由於數據量不是很大,讀寫操做也比較方便。這裏須要注意的是通常的網站簽到前提是須要登陸,因此必須在瀏覽器上有本身登陸信息的緩存才能夠哦~html

功能詳解

首先,簽到器中用到了全局的鼠標鉤子,運用鼠標鉤子的目的是可使得鼠標在脫離Winform窗體後,仍然可以捕獲鼠標的消息,如鼠標的移動、按鍵的按下等,當移動鼠標的時候,最上方的X、Y座標是實時變化的,當單擊鼠標右鍵時,能夠記錄單擊時的座標信息,做爲新建任務的一部分信息。這一塊用到了WinAPI的函數SetWindowsHookEx,具體代碼以下:git

 1 //裝置鉤子的函數  
 2 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
 3 public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
 4 
 5 //卸下鉤子的函數  
 6 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
 7 public static extern bool UnhookWindowsHookEx(int idHook);
 8 
 9 //下一個鉤掛的函數  
10 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
11 public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);
12 
13 //聲明委託
14 public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);

安裝鉤子,代碼以下:github

 1 public void Start()
 2 {
 3       //安裝鼠標鉤子  
 4       if (hMouseHook == 0)
 5       {
 6           //生成一個HookProc的實例.  
 7           MouseHookProcedure = new HookProc(MouseHookProc);
 8 
 9           //hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]), 0);
10          hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
11 
12          //若是裝置失敗中止鉤子  
13          if (hMouseHook == 0)
14          {
15              Stop();
16              throw new Exception("SetWindowsHookEx failed.");
17          }
18      }
19 }

卸載鉤子,代碼以下:瀏覽器

 1 public void Stop()
 2 {
 3      bool retMouse = true;
 4      if (hMouseHook != 0)
 5      {
 6          retMouse = UnhookWindowsHookEx(hMouseHook);
 7          hMouseHook = 0;
 8      }
 9      //若是卸下鉤子失敗
10      if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed.");
11 }

 最重要的一步,監聽鼠標消息,代碼以下:緩存

 1 private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam) 
 2 {
 3      //若是正常運行而且用戶要監聽鼠標的消息
 4      if ((nCode >= 0) && (OnMouseActivity != null)) {
 5          MouseButtons button = MouseButtons.None;
 6          int clickCount = 0;
 7 
 8          switch (wParam) {
 9          case WM_LBUTTONDOWN:
10              button = MouseButtons.Left;
11              clickCount = 1;
12              break;
13          case WM_LBUTTONUP:
14              button = MouseButtons.Left;
15              clickCount = 2;
16              break;
17          case WM_LBUTTONDBLCLK:
18              button = MouseButtons.Left;
19              clickCount = 3;
20              break;
21          case WM_RBUTTONDOWN:
22              button = MouseButtons.Right;
23              clickCount = 4;
24              break;
25          case WM_RBUTTONUP:
26              button = MouseButtons.Right;
27              clickCount = 5;
28              break;
29          case WM_RBUTTONDBLCLK:
30              button = MouseButtons.Right;
31              clickCount = 6;
32              break;
33          }
34 
35          //從回調函數中獲得鼠標的信息
36          MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
37          MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);
38          //if(e.X>700)return 1;//若是想要限制鼠標在屏幕中的移動區域能夠在此處設置
39          OnMouseActivity(this, e);
40      }
41      return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
42 }

最後在MainForm中,實例化並綁定委託方法就能夠了。代碼以下:多線程

 1 public MainFrom()
 2 {
 3     InitializeComponent();
 4     mouse = new MouseHookEvents();
 5     mouse.OnMouseActivity += new MouseEventHandler(mouse_OnMouseActivity);
 6     mouse.Start();
 7     task = new Task();
 8 }
 9 
10 
11 private void mouse_OnMouseActivity(object sender, MouseEventArgs e)
12 {
13     txt_X.Text = e.X.ToString();
14     txt_Y.Text = e.Y.ToString();
15     //使用鼠標右鍵對當前座標進行存儲
16     if (e.Button == MouseButtons.Right)
17     {
18         SavePoint();
19         lblMsg.Text = string.Format("當前座標(X,Y)=({0},{1})已存儲", txt_X.Text, txt_Y.Text);
20     }
21 }

OK,到這裏鼠標消息的捕獲工做就完成了。下面說說數據的存儲,以下XML代碼就是存儲任務數據的結構:app

 1 <tasks>
 2     <task>
 3         <taskName>百度雲盤</taskName>
 4         <application>iexplore.exe</application>
 5         <param>http://www.baiduyun.me/forum.php</param>
 6         <position>
 7             <x>1244</x>
 8             <y>140</y>
 9         </position>
10     </task>
11 </tasks>

而後創建Task實體,包括對Task的增長、修改和執行等操做,這裏比較簡單,無非就是對XML節點的操做。函數

 1 public static List<Task> GetXmlTaskList()
 2 {
 3     doc.Load(path);//注意Load數據
 4     XmlNodeList list = doc.SelectNodes("tasks/task");
 5     List<Task> tasks = new List<Task>();
 6     foreach (XmlElement item in list)
 7     {
 8         Task task = new Task();
 9         task.Name = item.SelectSingleNode("./taskName").InnerText;
10         task.Application = item.SelectSingleNode("./application").InnerText;
11         task.Url = item.SelectSingleNode("./param").InnerText;
12         task.PositionX = item.SelectSingleNode("./position/x").InnerText.ToInt();
13         task.PositionY = item.SelectSingleNode("./position/y").InnerText.ToInt();
14         tasks.Add(task);
15     }
16     return tasks;
17 }

而後在MainForm中取出任務,依次執行。對了,前面的增長任務無非就是執行任務的反向操做,向XML中添加節點。
還有一個問題,當執行任務時,若是執行任務的線程在UI主線程中時,簽到器的界面會出現假死的狀況,這時候就須要採用多線程來進行處理,避免主線程的休眠致使的假死,代碼以下:工具

 1  //執行任務列表
 2  private void button2_Click(object sender, EventArgs e)
 3  {
 4      //ExcuteTask()
 5      List<Task> tasks = TaskModel.GetTaskList();
 6      new Thread(() =>
 7      {//開啓新線程,避免與主線程UI衝突,致使界面假死
 8          foreach (Task item in tasks)
 9          {
10              ExcuteTask(item);
11              Thread.Sleep((int)numericUpDown1.Value*BASENUM);
12          }
13      }).Start();
14  }

 開啓進程使用Process類來完成,代碼以下:

 1  public void ExcuteTask(Task task)
 2  {
 3      ProcessStartInfo ps = new ProcessStartInfo(task.Application, task.Url);
 4      Process.Start(ps);
 5      Thread.Sleep((int)numericUpDown2.Value * BASENUM);
 6      //設置鼠標位置
 7      MouseEvents.SetCursorPosition(task.PositionX, task.PositionY);
 8      //模擬鼠標單擊
 9      MouseEvents.MouseClick();
10  }

至此,簽到工具基本的功能就實現了,原來懶人不是這麼好作的呀啊哈哈,這就是爲一個「懶」字付出的代價~~~~

總結

經過製做這個小玩意兒,也鞏固和擴展了本身的知識,寫代碼的過程當中也遇到了一些問題,可是都被一個一個地解決掉了,只有這樣,本身的印象纔會加深,下一次纔不會在同一塊石頭上絆倒。好比,前面遇到了一個棘手的問題,關於鉤子的卸載,每次關閉程序,都會提示鉤子卸載失敗!最後發現,卸載鉤子寫在了建立鉤子的類的析構函數中,把卸載的函數放在Form_CLosed事件中就OK了。這只是一個初級的版本,我還設想了一些新的功能,若是能實現Task的Step定製就行了,就能夠突破每次只能單擊一次的侷限了。還有,不只僅是執行IE下的任務,結合多步定製還能夠執行其餘應用程序,那這個小玩意兒的功能就豐富了。各位大神以爲有改進的意見或建議儘管提出,小弟感激涕零~~若是以爲好玩兒就給個贊吧~\(≧▽≦)/~

補充點兒

下班把項目帶回家,我發現出現Visual Studio無可用源,不可用源的錯誤,就是不能進入調試。原來是本身的IDE設置問題,這裏提供個辦法,進入工具->選項->調試->常規->去掉「要求源文件與原始版本徹底匹配」複選框就OK啦~~

另外,下一個版本準備添加一些新功能進去,那就不僅僅是個簡單的簽到器了,好比:

(1)任務按照進程進行分類:用IE就是執行IE的任務,與其餘(如資源管理器等)無關

(2)新增其餘的進程任務:如上面提到的資源管理器,咱們平常工做中經常使用的文件夾就那麼幾個,但每次都要雙擊,雙擊,再雙擊才能進入目標文件夾,簡直是浪費時間,有了這個東東,就能夠把最經常使用的目錄放在眼前,固然你喜歡建立快捷方式也無所謂,蘿蔔青菜,各有所愛,我強調的只是集中管理,把懶人精神發揚到底~

(3)每執行完一個任務關閉任務窗口:目前的功能比較粗糙,一兩個任務還好,一旦加到十個八個就會發現,窗口是一個接一個地往外躥,簡直受不了啊 ...

(4)對簽到性質的任務進行」已簽到「過濾:若是當天的簽到任務完成了,那麼再次運行時,直接忽略已簽到的任務,直接去執行因各類緣由而沒執行簽到的任務

嗯,暫時就這些吧,謝謝你們,不早了,洗洗睡了 ... ...

 補充GitHub地址:請點我

 做者:悠揚的牧笛

 博客地址:http://www.cnblogs.com/xhb-bky-blog/p/4112441.html

 聲明:本博客原創文字只表明本人工做中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關係。非商業,未受權貼子請以現狀保留,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。

相關文章
相關標籤/搜索