C#制作QQ截图的自动框选功能的个人思路(二)<设置Hook>

长平狐 发布于 2012/12/10 17:21
阅读 213
收藏 0

上一篇介绍了一下我的一个个人思路而已、、这一篇来分析分析代码、、、

主要分为两大部分 第一部分 就是 那个自动框选的那部分了啊 第二部分 就是设置Hook(不然窗体一直禁用啊)

先来说说Hook 也就是 钩子 哎哟 叫我说 我也不怎么说的清楚 好吧 就不百度了 根据我的个人理解来说说吧 注意是 个人理解啊

首先呢 平时 我们敲键盘 点 鼠标 的时候  比如 敲键盘   比如我们现在在qq聊天 现在我们正在打字 比如现在我按下了a

现在我们是在键盘上按下了 a 然后呢 键盘上面不是有一条线(好吧无线就算了吧) 然后呢根据这个线 键盘把a传到了机箱 然后呢(处理处理、、)然后呢操作系统接收到了这个按键消息(按下了a) 然后操作系统呢 把这个按键消息 投放到 windows的消息列队中(哎呦 就当是处理消息然后把消息分配到相应地方吧 就相当于邮局) 然后消息列队 根据情况呢(就相当于邮局送快递) 把这个按键消息(a)发送给qq程序 然后 这个按键a就到qq程序上面呢(好吧 弹出来的是输入法 a发送到了输入法 貌似输入法的运行原理就是Dll注入然后打字的时候把按键拦截?、、呃呃呃  我猜的 、、、)  然后Hook了就是在这个消息列队里面安插一个间谍、、比如 我在里面发现a被按下了 我可以把它拦截下来 或者做一些我的处理 或者不管他  好吧正如我刚才说说 安插间谍、、那个这个间谍是什么呢?、、就是回调函数、、当Hook事件发送的时候 会调用回调函数(间谍) 这与这个间谍要干什么 那就看你代码怎么写了、、 很明显 我们这个程序中 这个间谍只需要去监听 鼠标是否按下就是了 然后 根据间谍回报的消息决定窗体是否恢复禁用、、

哎哟 至于Hook什么的这里就不多做讲解了 我讲的对不对我都还不知道呢、、、

得 一次性把Hook的代码放上来 为了避免代码太多杂乱 所以设置Hook的代码我写到了一个类里面 而且 我也觉得上面代码很详细了

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Diagnostics;
using System.Runtime.InteropServices;

namespace AutoDrawRect
{
    public class MouseHook
    {
        //好吧这个没有用到
        private bool isSet;
        public bool IsSet {
            get { return isSet; }
        }
        //这个也没有用到
        private int handleOfHook;
        public int HandleOfHook {
            get { return handleOfHook; }
        }
        //这个还是没有用到、、、淡定!
        private bool isStopMsg;
        public bool IsStopMsg {
            get { return isStopMsg; }
            set { isStopMsg = value; }
        }
        //自己定义了一个事件 放到Hook里面去
        public delegate void MEventhandler(object sender, MouseInfoEventArys e);
        public event MEventhandler HooKMouseEvent;

        [DllImport("user32.dll")]//设置钩子  第二个参数为回调函数指针
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hmod, int dwThreadid);
        [DllImport("user32.dll")]//传递到下一个钩子
        public static extern int CallNextHookEx(int hHook, int nCode, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]//卸载钩子
        public static extern bool UnhookWindowsHookEx(int hHook);
        [DllImport("kernel32.dll")]//获取模块句柄  
        public static extern IntPtr GetModuleHandle(string lpModuleName);
        
