2012-06-25 57 views
3

我編寫了下面的代碼(C++ Win32)來捕獲遊戲窗口屏幕並從圖像中獲取像素顏色數組。函數autoB()完成這項工作。用BitBlt捕獲程序窗口總是返回相同的圖像

然後我將結果數組繪製到我的窗口中,以便直觀地檢查我得到的結果。

問題是這個程序在我啓動計算機之後只能運行一次,在第一次「緩存」從遊戲中獲得的第一個截圖後,我總是得到相同的像素數組。即使我關閉並重新啓動程序,我也會得到相同的屏幕截圖。

遊戲並未使用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

'autoB'是否過早返回? –

+0

不,它沒有。如果我在sp = NUll之後添加MessageBox,每次調用函數時都會看到它。 – user1481126

回答

1

你確定你找回相同的像素嗎?或者你剛纔在調試窗口中看到屏幕上有相同的圖像?原始圖像複製代碼看起來不錯,但在「調試」代碼中,即使您直接調用SetPixel(),仍需要調用InvalidateRect()以使Windows發送新的WM_PAINT消息。如果你不這樣做,你可能只是看舊的圖像,即使新的位已經被捕獲(但沒有繪製)。

+0

SetPixel的工作速度很慢,所以每次調用這個函數時,我都會看到它是如何將位圖繪製到程序窗口中的。添加InvalidateRect不會改變任何東西。 – user1481126

相關問題