In this function, after about 90 calls (it's called in a loop and the idea is to load in a separate image each time, but I have kept it to one image for simplicity).The global variables now changed to local ones.
void CDLP_Printer_ControlDlg::DisplayBMPfromSVG(CString& strDsiplayFile)
{
HBITMAP hbmp_temp = (HBITMAP)::LoadImage(0, strDsiplayFile, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if (!hbmp_temp)
{
//hbmp_temp = ::LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_BITMAP1));
ActionList.AddString(L"Bitmap Load Failure: GetBMPromSVG");
ActionList.UpdateWindow();
if (!hbmp_temp)
return;
}
CBitmap bmp_temp;
bmp_temp.Attach(hbmp_temp);
mProjectorWindow.m_picControl.ModifyStyle(0xF, SS_BITMAP, SWP_NOSIZE);
mProjectorWindow.m_picControl.SetBitmap(bmp_temp);
return;
}
I hope someone can come up with an Idea whats wrong. GetLastError returns "8" which means nothing to me.
Detach
will destroy the previous handle.Note that if you call
Detach
after callingSetBitmap
, the picture control's bitmap is destroyed. The result is that the picture control is painted once, but it won't be repainted. For example picture control goes blank if dialog is resized.EDIT
To destroy the old bitmap, call
Detach
followed byDestroyObject
. ExampleIf it's a temporary
CBitmap
thenDeleteObject
is not necessary, becauseDeleteObject
is called automatically whenCBitmap
goes out of scope.Note that if you destroy the bitmap after calling
SetBitmap
, the picture control's bitmap is destroyed. The result is that the picture control is painted once, but it won't be repainted. For example picture control goes blank if dialog is resized.It's the same problem if you declare a temporary
CBitmap
on stack and attach the bitmap handle. That bitmap handle will be destroyed and picture control can't repaint itself.In addition, Windows XP sometimes makes duplicate bitmap which needs to be destroyed as well.
SetBitmap
returns a handle to previous bitmap. In Vista+ the returned bitmap is the same one which was save inm_bitmap
, we already destroy that withDetach
. But in XP we need to destroy this copy if it is a different handle.Also,
SetBitmap
takesHBITMAP
parameter and returnsHBITMAP
, so you can avoid usingCBitmap
altogether. The following example works in Vista+Your code has several issues, some minor, others are fatal (and the implementation really only appears to work, because the OS is prepared to deal with those common bugs). Here is an annotated listing of the original code:
The two major issues are:
SetBitmap
). This eventually causes any attempt to create additional GDI resources to fail.HBITMAP
) caused by assigning two owners to the same resource (hbmp_temp
).Following is a version with fixed-up resource management. This won't make any sense to you, since you don't know MFC (or C++ for that matter) well enough to understand, how either one aids in automatic resource management. Anyhow:
The last line is the critical part. It implements the canonical way to swap raw Windows API resources with resource management wrappers. This is the sequence of operations:
bmp_temp.Detach()
releases ownership of the GDI resource.SetBitmap()
passes ownership of the GDI resource to the control, and returns the previous GDI object (if any).bmp_temp.Attach()
acquires ownership of the returned GDI resource. This ensures that the previous resource gets cleaned up, whenbmp_temp
goes out of scope (at the end of the function).