我编写了以下代码(C ++ Win32)来捕获游戏窗口屏幕并从图像中获取像素颜色数组。函数autoB()完成这项工作。
然后我将结果数组绘制到我的窗口中,目视检查我得到了什么。
问题是这个程序在我启动计算机后只运行一次,在第一次“缓存”从游戏中获取的第一个截图后,我总是得到相同的像素数组。即使我关闭并重新启动程序,我也会获得相同的屏幕截图。
游戏没有使用DirectX在屏幕上绘图,我总是可以使用Alt + PrtSc截取屏幕截图。
理解为什么会发生这种情况的任何帮助都表示赞赏。
int getPixels(HDC *eClientHdcMem, HBITMAP *eClientBmp, unsigned char **lp) {
BITMAP bmpScreen;
BITMAPINFOHEADER bi;
GetObject(*eClientBmp, sizeof(BITMAP), &bmpScreen);
LONG bW = bmpScreen.bmWidth, bH = bmpScreen.bmHeight;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bW;
bi.biHeight = -bH;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
DWORD dw = ((bW * bi.biBitCount + 31) / 32) * 4 * bH;
*lp = new unsigned char[dw];
return GetDIBits(*eClientHdcMem, *eClientBmp, 0, (UINT)bH, *lp, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
}
void autoB() {
HWND hwnd;
HDC hDC0 = NULL, eClientHdcMem = NULL;
HBITMAP eClientBmp = NULL;
BITMAP bmp = {0};
unsigned char *lp = NULL, *sp = NULL;
WINDOWINFO wi;
wi.cbSize = sizeof(WINDOWINFO);
RECT vp;
int vpW, vpH;
long iW, iH;
if (!(hwnd = FindWindow(NULL,TEXT("Client")))) return;
if (!(hDC0 = GetDC(hwnd))) return;
GetWindowInfo(hwnd,&wi);
vp = wi.rcClient;
vpW = vp.right - vp.left;
vpH = vp.bottom - vp.top;
if (!(eClientBmp = CreateCompatibleBitmap(hDC0, vpW, vpH))) return;
if (!(eClientHdcMem = CreateCompatibleDC(hDC0))) return;
SelectObject(eClientHdcMem, eClientBmp);
BitBlt(eClientHdcMem, 0, 0, vpW, vpH, hDC0, 0, 0, SRCCOPY);
int res = getPixels(&eClientHdcMem, &eClientBmp, &lp);
DeleteObject(eClientBmp);
DeleteObject(eClientHdcMem);
// begin testing
HDC sts = GetDC(hStats);
HBITMAP stsBmp = CreateCompatibleBitmap(sts, vpW, vpH);
HBITMAP stsBmpOld = (HBITMAP)SelectObject(sts, stsBmp);
unsigned char r,g,b;
for(unsigned int i=0;i<vpW;i++) {
for(unsigned int j=0;j<vpH;j++) {
r = lp[(vpW*j+i) * 4 + 2];
g = lp[(vpW*j+i) * 4 + 1];
b = lp[(vpW*j+i) * 4 + 0];
SetPixel(sts,i,j,RGB(r,g,b));
}
}
SelectObject(sts, stsBmpOld);
DeleteObject(stsBmp);
DeleteObject(stsBmpOld);
ReleaseDC(hStats,sts);
// end testing
DeleteDC(eClientHdcMem);
ReleaseDC(hwnd,hDC0);
delete [] lp;
lp = NULL;
delete [] sp;
sp = NULL;
}
更改屏幕截图的唯一方法是重新启动游戏。然后再次捕获第一个屏幕截图,无论游戏窗口中发生了什么,都会反复显示。
答案 0 :(得分:1)
您确定要获得相同的像素,还是只是在调试窗口中看到屏幕上的相同图像?原始图像复制代码看起来没问题,但在“调试”代码中,即使您直接调用SetPixel(),仍需要调用InvalidateRect()
以使Windows发送新的WM_PAINT消息。如果你不这样做,你可能只是看着旧图像,即使新的比特确实已被捕获(但未被绘制)。
答案 1 :(得分:0)
我遇到了同样的问题,我注意到 HDC 变量(在您的情况下为 hDC0 )曾经调用过 CreateCompatibleDC BitBlt 有所作为。如果使用 GetDC(NULL),则会得到整个屏幕的图像,在这种情况下,图像每次都会更新,而使用 GetDC(myWindowHwnd)会出现问题您提到的是总是返回相同的图像而没有任何刷新。
我要捕获的窗口是一个全屏,最顶部的窗口,其创建方式如下:
hwnd = CreateWindowExA(0, "myWindow", "myWindow", WS_POPUP, x, y, w, h, NULL, NULL, wc.hInstance, NULL);
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT);
SetLayeredWindowAttributes(hwnd, 0, 0xFF, LWA_ALPHA);
ShowWindow(hwnd, SW_SHOW);
SetWindowPos(hwnd, HWND_TOPMOST, x, y, w, h, SWP_NOACTIVATE);
即使显示了窗口并且在所有其他窗口之上, BitBlt 函数也无法捕获由另一个线程更新的窗口的更新帧。