2015-02-01 26 views
5

Pracuję nad przechwytywaniem ekranu za pomocą wielu wyświetlaczy. Ponieważ GetDesktopWindow() pobiera tylko uchwyt do podstawowych monitorów, próbowałem użyć EnumDisplayMonitors(), aby wykonać to zadanie.przechwytywanie wielu ekranów przy użyciu biblioteki MSDN

Po przeczytaniu na stronie MSDN, napisałem to w main():

HDC hdc = GetDC(NULL); 
EnumDisplayMonitors(hdc, NULL, MyCapScreenEnumProc, 0); 
ReleaseDC(NULL, hdc); 

A dla "BOOL CALLBACK MyCapScreenEnumProc (Hmonitor Hmonitor, HDC hdcMonitor, lpRect lprcMonitor, LPARAM dwData)" callback funkcja, skopiowane przykładową funkcję "Int CaptureAnImage (hWND hWnd)" z MSDN:Capturing an Image i nie następującą modyfikację:

  1. zamiast czytania Parametr HWND, to uznane go w funkcji i zainicjowaniu jej GetDesktopWindow()
  2. usunięto kody rozciąganie kontekstu urządzenia
  3. wykorzystywany parametr hdcMonitor w kontekście urządzenia
  4. użył lprcMonitor parametrów dla RECT
  5. dodaje kody do generowania unikalnych nazw plików

Oto pełny kod:

BOOL CALLBACK MyCapScreenEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) 
{ 
    HWND hWnd = GetDesktopWindow(); 
    HDC hdcMemDC = NULL; 
    HBITMAP hbmScreen = NULL; 
    BITMAP bmpScreen; 

    //generate a unique file name for the bitmaps 
    static int file_number = 1; 
    stringstream ss; 
    ss << "all_capture_" << file_number++ << ".bmp"; 
    string filename = ss.str(); 
    wstring widestr = wstring(filename.begin(), filename.end()); 

    // Create a compatible DC which is used in a BitBlt from the window DC 
    hdcMemDC = CreateCompatibleDC(hdcMonitor); 

    if (!hdcMemDC) 
    { 
     MessageBox(hWnd, L"CreateCompatibleDC has failed", L"Failed", MB_OK); 
     goto done; 
    } 

    // Get the client area for size calculation 
    RECT rcClient = *lprcMonitor; 

    // Create a compatible bitmap from the Window DC 
    hbmScreen = CreateCompatibleBitmap(hdcMonitor, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); 

    if (!hbmScreen) 
    { 
     MessageBox(hWnd, L"CreateCompatibleBitmap Failed", L"Failed", MB_OK); 
     goto done; 
    } 

    // Select the compatible bitmap into the compatible memory DC. 
    SelectObject(hdcMemDC, hbmScreen); 

    // Bit block transfer into our compatible memory DC. 
    if (!BitBlt(hdcMemDC, 
       0, 0, 
       rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, 
       hdcMonitor, 
       0, 0, 
       SRCCOPY)) 
    { 
     MessageBox(hWnd, L"BitBlt has failed", L"Failed", MB_OK); 
     goto done; 
    } 

    // Get the BITMAP from the HBITMAP 
    GetObject(hbmScreen, sizeof(BITMAP), &bmpScreen); 

    BITMAPFILEHEADER bmfHeader; 
    BITMAPINFOHEADER bi; 

    bi.biSize = sizeof(BITMAPINFOHEADER); 
    bi.biWidth = bmpScreen.bmWidth; 
    bi.biHeight = bmpScreen.bmHeight; 
    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 dwBmpSize = ((bmpScreen.bmWidth * bi.biBitCount + 31)/32) * 4 * bmpScreen.bmHeight; 

    // Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that 
    // call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc 
    // have greater overhead than HeapAlloc. 
    HANDLE hDIB = GlobalAlloc(GHND, dwBmpSize); 
    char *lpbitmap = (char *)GlobalLock(hDIB); 

    // Gets the "bits" from the bitmap and copies them into a buffer 
    // which is pointed to by lpbitmap. 
    GetDIBits(hdcMonitor, hbmScreen, 0, 
       (UINT)bmpScreen.bmHeight, 
       lpbitmap, 
       (BITMAPINFO *)&bi, DIB_RGB_COLORS); 




    // A file is created, this is where we will save the screen capture. 
    HANDLE hFile = CreateFile(widestr.c_str(), 
           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 = dwBmpSize + 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(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL); 
    WriteFile(hFile, (LPSTR)&bi, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL); 
    WriteFile(hFile, (LPSTR)lpbitmap, dwBmpSize, &dwBytesWritten, NULL); 

    //Unlock and Free the DIB from the heap 
    GlobalUnlock(hDIB); 
    GlobalFree(hDIB); 

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

    //Clean up 
    done: 
    DeleteObject(hbmScreen); 
    DeleteObject(hdcMemDC); 
    return TRUE; 
} 

Okazuje się jednak, że dwukrotnie przechwytuje podstawowy ekran. Z drugim rozmiarem ekranu tak samo jak mój drugi monitor. Nie wiem, co jest nie tak z kodami. Czy ktoś może to wskazać lub zaproponować lepszy sposób na wykonanie zadania? Dzięki!

Odpowiedz

4

Trzeba BitBlt z monitorem współrzędne dostarczone Państwu w lprcMonitor, a nie z punktu zerowego:

// Bit block transfer into our compatible memory DC. 
if (!BitBlt(hdcMemDC, 
      0, 0, 
      rcClient.right - rcClient.left, rcClient.bottom - rcClient.top, 
      hdcMonitor, 
      lprcMonitor->left, lprcMonitor->top, // <<--- !!! 
      SRCCOPY)) 
+0

Dzięki! To rozwiązało problem! – Samuel

Powiązane problemy