        public const int WH_MOUSE_LL = 14;//全局鼠标Hook 7是局部的 13全局键盘 2局部键盘
        public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);//话说c#里面委托就是函数指针?、

        private const int WM_LBUTTONDOWN = 0x201;   //在Hook里面判断是否左键点下
        private const int WM_RBUTTONUP = 0x205;     //在Hook里面判断是否右键抬起

        public struct POINT {//鼠标位置的结构体
            public int x;
            public int y;
        }
        public struct MouseLLInfo {//全局鼠标Hook的结构体
            public POINT pt;    //其实这里可以用Point只是这个新建的类里面没有应用System.Windows.Forms(应该是这个)
            public int mouseData;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }

        GCHandle gc;//好吧 话说就是应为这个东西害得我研究了两天 没有这个的话 程序运行一会儿就提示崩溃了
        //因为垃圾回收期把我的回调函数当垃圾收了 所以运行程序的时候 一会儿就提示我 一个垃圾的回调导致程序崩溃
        //在非托管调用托管的时候 必须保持托管代码的或活动性 大概就这个意思 反正就是被收废品的收了、害的我用.net3.5用其他方式设置Hook

        public int MouseHookProcedure(int nCode, IntPtr wParam, IntPtr lParam) {//这个就是回调函数了
            if (nCode >= 0 && HooKMouseEvent != null) {//先判断是否事件被绑定(感觉有点多余的判断 丫的我不在上面绑定 我写Hook干嘛)
                //话说是把内存的什么什么转换成结构体
                MouseLLInfo mouseInfo = (MouseLLInfo)Marshal.PtrToStructure(lParam, typeof(MouseLLInfo));
                Btn btn = Btn.None;         //自己定义的一个枚举 里面只有三个值
                if (wParam == (IntPtr)WM_LBUTTONDOWN) {         //如果左键被点下
                    btn = Btn.LeftDowm;
                } else if (wParam == (IntPtr)WM_RBUTTONUP) {    //如果右键被抬起
                    btn = Btn.RightUp;
                }
                //好吧 我就不知道当时我怎么想的 在Hook里面获取的坐标 有负数的现象 所以在那边 我没用这个坐标
                MouseInfoEventArys e = new MouseInfoEventArys(btn, mouseInfo.pt.x, mouseInfo.pt.y);
                HooKMouseEvent(this, e);//触发绑定到这个上面的事件
            }
            return CallNextHookEx(handleOfHook, nCode, wParam, lParam);//继续下一个钩子
        }
        
        public bool SetMouseHook() {    //设置Hook
            if (isSet) {//如果已经设置了 就不要设置啦、、、
                return false;
            }
            HookProc MouseCallBack = new HookProc(MouseHookProcedure);
            handleOfHook = SetWindowsHookEx(WH_MOUSE_LL, MouseCallBack, 
                GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
            if (handleOfHook != 0) {//如果设置成功、、
                gc = GCHandle.Alloc(MouseCallBack);//这个就是那个什么什么、、然后我的回调就不会被收废品的拣去了
                isSet = true;
                return true;
            }
            return false;
        }
        public bool UnLoadMouseHook() {
            if (!isSet) {//如果装都没有装那么久不要卸载啦、、
                return false;
            }
            if (UnhookWindowsHookEx(handleOfHook)) {
                gc.Free();//将回调释放掉、、
                isSet = false;
                return true;
            }
            return false;
        }

    }

    public enum Btn//我只感觉到这三个有用、(应该是两个 左键点下 右键抬起)
    {
        LeftDowm, RightUp, None
    }
    public class MouseInfoEventArys {//话说定义事件的时候都是这么写的 所以我也弄一个内出来保存事件参数
        private int x;//坐标 多余的后来才发现 鼠标慢慢贴近屏幕边缘的时候 3 2 1 0 -1 、、丫的 负数都出来了
        public int X {
            get { return x; }
        }

        private int y;//坐标
        public int Y {
            get { return y; }
        }

        private Btn mBtn;
        public Btn MBtn {
            get { return mBtn; }//鼠标的情况
        }
        public MouseInfoEventArys(Btn btn,int x,int y) {//构造器
            mBtn = btn;
            this.x = x;
            this.y = y;
        }

    }
}

这里我自己定义了一个事件、、然后再程序中 绑定这个事件来完成要做的事情 其实后来 我感觉没有必要弄这么复杂 比如 那个Hook里面获取到的x y坐标都没有用 因为那个坐标会出现负数的情况 所以感觉不爽
效果图:

OH

 


原文链接:http://blog.csdn.net/crystal_lz/article/details/7327277
加载中
返回顶部
顶部