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 🙂