HBITMAP memory leak - c++

No matter how hard I looked and whatever I tried, I couldn't find why this code is leaking. Actually, I'm not sure about the leak but the number of GDI objects increases everytime I use this piece of code.
HBITMAP hBmp;
hBmp = CreateDIBitmap(dc, &stBmpIH, CBM_INIT, m_pBitmapData, m_pBitmapInfo, DIB_RGB_COLORS) ;
Bitmap *pBMP = NULL;
HPALETTE hPal = NULL;
Color col = 0;
pBMP = Bitmap::FromHBITMAP(hBmp, hPal);
if (m_bFlip)
{
pBMP->RotateFlip( Rotate90FlipXY );
pBMP->GetHBITMAP(col,&hBmp);
m_bFlip = FALSE;
}
else
{
pBMP->RotateFlip( RotateNoneFlipX );
pBMP->GetHBITMAP(col,&hBmp);
}
delete pBMP;
I've checked the GDI objects with a tool, and what I found is the HBITMAP hBmp is the one that is leaking. How should I remove it?
DeleteObject is NOT working.
Thanks

From the FromHBITMAP documentation:
You are responsible for deleting the GDI bitmap and the GDI palette.
However, you should not delete the GDI bitmap or the GDI palette until
after the GDI+ Bitmap object is deleted or goes out of scope.
Deleting the Bitmap object is not enough, you need to call DeleteObject on hBmp afterwards.

DeleteObject is NOT working.
Let's assume that it is actually in your code even though the snippet doesn't show it. Then the next explanation is this statement:
pBMP->GetHBITMAP(col,&hBmp);
Which overwrites the value for hBmp, preventing you from releasing it properly. Fix:
HBITMAP prev = hBmp;
Status status = pBMP->GetHBITMAP(col,&hBmp);
if (status == Ok) DeleteObject(prev);
You'll probably need to do some more work on the error handling code.

You need a call to DeleteObjectto match the call to CreateDIBitmap. How exactly is it now working?

Related

How do I get a rectangle (or &rc) from a memory hdc without using a handle or HWND

I am using Microsoft Windows (32 bit). Please, no Visual Studio anything, or .net.
I have the following that works if I have a windows handle to use for it:
// I have a handle to a window.
// HWND Handle_Of_SomeWindow
// I previously assigned a handle for that and use it.
// I have some Unicode text that I am using.
wstring SomeWideStringText = L"C++ stole my lunch money.";
// I convert that wstring to LPWSTR using
LPWSTR Text_Being_Added = const_cast<wchar_t*>(SomeWideStringText.c_str());
//I create a rectangle to use in my DrawTextExW
RECT rc;
// If I have a handle to a window then I can do this.
GetClientRect(Handle_Of_SomeWindow, & rc);
//But, if I do not have a handle to a window and if I only have a hdc, then that does not work.
When I have an HDC without a window handle (I think that this is a memory dc but I do not yet understand that so well) which I am using in double buffering, then there is no handle to use. And, I can not get a handle for it. Get handle from DC does not work.
So, my question is How do I get a rectangle or &rc for that to use in my command of :
DrawTextExW(HDC_of_FRONT_BUFFER_001, Text_Being_Added, -1, & rc, DT_WORDBREAK, nullptr);
?
Maybe there might be something else other than a rectangle &rc that I could use, but I have not found it.
I have been studying this and I do not understand how to get a rectangle or a &rc to use.
You're misunderstanding what the rectangle you provide to DrawTextEx is, it's not the size of your bitmap, it's the size you want your text to occupy. It should obviously be less than or equal to the size of your backing bitmap, but it has no other relation to it.
then there is no handle to use. And, I can not get a handle for it. Get handle from DC does not work.
Literally no idea what you're trying to express here.
I do not understand how to get a rectangle or a &rc to use
Again, you aren't handed this, you provide it.
A memory DC has a bitmap selected into it, and that bitmap has a size. In most cases your code created that bitmap, so it should already know the size.
But if it doesn't, you have a couple options.
Option 1: You can select the bitmap out of the DC, get its size, and then select it back in. This is kind of kludgy and I've omitted error checking:
// assuming you're given hdcMem...
HBITMAP hbmpTemp = CreateCompatibleDC(hdcMem, 1, 1);
HBITMAP hbmpActual = SelectObject(hdcMem, hdcTemp);
BITMAP bm = {0};
GetObject(hbmpActual, sizeof(bm), &bm);
// now your size is in bm.bmWidth and bm.bmHeight,
RECT rc = {0, 0, bm.bmWidth, bm.bmHeight};
SelectObject(hdcMem, hdcActual); // put the memory DC back
DeleteObject(hbmpTemp);
Option 2: [untested] You could try to query the DC for its "resolution" caps. I know this works for device DCs, like a monitor or printer. I don't know whether it works for a memory DC.
int width = GetDeviceCaps(hdcMem, HORZRES);
int height = GetDeviceCaps(hdcMem, VERTRES);

GDI+ GetHBITMAP memory error?

So I was trying to learn some GDI basics and my code breaks when I try to get the HBITMAP for a png image I want to display...
HBITMAP SplashScreen::LoadPng(WCHAR* path)
{
HBITMAP bmp;
fstream f;
f.open(path);
if(!f.good())
{
throw std::exception("Can't find/read file.");
}
f.close();
Gdiplus::Bitmap* img = Gdiplus::Bitmap::FromFile(path, FALSE);
Gdiplus::Color bg(0,0,0,0);
img->GetHBITMAP(bg, &bmp); // <--- Breaks here! Memory access exception!
return bmp;
}
The code is already so simple, I can't think of anything wrong with it, except maybe I just didn't set something up beforehand??
Thoughts?
Not sure what your problem is, though, I do note that you've got a memory leak.
img is never deleted - you should call delete img; after the call to GetHBITMAP
I use the following (less thorough code) in quick test projects.
// BMP, GIF, JPEG, PNG, TIFF, Exif, WMF, and EMF
HBITMAP mLoadImg(WCHAR *szFilename)
{
HBITMAP result=NULL;
Gdiplus::Bitmap* bitmap = new Gdiplus::Bitmap(szFilename,false);
bitmap->GetHBITMAP(0, &result);
delete bitmap;
return result;
}
I didn't initialize GDI correctly. After fixing my init code, it works fine. That was annoying. Now I know.

