2017-12-07 13 views
2

포커스가없는 창의 스크린 샷을 찍고 싶습니다. 내 기능은 일부 창에서는 작동하지만 모든 기능에서는 작동하지 않으며 이유를 모르겠습니다. Bluestacks App Player의 창을 캡처하려고 시도했지만 완벽하게 작동합니다. 그러나 Nox App Player와 다른 게임에서는 전혀 작동하지 않습니다. 방금 창 크기와 함께 검은 색 이미지가 나타납니다. 여기 C++ 배경에있는 창 WinAPI 스크린 샷

지금까지 코드 :

void screenshot_window(HWND handle) { 
    RECT client_rect = { 0 }; 
    GetClientRect(handle, &client_rect); 
    int width = client_rect.right - client_rect.left; 
    int height = client_rect.bottom - client_rect.top; 


    HDC hdcScreen = GetDC(handle); 
    HDC hdc = CreateCompatibleDC(hdcScreen); 
    HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, width, height); 
    SelectObject(hdc, hbmp); 

    BitBlt(hdc, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY); 

    BITMAPINFO bmp_info = { 0 }; 
    bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader); 
    bmp_info.bmiHeader.biWidth = width; 
    bmp_info.bmiHeader.biHeight = height; 
    bmp_info.bmiHeader.biPlanes = 1; 
    bmp_info.bmiHeader.biBitCount = 24; 
    bmp_info.bmiHeader.biCompression = BI_RGB; 

    int bmp_padding = (width * 3) % 4; 
    if (bmp_padding != 0) bmp_padding = 4 - bmp_padding; 

    BYTE *bmp_pixels = new BYTE[(width * 3 + bmp_padding) * height];; 
    GetDIBits(hdc, hbmp, 0, height, bmp_pixels, &bmp_info, DIB_RGB_COLORS); 

    BITMAPFILEHEADER bmfHeader; 
    HANDLE bmp_file_handle = CreateFile("TestFile.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 

    // Add the size of the headers to the size of the bitmap to get the total file size 
    DWORD dwSizeofDIB = (width * 3 + bmp_padding) * height + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); 

    //Offset to where the actual bitmap bits start. 
    bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); 

    //Size of the file 
    bmfHeader.bfSize = dwSizeofDIB; 

    //bfType must always be BM for Bitmaps 
    bmfHeader.bfType = 0x4D42; //BM 

    DWORD dwBytesWritten = 0; 
    WriteFile(bmp_file_handle, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL); 
    WriteFile(bmp_file_handle, (LPSTR)&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL); 
    WriteFile(bmp_file_handle, (LPSTR)bmp_pixels, (width * 3 + bmp_padding) * height, &dwBytesWritten, NULL); 

    //Close the handle for the file that was created 
    CloseHandle(bmp_file_handle); 

    DeleteDC(hdc); 
    DeleteObject(hbmp); 
    ReleaseDC(NULL, hdcScreen); 
    delete[] bmp_pixels; 
} 

답변

3

대상 윈도우는 단순히 컨테이너 및 페인트 메시지에 대한 책임을지지 않습니다 곳이 많은 응용 프로그램과 함께 발생할 수 있습니다. 메모장과 같은 표준 win32 응용 프로그램은 이와 같이 작동하지 않습니다. 그러나 예를 들어 많은 브라우저에서이 문제를 해결할 수 있습니다.

언제든지 데스크톱 창의 스크린 샷을 찍을 수 있습니다. 당신은 표적 창의 창의 좌표를 얻을 수 있고, 그 후에 bitblt 표적 창의 단면도를 얻을 수있다. 코드를 다음과 같이 변경하십시오.

//GetClientRect(handle, &client_rect); 
GetWindowRect(handle, &client_rect); 

//HDC hdcScreen = GetDC(handle); 
HDC hdcScreen = GetDC(HWND_DESKTOP); 

//BitBlt(hdc, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY); 
BitBlt(hdc, 0, 0, width, height, hdcScreen, client_rect.left, client_rect.top, SRCCOPY); 

//ReleaseDC(NULL, hdcScreen); 
ReleaseDC(HWND_DESKTOP, hdcScreen); 

스크린 샷을 찍기 전에 대상 창이 가장 많이 보이는 창이어야합니다. 예를 들어, 당신은 순서대로 screenshot_window를 호출 할 수

HWND hwnd = FindWindow(0, L"Calculator"); 
SetForegroundWindow(hwnd); 
Sleep(1000); 
screenshot_window(hwnd); 

을 양자 택일로, 당신은 당신의 자신의 창에서 대상 창을 페인트 Dwm Thumbnail API를 사용할 수 있습니다. 그러나 다시, GetDC(my_hWnd)을 사용하여 창에서 "Dwm 축소판 그림"의 비트 맵에 액세스 할 수 없습니다. 다시 GetDC(HWND_DESKTOP)을 사용하여 데스크톱 창 스크린 샷을 찍어야합니다. 이번에는 자신의 창이 최상위 창인지 확인하십시오.

응용 프로그램이 DPI를 인식해야합니다. 그렇지 않으면 화면 좌표가 일치하지 않습니다.


원본 코드에 리소스 누출이 있습니다. GetDC이 있어야합니다 같은 handle하지 NULL

HDC hdcScreen = GetDC(handle); 
... 
//ReleaseDC(NULL, hdcScreen); 
ReleaseDC(handle, hdcScreen); 
+1

마지막 라인을 사용하여 ReleaseDC와 청소해야'ReleaseDC은 (hdcScreen 처리)'. – zett42

+0

고마워요 @ zett42, 대답을 주셔서 감사합니다 –

+0

, 전경으로 창을 데려 오지 않고 다른 창에 의해 겹쳐있는 동안이 창을 캡처 할 수있는 방법이 있습니까? – SYY99