Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS General Discussion » CExtDynamicBarSite::StateLoad() Collapse All
Subject Author Date
Andrew Harding May 24, 2006 - 6:24 PM

Is it possible to have multiple CFrameWnd’s in a single app that share the same Company, Product and Profile location in the registry? For instance say that you have a CMainFrame that contains a list of clients, when you double click a client it opens a client information window (CFrameWnd which contains several dynamic control bars), you can have multiple client information windows open.

I would like to be able to save and restore the layout of the dynamic control bars on the client information window, if the layout is saved then any subsequent window that is opened would have the same layout as the window that saved the state.

The problem I have is that each client information window must call CExtDynamicBarSite::StateLoad() to allocate and position the control bars, if I open more than one client information window then CExtDynamicBarSite::StateLoad() ASSERTs in CExtDynamicBarSite::StateSerialize() because BarAlloc() returns NULL.

Technical Support May 25, 2006 - 8:11 AM

We just added a FAQ with this. If the answer is not complete, please let us know.

Andrew Harding May 25, 2006 - 10:58 AM

Well I modified my code to match what the FAQ suggested but I’m still getting an assertion in the same place, here is my OnCreate():

int MyCFrameWnd::OnCreate( LPCREATESTRUCT lpcs )
{
    CTypedPtrArray<CPtrArray, CExtDynamicControlBar*> aAllControlBars;
    CExtDynamicControlBar    *pBar = NULL;
    CString                    barCaption;
    CExtCmdIcon                icon;
CRect                    rect;
    int                        i, n;

    // init variables
    m_controlBars.clear ( );
    icon.CreateEmptyIcon ( );

    // add this window to the command manager
    VERIFY( g_CmdManager->ProfileWndAdd( theApp.m_pszProfileName, GetSafeHwnd()    ) );
    VERIFY(    g_CmdManager->UpdateFromMenu( theApp.m_pszProfileName, IDR_CASEMG_CASEMENU ) );

    // Create the docking bars ( THE ASSERT HAPPENS HERE )
    if ( !CExtDynamicBarSite::StateLoad(theApp.GetCompanyName(), theApp.GetProductName(), m_szFrameName) )
    {
        aAllControlBars.Add ( CExtDynamicBarSite::BarAlloc ( ResString(IDS_MY_WINDOW_TITLE_1).GetString(), icon, 0, RUNTIME_CLASS(CExtDynamicControlBar) ) );
        aAllControlBars.Add ( CExtDynamicBarSite::BarAlloc ( ResString(IDS_MY_WINDOW_TITLE_2).GetString(), icon, 0, RUNTIME_CLASS(CExtDynamicControlBar) ) );
    }
    else
    {
        CExtDynamicBarSite::BarEnumGetArray( aAllControlBars, true, true );
    }

    // Populate the map of resource id’s to control bars
    n = int(aAllControlBars.GetSize());
    for ( i = 0; i < n; i++ )
    {
        pBar = (CExtDynamicControlBar*)aAllControlBars[i];
        barCaption = pBar->m_strCaptionText;
        if ( barCaption.Compare ( ResString(IDS_MY_WINDOW_TITLE_1) ) == 0 )
            m_controlBars[IDS_MY_WINDOW_TITLE_1] = pBar;
        else if ( barCaption.Compare ( ResString(IDS_MY_WINDOW_TITLE_2) ) == 0 )
            m_controlBars[IDS_MY_WINDOW_TITLE_2] = pBar;
        else
        {
            TRACE ( "Unhandled control bar, it needs to be added to this map!" );
            ASSERT ( 0 );
        }
    }

    // Create the dialog boxes that go inside of the
    // docking containers
    m_myDockedWindow1 = new CExtWFF<CInformativeDialog>;
    m_myDockedWindow1->Create(CInformativeDialog::IDD, m_controlBars[IDS_MY_WINDOW_TITLE_1] );
    m_myDockedWindow2 = new CExtWFF<CMoreInformationDialog>;
    m_myDockedWindow2->Create(CMoreInformationDialog::IDD, m_controlBars[IDS_MY_WINDOW_TITLE_2]);

    // dock the windows
    if ( !CExtControlBar::ProfileBarStateLoad(this, theApp.GetCompanyName(), theApp.GetProductName(), m_szFrameName, &m_dataFrameWP) )
    {
        m_controlBars[IDS_MY_WINDOW_TITLE_1]->BarStateSet ( CExtDynamicControlBar::__EDBS_DOCUMENT, true );
        m_controlBars[IDS_MY_WINDOW_TITLE_2]->BarStateSet ( m_controlBars[IDS_MY_WINDOW_TITLE_2]->BarStateGet(), true );
        m_controlBars[IDS_MY_WINDOW_TITLE_2]->DockControlBarInnerOuter ( AFX_IDW_DOCKBAR_TOP, false, this, true );
    }
}

