Click here to Skip to main content
16,020,990 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello everyone.

I am developing a new MFC Multiple Top Level Document Application.

At the moment i am trying to figure a way to change the ribbon bar of a MainFrm
dynamically at two certain points of the application's lifecycle.

The first one is when the app has just opened and no document is opened yet. At this point i suppose that the application is in a initial state.
So, the first frame has a ribbon bar with some basic controls. When the user selects to create a new frame or open a saved document,
then instead of opening a new frame window, i "convert" the already opened window by loading another ribbon resource.

The code i achieve this is the following:

C++
void CMyAppMainFrame::LoadRibbonFromUINT(UINT ribbon_res) 
{
    //close cats/tabs to avoid appending when new ribbon opens
    m_wndRibbonBar.RemoveAllCategories();
    m_wndRibbonBar.RemoveAllFromTabs();

    //close ribbon bar
    RemovePaneFromDockManager(&m_wndRibbonBar, TRUE, TRUE, FALSE, NULL);

    VERIFY(m_wndRibbonBar.Create(this));
    VERIFY(m_wndRibbonBar.LoadFromResource(ribbon_res));
	m_wndRibbonBar.ForceRecalcLayout();
}


This step works fine.

The second case is when the user has only one document open and closes it.
In this case i want to keep the document open and just change the ribbon bar back to the basic one.
The user can close the document in two ways.

  • The first one is from the main menu (Main Button -> Close). This action calls the
    C++
    CMyAppDoc::OnCloseDocument().

    Inside the OnCloseDocument i trace that this is the last document open, so i keep it alive and load the basic ribbon bar.


  • The second way is when the user presses the top right X button to close it.
    Then the overriden function CMyAppMainFrame::OnClose is called.
    Inside there i call the CMyAppDoc::OnCloseDocument() which (as before) checks that this is the last document, so instead of closing, calls the CMyAppMainFrame::LoadRibbonFromUINT in order to load the basic RibbonBar.

The first way works just fine!
But when i press the top right X button, although the control is also sent to CMyAppDoc::OnCloseDocument(), when the m_wndRibbonBar.ForceRecalcLayout() is called i get an exception.

I suppose that when i press the X button, perhaps the MFC frameworks invalidates some of FrameWnd members before the control reaches the CMyAppMainFrame::OnClose.
So when i try to recalc the RibbonBar layout, i get the exception.

Does anyone have a deeper understanding on the closing mechanism of MFC and how i could overcome this behaviour?

Thank you in advance!

What I have tried:

C++
void CMyAppMainFrame::LoadRibbonFromUINT(UINT ribbon_res) 
{
    //close cats/tabs to avoid appending when new ribbon opens
    m_wndRibbonBar.RemoveAllCategories();
    m_wndRibbonBar.RemoveAllFromTabs();

    //close ribbon bar
    RemovePaneFromDockManager(&m_wndRibbonBar, TRUE, TRUE, FALSE, NULL);

    VERIFY(m_wndRibbonBar.Create(this));
    VERIFY(m_wndRibbonBar.LoadFromResource(ribbon_res));
	m_wndRibbonBar.ForceRecalcLayout();
}
Posted
Updated 7-May-22 13:18pm

1 solution

When the X button is pressed, windows sends a WM_SYSCOMMAND message which can be handling using an override of the OnSysCommand method. Here's a little snippet that traps the message sent when the X button is pressed :
C++
void CMainFrame::OnSysCommand( UINT id, LPARAM lParam )
{
	UINT value = id & 0x0FFF0;
	switch( value )
	{
    case SC_CLOSE :
		TRACE( "this application is closing\n" );
		return;
    }
	__super::OnSysCommand( id, lParam );
}
I believe that internally MFC starts shutting down windows and refuses to do certain other things because an application flag is set signifying the app is closing. For this reason, you can't really do very much in terms of creating new controls or loading resource.

Note - this is my hypothesis from working with MFC a long time and I am not certain of it. However, if you add the above code snippet into your application you can step through the code with a debugger and see why certain things are failing.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900