Reputation: 4869
I have a program that takes a screenshot every second and calculates the average colour of the screen. However, after about 45min of running, my check
if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, nScreenWith, nScreenHeight)) == NULL)
begins returning true
. A call to GetLastError()
returns 6
, though I cannot seem to find any documentation on what this means.
Why would thousands of calls to this function work fine, and then abruptly every call fails?
Here's my entire function:
COLORREF ScreenColourCapture::getScreenColour() {
// Most of this is adapted from http://www.cplusplus.com/forum/beginner/25138/
LPBITMAPINFO lpbi = NULL;
HBITMAP OffscrBmp = NULL;
HDC OffscrDC = NULL;
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HDC bitmapDC = CreateCompatibleDC(0);
HBITMAP hBmp = CreateCompatibleBitmap(GetDC(0), nScreenWidth, nScreenHeight);
SelectObject(bitmapDC, hBmp);
BitBlt(bitmapDC, 0, 0, nScreenWidth, nScreenHeight, GetDC(0), 0, 0, SRCCOPY);
if ((OffscrBmp = CreateCompatibleBitmap(bitmapDC, nScreenWidth, nScreenHeight)) == NULL) {
int error = GetLastError();
logging->error("CreateCompatibleBitmap failed!");
return 0;
}
if ((OffscrDC = CreateCompatibleDC(bitmapDC)) == NULL) {
logging->error("CreateCompatibleDC failed!");
return 0;
}
HBITMAP OldBmp = (HBITMAP)SelectObject(OffscrDC, OffscrBmp);
BitBlt(OffscrDC, 0, 0, nScreenWidth, nScreenHeight, bitmapDC, 0, 0, SRCCOPY);
if ((lpbi = (LPBITMAPINFO)(new char[sizeof(BITMAPINFOHEADER)+256 * sizeof(RGBQUAD)])) == NULL)
return 0;
ZeroMemory(&lpbi->bmiHeader, sizeof(BITMAPINFOHEADER));
lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
SelectObject(OffscrDC, OldBmp);
// First, call GetDIBits with no pixel array. This way it will populate bitmapinfo for us. Then
// call it with the pixel array and the now populated lpbi.
GetDIBits(OffscrDC, OffscrBmp, 0, nScreenHeight, NULL, lpbi, DIB_RGB_COLORS);
LPVOID lpvBits = new char[lpbi->bmiHeader.biSizeImage];
GetDIBits(OffscrDC, OffscrBmp, 0, nScreenHeight, lpvBits, lpbi, DIB_RGB_COLORS);
// Pass BMP data off for computation
COLORREF averageColour = getMeanColourFromPixels((BYTE *)lpvBits, lpbi);
// Wrap things up
delete[] lpvBits;
delete[] lpbi;
DeleteObject(hBmp);
DeleteObject(OldBmp);
DeleteObject(OffscrBmp);
ReleaseDC(GetDesktopWindow(), bitmapDC);
DeleteDC(OffscrDC);
return averageColour;
}
The rest of my code is here, for what it's worth: https://github.com/crummy/screenglow/tree/master/ConsoleApplication1
Upvotes: 3
Views: 1338
Reputation: 52471
You must de-select the bitmap from HDC
before you can destroy it, otherwise you are leaking it. It goes like this:
HBITMAP hBmp = CreateCompatibleBitmap(...);
HBITMAP previousBitmap = (HBITMAP)SelectObject(bitmapDC, hBmp);
// ...
SelectObject(bitmapDC, previousBitmap);
DeleteObject(hBmp);
Also, you call GetDC(0)
but don't save the return value so you can't ReleaseDC
it. Also, bitmapDC
is created by CreateCompatibleDC
, and should be deleted with DeleteObject
, not ReleaseDC
.
Upvotes: 10