关于C# windows发送消息
今天终于又有一点心得啦..这一切都源于我喜欢的一个游戏. 由于在玩游戏,所以用按键精灵做了个外挂,使用后发现游戏中是针对按键精灵处理过的,当使用它一定的时间后,后隐去人物的红和蓝,让自己不能加血,够狠的!! 于是今天上午想能不能用C#来做一个类似的东西呢,过程如下: 一、获取指定坐标的颜色 在游戏中,怪物的血是显示在一个固定的地方的,所以,只要这个点没有血,那么表示当前没有怪可攻击,意思就是可以找怪了,但是这个坐标是多少我都不知道。于是,我在游戏中截了下屏,并保存了图片,把它设为桌面背景色,哈哈,我真是太聪明啦~~在程序中BUTTON下写一行:lbpoint.Text = Cursor.Position.X.ToString() + "," + Cursor.Position.Y.ToString();把鼠标放到血是最左边,也就是怪物血最少的那里,按了下空格,嘿嘿,坐标出来了:293, 35,当然是不是一次完成的,多几下就差不多了。 现在坐标出来了,怎么取它的色呢?经过一阵“摆渡”,原来windows的一个API可以实现这样的功能,OK,那就用它吧,代码如下: [DllImport("gdi32.dll")] [DllImport("gdi32.dll")] [DllImport("gdi32.dll")] static public byte GetRValue(uint color) static public byte GetGValue(uint color) static public byte GetBValue(uint color) static public byte GetAValue(uint color) static public Color GetColorOfScreen(Point screenPoint) 我现在只要调用GetColorOfScreen这个方法就可以得到相应坐标点的色了,作了下测试,OK!游戏中怪的血条色为:(255, 162, 2, 5)可以Color redColor = Color.FromArgb(255, 162, 2, 5);这可构造出色。 二、获取游戏窗口 如果按逻辑的顺序的话,这一步应该放在第一的,这里也是应用的API [DllImport("user32.dll")] IntPtr 这个东西,其实说白了就是窗口的句柄, 同时,我用进程名称要获取这个游戏窗口,如下: Process[] pros = Process.GetProcessesByName(txtProName.Text.Trim()); SetActiveWindow(pGame); BeginGame(); 三、开始游戏 先是定义一个色表示为怪物的血条Color redColor = Color.FromArgb(255, 162, 2, 5); 再定义一个点,并获取它的色: Point p = new Point(293, 35); 当这两个色相同时,那么就打怪: 不相等时,再找怪 方法是这样的: private void BeginGame() Point p = new Point(293, 35); if (gameColor == redColor) BeginGame(); BeginGame(); 四、找怪 核心: SendKeys.SendWait("{Tab}"); 向指定的窗口发送消息,SendKeys还有一个方法Send,有什么区别呢,自己试了就知道了,输出到文本文件里看就明白了,这里表示按了一下Tab这个键,关于其它键的用法如下: 键 代码 如果是一般的数据和字母,就只要写进去就可以了,如:SendKeys.SendWait("A"); 五、打怪 找怪都做好了,那打怪就好办了,我想(事实不是这样的) 把攻击键放到3这个位置, SendKeys.SendWait("3"); OK。这样就差不多了,再加个线程进去,不然,怎么停止呢~~,完整的代码如下(主要部分): Thread th = null; //开始挂机 private void btStart_Click(object sender, EventArgs e) btStart.Enabled = false; //停止挂机 private void btStop_Click(object sender, EventArgs e) btStart.Enabled = true; private void StartGame() SetActiveWindow(pGame); BeginGame(); private void BeginGame() Point p = new Point(293, 35); if (gameColor == redColor) BeginGame(); BeginGame(); private void Fight() Thread.Sleep(2000); private void FindMonster() 到这里为止,我认为就差不多了,测试: 把游戏图片设为桌面背景,打开一个记事本,在窗体中输入notepad,点开始挂机, 找到记事本,OK 由于桌面那张图片是有怪物的,输入33 OK 再把记事本最大化,找不到怪物血条了,输入tab OK。。 哈哈,,说明测试成功!! 但是,问题也出来了,进入游戏后,找怪都可以正常,就是不能按3这个键,,不知道为什么,我在自己写的窗体上都可以的~~~ 于是,再做了个窗体; protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 这样,窗体上输入的按键都会显示到控件是去,然后用刚刚那个窗口,输入这个程的名称,点开始挂机,在没有怪血条的时候是输入的Tab,OK。但有怪的时候是输入的D3而不是3,啊。。这是怎么回事呢,于是我把打怪那一行改为:SendKeys.SendWait("D3");但是由于下午上班了,没时间测试,晚上回去再试试吧。 后记: 我还用鼠标点示来实现触发打怪,取到攻击技能的坐标, [Flags]
[DllImport("user32.dll")] SetCursorPos(418, 744); MouseEventFlag 这个枚举基本上所有的鼠标事件都有了,不错,可以做很多事啦,但在游戏中还是不行,我怀疑是游戏处理了这种消息的发送的,不让这种模拟的消息传入,那样的话,做外挂可以麻烦了,不过。今天还是有不少的体会的,因为我一开始什么都不懂,到后来还是学到点东西啦~ [DllImport("user32.dll")] 表示调用Windows的一个DLL,它是Windows自带的,不过要对它有所了解才能用它,我们用的时候只要定义好它的方法就行了,实现交给它自身去处理,就是extern |