1

I use a function which captures a screen using the BitBlt mehtod and can then return a HBITMAP.

int screenCapture() {
    int width = 1000;
    int height = 700;

    HDC hdcTemp, hdc;
    BYTE* bitPointer;

    hdc = GetDC(HWND_DESKTOP);
    hdcTemp = CreateCompatibleDC(hdc);

    BITMAPINFO bitmap;
    bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
    bitmap.bmiHeader.biWidth = width;
    bitmap.bmiHeader.biHeight = -height;
    bitmap.bmiHeader.biPlanes = 1;
    bitmap.bmiHeader.biBitCount = 24;
    bitmap.bmiHeader.biCompression = BI_RGB;
    bitmap.bmiHeader.biSizeImage = 0;
    bitmap.bmiHeader.biClrUsed = 0;
    bitmap.bmiHeader.biClrImportant = 0;
    HBITMAP hBitmap = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)(&bitPointer), NULL, NULL);
    SelectObject(hdcTemp, hBitmap);
    BitBlt(hdcTemp, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
    ReleaseDC(HWND_DESKTOP, hdc);
    DeleteDC(hdcTemp);
    return (int)bitPointer[0];
}

Here, the function only returns the first value of the pixels array.
Actually, it works fine.

for (int i = 0; i >= 0; i++) {
        cout << i << ": " << screenCapture() << endl;
    }

But when I try to loop this, an error is generated after a few hundred rounds (a little over 900 for me), an Access violation reading location error.

I also noticed that if I reduced the values of width and height, then the error took longer to be called.

I am a true beginner and I do not know where the error may come, but it would look like a memory problem, right?

Delgan
  • 18,571
  • 11
  • 90
  • 141
  • 4
    You should `DeleteObject(hBitmap)` – Alex K. Oct 03 '14 at 10:53
  • 2
    Do you eventually call DeleteObject on the bitmap handle? Generally you want to save the old object when you select a new object into a dc and then select that old object back when you're done. It may not matter since you delete the dc, but another potential leak. – Retired Ninja Oct 03 '14 at 10:53
  • @AlexK. @RetiredNinja I tried with `DeleteObject` but I did not do it the right way. Now, it works fine and I have no more "access violation reading location" error, thank you! – Delgan Oct 03 '14 at 11:19
  • 3
    "something fails" + "after a period of time" + "on Windows" + "involving graphics" = "GDI object leak" – Jonathan Potter Oct 03 '14 at 13:28

1 Answers1

4

As was stated in comments, you are leaking your HBITMAP, and also the original HBITMAP that was already in the HDC before you called SelectObject(). Whenever you use SelectObject(), you must always restore the original value (you don't own it).

And don't forget to do error checking!

Try this:

int screenCapture()
{
    int result = -1;

    int width = 1000;
    int height = 700;

    HDC hdcTemp, hdc;
    BYTE* bitPointer;

    hdc = GetDC(HWND_DESKTOP);
    if (hdc != NULL)
    {
        hdcTemp = CreateCompatibleDC(hdc);
        if (hdcTemp != NULL)
        {
            BITMAPINFO bitmap;
            bitmap.bmiHeader.biSize = sizeof(bitmap.bmiHeader);
            bitmap.bmiHeader.biWidth = width;
            bitmap.bmiHeader.biHeight = -height;
            bitmap.bmiHeader.biPlanes = 1;
            bitmap.bmiHeader.biBitCount = 24;
            bitmap.bmiHeader.biCompression = BI_RGB;
            bitmap.bmiHeader.biSizeImage = 0;
            bitmap.bmiHeader.biClrUsed = 0;
            bitmap.bmiHeader.biClrImportant = 0;

            HBITMAP hBitmap = CreateDIBSection(hdcTemp, &bitmap, DIB_RGB_COLORS, (void**)&bitPointer, NULL, NULL);
            if (hBitmap != NULL)
            {
                HBITMAP hPrevBitmap = SelectObject(hdcTemp, hBitmap);

                BitBlt(hdcTemp, 0, 0, width, height, hdc, 0, 0, SRCCOPY);
                result = (int) bitPointer[0];

                SelectObject(hdcTemp, hPrevBitmap);
                DeleteObject(hBitmap);
            }

            DeleteDC(hdcTemp);
       }

       ReleaseDC(HWND_DESKTOP, hdc);
    }

    return result;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770