2012-06-25 4 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()을 직접 호출하더라도 Windows에서 새 WM_PAINT 메시지를 보내려면 InvalidateRect()을 호출해야합니다. 당신이 그렇게하지 않는다면 새로운 비트가 실제로 포착되었지만 (그려지지 않았음에도 불구하고) 오래된 이미지를 보았을 것입니다.

+0

SetPixel 매우 느린 작동하므로이 함수를 호출 할 때마다 실제로 어떻게 비트 맵을 프로그램 창에 그리는 볼 수 있습니다. InvalidateRect를 추가해도 아무 것도 변경되지 않습니다. – user1481126