前面我们讲述了一个按键精灵的实现,现在的问题如何监视HP 既血的变化,来控制 补血.
先看下面几个API函数:
[ DllImport ( "gdi32.dll" ) ]
private static extern bool BitBlt (
IntPtr hdcDest, // 目标设备的句柄
int nXDest, // 目标对象的左上角的X坐标
int nYDest, // 目标对象的左上角的X坐标
int nWidth, // 目标对象的矩形的宽度
int nHeight, // 目标对象的矩形的长度
IntPtr hdcSrc, // 源设备的句柄
int nXSrc, // 源对象的左上角的X坐标
int nYSrc, // 源对象的左上角的X坐标
int dwRop // 光栅的操作值
);
[ DllImport ( "gdi32.dll" ) ]
private static extern IntPtr CreateDC (
string lpszDriver, // 驱动名称
string lpszDevice, // 设备名称
string lpszOutput, // 无用,可以设定位"NULL"
IntPtr lpInitData // 任意的打印机数据
);
private static extern bool BitBlt (
IntPtr hdcDest, // 目标设备的句柄
int nXDest, // 目标对象的左上角的X坐标
int nYDest, // 目标对象的左上角的X坐标
int nWidth, // 目标对象的矩形的宽度
int nHeight, // 目标对象的矩形的长度
IntPtr hdcSrc, // 源设备的句柄
int nXSrc, // 源对象的左上角的X坐标
int nYSrc, // 源对象的左上角的X坐标
int dwRop // 光栅的操作值
);
[ DllImport ( "gdi32.dll" ) ]
private static extern IntPtr CreateDC (
string lpszDriver, // 驱动名称
string lpszDevice, // 设备名称
string lpszOutput, // 无用,可以设定位"NULL"
IntPtr lpInitData // 任意的打印机数据
);
我们从游戏屏幕上 捕获 左上角用来显示血多少的数值颜色 的变化来实现监视.
第一个函数BitBlt 就是用来截屏的.前面我们定义了timer2,下在我们来看看他是用来做什么的:
private void timer2_Tick(object sender, System.EventArgs e){
// 创建显示器的DC
IntPtr hdlDisplay = CreateDC("DISPLAY", null, null, IntPtr.Zero);
// 从指定设备的句柄创建新的 Graphics 对象
Graphics gfxDisplay = Graphics.FromHdc(hdlDisplay);
// 创建只有一个象素大小的 Bitmap 对象
Bitmap bmp1 = new Bitmap(1, 1, gfxDisplay);
Bitmap bmp2 = new Bitmap(1, 1, gfxDisplay);
// 从指定 Image 对象创建新的 Graphics 对象
Graphics gfxBmp1 = Graphics.FromImage(bmp1);
Graphics gfxBmp2 = Graphics.FromImage(bmp2);
// 获得屏幕的句柄
IntPtr hdlScreen = gfxDisplay.GetHdc();
// 获得位图的句柄
IntPtr hdlBmp1 = gfxBmp1.GetHdc();
IntPtr hdlBmp2 = gfxBmp2.GetHdc();
// 把当前屏幕中鼠标指针所在位置的一个象素拷贝到位图中
//97, 25,和97, 20,是游戏屏幕上HP值显示的坐标位置,
BitBlt(hdlBmp1, 0, 0, 1, 1, hdlScreen, 97, 25, 13369376);
BitBlt(hdlBmp2, 0, 0, 1, 1, hdlScreen, 97, 20, 13369376);
// 释放屏幕句柄
gfxDisplay.ReleaseHdc(hdlScreen);
// 释放位图句柄
gfxBmp1.ReleaseHdc(hdlBmp1);
gfxBmp2.ReleaseHdc(hdlBmp2);
Color temp1 = bmp1.GetPixel(0, 0); // 获取像素的颜色
Color temp2 = bmp2.GetPixel(0, 0);
int beforeCount = this.count;
if((temp1.ToArgb().ToString("x").ToUpper() == "FFFFFFFF") && (temp2.ToArgb().ToString("x").ToUpper() == "FFFFFFFF"))
this.count ++;
if(beforeCount == this.count)
this.count = 0;
if((temp1.ToArgb().ToString("x").ToUpper() == "FFFFFFFF") &&(count == 2) &&(beforeCount != this.count)){
this.count = 0;
System.Windows.Forms.SendKeys.Send(strHP); //按下补血键,就是喝药瓶的那个快界键
}
gfxDisplay.Dispose();
gfxBmp1.Dispose();
gfxBmp2.Dispose();
bmp1.Dispose(); // 释放 bmp 所使用的资源
bmp2.Dispose();
}
// 创建显示器的DC
IntPtr hdlDisplay = CreateDC("DISPLAY", null, null, IntPtr.Zero);
// 从指定设备的句柄创建新的 Graphics 对象
Graphics gfxDisplay = Graphics.FromHdc(hdlDisplay);
// 创建只有一个象素大小的 Bitmap 对象
Bitmap bmp1 = new Bitmap(1, 1, gfxDisplay);
Bitmap bmp2 = new Bitmap(1, 1, gfxDisplay);
// 从指定 Image 对象创建新的 Graphics 对象
Graphics gfxBmp1 = Graphics.FromImage(bmp1);
Graphics gfxBmp2 = Graphics.FromImage(bmp2);
// 获得屏幕的句柄
IntPtr hdlScreen = gfxDisplay.GetHdc();
// 获得位图的句柄
IntPtr hdlBmp1 = gfxBmp1.GetHdc();
IntPtr hdlBmp2 = gfxBmp2.GetHdc();
// 把当前屏幕中鼠标指针所在位置的一个象素拷贝到位图中
//97, 25,和97, 20,是游戏屏幕上HP值显示的坐标位置,
BitBlt(hdlBmp1, 0, 0, 1, 1, hdlScreen, 97, 25, 13369376);
BitBlt(hdlBmp2, 0, 0, 1, 1, hdlScreen, 97, 20, 13369376);
// 释放屏幕句柄
gfxDisplay.ReleaseHdc(hdlScreen);
// 释放位图句柄
gfxBmp1.ReleaseHdc(hdlBmp1);
gfxBmp2.ReleaseHdc(hdlBmp2);
Color temp1 = bmp1.GetPixel(0, 0); // 获取像素的颜色
Color temp2 = bmp2.GetPixel(0, 0);
int beforeCount = this.count;
if((temp1.ToArgb().ToString("x").ToUpper() == "FFFFFFFF") && (temp2.ToArgb().ToString("x").ToUpper() == "FFFFFFFF"))
this.count ++;
if(beforeCount == this.count)
this.count = 0;
if((temp1.ToArgb().ToString("x").ToUpper() == "FFFFFFFF") &&(count == 2) &&(beforeCount != this.count)){
this.count = 0;
System.Windows.Forms.SendKeys.Send(strHP); //按下补血键,就是喝药瓶的那个快界键
}
gfxDisplay.Dispose();
gfxBmp1.Dispose();
gfxBmp2.Dispose();
bmp1.Dispose(); // 释放 bmp 所使用的资源
bmp2.Dispose();
}
我们用temp1 和temp2分别捕获了屏幕上2点的颜色,然后看他们的RGB值,如果他们同时为0xFFFFFF那么就意味这2点都变成了白色,说明,HP直低于200了,这时就需要补血了,于是执行System.Windows.Forms.SendKeys.Send,其中的count和beforeCount 用来缓冲,时间是this.timer2.Interval * 3 .
这样,一个外挂就实现了!