Problem trying to screen capture a specific monitor to a thumbnail (on Clipboard)

82 Views Asked by At

My ultimate goal here is to try and display a small list of monitor thumbnails on a dialog. This is so that the user can click on one of those thumbnails and I then perform a certain action for them.

I have found out how to use EnumDisplayMonitors to get the array of monitor rectangles from a question here on SO:

struct MonitorRects
{
    std::vector<RECT>   rcMonitors;
    std::vector<CString> strMonitorNames;

    static BOOL CALLBACK MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData)
    {
        MonitorRects* pThis = reinterpret_cast<MonitorRects*>(pData);
        pThis->rcMonitors.push_back(*lprcMonitor);

        MONITORINFOEX sMI{};
        sMI.cbSize = sizeof(MONITORINFOEX);
        GetMonitorInfo(hMon, &sMI);

        pThis->strMonitorNames.push_back(sMI.szDevice);

        return TRUE;
    }

    MonitorRects()
    {
        EnumDisplayMonitors(nullptr, nullptr, MonitorEnum, (LPARAM)this);
    }
};

I extended it (for the timebeing) to also remember the list of monitor names. For now, I display the list of monitor names in a CListBox for the user to select that way, but eventually I want a list of display thumbnails.


So my next task was to try and create a screen grab and initially copy it to the clipboard. I thought I would try to paste it into a image editor, just to see if I had captured the right information. So I created this function (based on code on the internet):

BOOL CCenterCursorOnScreenDlg::CaptureRect(const CRect& rcCapture, CImage &rImage)
{
    // destroy the currently contained bitmap to create a new one
    rImage.Destroy();

    // create bitmap and attach it to this object 
    if (!rImage.Create(rcCapture.Width(), rcCapture.Height(), 32, 0))
    {
        AfxMessageBox(L"Cannot create image!", MB_ICONERROR);
        return FALSE;
    }


    // create virtual screen DC
    CDC dcScreen;
    dcScreen.CreateDC(_T("DISPLAY"), nullptr, nullptr, nullptr);

    // copy the contents from the virtual screen DC 
    BOOL bRet = ::BitBlt(rImage.GetDC(), 0, 0, rcCapture.Width(), rcCapture.Height(),
        dcScreen.m_hDC, rcCapture.left, rcCapture.top,
        SRCCOPY | CAPTUREBLT);

    // do cleanup and return
    dcScreen.DeleteDC();
    rImage.ReleaseDC();

    if (!(OpenClipboard() &&
        EmptyClipboard() &&
        ::SetClipboardData(CF_BITMAP, (HBITMAP)rImage)))
        AfxMessageBox(L"Error copying image to clipboard", MB_ICONERROR);
    CloseClipboard();

    return bRet;
}

I encounter two issues:

  1. When I paste the clipboard into HyperSnap the image is blank. I anticipated it being of the display in question.
  2. HyperSna "froze" and I had to crash it.

I used this code to create the image in the dialog:

CRect rcMonitor = m_monitors.rcMonitors.at(0);
CImage img;
CaptureRect(rcMonitor, img);

Update

If I do this:

rImage.Save(L"d:\\testthumb.jpg", Gdiplus::ImageFormatJPEG);

And manually open the JPG it is correctly captured of the screen. So in this instance my issue was copying that CImage to the clipboard. Not that I really need to do that (as my ultimate goal is a list of thumbnails the user can click. But I best stick with the one question for now.

0

There are 0 best solutions below