FIX: Internal State of ControlBars Corrupted

Last reviewed: September 19, 1997
Article ID: Q151446
4.00 4.10 WINDOWS NT kbui kbprg kbbuglist kbcode kbfixlist

The information in this article applies to:

  • The Microsoft Foundation Classes (MFC), included with: Microsoft Visual C++, 32-bit Edition, versions 4.0, 4.1

SYMPTOMS

The internal state of the controlbars is corrupted when controlbars are docked and undocked. The size of the Registry key or the .INI file grows when SaveBarState is a result of this corruption.

CAUSE

The code for managing the controlbar docking and undocking has a bug which does not correctly remove information from the data structures. None of this code can be overridden to fix the bug because it is undocumented private implementation of the MFC.

RESOLUTION

The sample code at the end of this article cleans up the state of these internal structures. The CleanUpControlBarState function cleans up the information in the CDockState object passed to it. When the function returns, the CDockState object has the clean information.

Call this function with the present state of the controlbars, and use the information after calling CleanUpControlBarState.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. This bug was corrected in Visual C++ 32- bit Edition version 4.2.

MORE INFORMATION

There are two ways to get information into a CDockState object:

  • Call the CDockState::LoadState to load the state of the controlbars from the Registry or .INI file.
  • Use the CFrameWnd::GetDockState.

To save the state to the Registry or .INI file, use CDockState::SaveState. Use CFrameWnd::SetDockState to set the state of the controlbars at run time.

The following code was added to the Docktool sample. This code saves the non-corrupted controlbar information to the .INI file:

   void CMainFrame::OnClose()
   {
       // SaveBarState saves everything but the number of Columns in
       // the Palette we need to do that ourselves.
       SaveBarState(_T("General"));


   // Following code was added to the sample with Visual C++ 4.1
   #if _MFC_VER == 0x0400 || _MFC_VER == 0x0410

       CDockState state;
       GetDockState(state);

       CleanUpControlBarState(state);

       state.SaveState(_T("General"));

   #endif
   ...

Sample Code

// In this case the function is defined as a global function.
// You could make it a member of one of your classes

Add the following prototype to the end of your stdafx.h:

#if _MFC_VER == 0x0400 || _MFC_VER == 0x0410

void CleanUpControlBarState(CDockState& state);

#endif

and add the following code to one of your CPP files:

#if _MFC_VER == 0x0400 || _MFC_VER == 0x0410

void CleanUpControlBarState(CDockState& state)
{

    for (int i = 0; i < state.m_arrBarInfo.GetSize(); i++)
    {
        CControlBarInfo* pInfo1 = (CControlBarInfo*)state.m_arrBarInfo[i];

        for (int j = 0; j < state.m_arrBarInfo.GetSize(); j++)
        {
            if (i == j)
                continue;

            CControlBarInfo* pInfo2 =
                (CControlBarInfo*)state.m_arrBarInfo[j];

            if (pInfo1->m_uMRUDockID == pInfo2->m_nBarID)
                continue;

            int nSize = pInfo2->m_arrBarID.GetSize();
            for (int k = 0; k < nSize - 1; k++)
            {
                if ((LONG)pInfo2->m_arrBarID[k] ==
                    (LONG)pInfo1->m_nBarID + 0x10000)

                    pInfo2->m_arrBarID[k] = NULL;
            }
        }
    }

    for (i = 0; i < state.m_arrBarInfo.GetSize(); i++)
    {
        CControlBarInfo* pInfo = (CControlBarInfo*)state.m_arrBarInfo[i];

        int nSize = pInfo->m_arrBarID.GetSize();
        for (int j = 0; j < nSize - 1; j++)
        {
            if (pInfo->m_arrBarID[j]==NULL)
                continue;

            for (int k = j + 1; k < nSize; k++)
            {
                if (pInfo->m_arrBarID[k]==NULL)
                    continue;

                if (pInfo->m_arrBarID[k]==pInfo->m_arrBarID[j])
                    pInfo->m_arrBarID[k] = NULL;
            }
        }

        while ((nSize!=0) && (pInfo->m_arrBarID[nSize-1]==NULL))
        {
            nSize--;
            pInfo->m_arrBarID.RemoveAt(nSize);
        }
        if (nSize)
            pInfo->m_arrBarID.InsertAt(nSize, (void*)NULL);
    }
}

#endif

NOTE: The sample code above uses undocumented functionality of the MFC. To be compatible with future versions of MFC, enclose the code between the following directives:

   #if _MFC_VER == 0x0400 || _MFC_VER == 0x0410
   ...
   ...
   #endif

Also include any call to CleanUpControlBarState between these directives.


Additional reference words: 4.00 4.10 4.20 LoadBarState SaveBarState ini
grow vcbuglist400 vcfixlist420
KBCategory: kbui kbprg kbbuglist kbcode kbfixlist
KBSubcategory: MfcUI

Keywords : MfcUI kbbuglist kbcode kbfixlist kbprg kbui
Technology : kbMfc
Version : 4.00 4.10
Platform : NT WINDOWS
Solution Type : kbfix


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: September 19, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.