Index: src/chext/TContextMenuHandler.cpp =================================================================== diff -u -N -r5b53476be2173282f99dd5d72207de90317bacad -r3791a028b55dabb72c22d01c93a04794d8091fa4 --- src/chext/TContextMenuHandler.cpp (.../TContextMenuHandler.cpp) (revision 5b53476be2173282f99dd5d72207de90317bacad) +++ src/chext/TContextMenuHandler.cpp (.../TContextMenuHandler.cpp) (revision 3791a028b55dabb72c22d01c93a04794d8091fa4) @@ -232,7 +232,8 @@ spMenuItem->SetLocalName(wstrItemName.c_str()); } - return wstrItemName; + // NOTE: don't use wstrItemName here as there is an additional processing hidden in SetLocalName() + return spMenuItem->GetLocalName().c_str(); } void TContextMenuHandler::Clear() Index: src/common/TShellExtMenuConfig.cpp =================================================================== diff -u -N -r3921d82d9605d98b2281f3f42d9f9c8385b89a3e -r3791a028b55dabb72c22d01c93a04794d8091fa4 --- src/common/TShellExtMenuConfig.cpp (.../TShellExtMenuConfig.cpp) (revision 3921d82d9605d98b2281f3f42d9f9c8385b89a3e) +++ src/common/TShellExtMenuConfig.cpp (.../TShellExtMenuConfig.cpp) (revision 3791a028b55dabb72c22d01c93a04794d8091fa4) @@ -267,7 +267,7 @@ void TShellMenuItem::SetLocalName(const string::TString& strLocalName) { - m_strLocalName = strLocalName; + m_strLocalName = strLocalName + m_strWorkaroundSuffix.c_str(); } void TShellMenuItem::InitSeparatorItem() @@ -302,6 +302,44 @@ m_strItemTip = wstrItemTip; } +// function tries to make item names unique by setting a text suffix composed of spaces that will be used +// to display shell context menu; +// This workaround is required due to specific way of handling menus for more than 16 items (files/folders) +// selected in explorer - when invoking specific menu item, explorer forces shell extension to re-add all +// menu items to a menu, and then invokes the first one with the name matching the one clicked by user. +// Final effect was that a wrong menu item was selected when there were duplicate names in menu. +void TShellMenuItem::CalculateWorkaroundSuffixes() +{ + std::map mapNames; + std::list listToProcess; + listToProcess.insert(listToProcess.end(), m_vChildItems.begin(), m_vChildItems.end()); + + while(!listToProcess.empty()) + { + TShellMenuItemPtr spItem = listToProcess.front(); + listToProcess.pop_front(); + + if(spItem->GetItemType() == eStandardItem) + { + auto iterFnd = mapNames.find(spItem->GetName().c_str()); + if(iterFnd == mapNames.end()) + { + mapNames.emplace(spItem->GetName().c_str(), L""); + spItem->SetWorkaroundSuffix(L""); + } + else + { + iterFnd->second += L" "; + spItem->SetWorkaroundSuffix(iterFnd->second); + } + } + else if(spItem->GetItemType() == eGroupItem) + { + listToProcess.insert(listToProcess.end(), spItem->m_vChildItems.begin(), spItem->m_vChildItems.end()); + } + } +} + bool TShellMenuItem::SpecifiesDestinationPath() const { return !IsGroupItem() && (m_tDestinationPath.GetDstPathSource() == TDestinationPathInfo::eDstType_Specified); @@ -529,8 +567,11 @@ if(!m_spDragAndDropRoot->ReadFromConfig(rConfig, Concat(strBuffer, pszNodeName, _T("DragAndDropRootItem")))) return false; + m_spDragAndDropRoot->CalculateWorkaroundSuffixes(); + if(!m_spNormalRoot->ReadFromConfig(rConfig, Concat(strBuffer, pszNodeName, _T("NormalRootItem")))) return false; + m_spNormalRoot->CalculateWorkaroundSuffixes(); return true; } Index: src/common/TShellExtMenuConfig.h =================================================================== diff -u -N -r0d5b67ee96b435d63f7bf075dc8e28603793b187 -r3791a028b55dabb72c22d01c93a04794d8091fa4 --- src/common/TShellExtMenuConfig.h (.../TShellExtMenuConfig.h) (revision 0d5b67ee96b435d63f7bf075dc8e28603793b187) +++ src/common/TShellExtMenuConfig.h (.../TShellExtMenuConfig.h) (revision 3791a028b55dabb72c22d01c93a04794d8091fa4) @@ -150,6 +150,8 @@ // initializer for group item void InitGroupItem(const string::TString& wstrName, const string::TString& wstrItemTip); + void CalculateWorkaroundSuffixes(); + // clears everything void Clear(); @@ -179,6 +181,9 @@ // helper - retrieves info if this command requires some paths present in clipboard to be enabled bool RequiresClipboardPaths() const; + std::wstring GetWorkaroundSuffix() const { return m_strWorkaroundSuffix; } + void SetWorkaroundSuffix(std::wstring val) { m_strWorkaroundSuffix = val; } + // operations on children size_t GetChildrenCount() const; TShellMenuItemPtr GetChildAt(size_t stIndex) const; @@ -216,6 +221,8 @@ // hints that this item is to be made default (bold), when detected operation type is equal to this operation type chengine::EOperationType m_eDefaultItemHint; + std::wstring m_strWorkaroundSuffix; + std::vector m_vChildItems; };