我正在尝试编写一些代码来检测游戏的壁垒。 基本上,存在一些创建windows aero透明窗口的hacks,并且它们将hack绘制到这个外部窗口上,因此无法通过截取游戏本身来检测它。
我目前的做法是 - 1.截取游戏窗口的截图。 2.为相同的坐标拍摄Windows桌面的屏幕截图。 3.执行图像分析,将屏幕截图1与屏幕截图2进行比较,看是否存在差异。
我的问题是屏幕截图1和屏幕截图2不会同时执行,因此可以在两个屏幕截图之间绘制新的游戏帧,从而在比较图像时导致误报。
我想知道是否有办法协调屏幕截图,以便它们在同一时间出现?或以某种方式停止屏幕绘制任何新帧,直到我的截图完成?
这是我用于截屏的代码。 请注意,我甚至试图通过排队两个工作项来并行拍摄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;
}
答案 0 :(得分:1)
除非您为某些图形加速器提供资源,否则您无法同时拥有这两个屏幕截图,这意味着它不会在每台计算机上都有效...
关于停止渲染,因为它是一款游戏,我认为这不是一个好主意......你希望你的游戏顺利运行。
相反,我建议将最近渲染的游戏图像存储在内存中,当您截取屏幕截图时将其与它们进行比较。如果你可以添加一些视觉线索来决定哪些最近的帧要比较,那么它将更好地工作,因为否则你将不得不将屏幕截图与所有这些相比较,这肯定会占用一些CPU / GPU时间。
您使用GDI进行渲染吗?如果是这样,你想要的是将你的游戏帧存储在DIB(设备无关位图)中,以便能够比较它们。
至于决定使用哪个图像的线索,我会在屏幕上进行某种时间表示,也许是改变颜色的单个像素。如果是这样,您将读取该像素的颜色,使用它来找到正确的帧,并使用它们来比较整个图像。