RE: CToolBarCtrl::GetButtonInfo Bug?
Doing a little more research, I've found the problem.
CToolBarCtrl::GetButtonInfo looks like this:
_AFXCMN_INLINE BOOL CToolBarCtrl::GetButtonInfo(int nID, TBBUTTONINFO*
ptbbi) const
{ ASSERT(::IsWindow(m_hWnd)); return (BOOL) ::SendMessage(m_hWnd,
TB_GETBUTTONINFO, nID, (LPARAM)ptbbi); }
The TB_GETBUTTONINFO msg returns a 0 based index. Whoever wrapped that
message for this class incorrectly decided to cast the result to a BOOL, so
that valid 0 index is returned as FALSE. So the only way to accurately
handle this is to not use the GetButtonInfo method, and just send the msg
yourself.
Torin
"T. Ford" wrote:
I'm not sure if this is a bug in my code or a bug in MFC.
1 - Create a test SDI MFC app.
2 - Add a new toolbar to this app.
3 - Add only 1 button to the toolbar (call it ID_FIRST_BUTTON).
4 - Add ID_FIRST_BUTTON to any of the drop down menus.
5 - Add a menu handler to app class for ID_FIRST_BUTTON.
6 - Add public method to CMainFrame class with this signature:
void Toggle(void)
7 - Have the ID_FIRST_BUTTON handler (in app class) get a reference to your
main frame, and then call the Toggle method.
8 - Toggle should look like this:
void CMainFrame::Toggle(void)
{
static bool bPressed = false;
CToolBarCtrl &toolBarCtrl = m_wndToolBar2.GetToolBarCtrl();
TBBUTTONINFO buttonInfo;
memset(&buttonInfo, 0, sizeof(TBBUTTONINFO));
buttonInfo.cbSize = sizeof(TBBUTTONINFO);
buttonInfo.dwMask = TBIF_STATE;
bPressed = !bPressed;
if (toolBarCtrl.GetButtonInfo(ID_FIRST_BUTTON, &buttonInfo) != FALSE)
{
if (!bPressed)
{
buttonInfo.fsState &= ~TBSTATE_PRESSED;
}
else if (bPressed)
{
buttonInfo.fsState |= TBSTATE_PRESSED;
}
toolBarCtrl.SetButtonInfo(ID_FIRST_BUTTON, &buttonInfo);
}
CToolBarCtrl &toolBarCtrl2 = m_wndToolBar.GetToolBarCtrl();
memset(&buttonInfo, 0, sizeof(TBBUTTONINFO));
buttonInfo.cbSize = sizeof(TBBUTTONINFO);
buttonInfo.dwMask = TBIF_STATE;
if (toolBarCtrl2.GetButtonInfo(ID_FILE_OPEN, &buttonInfo) != FALSE)
{
buttonInfo.fsState |= TBSTATE_PRESSED;
toolBarCtrl2.SetButtonInfo(ID_FILE_OPEN, &buttonInfo);
}
memset(&buttonInfo, 0, sizeof(TBBUTTONINFO));
buttonInfo.cbSize = sizeof(TBBUTTONINFO);
buttonInfo.dwMask = TBIF_STATE;
if (toolBarCtrl2.GetButtonInfo(ID_FILE_NEW, &buttonInfo) != FALSE)
{
buttonInfo.fsState |= TBSTATE_PRESSED;
toolBarCtrl2.SetButtonInfo(ID_FILE_NEW, &buttonInfo);
}
}
The point of Toggle is to set your new button to the pressed state when you
click it. It also attempts to do the same for ID_FILE_NEW and ID_FILE_OPEN.
You will see that GetButtonInfo(ID_FIRST_BUTTON, ...) and
GetButtonInfo(ID_FILE_NEW, ...) will fail. GetButtonInfo(ID_FILE_OPEN, ...)
will not fail. This appears to real some failure with GetButtonInfo where it
fails to return the information for the first button on a toolbar. Is this a
bug in my code or in MFC? Any way around it? If you insert a button before
ID_FIRST_BUTTON, then the calls for ID_FIRST_BUTTON will succeed.
Torin