MFC HBITMAP memory leak does not go away - c++

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.

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);

Converting a CBitmap to HICON and using it on a status bar

I found this link that shows you how to convert a CBitmap into a HICON:
HICON HICONFromCBitmap(CBitmap& bitmap)
{
BITMAP bmp;
bitmap.GetBitmap(&bmp);
HBITMAP hbmMask = ::CreateCompatibleBitmap(::GetDC(NULL),
bmp.bmWidth, bmp.bmHeight);
ICONINFO ii = {0};
ii.fIcon = TRUE;
ii.hbmColor = bitmap;
ii.hbmMask = hbmMask;
HICON hIcon = ::CreateIconIndirect(&ii);
::DeleteObject(hbmMask);
return hIcon;
}
So I have tried this in my application:
HICON hIcon = HICONFromCBitmap(m_mapMenuBitmap[5]);
VERIFY(hIcon);
m_StatusBar.GetStatusBarCtrl().SetIcon(paneProgressOrZoomFactor, hIcon);
It works:
Does hIcon need to be alive for the duration of my window? And do I have to free it?
For your clarification, my m_mapMeniBitmaps is a map of CBitmap objects and they do remain alive.
Does hIcon need to be alive for the duration of my window? And do I have to free it?
Yes and yes! From the documentation for CreateIconIndirect (bolding mine):
When you are finished using the icon, destroy it using the
DestroyIcon function.
My m_mapMenuBitmaps is a map of CBitmap objects and they do remain alive.
You can free those CBitmap objects once you've created the icon(s) but, as you correctly note, they remain 'alive', so you should always 'kill' them when you no longer need them. From the same M/S document:
The system copies the bitmaps in the ICONINFO structure before
creating the icon or cursor.
...
The application must continue to manage the original bitmaps and
delete them when they are no longer necessary.

How does GDI::DeleteObject exactly work

According to MSDN
The DeleteObject function deletes a logical pen, brush, font, bitmap,
region, or palette, freeing all system resources associated with the
object. After the object is deleted, the specified handle is no longer
valid.
So one(myself) would think that once DeleteObject is executed, the HANDLE is no longer valid. but what happens to the objects retrieved by ::GetObject() once i delete the object before saving them with other WinAPI calls?
HFONT hFont = reinterpret_cast<HFONT>(::SendMessage(hwndCtrl, WM_GETFONT, 0, 0));
if (nullptr == hFont)
{
LOG_ERROR(L"Invalid font specified");
return false;
}
LOGFONT font = { 0 };
if (0 == ::GetObject(hFont, sizeof(font), &font))
{
LOG_ERROR(L"Failed getting font");
return false;
}
font.lfHeight = nSize;
::DeleteObject(hFont);
HFONT hFontEx = ::CreateFontIndirect(&font);
LPARAM lparam = MAKELPARAM(TRUE, 0);
WPARAM wparam = (WPARAM)(hFontEx);
SendMessage(hwndCtrl, WM_SETFONT, wparam, lparam);
As in the following example, if i decide to delete my HFONT, before sending the new message via SendMessage, i'd retrieve some unexpected results, where other controls gets their font changed, as if i'd generated some kind of a handle leak.
So one(myself) would think that once DeleteObject is executed, the
HANDLE is no longer valid. but what happens to the objects retrieved
by ::GetObject() once i delete the object before saving them with
other WinAPI calls?
With GetObject you get a description for the object, not a new object. It remains the same after handle deletion.
As in the following example, if i decide to delete my HFONT, before
sending the new message via SendMessage, i'd retrieve some unexpected
results, where other controls gets their font changed, as if i'd
generated some kind of a handle leak.
If you want to send a message with deleted HFONT, I guess the result will be the same if you send it with any other garbage.

HBITMAP memory leak

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?

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.