MFC HBITMAP memory leak does not go away

whenever I execute the below code, my memory in task manager for the application keeps on increasing endlessly. I found similiar questions here on stackoverflow and I did some DeleteObject calls like they stated but this still did not solve the ever increasing memory when this code executes.
How can this be solved? What am I doing wrong?
SetControlPicture(const UINT ID_PICTURE_CONTROL)
{
CImage image;
CBitmap bitmap;
HRESULT hresult;
CStatic* pItem = (CStatic*)GetDlgItem(ID_PICTURE_CONTROL);
hresult = image.Load(_T("./Data/Images/RED_ON.png"));
if(hresult != E_FAIL)
{
HBITMAP hBitMap = image.Detach();
bitmap.Attach(hBitMap);
HBITMAP hBitMapPrev = pItem->SetBitmap(bitmap);
if (hBitMapPrev)
{
DeleteObject(hBitMapPrev); // *** do not forget to delete the previously associated bitmap
}
DeleteObject(hBitMap);
}
}
AFAIK According to the documentation this must leak. Since Common Control ver. 6.0 you are repsonsible to delete the Bitmap. It is not enough to delete the Bitmap that was returned.
http://msdn.microsoft.com/en-us/library/windows/desktop/bb760782(v=vs.85).aspx
In version 6 of the Microsoft Win32 controls, a bitmap passed to a static control using the STM_SETIMAGE message was the same bitmap returned by a subsequent STM_SETIMAGE message. The client is responsible to delete any bitmap sent to a static control.

deleting HBITMAP causes an access violation at runtime

I have the following code to take a screenshot of a window, and get the colour of a specific pixel in it:
void ProcessScreenshot(HWND hwnd){
HDC WinDC;
HDC CopyDC;
HBITMAP hBitmap;
RECT rt;
GetClientRect (hwnd, &rt);
WinDC = GetDC (hwnd);
CopyDC = CreateCompatibleDC (WinDC);
//Create a bitmap compatible with the DC
hBitmap = CreateCompatibleBitmap (WinDC,
rt.right - rt.left, //width
rt.bottom - rt.top);//height
SelectObject (CopyDC, hBitmap);
BitBlt (CopyDC, //destination
0,0,
rt.right - rt.left, //width
rt.bottom - rt.top, //height
WinDC, //source
0, 0,
SRCCOPY);
COLORREF col = ::GetPixel(CopyDC,145,293);
// Do some stuff with the pixel colour....
delete hBitmap;
ReleaseDC(hwnd, WinDC);
ReleaseDC(hwnd, CopyDC);
}
the line 'delete hBitmap;' causes a runtime error: an access violation. I guess I can't just delete it like that?
Because bitmaps take up a lot of space, if I don't get rid of it I will end up with a huge memory leak. My question is: Does releasing the DC the HBITMAP is from deal with this, or does it stick around even after I have released the DC? If the later is the case, how do I correctly get rid of the HBITMAP?
You must destroy GDI objects with DeleteObject, not delete. The latter is only used to free objects allocated using new.
delete should only be used to deallocate things allocated via new.
HBITMAP is a bitmap handle and you need to release the associated object using the GDI function DeleteObject.
Strictly, you should save the result of SelectObject from when you selected the bitmap into the device context and pass that to another call to SelectObject to ensure that the bitmap is not in use by the device context when you call DeleteObject. Things often work if you don't do this, especially if you're about to release the device context anyway but it is safest to do so.

Strange error with CreateCompatibleDC

Maybe this is a foolish question, I can't see why I can not get a DC created in the following code :
HBITMAP COcrDlg::LoadClippedBitmap(LPCTSTR pathName,UINT maxWidth,UINT maxHeight)
{
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, pathName, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (!hBmp)
return NULL;
HDC hdc = (HDC)GetDC();
HDC hdcMem = CreateCompatibleDC(hdc);
if (!hdcMem)
{
DWORD err = GetLastError();
}
...
...
...
The bitmap hBmp is loaded fine and hdc has a valid value. But the call to CreateCompatibleDC() returns a NULL pointer. Then, GetLastError() returns 0 !
Anybody can guess what's going on here , please ?
PS : There are no memory allocations or GDI routines called before this one...so I think memory leaks should be ruled out.
You are improperly casting the result of GetDC() to an HDC. GetDC() returns a pointer to a CDC object.
To do what you want you can do either of the following. The first choice fits more into how MFC likes to do things, but both work just fine:
CDC *pDC = GetDC();
// Option 1
CDC memDC;
memDC.CreateCompatibleDC(pDC);
// Option 2
HDC hMemDC = CreateCompatibleDC((HDC)(*pDC));
It is important to note that option 2 does not do the same thing that you're currently doing wrong. The CDC class has an operator HDC() member that allows it to be converted to an HDC, but this does NOT apply to the pointer. You must dereference it first.
Certain device contexts won't work with CreateCompatibleDC(). The DC has to support raster operations. You can feed the hdc to GetDeviceCaps() and check RASTERCAPS.
But it turns out the GetDC you're calling is a method on a class and not the C binding I thought you meant. SoapBox has the right answer.