2015-02-01 3 views
5

Я работаю над захватом экрана с несколькими единицами отображения. Поскольку GetDesktopWindow() получает только обработчик первичных мониторов, я попытался использовать EnumDisplayMonitors() для выполнения этой задачи.множественный захват экрана с помощью библиотеки MSDN

После прочтения веб-сайта MSDN, я написал это в основном():

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

И для "BOOL CALLBACK MyCapScreenEnumProc (HMonitor HMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)" обратного вызова функция, я скопировал образец функцию "INT CaptureAnImage (HWND HWND)" из MSDN:Capturing an Image и сделал следующую модификацию:

  1. вместо чтения Параметр HWND, я объявил его в функции и инициализируется его с GetDesktopWindow()
  2. удалены коды для растягивания контекст устройства
  3. используется параметр hdcMonitor в качестве контекста устройства
  4. использовал lprcMonitor параметр для RECT
  5. добавлены коды для генерации уникальных имен файлов

Вот полный код:

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; 
} 

Однако оказывается, что он захватывает основной экран дважды. С размером экрана второго захвата, таким же, как у моего второго монитора. Я не знаю, что не так с кодами. Может ли кто-нибудь указать на это или предложить лучший способ выполнить эту задачу? Спасибо!

ответ

4

Вы должны BitBlt от монитора координат предоставляются Вам в lprcMonitor, а не с нуля:

// 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

Спасибо! Это решило проблему! – Samuel