我试图编写一些代码来检测游戏中的透视作弊。基本上,某些作弊程序会创建一个Windows Aero透明窗口,并在该外部窗口上绘制作弊内容,因此无法通过对游戏本身进行屏幕截图来检测。
目前我的方法是: 1. 对游戏窗口进行屏幕截图。 2. 对同一坐标的Windows桌面进行屏幕截图。 3. 进行图像分析以比较截图1和截图2是否有差异。
我的问题是,截图1和截图2不是同时进行的,因此在两个屏幕截图之间可能会绘制新的游戏画面,导致图像比较时出现误报。
我想知道是否有一种方法可以协调这些屏幕截图,使它们在完全相同的时间发生?或者以某种方式停止屏幕绘制任何新帧,直到我的屏幕截图完成?
以下是我用于截屏的代码。 请注意,我甚至尝试了使用两个工作项排队并行地进行两次屏幕截图。然而,即使这样也不能确保两个屏幕截图完全同时进行。 所以我想知道是否有一种方法可以阻止显卡更新屏幕,直到我的屏幕截图完成?或者是否有其他方法可以实现这一点?
目前我的方法是: 1. 对游戏窗口进行屏幕截图。 2. 对同一坐标的Windows桌面进行屏幕截图。 3. 进行图像分析以比较截图1和截图2是否有差异。
我的问题是,截图1和截图2不是同时进行的,因此在两个屏幕截图之间可能会绘制新的游戏画面,导致图像比较时出现误报。
我想知道是否有一种方法可以协调这些屏幕截图,使它们在完全相同的时间发生?或者以某种方式停止屏幕绘制任何新帧,直到我的屏幕截图完成?
以下是我用于截屏的代码。 请注意,我甚至尝试了使用两个工作项排队并行地进行两次屏幕截图。然而,即使这样也不能确保两个屏幕截图完全同时进行。 所以我想知道是否有一种方法可以阻止显卡更新屏幕,直到我的屏幕截图完成?或者是否有其他方法可以实现这一点?
public void DoBitBlt(IntPtr dest, int width, int height, IntPtr src)
{
GDI32.BitBlt(dest, 0, 0, width, height, src, 0, 0, GDI32.SRCCOPY);
}
public struct Windows
{
public Bitmap window;
public Bitmap desktop;
}
public Windows CaptureWindows(IntPtr window, IntPtr desktop, User32.RECT coords)
{
Windows rslt = new Windows();
// get te hDC of the target window
IntPtr hdcSrcWindow = User32.GetWindowDC(window);
IntPtr hdcSrcDesktop = User32.GetWindowDC(desktop);
// get the size
int width = coords.right - coords.left;
int height = coords.bottom - coords.top;
// create a device context we can copy to
IntPtr hdcDestWindow = GDI32.CreateCompatibleDC(hdcSrcWindow);
IntPtr hdcDestDesktop = GDI32.CreateCompatibleDC(hdcSrcDesktop);
// create a bitmap we can copy it to,
// using GetDeviceCaps to get the width/height
IntPtr hBitmapWindow = GDI32.CreateCompatibleBitmap(hdcSrcWindow, width, height);
IntPtr hBitmapDesktop = GDI32.CreateCompatibleBitmap(hdcSrcDesktop, width, height);
// select the bitmap object
IntPtr hOldWindow = GDI32.SelectObject(hdcDestWindow, hBitmapWindow);
IntPtr hOldDesktop = GDI32.SelectObject(hdcDestDesktop, hBitmapDesktop);
// bitblt over
var handle1 = new ManualResetEvent(false);
var handle2 = new ManualResetEvent(false);
Action actionWindow = () => { try { DoBitBlt(hdcDestWindow, width, height, hdcSrcWindow); } finally { handle1.Set(); } };
Action actionDesktop = () => { try { DoBitBlt(hdcDestDesktop, width, height, hdcSrcDesktop); } finally { handle2.Set(); } };
ThreadPool.QueueUserWorkItem(x => actionWindow());
ThreadPool.QueueUserWorkItem(x => actionDesktop());
WaitHandle.WaitAll(new WaitHandle[] { handle1, handle2 });
rslt.window = Bitmap.FromHbitmap(hBitmapWindow);
rslt.desktop = Bitmap.FromHbitmap(hBitmapDesktop);
// restore selection
GDI32.SelectObject(hdcDestWindow, hOldWindow);
GDI32.SelectObject(hdcDestDesktop, hOldDesktop);
// clean up
GDI32.DeleteDC(hdcDestWindow);
GDI32.DeleteDC(hdcDestDesktop);
User32.ReleaseDC(window, hdcSrcWindow);
User32.ReleaseDC(desktop, hdcSrcDesktop);
// free up the Bitmap object
GDI32.DeleteObject(hBitmapWindow);
GDI32.DeleteObject(hBitmapDesktop);
return rslt;
}
Parallel.Foreach
的适当情况。ThreadPool
不保证并行性。 - Dustin Kingen