最近公司沒有什麼項目,想經過項目練練手的機會也沒有,只能本身學習了,所以空下來的時間也挺多的,就打開網頁看看吧,哎,一打開就讓簽到(像什麼百度知道啊、百度雲盤啊之類的),我簽到的目的是獲取積分,便於下載資料^_^,真是煩的很,要是有個工具能幫助我全自動處理該有多好,想着想着大概的思路就出來了,無非就是開啓進程,傳入參數,肯定座標,點擊。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
聲明:本博客原創文字只表明本人工做中在某一時間內總結的觀點或結論,與本人所在單位沒有直接利益關係。非商業,未受權貼子請以現狀保留,轉載時必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接。