【发布时间】:2013-08-14 23:52:11
【问题描述】:
我正在尝试编写一些代码来检测游戏的壁挂。 基本上,存在一些创建 windows aero 透明窗口的 hack,他们将 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;
}
【问题讨论】:
-
我不相信你的所作所为是合乎道德的。您的“wallhack”检测器正在收集用户可能不希望泄露的信息。为什么用户会同意你在玩游戏时截取他们的桌面?您尝试实施的行为属于特洛伊木马的分类。当然,前提是您没有对程序的目的撒谎。
-
这可能是
Parallel.Foreach的适当用法。ThreadPool不保证并行性。 -
假设我在一个窗口中打开了你的游戏,然后在该窗口上打开一个网络浏览器(谷歌搜索|检查我的银行账户|浏览 Facebook|做一些非法的事情)然后你截取了那。你会记录一个误报——我在作弊,而我没有作弊,如果你决定上传“伪造”的屏幕截图以进行证明/验证,你可能会意外捕获我的私人详细信息。
-
Tim S. 不,这不会发生,只有当游戏窗口是活动窗口时才会运行检查。所以如果你打开浏览器,什么都不会发生。
-
PunkBuster 在用户同意的情况下这样做。因此,如果你们抱怨它不道德,那么其他人已经这样做了,原因与 DaManJ 声称他这样做的原因相同。
标签: c# screenshot gdi user32 bitblt