dcsimg

A Fix for CToolBar with IE4

WEBINAR:
On-Demand

Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame


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 :-)



Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date