Home made MDI windows list in Window menu

-->

Why we need it.

Windows list is a part of standard MDI windows interface. There are some bug(s) admitted by Microsoft. See MS KB article Q125435 for example. It is (almost) impossible to modify it. It is much easier to reproduce Windows menu behavior. This project can serve as a start point for window menu modification. Add something to menu items, graphics for example, or create a different MoreWindows dialog. To include invisible MDIChilds to activate them from a menu etc.

How to do this thing.

First of all this example based on MFC application generated by AppWizard. Modifications are mostly made in MainFrm.cpp,.h module, using wizards when possible.

1. Remove standard windows list.

Modify all standard Window menu IDs generated by AppWizard. MDI interface relays on this IDs. So just rename ID_WINDOW_NEW to ID_WINDOWS_NEW ID_WINDOW_CASCADE to ID_WINDOWS_CASCADE etc. for all menu items under Window menu. AppStudio creates new IDs for existing items. Build and run project to be sure the windows list does not exist any more and standard MDI commands (New Window, Cascade, Tile...) don't work. Add the fifth item - separator to the menu. Add #define NUM_FIXED_ITEMS 5 to MainFrm.cpp

2. Using ClassWizard add message handlers for new menu IDs.

Implement them however you want. For Example mimic a usual behavior.

void CMainFrame::OnWindowsTileHorz() 
{
 // TODO: Add your command handler code here
 MDITile(MDITILE_HORIZONTAL);
}

Now we have reproduced a fixed part of Window menu. Build and try it.

3. Add a protected member function to return CMenu object for Window menu to CMainFrame


CMenu* CMainFrame::GetWindowMenu()
{
// MENU_POSITION is not reliable because it's different for different views
		
	CMenu* pWindowMenu = NULL;
	CMenu* pTopMenu = GetMenu();
	CString strMenu;
	for (int iPos = pTopMenu->GetMenuItemCount()-1; iPos >= 0; iPos--)
	{
		pTopMenu->GetMenuString( iPos, strMenu, MF_BYPOSITION );
		if (strMenu == "&Window")
		{
			pWindowMenu = pTopMenu->GetSubMenu(iPos);
			break;
		}
	}
	ASSERT(pWindowMenu != NULL);
	return pWindowMenu;
}

Now we are ready to modify the menu.

4. Add new ID to resource.h manually


#define ID_WINDOWS_FIRST                32001
#define ID_WINDOWS_2                    32002
#define ID_WINDOWS_3                    32003
#define ID_WINDOWS_4                    32004
#define ID_WINDOWS_5                    32005
#define ID_WINDOWS_6                    32006
#define ID_WINDOWS_7                    32007
#define ID_WINDOWS_8                    32008
#define ID_WINDOWS_LAST                 32009
#define ID_WINDOWS_MORE                 32010

Actually we need the first and two last. But just in case reserve all of them Also define a max number of windows in windows list in a menu. Add #define NUM_WINDOWS_ITEMS 9 to MainFrm.cpp

5. Add a protected member function looping through all visible MDI childs in CMainFrame to add them to Window menu.


void CMainFrame::UpdateWindowMenu()
{
	CMenu* pWindowMenu = GetWindowMenu();

	//Remove all entries after separator
	for (	int i = pWindowMenu->GetMenuItemCount()- 1 ; i > NUM_FIXED_ITEMS - 1;
			pWindowMenu->DeleteMenu(i--, MF_BYPOSITION) );

	//m_hWndMDIClient - undocumented

	CWnd* pWnd = CWnd::FromHandle(m_hWndMDIClient)->GetWindow(GW_CHILD);

	CString strTitle;
	i = 0;
	char buff[3];

	while(pWnd)
	{
		if(pWnd)
			if(pWnd->IsWindowVisible())
			{
			    if (i == NUM_WINDOWS_ITEMS)    //Critical number ow windows (9) reached
				{
					pWindowMenu->AppendMenu( MF_STRING,  ID_WINDOWS_MORE, "&Windows...");
					return;
				}
				pWnd->GetWindowText(strTitle);
				strTitle = CString("&") + itoa(i + 1,buff,10) + " " + strTitle;
				pWindowMenu->AppendMenu( MF_STRING,  ID_WINDOWS_FIRST + i++,strTitle);
			}
		pWnd = pWnd->GetWindow(GW_HWNDNEXT);
	}

}

OK. Well done with implementation. Now we need to call this function from somewhere. Not the best but possible place to do it is one of OnUpdateUI for a fixed menu item.

void CMainFrame::OnUpdateWindowsCascade(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	//It is a challenge to find a better place to call it from
	UpdateWindowMenu();
}

7. Add a member function to activate a particular MDI child


void CMainFrame::ActivateFrameFromMenu(int nItem)
{
	CWnd* pWnd = CWnd::FromHandle(m_hWndMDIClient)->GetWindow(GW_CHILD);
	int i = ID_WINDOWS_FIRST;
	BOOL bMaximized;

	while(pWnd)
	{
		if(pWnd)
			if(pWnd->IsWindowVisible())
				if ( i++ == nItem)
				{
					MDIGetActive( &bMaximized );
					if (!bMaximized)
						MDIRestore(pWnd);
					MDIActivate(pWnd);
					return;
				}
		pWnd = pWnd->GetWindow(GW_HWNDNEXT);
	}
}

