自己动手写工具----签到器
来源:互联网 发布:查车架号软件 编辑:程序博客网 时间:2024/06/05 08:16
最近公司没有什么项目,想通过项目练练手的机会也没有,只能自己学习了,因此空下来的时间也挺多的,就打开网页看看吧,哎,一打开就让签到(像什么百度知道啊、百度云盘啊之类的),我签到的目的是获取积分,便于下载资料^_^,真是烦的很,要是有个工具能帮助我全自动处理该有多好,想着想着大概的思路就出来了,无非就是开启进程,传入参数,确定坐标,点击。OK啦啊哈哈~ 起来码砖了……
好了,不闲聊了,干活,先上效果图。(我对win7的毛玻璃界面情有独钟……^_^)
二、功能概览
总体来说,这款小工具就是打开IE浏览器,输入地址,然后通过API给鼠标定位,在模拟鼠标点击的过程。但是在写代码的过程中,发现其实它不仅仅可以打开浏览器,还可以打开各种Windows下的工具,但是相对于浏览器的签到功能,还是比较麻烦的,因为打开Windows下的工具后需要的操作比较复杂,而这个工具当初的定位也仅仅是签到(点击一下)。此外,这个小工具还可以添加任务、批量执行任务,添加任务时,首先把中间的三个文本框填好,也就是任务名称、进程名称、进程参数,详细的内容参考上面的截图,除了这些参数,还需要确定鼠标点击的位置,在指定的位置点击鼠标右键,就可以将任务中需要点击的位置存储起来,每点击一次,该坐标都会更新一次。所有的参数都满足了之后,最后单击“新增任务”,那么一个任务就建立好了,以后就可以通过签到器来帮你实现了~~。另外,下面有两个线程休眠时间,一个是任务与任务之间的,另一个是单个任务之内的。在执行任务的过程中,需要将指定的线程Sleep,否则程序执行太快,浏览器还没有打开,程序就结束了,岂不是很悲催~~~~所以这就需要设置线程内的休眠时间。那么线程间的休眠呢,其实这个倒无所谓了,怎么设置都可以,因为它不会影响任务的执行,不过为了不把我的签到器累坏,还是设置了2秒钟~~~~~~~哈哈。另外,任务的存储我是采用XML格式的文件进行存储,因为数据量不是很大,读写操作也比较方便。
三、功能详解
首先,签到器中用到了全局的鼠标钩子,运用鼠标钩子的目的是可以使得鼠标在脱离Winform窗体后,仍然能够捕获鼠标的消息,如鼠标的移动、按键的按下等,当移动鼠标的时候,最上方的X、Y坐标是实时变化的,当单击鼠标右键时,可以记录单击时的坐标信息,作为新建任务的一部分信息。这一块用到了WinAPI的函数SetWindowsHookEx,具体代码如下:
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);
安装钩子,代码如下:
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 //如果卸下钩子失败11 if (!(retMouse)) throw new Exception("UnhookWindowsHookEx failed.");12 }
最重要的一步,监听鼠标消息,代码如下:
1 private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam) 2 { 3 //如果正常运行并且用户要监听鼠标的消息 4 if ((nCode >= 0) && (OnMouseActivity != null)) 5 { 6 MouseButtons button = MouseButtons.None; 7 int clickCount = 0; 8 9 switch (wParam)10 {11 case WM_LBUTTONDOWN:12 button = MouseButtons.Left;13 clickCount = 1;14 break;15 case WM_LBUTTONUP:16 button = MouseButtons.Left;17 clickCount = 2;18 break;19 case WM_LBUTTONDBLCLK:20 button = MouseButtons.Left;21 clickCount = 3;22 break;23 case WM_RBUTTONDOWN:24 button = MouseButtons.Right;25 clickCount = 4;26 break;27 case WM_RBUTTONUP:28 button = MouseButtons.Right;29 clickCount = 5;30 break;31 case WM_RBUTTONDBLCLK:32 button = MouseButtons.Right;33 clickCount = 6;34 break;35 }36 37 //从回调函数中得到鼠标的信息 38 MouseHookStruct MyMouseHookStruct = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));39 MouseEventArgs e = new MouseEventArgs(button, clickCount, MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y, 0);40 //if(e.X>700)return 1;//如果想要限制鼠标在屏幕中的移动区域可以在此处设置 41 OnMouseActivity(this, e);42 }43 return CallNextHookEx(hMouseHook, nCode, wParam, lParam);44 }
最后在MainForm中,实例化并绑定委托方法就可以了。代码如下:
public MainFrom() { InitializeComponent(); mouse = new MouseHookEvents(); mouse.OnMouseActivity += new MouseEventHandler(mouse_OnMouseActivity); mouse.Start(); task = new Task(); } private void mouse_OnMouseActivity(object sender, MouseEventArgs e) { txt_X.Text = e.X.ToString(); txt_Y.Text = e.Y.ToString(); //使用鼠标右键对当前坐标进行存储 if (e.Button == MouseButtons.Right) { SavePoint(); lblMsg.Text = string.Format("当前坐标(X,Y)=({0},{1})已存储", txt_X.Text, txt_Y.Text); } }
OK,到这里鼠标消息的捕获工作就完成了。下面说说数据的存储,如下XML代码就是存储任务数据的结构:
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节点的操作。
public static List<Task> GetXmlTaskList() { doc.Load(path);//注意Load数据 XmlNodeList list = doc.SelectNodes("tasks/task"); List<Task> tasks = new List<Task>(); foreach (XmlElement item in list) { Task task = new Task(); task.Name = item.SelectSingleNode("./taskName").InnerText; task.Application = item.SelectSingleNode("./application").InnerText; task.Url = item.SelectSingleNode("./param").InnerText; task.PositionX = item.SelectSingleNode("./position/x").InnerText.ToInt(); task.PositionY = item.SelectSingleNode("./position/y").InnerText.ToInt(); tasks.Add(task); } return tasks; }
然后在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下的任务,结合多步定制还可以执行其他应用程序,那这个小玩意儿的功能就丰富了。各位大神觉得有改进的意见或建议尽管提出,小弟感激不尽~~如果觉得好玩儿就给个赞吧~\(≧▽≦)/~
- 自己动手写工具----签到器
- 自己动手写工具----签到器
- 自己动手写工具----签到器(升级版)
- 自己动手写操作系统 开发工具
- 自己动手写一个野指针检查工具
- 自己动手写空间配置器
- 自己动手写编译器、链接器
- 自己动手写垃圾收集器
- 自己动手写ehcache工具类和配置文件ehcache.xml
- 反编译不完全的代码(自己动手写开发工具总结)
- 自己动手写basic解释器(一)
- 自己动手写basic解释器(二)
- 自己动手写basic解释器(三)
- 自己动手写basic解释器(四)
- 自己动手写basic解释器(五)
- 自己动手写basic解释器(六)
- 自己动手写basic解释器(七)
- 自己动手写一个APK安装器(一)
- C#数值的大小范围限制处理.
- LA3415保守的老师
- webService xml解析 android测试 linux 学习-----博客大搜集
- Android开发:分享文字跟多张图片到微信朋友圈
- 电子政务大数据的根基——部门间信息共享与服务平台
- 自己动手写工具----签到器
- 问题解决——基于MSCOMM32.OCX控件的类在客户机不能创建控件
- LA3602DNA序列
- Android 解决 HorizontalScrollView 里的内容滑动不全的问题
- 循环卷积和线性卷积
- JQuery鼠标经过弹出气泡状提示框
- cc2538平台下的Contiki基本试验
- LA3635派
- 几篇有关 systemtap kdump crash perf 比较实用工具的转载