Support
Joined: 18 Jul 2005 Posts: 731
|
Posted: Tue Oct 07, 2008 7:43 am Post subject: HOWTO: Add large number of menu items (beyond the number of menu item slots provided by Windows) |
|
|
Windows reserves a specific number of menu item IDs for each context menu extension. This limit is generally at least 100. The exact number can be determined in the OnGetMenuItems function using e.maxMenuItemsAvailable (CGetMenuitemsEventArgs.maxMenuItemsAvailable ). This limit is sufficient for most purposes, but if you need to add a large number of menu items (including all items in sub-menus and sub-sub-menus), you must reuse the same IDs for menu items in different sub-menus (reasonably assuming that your large number of items are spread across more than one sub-menu). The following code demonstrates how to achieve that :
Code: | int startID; // start ID available for our use
CShellMenuItem* lastpopupMenuItem ; // last sub menu which popped
void CContextMenuExtension1::OnGetMenuItems(CGetMenuitemsEventArgs& e)
{
// Add main menus
CShellMenuItem* mi1 = e.menu->AddItem(_T("MenuItem1"));
mi1->SetTag((void*)1); // level 1
CShellMenuItem* mi2 = e.menu->AddItem(_T("MenuItem2"));
mi2->SetTag((void*)1); // level 1
CShellMenuItem* mi3 = e.menu->AddItem(_T("MenuItem3"));
mi3->SetTag((void*)1); // level 1
mi1->SetHasSubMenu(TRUE); // Indicate menu has submenu
// Store the ID of the 'dummy menu item.
// All dummy menu items will have this ID
// All actual menu items will have IDs starting from startID to startID+49 (total 50 items)
startID = mi1->GetSubMenu()->AddItem(_T("dummy"))->GetID(); // Add a dummy item to submenu **necessary
mi2->SetHasSubMenu(TRUE); // Indicate menu has submenu
mi2->GetSubMenu()->AddItem(_T("dummy"),startID); // Add a dummy item to submenu **necessary
mi3->SetHasSubMenu(TRUE); // Indicate menu has submenu
mi3->GetSubMenu()->AddItem(_T("dummy"),startID); // Add a dummy item to submenu **necessary
// Each submenu of mi1,mi2 and mi3 can have maximum of 50 submenu items, so reserve space for
// 49 more (1 ID for the 'dummy' item already added which will be removed as each submenu pops up)
e.reservedMenuItemCount=49;
}
void CContextMenuExtension1::OnPopupSubMenu(CShellMenuItem* menuItem)
{
// New menu items are at current level + 1
int level = (int)(menuItem->GetTag()) + 1;
lastpopupMenuItem = menuItem; // store the last menu which popped up
menuItem->GetSubMenu()->RemoveAll(); // remove 'dummy' item
// Add the 50 menu items
for (int i = 0; i < 50;i++)
{
// Explicitly specify id for the menu item.
CString str;
str.Format(menuItem->GetCaption()+ _T("_subMenuItem %d") ,i);
CShellMenuItem* item = menuItem->GetSubMenu()->AddItem(str, startID + i);
// We will limit sub-menus to 2 levels
if (level<=2)
{
item->SetHasSubMenu(true);
item->GetSubMenu()->AddItem(_T("dummy"), startID);
item->SetTag((void*)(level + 1));
}
}
}
BOOL CContextMenuExtension1::OnExecuteMenuItem(CExecuteItemEventArgs& e)
{
// e,MenuItem is not the correct menu item because we have used duplicate ids which confuses Windows.
// The real menu item which has been clicked is the one with the same ID as e.MenuItem.ID but which is
// a sub menu item of 'lastpopupMenuItem'
CShellMenuItem* real = lastpopupMenuItem->GetSubMenu()->GetItemFromID(e.menuItem->GetID());
AfxMessageBox(real->GetCaption());
return TRUE;
} |
|
|