Forum
Please
Log In
to post a new message or reply to an existing one. If you are not registered, please
register.
NOTE: Some forums may be read-only if you are not currently subscribed to
our technical support services.
Subject |
Author |
Date |
|
Chris Mason
|
Jun 5, 2008 - 4:08 AM
|
Hi. We have a memory leak within our project, which seems to be concerned with the CExtPageContainerWnd class. We are running v2.60 of prof uis. Here are some more details. The CExtPageContainerWnd is used to contain an unknown number of a CExtToolControlBar (well bars derived from), where the needed details are gathered from an xml file. Therefore these bars have to be created dynamically; CRuntimeClass *pRTC = RUNTIME_CLASS( CAppToolControlBar);
CAppToolControlBar *pBar = DYNAMIC_DOWNCAST(CAppToolControlBar, pRTC->CreateObject());
if (!pBar->Create(cGroupName, &m_wndAppPageContainer, NULL))
{
TRACE0( "Failed to create resizable bar" );
return false;
} This bar is then placed inside the CExtPageContainerWnd; m_wndAppPageContainer.PageInsert(pBar->GetSafeHwnd(),-1, cGroupName); Then CExtToolBarButtons are added to the bar. Still fine here. This all works fine. However, our problem starts when we call CExtPageContainerWnd::PageExpand at the end of our initialisation function. When this method is called the memory of the program increases at 4kb per second until it crashes our program and then others that we may be running on the same system. We have found that if you click the left mouse button on any of the toolbars then the leak will stop. Our inclination is that it has something to do with us using runtime created toolbars, as looking at your Page_Container example this problem does not occur. If you need more information, such as the source files for the affected class, or maybe even a small example project, please don’t hesitate to ask. Cheers.
|
|
Chris Mason
|
Jun 9, 2008 - 3:16 AM
|
Thanks for your help, but it was the OnAppUpdateCommand function which was the problem. I had forgotten to add the following code: FindClose(hFindExe);
FindClose(hFindScript);
FindClose(hFindOther);
|
|
Technical Support
|
Jun 6, 2008 - 1:26 PM
|
Using the FindFirstFile() Win32 API without a final invocation of the FindClose() Win32 API causes memory leaks. This also relates to similar C runtime APIs.
Besides this function is very heavy. The command updating method should be as light as possible. We mean they should return as soon as possible. Otherwise your application will work quite slow.
|
|
Chris Mason
|
Jun 6, 2008 - 9:11 AM
|
Edit: After some more experimentation we have found that it is the OnAppUpdateCommand(CCmdUI *pCmdUI) function that is causing the problem: void CAppControlBar::OnAppUpdateCommand(CCmdUI *pCmdUI)
{
UINT m_iButtonID = (pCmdUI->m_nID) - 2100; // 2100 being the start of the range used
//to identify the appcontrolbar commands
CString m_cButtonID = g_PseudoAppClasses.GetAt(m_iButtonID);
//Need to remove the %DATS% in order to use the GetDatsDirectory function
int m_iDatsDirectoryUsed = m_cButtonID.Find("%DATS%");
if (m_iDatsDirectoryUsed > -1)
{
int n = m_cButtonID.Replace("%DATS%","");
}
WIN32_FIND_DATA findFileData;
HANDLE hFindExe;
HANDLE hFindScript;
HANDLE hFindOther; //Here we search for whether the .exe or script associated with the command is installed, and
//to disable/grey out the button if the desired object is not installed.
hFindExe = FindFirstFile((CDatsUtil::GetDatsDirectory()+"\\bin\\"+m_cButtonID), &findFileData);
hFindScript = FindFirstFile((CDatsUtil::GetDatsDirectory()+"\\bin\\Scripts\\"+m_cButtonID), &findFileData);
hFindOther = FindFirstFile((CDatsUtil::GetDatsDirectory()+m_cButtonID), &findFileData);
if (hFindExe == INVALID_HANDLE_VALUE && hFindScript == INVALID_HANDLE_VALUE && hFindOther == INVALID_HANDLE_VALUE)
{
pCmdUI->Enable(FALSE);
return;
}
pCmdUI->Enable(TRUE);
} This function is used as our product has options that a customer may not purchase, so these options need to be disabled. We scan the installation folder of our program to see if these have been installed and enable the buttons accordingly. So it may not be a prof-uis problem at all.
|
|
Chris Mason
|
Jun 6, 2008 - 8:49 AM
|
This is a project I’ve taken on from someone who has left, and let’s just say that the previous programmer wasn’t the biggest fan of commenting code! The buttons are custom painted, and as far I can tell the code is identical to that found in your funnybars example. // ---------------------------------------------
// class CAppToolButton
// ---------------------------------------------
IMPLEMENT_DYNAMIC( CAppToolButton, CExtBarButton );
CAppToolButton::CAppToolButton(
CExtToolControlBar * pBar,
UINT nCmdID,
LPCTSTR strFunnyText,
double lfHotPercent
) : CExtBarButton( pBar, nCmdID, 0 )
, m_strFunnyText( (strFunnyText==NULL) ? _T("") : strFunnyText )
, m_sizeFunnyTextCalc( 0, 0 )
, m_sizeFunnyTextWell( 0, 0 )
, m_lfHotPercent( lfHotPercent )
{
m_cMouseDownPosition = CPoint(-1, -1);
}
CSize CAppToolButton::CalculateLayout(
CDC & dc,
CSize sizePreCalc,
BOOL bHorz
)
{
ASSERT_VALID( this );
CSize _size = CExtBarButton::CalculateLayout( dc, sizePreCalc, bHorz );
ASSERT( !IsSeparator() );
if( ! m_strFunnyText.IsEmpty() )
{
CFont * pOldFont = dc.SelectObject( &g_PaintManager->m_FontNormal );
CRect rcMeasured( 0, 0, 0, 0 );
dc.DrawText( m_strFunnyText, &rcMeasured, DT_LEFT|DT_CALCRECT );
m_sizeFunnyTextWell = rcMeasured.Size();
m_sizeFunnyTextWell.cx += __EXT_TB_BUTTON_TEXT_MARGIN*10;
static CString strMeasureTemplate( _T("AapqWZz\nAapqWZz") );
dc.DrawText( strMeasureTemplate, &rcMeasured, DT_LEFT|DT_CALCRECT );
dc.SelectObject( pOldFont );
m_sizeFunnyTextCalc = rcMeasured.Size();
m_sizeFunnyTextCalc.cx += __EXT_TB_BUTTON_TEXT_MARGIN*2;
m_sizeFunnyTextCalc.cx = max( m_sizeFunnyTextWell.cx, m_sizeFunnyTextCalc.cy );
m_sizeFunnyTextCalc.cy = max( m_sizeFunnyTextWell.cy, m_sizeFunnyTextCalc.cy );
m_sizeFunnyTextCalc.cx += __EXT_TB_BUTTON_INNER_MARGIN*2;
_size.cx = max( m_sizeFunnyTextCalc.cx, _size.cx );
_size.cy += m_sizeFunnyTextCalc.cy + 4;
}
m_ActiveSize = _size;
return m_ActiveSize;
}
void CAppToolButton::PaintCompound(CDC & dc,
bool bPaintParentChain,
bool bPaintChildren,
bool bPaintOneNearestChildrenLevelOnly
)
{
ASSERT_VALID( this );
ASSERT( dc.GetSafeHdc() != NULL );
CExtToolControlBar * pBar = GetBar();
ASSERT_VALID( pBar );
if( (m_pCtrl != NULL) && (!m_bVertDocked || GetCtrlVisibleVertically()) )
return;
ASSERT( ! IsSeparator() );
if( ! IsPaintAble( dc ) )
return;
if( AnimationClient_StatePaint( dc ) )
return;
if( bPaintParentChain )
PaintParentChain( dc );
CRect rcArea( m_ActiveRect );
rcArea.DeflateRect( __EXT_TB_BUTTON_INNER_MARGIN, __EXT_TB_BUTTON_INNER_MARGIN );
if( (!IsVisible())
|| rcArea.right <= rcArea.left || rcArea.bottom <= rcArea.top
|| (GetStyle() & TBBS_HIDDEN) != 0
|| (!dc.RectVisible(&m_ActiveRect))
)
return;
bool bPushed = IsPressed() ? true : false;
bool bEnabled = IsDisabled() ? false : true;
bool bHover =
( IsHover()
&& (! CExtToolControlBar::g_bMenuTracking )
&& (! CExtPopupMenuWnd::IsMenuTracking() )
) ? true : false;
bool bIndeterminate = IsIndeterminate() ? true : false;
CExtCmdIcon * pIcon = GetIconPtr();
if( m_lfHotPercent >= -1.0 && pIcon != NULL && (! pIcon->IsEmpty() ) )
{
ASSERT( m_lfHotPercent <= 1.0 );
if( m_iconCold.IsEmpty() )
{
m_iconCold.m_bmpNormal = pIcon->m_bmpNormal;
COLORREF clrIconAlphaAccent =
pBar->PmBridge_GetPM()->GetIconAlphaColor();
if( clrIconAlphaAccent != COLORREF(-1L) )
{
double H = 0.0, S = 0.0, L = 0.0;
CExtBitmap::stat_RGBtoHSL( clrIconAlphaAccent, &H, &S, &L );
S = 0.3;
clrIconAlphaAccent = CExtBitmap::stat_HLStoRGB( H, L, S );
} // if( clrIconAlphaAccent != COLORREF(-1L) )
m_iconCold.m_bmpNormal.MakeMono( clrIconAlphaAccent );
m_iconCold.m_bmpNormal.AdjustHLS(
COLORREF(-1L),
COLORREF(-1L),
0.0,
m_lfHotPercent,
0.0
);
m_iconCold.m_bmpNormal.AdjustAlpha( -0.5 );
} // if( m_iconCold.IsEmpty() )
if( (! bHover) && (! bPushed) && (! m_iconCold.IsEmpty() ) )
pIcon = &m_iconCold;
} // if( m_lfHotPercent >= -1.0 && pIcon != NULL && (! pIcon->IsEmpty() ) )
CExtPaintManager::PAINTPUSHBUTTONDATA _ppbd(
this, /*bHorz*/true, rcArea, NULL, pIcon,
true, bHover, bPushed, bIndeterminate, bEnabled,
true, false, false, CExtPaintManager::__ALIGN_HORIZ_CENTER, NULL,
( IsAbleToTrackMenu()
&& (!m_pBar->IsKindOf(RUNTIME_CLASS(CExtMenuControlBar)))
) ? true : false,
0, ( bEnabled && (!bHover) && (!bPushed) )
);
if( m_bSeparatedDropDown )
{
_ppbd.m_bSeparatedDropDown = true;
if( (m_bDropDownHT || CExtToolControlBar::g_bMenuTracking)
&& bPushed
)
_ppbd.m_bPushedDropDown = true;
} // if( m_bSeparatedDropDown )
g_PaintManager->PaintPushButton( dc, _ppbd );
CRect rcText( rcArea );
rcText.DeflateRect( __EXT_TB_BUTTON_OUTER_MARGIN, __EXT_TB_BUTTON_OUTER_MARGIN+__EXT_TB_BUTTON_INNER_MARGIN );
rcText.top = rcText.bottom - m_sizeFunnyTextCalc.cy;
rcText.OffsetRect(
( m_sizeFunnyTextCalc.cx - m_sizeFunnyTextWell.cx ) / 2,
( m_sizeFunnyTextCalc.cy - m_sizeFunnyTextWell.cy ) / 2
);
if( bPushed )
rcText.OffsetRect( g_PaintManager->GetPushedOffset() );
CFont fontTmp;
CFont * pOldFont = NULL;
COLORREF clrText =
bEnabled
? ( ( m_lfHotPercent >= -1.0f )
? g_PaintManager->GetColor(
(bHover || bPushed) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT,
this
)
: dc.GetNearestColor(
(bHover || bPushed) ? ( RGB(255,64,64) ) : ( RGB(64,64,255) )
)
)
: g_PaintManager->GetColor( COLOR_3DSHADOW, this )
;
if( bEnabled && bHover || bPushed )
{
LOGFONT lf;
VERIFY( g_PaintManager->m_FontNormal.GetLogFont(&lf) );
lf.lfUnderline = TRUE;
VERIFY( fontTmp.CreateFontIndirect(&lf) );
dc.SelectObject( &fontTmp );
}
else
dc.SelectObject( &g_PaintManager->m_FontNormal );
int nOldBkMode = dc.SetBkMode( TRANSPARENT );
COLORREF clrTextOld = dc.SetTextColor( clrText );
dc.DrawText( m_strFunnyText, &rcText, DT_CENTER|DT_VCENTER );
dc.SetTextColor( clrTextOld );
dc.SetBkMode( nOldBkMode );
dc.SelectObject( pOldFont );
if( bPaintChildren )
PaintChildren( dc, bPaintOneNearestChildrenLevelOnly );
}
void CAppToolButton::OnClick(CPoint point, bool bDown)
{
if( bDown )
{
m_cMouseDownPosition = point;
}
__super::OnClick(point, bDown);
}
We also have a CExtToolControlBar derived class where OnQuerytMultiRowLayout() is overridden. This class also has the DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE macros implemented. The Code for the main toolbar CAppControlBar class has the following code: // ---------------------------------------------
// class CAppControlBar
// ---------------------------------------------
CAppControlBar::CAppControlBar()
{
m_bCanDragButtons = true;
g_PseudoAppMap[".exe"] = CPseudoCommand(this, &CAppControlBar::OnApplicationRun);
g_PseudoAppMap[".dbs"] = CPseudoCommand(this, &CAppControlBar::OnScriptRun);
}
CAppControlBar::~CAppControlBar()
{
for( int i=0; i<m_cToolBarHooks.GetSize(); i++ )
{
delete m_cToolBarHooks[i];
}
m_cToolBarHooks.RemoveAll();
}
BEGIN_MESSAGE_MAP(CAppControlBar, CExtControlBar)
ON_WM_CREATE()
END_MESSAGE_MAP()
int CAppControlBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (__super::OnCreate(lpCreateStruct) == -1)
return -1;
// Create the page container toolbar
if(!m_wndAppPageContainer.Create(this))
{
TRACE0("Failed to create application toolbar\n");
return -1; // fail to create
}
// The owner of this toolbar and any subsequent bars should
// be the CFrameWnd (CMainFrame)
m_wndAppPageContainer.SetOwner(GetParent());
Initialise();
return 0;
}
bool CAppControlBar::Initialise()
{
CString cPath = CDatsUtil::GetDatsDirectory() + "\\Lib\\Menus\\App.xml";
UINT nCmdID = APPCONTROLBAR_COMMAND_BASE;
CXmlDocument cXMLFile;
cXMLFile.Load(cPath);
CXmlNode cNode(cXMLFile.AsNode());
CXmlNodeList cGroups(cNode.FindNodes("/MenuItem/MenuItem"));
for(int i=0; i<cGroups.Count(); i++)
{
CXmlNode cGroup(cGroups.Node(i));
CString cGroupName(cGroup.GetValue("id"));
// Add the toolbar
CRuntimeClass *pRTC = RUNTIME_CLASS( CAppToolControlBar);
CAppToolControlBar *pBar = STATIC_DOWNCAST(CAppToolControlBar, pRTC->CreateObject());
if (!pBar->Create(cGroupName, &m_wndAppPageContainer, NULL))
{
TRACE0( "Failed to create resizable bar" );
return false;
}
m_wndAppPageContainer.PageInsert(pBar->GetSafeHwnd(),-1, cGroupName);
CAppToolControlBarHook *pHook = new CAppToolControlBarHook(pBar, this);
m_cToolBarHooks.Add(pHook);
// NB: Prof-UIS toolbar owners should
// i) Be the command target
// ii) Not be control bar’s
pBar->SetOwner(GetParent());
pBar->SetBarStyle(CBRS_ALIGN_LEFT);
// Add items to control bar
CXmlNodeList cItems(cGroup.FindNodes("MenuItem"));
for(int j=0; j<cItems.Count(); j++)
{
CXmlNode cItem(cItems.Node(j));
CExtBitmap cExtBitmap;
COLORREF crBackground = RGB(255,0,255);
CString cFileName("");
cFileName = CDatsUtil::GetDatsDirectory()
+ "\\Lib\\Applications\\Png\\"
+ cItem.GetValue("icon");
if(CreateButtonBitmap(cFileName, cExtBitmap, crBackground))
{
InsertButton(pBar, nCmdID++, cItem, cExtBitmap, crBackground);
}
}
//make sure that the buttons are displayed vertically by forcing them to wrap
if (pBar->GetButtonsCount() <= 3)
{
pBar->SetMultiRow(false);
}
else
{
int iRowNumber = (pBar->GetButtonsCount() / 2) - 1;
pBar->SetMultiRow(true);
pBar->GetButton(iRowNumber)->SetWrap( CAppToolButton::__EVT_VERT);
pBar->GetButton(iRowNumber)->SetWrap( CAppToolButton::__EVT_HORZ);
pBar->GetButton(iRowNumber)->SetWrap( CAppToolButton::__EVT_FLOAT);
pBar->GetButton(iRowNumber)->SetVertDocked(true);
pBar->GetButton(iRowNumber)->SetNoRotateVerticalLayout(true);
}
}
m_wndAppPageContainer.PageExpand(0);
return true;
}
bool CAppControlBar::InsertButton(CExtToolControlBar *pBar, UINT nCmdID, CXmlNode& node, CExtBitmap& bmp, COLORREF crTransparent)
{
CString cProfileName = g_CmdManager->ProfileNameFromWnd(m_hWnd);
// Add the command name and set the commands user data to point to it
CExtCmdItem cExtCmd(nCmdID);
int iIndex = g_PseudoAppClasses.Add(node.GetValue("class"));
g_PseudoAppID.Add(node.GetValue("id"));
cExtCmd.m_nLParamUserData = iIndex;
// Add the dynamically allocated command id into the command manager
g_CmdManager->CmdSetup(
cProfileName,
cExtCmd,
true,
NULL);
// Change the commands icon to the one supplied
g_CmdManager->CmdSetIcon(
cProfileName,
nCmdID,
bmp,
crTransparent,
NULL);
// Finally, Insert the button
//pBar->InsertButton( -1, cExtCmd.m_nCmdID, NULL );
CAppToolButton * pTBB = new CAppToolButton(pBar, nCmdID,
(LPCTSTR)node.GetValue("label"),-2.0);
pBar->InsertSpecButton(-1, pTBB);
return true;
}
bool CAppControlBar::CreateButtonBitmap(LPCTSTR lpszPath, CExtBitmap& bmp, COLORREF crBackground)
{
// Use GdiPlus to load the png image (seems to be the easiest way to
// load a .png file into an HBITMAP compatible class)
// Convert path to wchar
WCHAR wszFileName[256];
MultiByteToWideChar( CP_ACP, 0, lpszPath,
strlen(lpszPath)+1, wszFileName,
sizeof(wszFileName)/sizeof(wszFileName[0]) );
// Load it
Bitmap *pOrigBitmap = Bitmap::FromFile(wszFileName);
// Work out target size to maintain its aspect ratio
CSize cTargetSize;
Rect buttonRect(0,0,32,32);
int iWidth = pOrigBitmap->GetWidth();
int iHeight = pOrigBitmap->GetHeight();
if(iWidth*buttonRect.Height > iHeight*buttonRect.Width)
{
cTargetSize.cx = buttonRect.Width;
cTargetSize.cy = buttonRect.Width * iHeight / iWidth;
}
else
{
cTargetSize.cy = buttonRect.Height;
cTargetSize.cx = buttonRect.Height * iWidth / iHeight;
}
// Adjust button rect to maintain aspect and create the initial button bitmap
buttonRect = Rect(0,0,cTargetSize.cx, cTargetSize.cy);
Bitmap *pButtonBitmap = (Bitmap *)pOrigBitmap->GetThumbnailImage(buttonRect.Width, buttonRect.Height);
// Prepare a mask the same size as the bitmap (we need to draw onto a white background
// to preseve the way semi-transparent colours look in the worksheet)
Color backColor(GetRValue(crBackground), GetGValue(crBackground), GetBValue(crBackground));
Bitmap *pMask = new Bitmap(pButtonBitmap->GetWidth(), pButtonBitmap->GetHeight());
for(int y=0; y<(int)pMask->GetHeight(); y++)
{
for(int x=0; x<(int)pMask->GetWidth(); x++)
{
Color c; pButtonBitmap->GetPixel(x,y,&c);
if(c.GetA() > 0)
{
pMask->SetPixel(x,y,Color(255,255,255,255));
}
else
{
pMask->SetPixel(x,y,backColor);
}
}
}
// Create the graphics object
CBitmapDC bitmapDC(CDC::FromHandle(::GetDC(::GetDesktopWindow())), buttonRect.Width, buttonRect.Height);
Graphics *pGraphics = Graphics::FromHDC(bitmapDC);
// Fill with background (transparent) colour
SolidBrush brush(backColor);
pGraphics->FillRectangle(&brush, buttonRect);
// Draw the mask and the image into the graphics object
pGraphics->DrawImage(pMask, buttonRect);
pGraphics->DrawImage(pButtonBitmap, buttonRect);
// Finally create the proper bitmap
bmp.FromBitmap(bitmapDC.GetHBITMAP());
return true;
}
void CAppControlBar::OnApplicationRun()
{
CString m_cAppID = AfxGetApp()->GetAppID(); //Get the name of the .exe to open
CString cDirectory = CDatsUtil::GetDatsDirectory()
+ "\\bin\\" + m_cAppID; //point to the default directory for these kinds of things
ShellExecute(0, "open", cDirectory, 0, 0, SW_SHOW); //Open the exe
}
void CAppControlBar::OnScriptRun()
{
CString m_cAppID = AfxGetApp()->GetAppID(); //Get the name of the script to open
int m_iIsScriptDefault = m_cAppID.Find(":"); //Test to see if the script is in the default location
int m_iIsScriptInDats = m_cAppID.Find("%DATS%"); //Test to see if %DATS% has been used
if (m_iIsScriptDefault > -1 || m_iIsScriptInDats > -1)
{
AfxGetApp()->RunScript(m_cAppID);// Open the script with the path provided
}
else
{
CString cDirectory = CDatsUtil::GetDatsDirectory()
+ "\\bin\\Scripts\\" + m_cAppID;
AfxGetApp()->RunScript(cDirectory); //Open the script with the default path
}
}
void CAppControlBar::OnAppUpdateCommand(CCmdUI *pCmdUI)
{
UINT m_iButtonID = (pCmdUI->m_nID) - 2100; // 2100 being the start of the range used
//to identify the appcontrolbar commands
CString m_cButtonID = g_PseudoAppClasses.GetAt(m_iButtonID);
//Need to remove the %DATS% in order to use the GetDatsDirectory function
int m_iDatsDirectoryUsed = m_cButtonID.Find("%DATS%");
if (m_iDatsDirectoryUsed > -1)
{
int n = m_cButtonID.Replace("%DATS%","");
}
WIN32_FIND_DATA findFileData;
HANDLE hFindExe;
HANDLE hFindScript;
HANDLE hFindOther;
//Here we search for whether the .exe or script associated with the command is installed, and
//to disable/grey out the button if the desired object is not installed.
hFindExe = FindFirstFile((CDatsUtil::GetDatsDirectory()+"\\bin\\"+m_cButtonID), &findFileData);
hFindScript = FindFirstFile((CDatsUtil::GetDatsDirectory()+"\\bin\\Scripts\\"+m_cButtonID), &findFileData);
hFindOther = FindFirstFile((CDatsUtil::GetDatsDirectory()+m_cButtonID), &findFileData);
if (hFindExe == INVALID_HANDLE_VALUE && hFindScript == INVALID_HANDLE_VALUE && hFindOther == INVALID_HANDLE_VALUE)
{
pCmdUI->Enable(FALSE);
return;
}
pCmdUI->Enable(TRUE);
}
Now after taking your advise in regards to commenting out the code we found that the memory leak is stopped when pBar->InsertSpecButton(-1, pTBB); is not called within the following function. bool CAppControlBar::InsertButton(CExtToolControlBar *pBar, UINT nCmdID, CXmlNode& node, CExtBitmap& bmp, COLORREF crTransparent)
{
CString cProfileName = g_CmdManager->ProfileNameFromWnd(m_hWnd);
// Add the command name and set the commands user data to point to it
CExtCmdItem cExtCmd(nCmdID);
int iIndex = g_PseudoAppClasses.Add(node.GetValue("class"));
g_PseudoAppID.Add(node.GetValue("id"));
cExtCmd.m_nLParamUserData = iIndex;
// Add the dynamically allocated command id into the command manager
g_CmdManager->CmdSetup(
cProfileName,
cExtCmd,
true,
NULL);
// Change the commands icon to the one supplied
g_CmdManager->CmdSetIcon(
cProfileName,
nCmdID,
bmp,
crTransparent,
NULL);
// Finally, Insert the button
//pBar->InsertButton( -1, cExtCmd.m_nCmdID, NULL );
CAppToolButton * pTBB = new CAppToolButton(pBar, nCmdID,
(LPCTSTR)node.GetValue("label"),-2.0);
pBar->InsertSpecButton(-1, pTBB);
return true;
}
|
|
Technical Support
|
Jun 6, 2008 - 1:22 PM
|
Please let us know, if you are closing application in debug session, then whether the Output window in your Visual Studio contains dump information describing memory leaks? If yes, then you should be able to double click on the strings in the memory leaks dump text and you should see the source code points where the leaked memory was allocated. If no, then we suspect your code allocates command items in the command manager and does not release them. In this case command items are released at shutdown. If our guess is correct, then you should know that the 65534 number is maximal count of commands which can be allocated in one command manager’s profile.
We also suspect the CAppControlBar::CreateButtonBitmap() method can be source of memory leaks. It looks like it allocates some objects dynamically and we have no idea where they become released. The 4096 bytes looks like too big size for 16x16 icon with 32-BPP (4-bytes) because 16 * 16 * 4 = 1024. But 32 * 32 * 4 = 4096.
In any case, you can comment parts of your code for detecting situation when the memory will start growing. You can start from removing the image loading code and provide toolbar buttons with empty icons.
|
|
Technical Support
|
Jun 5, 2008 - 11:57 AM
|
Prof-UIS toolbars have never had such memory leak problems. We need more details about your toolbars. Do you use some custom painting code or some timer based code which creates dynamically instantiated objects and potentially do not release them? Before you spend your time for creating a test project, you can try to comment out some parts of your code related to your toolbar class(es) and try to find out when leaking stops.
|
|