最近在学习WTL时,尝试用CUpdateUI在非模态对话框中同时修改按钮和菜单的文本时,菜单文本总是修改不成功,但单独修改菜单项的文本则没有问题。经过反复试验和源码对照,终于确定了问题所在。现在将这个WTL中的bug与大家分享一下,以便其他人遇到类似问题,不在迷茫。
在WTL(版本81_9127)中,打开atlframe.h中的第2604行,也就是CUpDateUIBase类的 BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE) 方法。代码如下:
BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)
{
if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)
return TRUE;
const _AtlUpdateUIMap* pMap = m_pUIMap;
_AtlUpdateUIData* pUIData = m_pUIData;
if(pUIData == NULL)
return FALSE;
while(pMap->m_nID != (WORD)-1)
{
for(int i = 0; i < m_UIElements.GetSize(); i++)
{
if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)
{
if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))
UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
}
}
pMap++;
pUIData->m_wState &= ~UPDUI_CHILDWINDOW;
if(pUIData->m_wState & UPDUI_TEXT)
{
delete [] pUIData->m_lpstrText;
pUIData->m_lpstrText = NULL;
pUIData->m_wState &= ~UPDUI_TEXT;
}
pUIData++;
}
m_wDirtyType &= ~UPDUI_CHILDWINDOW;
return TRUE;
}
在while循环中,对pUIData 的处理存在问题。这段代码的本意是查找m_UIElement中的所有UPDUI_CHILDWINDOW项中的需要更新的项,在更新完成后删除已经更新过的pUIData中的m_lpstrText项。 但这段代码的处理变成了,删除所有pUIData的m_lpstrText 项。因此造成设置按钮项的文本造成菜单文本的丢失。
因此将代码改成如下则修正了这个bug:
BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)
{
if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)
return TRUE;
const _AtlUpdateUIMap* pMap = m_pUIMap;
_AtlUpdateUIData* pUIData = m_pUIData;
if(pUIData == NULL)
return FALSE;
//add by zry
while(pMap->m_nID != (WORD)-1)
{
for(int i = 0; i < m_UIElements.GetSize(); i++)
{
if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)
{
if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))
{
UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
pUIData->m_wState &= ~UPDUI_CHILDWINDOW;
if(pUIData->m_wState & UPDUI_TEXT)
{
delete [] pUIData->m_lpstrText;
pUIData->m_lpstrText = NULL;
pUIData->m_wState &= ~UPDUI_TEXT;
}
}
}
}
pMap++;
pUIData++;
}
m_wDirtyType &= ~UPDUI_CHILDWINDOW;
return TRUE;
}
将删除文本和修改标志的代码移动到if语句内,则保证了只删除已经更新了得TEXT。
另外,大家可能有个疑问,为什么状态条,工具条,和菜单同时修改就没有问题呢? 这是因为按钮或其它控件在添加UPDATE_ELEMENT 时,需要作为UPDUI_CHILDWINDOW进行添加,因此他们的更新需要调用UIUpdateChildWindows方法,而状态条,工具条的更新则不会调用这个方法,因此不会出现类似情况。