john k
john k

Reputation: 6615

Why does CreateCompatibleBitmap fail after about a thousand executions?

I am trying to write a screen capture/record application. Here's the part of the code that captures the screen and saves it:

width = GetSystemMetrics(SM_CXMAXTRACK)+8;
height = GetSystemMetrics(SM_CYMAXTRACK)-8;

hwindowDC=GetDC(GetDesktopWindow());
hwindowCompatibleDC=CreateCompatibleDC(hwindowDC);
SetStretchBltMode(hwindowCompatibleDC,COLORONCOLOR);  

// create a bitmap
hbwindow = CreateCompatibleBitmap( hwindowDC, width, height);
cout << " handle to newly created bitmap: " << hbwindow << "\n";

SelectObject(hwindowCompatibleDC, hbwindow); //copy from hwindowCompatibleDC to hbwindow
StretchBlt( hwindowCompatibleDC, 0,0, width, height, hwindowDC, 0, 0,width,height, SRCCOPY); //change SRCCOPY to NOTSRCCOPY for wacky colors !

src.create(height,width,CV_8UC4);   
src.empty();
GetDIBits(hwindowCompatibleDC,hbwindow,0,height,src.data,(BITMAPINFO *)&bi,DIB_RGB_COLORS); 


DeleteDC(hwindowCompatibleDC); 
DeleteObject(hbwindow);

After a thousand or so repetitions, my cout statement will show the newly created handle as 000000000000000 aka. NULL. My app works fine until that point.
I am deleting the created DC and bitmap each time so there is no memory leak. Task Manager also confirms there is no memory leak. So what is happening?

Thank you for anyone who can assist in this.

Upvotes: 4

Views: 3175

Answers (1)

Jonathan Potter
Jonathan Potter

Reputation: 37132

As mentioned in the comments, the two problems were 1) you weren't releasing the DC obtained from the desktop window, and 2) you weren't selecting the original bitmap back into the compatible DC before deleting it. Both of these cause a GDI resource leak which will lead to the symptoms you describe.

Fixed code below:

width = GetSystemMetrics(SM_CXMAXTRACK)+8;
height = GetSystemMetrics(SM_CYMAXTRACK)-8;

hwindowDC=GetDC(GetDesktopWindow());
hwindowCompatibleDC=CreateCompatibleDC(hwindowDC);
SetStretchBltMode(hwindowCompatibleDC,COLORONCOLOR);  

// create a bitmap
hbwindow = CreateCompatibleBitmap( hwindowDC, width, height);
cout << " handle to newly created bitmap: " << hbwindow << "\n";

// SAVE OLD BITMAP
HGDIOBJ hOldBmp = SelectObject(hwindowCompatibleDC, hbwindow); //copy from hwindowCompatibleDC to hbwindow
StretchBlt( hwindowCompatibleDC, 0,0, width, height, hwindowDC, 0, 0,width,height, SRCCOPY); //change SRCCOPY to NOTSRCCOPY for wacky colors !

src.create(height,width,CV_8UC4);   
src.empty();
GetDIBits(hwindowCompatibleDC,hbwindow,0,height,src.data,(BITMAPINFO *)&bi,DIB_RGB_COLORS); 

// RESTORE OLD BITMAP
SelectObject(hwindowCompatibleDC, hOldBmp);
DeleteDC(hwindowCompatibleDC); 
DeleteObject(hbwindow);

// RELEASE WINDOW DC
ReleaseDC(GetDesktopWindow(), hwindowDC);

You should also be doing proper error checking (as calls like GetDC, CreateCompatibleDC etc can fail and return NULL).

Upvotes: 6

Related Questions