A Fix for CToolBar with IE4

The new version of COMCTL32.DLL that is shipped with the release version of IE4 (4.71.1712.3) has a problem when combined with the MFC CToolBar.  When an MFC application is run under IE4, and a toolbar with separators (groups) is docked vertically, or floated with >1 row) then the bottom button/row is clipped.

The reason for this is that CToolBar was written with the assumption the horizontal separators are 8 pixels wide and vertical separator are (8*2/3) = 5 pixels high.  This was the case until IE4 came along.  Now the vertical separators are 8 pixels high instead of 5 pixels.  So CToolBar does not allocate enough room for the tooblar buttons.

If MFC had made the function which calculates the size of the buttons and separtors virtual, then all that would be required is to override that single function.  However, in their infinite wisdom, the MFC designers di not do this for us.  So now one needs to copy many functions with many many lines of code so one can patch up this 'mistake'.

The code below assumes that you have the code I published earlier the detects the version of COMCTL32 that is currently loaded.  It then makes the fixes required based on which version is running.  If it is the IE4 version, then it uses 8 pixels for the height, otherwise it uses 5 pixels as before (8*2/3)

Step 1:

To make the fix, copy the following functions verbatim from the "BARTOOL.CPP" in your MFC source tree, and change all occurences of "CToolBar" to "CMyToolBar"

void CMyToolBar::_GetButton(int nIndex, TBBUTTON* pButton) const
{
     ...
}
void CMyToolBar::_SetButton(int nIndex, TBBUTTON* pButton)
{
     ...
}

#ifdef _MAC
     #define CX_OVERLAP  1
#else
     #define CX_OVERLAP  0
#endif

void CMyToolBar::SizeToolBar(TBBUTTON* pData, int nCount, int nLength, BOOL bVert)
{
     ...
}
}

struct _AFX_CONTROLPOS
{
     int nIndex, nID;
     CRect rectOldPos;
};

CSize CMyToolBar::CalcLayout(DWORD dwMode, int nLength)
{
     ...
}

CSize CMyToolBar::CalcFixedLayout(BOOL bStretch, BOOL bHorz)
{
     ...
}
CSize CMyToolBar::CalcDynamicLayout(int nLength, DWORD dwMode)
{
     ...
}

Step 2:

Copy and MODIFY the CalcSize routine from "BARTOOL.CPP" as shown .. my changes and additions are commented with // RO

CSize CMyToolBar::CalcSize(TBBUTTON* pData, int nCount)
{
    // Check for COMCTL32 version number // RO
    bool isfullheightsep = false; // RO
    if (QWinApp::ComCtl32Version() >= COMCTL32_471) { // RO
        isfullheightsep = true;  // RO
    }    // RO
    ASSERT(pData != NULL && nCount > 0);

    CPoint cur(0,0);
    CSize sizeResult(0,0);

    for (int i = 0; i < nCount; i++)      
    {           
        if (pData[i].fsState & TBSTATE_HIDDEN)
            continue;
        int iBitmapx = pData[i].iBitmap;    // RO
        int iBitmapy = iBitmapx;            // RO           
        if (! isfullheightsep) 
            iBitmapy = iBitmapy * 2 / 3;    // RO

        if (pData[i].fsStyle & TBSTYLE_SEP)
        {                
            // A separator represents either a height or width                
            if (pData[i].fsState & TBSTATE_WRAP)                     
                sizeResult.cy = max(cur.y + m_sizeButton.cy + iBitmapy,sizeResult.cy);    // RO
                // RO sizeResult.cy = max(cur.y + m_sizeButton.cy + pData[i].iBitmap * 2 / 3, sizeResult.cy); 
            else                   
                sizeResult.cx = max(cur.x + iBitmapx, sizeResult.cx); // RO 
                // RO sizeResult.cx = max(cur.x + pData[i].iBitmap,sizeResult.cx);  
        }           
        else          
        {              
            sizeResult.cx="max(cur.x" + m_sizeButton.cx, sizeResult.cx);       
            sizeResult.cy="max(cur.y" + m_sizeButton.cy, sizeResult.cy); 
        }   
      
        if (pData[i].fsStyle & TBSTYLE_SEP)        
            cur.x +="pData[i].iBitmap;"         
        else              
            cur.x +="m_sizeButton.cx" CX_OVERLAP;         

        if (pData[i].fsState & TBSTATE_WRAP)        
        {            
            cur.x = 0;
            cur.y += m_sizeButton.cy;
            if (pData[i].fsStyle & TBSTYLE_SEP)        
                cur.y +=iBitmapy; // RO   
            cur.y +="pData[i].iBitmap" * 2 / 3;    
        }   
   }     

   return sizeResult; 
} 

In summary I have added 5 lines at the top to detect the version, added 3 lines before "if (pData[i].fsState & TBSTYLE_SEP)", replaced two lines in the following "if" and replaced one line near the end.

Step 3:

You need to define a CToolBar derived CMyToolBar (or CFlatToolBar-derived, or make the changes to CFlatTOolBar anyway which is what I did). In that class, you will need to copy the declarations for the functions we have copied - don't forget to make CalcDynamicSize and CalcFixedSize VIRTUAL functions !!

That should do it.  Now your toolbars will work under all versions of COMCTL32.DLL - well, at least until MS releases a new version :-)



Comments

  • GGFG

    Posted by Legacy on 06/10/2003 12:00am

    Originally posted by: JAIME

    HHHFFF

    Reply
  • Does anyone know how to get rid of the default spacing between buttons

    Posted by Legacy on 07/25/2001 12:00am

    Originally posted by: Tony Karam

    Does anyone know how to get rid of the default spacing between buttons ?

    Reply
  • Already fixed by MFC but still buggy

    Posted by Legacy on 06/09/1999 12:00am

    Originally posted by: Angela R�sch

    I spent a lot of time with the pixel errors around my toolbars I created with VC++6.0 and IE4.
    First I was lucky to find this page which seems to be the solution for my pixel problem. But when I started to implement the bugfix, I saw that the code was already extended in that way! But what about my still existing error ?!? So I visited the code guru again and - found a second entry which *really* fixed my problem: on the "Toolbar Open FAQ" list the entry named "Fixing Painting Problem With Flat Toolbar". I hope this tip protect some other users from wasting time.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • On-demand Event Event Date: December 18, 2014 The Internet of Things (IoT) incorporates physical devices into business processes using predictive analytics. While it relies heavily on existing Internet technologies, it differs by including physical devices, specialized protocols, physical analytics, and a unique partner network. To capture the real business value of IoT, the industry must move beyond customized projects to general patterns and platforms. Check out this webcast and join industry experts as …

Most Popular Programming Stories

More for Developers

RSS Feeds