Andrew Harding May 25, 2006 - 12:03 PM

We’re using Prof-UIS 2.52 professional version. The assert happens in extcontrolbar.cpp on line 23731, it fails because BarAlloc() returns NULL.

I believe that the FAQ was addressing a different issue than the one I was describing. I get the impression that the FAQ was talking about simply keeping all window registry information under a common root. The problem I’m having is that I have multiple CFrameWnd’s that use the same profile name template, the first such CFrameWnd to be created makes it past the StateLoad() just fine, it’s any subsequent CFrameWnd that is created while the first one is still created that causes the assert.

IE: in my CMainFrame I would call:

MyCFrameWnd *pWnd1 = new MyCFrameWnd();
pWnd1->Create(...);
MyCFrameWnd *pWnd2 = new MyCFrameWnd();
pWnd2->Create(...); // this call would cause the assert (I assume it’s asserting because StateLoad() doesn’t take a pointer to the docking site as a parameter it can’t handle multiple instances of windows which share the same profile name)

Technical Support May 25, 2006 - 11:35 AM

Please let us know the exact file name and line number where the assertion occurs. Of course, if you tell us which library version you are using, that would also be helpful.


Andrew Harding May 25, 2006 - 12:07 PM

Oops, I clicked on the wrong reply link sorry for the double post.

We’re using Prof-UIS 2.52 professional version. The assert happens in extcontrolbar.cpp on line 23731, it fails because BarAlloc() returns NULL.

I believe that the FAQ was addressing a different issue than the one I was describing. I get the impression that the FAQ was talking about simply keeping all window registry information under a common root. The problem I’m having is that I have multiple CFrameWnd’s that use the same profile name template, the first such CFrameWnd to be created makes it past the StateLoad() just fine, it’s any subsequent CFrameWnd that is created while the first one is still created that causes the assert.

IE: in my CMainFrame I would call:

MyCFrameWnd *pWnd1 = new MyCFrameWnd();
pWnd1->Create(...);
MyCFrameWnd *pWnd2 = new MyCFrameWnd();
pWnd2->Create(...); // this call would cause the assert (I assume it’s asserting because StateLoad() doesn’t take a pointer to the docking site as a parameter it can’t handle multiple instances of windows which share the same profile name)

Technical Support May 26, 2006 - 3:24 AM

We guess the problem is caused by a collision of command identifiers. The main frame window allocates some dynamic bar(s) with their unique identifiers. The client information frame allocates some bar which has identifier which is equal to the identifier of one of the bars in the main frame window. The problem is not with bar allocation. The problem is in command identifier allocation in the command manager. We recommend you to do the following steps:

1) Clean the registry state.

2) Change the nDesiredCmdID parameter in all the invocations of the CExtDynamicBarSite::BarAlloc() method in all your frame classes. All the bars in all the frames should be allocated using the unique nDesiredCmdID value. For instance, you can use the command range starting from 10000.

Andrew Harding May 26, 2006 - 9:46 AM

Well I changed the BarAlloc function calls to use an incrementing global variable starting at 10000 (there are no resource collisions in that range), cleaned the registry state, loaded the first child window and saved the state, then I tried to load the second child window and it crashed in the same place.

I stepped through the BarAlloc function to see why it was returning NULL, it returns NULL because OnDbsAllocNewBarCommandID() returns 0;

I believe you are correct in that the reason it is crashing is because of conflicting command id’s, the problem is that I have no control over what the command id’s will be when the second child window is created because in my OnCreate() I first call CExtDynamicBarSite::StateLoad() to see if I can load the bars positions and sizes and if that fails (it always will when opening the second window since they share the same profile name because I want them to have the same layout) then I call CExtDynamicBarSite::BarEnumGetArray( aAllControlBars, true, true ) to get the control bars instead. It’s from inside this BarEnumGetArray() that the command id’s are specified automatically from the archive.

Technical Support May 28, 2006 - 1:08 PM

Thank you for the details. The CExtDynamicBarSite::OnDbsAllocNewBarCommandID() method simply invokes CExtCmdManager::CmdAllocPtr(). The latter fails to allocate a new command identifier only in two cases:

1) The specified command identifier is not free. This can happen when loading the UI state of the dynamic bar site and the identifier is not free. This can happen in any other case when the identifier is not free and this is very unlikely.

2) All the range of available command identifiers [ 1 . . 65635 ] is allocated. We did come across this case except our tests.

It seems at this point we can effectively help you in two ways:

1) Send us a project that demonstrates the problem so we can find out what’s wrong.
2) We can debug your app remotely by connecting to your desktop. In this case, contact us by e-mail for details.