6. Add message handler for all new menu items.

First we need to handle WM_COMMAND. Using ClassWizard add virtual OnCmdMsg and implement it like:

BOOL CMainFrame::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) 
{
	// If pHandlerInfo is NULL, then handle the message
	if (pHandlerInfo == NULL)
	{
		// Filter the commands sent to Window menu
		if (nID >= ID_WINDOWS_FIRST && nID <= ID_WINDOWS_LAST)
		{
			if (nCode == CN_COMMAND)
				// Handle WM_COMMAND message
				ActivateFrameFromMenu(nID);
			else 
				if (nCode == CN_UPDATE_COMMAND_UI)
					// Update UI element state
				DoUpdateWindowMenu(nID, (CCmdUI*)pExtra);
			return TRUE;
		}
				
	}

	// If we didn't process the command, call the base class
	// version of OnCmdMsg so the message-map can handle the message
	
	return CMDIFrameWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

}

We also need a function to update UI for windows list items

void CMainFrame::DoUpdateWindowMenu(int nID, CCmdUI* pCCmdUI)
{
	pCCmdUI->Enable(TRUE);
	if (nID == ID_WINDOWS_FIRST)
		pCCmdUI->SetCheck();
}

7. Add a windows list dialog.

CWinList is a CDialog derived class based on template with a non-sorted listbox and a couple of buttons. On Init Dialog we call a CMainFrame public function to fill a list box like we did for a menu.

((CMainFrame*) AfxGetMainWnd())->FillWinList(&m_lbWinList);

void CMainFrame::FillWinList(CListBox* pListBox)
{
	CWnd* pWnd = m_wndMdiClient.GetWindow(GW_CHILD);
	CString strTitle;
	while(pWnd)
	{
		if(pWnd)
			if(pWnd->IsWindowVisible())
			{
				pWnd->GetWindowText(strTitle);
				pListBox->AddString(strTitle);
			}
		pWnd = pWnd->GetWindow(GW_HWNDNEXT);
	}
	pListBox->SetCurSel(0);
}

OnOk the dialog returns item selected:

void CWinList::OnOK() 
{
	// TODO: Add extra validation here
	EndDialog(m_lbWinList.GetCurSel() + ID_WINDOWS_FIRST);
	//CDialog::OnOK(); Do not call default implementation
}

8. Handle ID_WINDOWS_MORE command

The only thing left is to handle ID_WINDOWS_MORE command. There is a little problem here. ClassWizard doesn't see ID_WINDOWS_MORE command. So either add a handler manually or temporary add this extra item to any menu and use ClassWizard, then remove it.

void CMainFrame::OnWindowsMore()
{
	int nItem = CWinList().DoModal();
	if (nItem != IDCANCEL) 
		ActivateFrameFromMenu(nItem);
}

9. Build. Run. Enjoy!

Download demo project - 21 KB

Last Updated: January 15, 1999



Comments

  • Nike Air Max 1 FB publicity, father a strong color texture, the new shoes

    Posted by Geozyoceada on 04/25/2013 03:47pm

    In the summer in a tumbler guts the cool sprite seems to be a good preferred, but if the sprite "feet"? Will also give you a frisk, bring a sustenance! This summer, Nike and Sprite [url=http://markwarren.org.uk/property-waet.cfm]air max 90[/url] and his sneakers to a blend of outstanding example snow spread of non-professional, white and dejected color schematic in the time-honoured Nike Feeling Max 1 shoes let slip a refreshing impertinent scent.[url=http://markwarren.org.uk/goodbuy.cfm]nike free run uk[/url] Summer is the time to select a clean shoe, shoes should be a good choice. Qualifying series Nike Freshen Max HomeTurf borough recently definitely comes up, this series in the masterpiece Freshen Max shoes to London, Paris and Milan the three paid glorification to the iconic metropolis of Europe, combined with the characteristics of the three cities, Like Max 1 HYP,Air Max 90 HYP,Air Max 1 and shoes such as Quality Max 95, combined [url=http://northernroofing.co.uk/roofins.cfm]nike free run 3[/url] with the Hyperfuse, as kind-heartedly as a heterogeneity of materials, such as suede, Whether you want functional or retro-everything.

    Reply
  • More concessions with herveleger, more surprise!

    Posted by wolemrfvtu on 04/04/2013 09:05am

    herve leger gown herve leger herve leger herve leger outlet

    Reply
  • Small bug fix

    Posted by blamond on 05/01/2008 03:15pm

    Hi Sergey, Thanks for the code - it does exactly what it's supposed to and saved me some time. One small bug in your html code of FillWinList(): instead of CWnd* pWnd = m_wndMdiClient.GetWindow(GW_CHILD); it should be: CWnd* pWnd = CWnd::FromHandle(m_hWndMDIClient)->GetWindow(GW_CHILD); At least that's what I had to do to use it. Cheers, Bruce Lamond

    Reply
  • Home made MDI windows list in Window menu

    Posted by Legacy on 08/09/1999 12:00am

    Originally posted by: Steve Sun

    Hi Sergey Karyshev,
    
    

    I tried this code, work very good.
    Thank you !

    Steve Sun
    1999/08/09

    Reply
  • WindowMenu

    Posted by Legacy on 04/22/1999 12:00am

    Originally posted by: Suja

    I tried this out but the list of open windows remained disabled.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds