@@ -58,10 +58,10 @@ static const struct _StaticInvokeCommandMap_
5858 SHORT DfmCmd;
5959} g_StaticInvokeCmdMap[] =
6060{
61- { " RunAs " , 0 }, // Unimplemented
62- { " Print " , 0 }, // Unimplemented
63- { " Preview " , 0 }, // Unimplemented
64- { " Open " , FCIDM_SHVIEW_OPEN },
61+ { " runas " , 0 }, // Unimplemented
62+ { " print " , 0 }, // Unimplemented
63+ { " preview " , 0 }, // Unimplemented
64+ { " open " , FCIDM_SHVIEW_OPEN },
6565 { CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER, (SHORT)DFM_CMD_NEWFOLDER },
6666 { " cut" , FCIDM_SHVIEW_CUT, /* ? */ },
6767 { " copy" , FCIDM_SHVIEW_COPY, (SHORT)DFM_CMD_COPY },
@@ -139,6 +139,36 @@ EXTERN_C HRESULT SHELL32_EnumDefaultVerbList(LPCWSTR List, UINT Index, LPWSTR Ve
139139 return HRESULT_FROM_WIN32 (ERROR_NO_MORE_ITEMS);
140140}
141141
142+ static HRESULT GetFriendlyVerb (_In_ PCWSTR pszVerb, _Out_ PWSTR pszBuf, _In_ SIZE_T cchMax)
143+ {
144+ static const struct { PCWSTR pszVerb; WORD iResId; } map[] =
145+ {
146+ // { L"open", IDS_OPEN_VERB }, These two have already been handled
147+ // { L"explore", IDS_EXPLORE_VERB },
148+ { L" edit" , IDS_EDIT_VERB },
149+ { L" print" , IDS_PRINT_VERB },
150+ { L" runas" , IDS_RUNAS_VERB },
151+ { L" openas" , IDS_OPEN_VERB },
152+ { L" find" , IDS_FIND_VERB },
153+ };
154+ for (SIZE_T i = 0 ; i < _countof (map); ++i)
155+ {
156+ if (!_wcsicmp (pszVerb, map[i].pszVerb ) &&
157+ LoadStringW (shell32_hInstance, map[i].iResId , pszBuf, cchMax))
158+ {
159+ return S_OK;
160+ }
161+ }
162+
163+ // Try to make a friendly verb based on the verb subkey
164+ if (pszVerb[0 ] < 127 && !StrChrW (pszVerb, ' &' ) && SUCCEEDED (StringCchCopyW (pszBuf + 1 , --cchMax, pszVerb)))
165+ {
166+ *pszBuf = L' &' ;
167+ return S_OK; // This can be changed to S_FALSE if the caller needs to know we faked it
168+ }
169+ return E_FAIL;
170+ }
171+
142172class CDefaultContextMenu :
143173 public CComObjectRootEx<CComMultiThreadModelNoCS>,
144174 public IContextMenu3,
@@ -572,9 +602,8 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
572602{
573603 UINT ntver = RosGetProcessEffectiveVersion ();
574604 MENUITEMINFOW mii = { sizeof (mii) };
575- UINT idResource;
576605 WCHAR wszDispVerb[80 ]; // The limit on XP. If the friendly string is longer, it falls back to the verb key.
577- UINT fState ;
606+ UINT fState , idVerbRes ;
578607 UINT cIds = 0 , indexFirst = *pIndexMenu, indexDefault;
579608 int iDefVerbIndex = -1 ;
580609
@@ -587,6 +616,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
587616 {
588617 StaticShellEntry& info = m_StaticEntries.GetNext (it);
589618 BOOL forceFirstPos = FALSE ;
619+ bool hide = false ;
590620
591621 fState = MFS_ENABLED;
592622
@@ -599,86 +629,59 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
599629
600630 if (info.Verb .CompareNoCase (L" open" ) == 0 )
601631 {
602- idResource = IDS_OPEN_VERB;
632+ idVerbRes = IDS_OPEN_VERB; // TODO: This string should include '&'
603633 fState |= MFS_DEFAULT; /* override default when open verb is found */
604634 forceFirstPos++;
605635 }
606636 else if (info.Verb .CompareNoCase (L" explore" ) == 0 )
607637 {
608- idResource = IDS_EXPLORE_VERB;
638+ idVerbRes = IDS_EXPLORE_VERB; // TODO: This string should include '&'
609639 if (uFlags & CMF_EXPLORE)
610640 {
611641 fState |= MFS_DEFAULT;
612642 forceFirstPos++;
613643 }
614644 }
615- else if (info.Verb .CompareNoCase (L" runas" ) == 0 )
616- idResource = IDS_RUNAS_VERB;
617- else if (info.Verb .CompareNoCase (L" edit" ) == 0 )
618- idResource = IDS_EDIT_VERB;
619- else if (info.Verb .CompareNoCase (L" find" ) == 0 )
620- idResource = IDS_FIND_VERB;
621- else if (info.Verb .CompareNoCase (L" print" ) == 0 )
622- idResource = IDS_PRINT_VERB;
623645 else if (info.Verb .CompareNoCase (L" printto" ) == 0 )
624- continue ;
646+ hide = true ;
625647 else
626- idResource = 0 ;
648+ idVerbRes = 0 ;
627649
628650 /* By default use verb for menu item name */
629651 mii.dwTypeData = (LPWSTR)info.Verb .GetString ();
630652
631653 WCHAR wszKey[sizeof (" shell\\ " ) + MAX_VERB];
632- HRESULT hr;
633- hr = StringCbPrintfW (wszKey, sizeof (wszKey), L" shell\\ %s" , info.Verb .GetString ());
654+ HRESULT hr = StringCbPrintfW (wszKey, sizeof (wszKey), L" shell\\ %s" , info.Verb .GetString ());
634655 if (FAILED_UNEXPECTEDLY (hr))
635- {
636- continue ;
637- }
656+ hide = true ;
638657
639658 UINT cmdFlags = 0 ;
640- bool hide = false ;
641659 HKEY hkVerb;
642- if (idResource > 0 )
660+ if (RegOpenKeyExW (info. hkClass , wszKey, 0 , KEY_READ, &hkVerb) == ERROR_SUCCESS )
643661 {
644662 if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
645663 {
646- if (LoadStringW (shell32_hInstance, idResource, wszDispVerb, _countof (wszDispVerb)))
647- mii.dwTypeData = wszDispVerb; /* use translated verb */
648- else
649- ERR (" Failed to load string\n " );
664+ DWORD cbVerb = sizeof (wszDispVerb);
665+ LONG res = RegLoadMUIStringW (hkVerb, L" MUIVerb" , wszDispVerb, cbVerb, NULL , 0 , NULL );
666+ if (res || !*wszDispVerb)
667+ res = RegLoadMUIStringW (hkVerb, NULL , wszDispVerb, cbVerb, NULL , 0 , NULL );
668+
669+ if ((res == ERROR_SUCCESS && *wszDispVerb) ||
670+ (idVerbRes && LoadStringW (shell32_hInstance, idVerbRes, wszDispVerb, _countof (wszDispVerb))) ||
671+ SUCCEEDED (GetFriendlyVerb (info.Verb , wszDispVerb, _countof (wszDispVerb))))
672+ {
673+ mii.dwTypeData = wszDispVerb;
674+ }
650675 }
651-
652- if (RegOpenKeyW (info.hkClass , wszKey, &hkVerb) != ERROR_SUCCESS)
653- hkVerb = NULL ;
654676 }
655677 else
656678 {
657- if (RegOpenKeyW (info.hkClass , wszKey, &hkVerb) == ERROR_SUCCESS)
658- {
659- if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
660- {
661- DWORD cbVerb = sizeof (wszDispVerb);
662- LONG res = RegLoadMUIStringW (hkVerb, L" MUIVerb" , wszDispVerb, cbVerb, NULL , 0 , NULL );
663- if (res || !*wszDispVerb)
664- res = RegLoadMUIStringW (hkVerb, NULL , wszDispVerb, cbVerb, NULL , 0 , NULL );
665-
666- if (res == ERROR_SUCCESS && *wszDispVerb)
667- {
668- /* use description for the menu entry */
669- mii.dwTypeData = wszDispVerb;
670- }
671- }
672- }
673- else
674- {
675- hkVerb = NULL ;
676- }
679+ hkVerb = NULL ;
677680 }
678681
679682 if (hkVerb)
680683 {
681- if (!(uFlags & CMF_EXTENDEDVERBS))
684+ if (!hide && ! (uFlags & CMF_EXTENDEDVERBS))
682685 hide = RegValueExists (hkVerb, L" Extended" );
683686
684687 if (!hide)
@@ -687,6 +690,9 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
687690 if (!hide && !(uFlags & CMF_DISABLEDVERBS))
688691 hide = RegValueExists (hkVerb, L" LegacyDisable" );
689692
693+ if (DWORD dwRest = (hide ? 0 : RegGetDword (hkVerb, NULL , L" SuppressionPolicy" , 0 )))
694+ hide = SHRestricted ((RESTRICTIONS)dwRest);
695+
690696 if (RegValueExists (hkVerb, L" NeverDefault" ))
691697 fState &= ~MFS_DEFAULT;
692698
@@ -924,6 +930,11 @@ CDefaultContextMenu::QueryContextMenu(
924930
925931 // TODO: DFM_MERGECONTEXTMENU_TOP
926932
933+ // TODO: Remove duplicate verbs. This will be easier when the static items handling
934+ // has been moved to CLSID_ShellFileDefExt so we only have to deal with ShellEx.
935+ // This is a Windows XP+ feature. On an unknown file type, Windows 2000 will
936+ // display both "Open" (openas from Unknown) and "Open with..." (openas from *).
937+
927938 return MAKE_HRESULT (SEVERITY_SUCCESS, 0 , cIds);
928939}
929940
@@ -1278,8 +1289,6 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX lpcmi, PStatic
12781289 LPCWSTR FlagsName;
12791290 WCHAR wszKey[sizeof (" shell\\ " ) + MAX_VERB];
12801291 HRESULT hr;
1281- DWORD wFlags;
1282- DWORD cbVerb;
12831292
12841293 if (!m_site)
12851294 return 0 ;
@@ -1306,14 +1315,7 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX lpcmi, PStatic
13061315 hr = StringCbPrintfW (wszKey, sizeof (wszKey), L" shell\\ %s" , pEntry->Verb .GetString ());
13071316 if (FAILED_UNEXPECTEDLY (hr))
13081317 return 0 ;
1309-
1310- cbVerb = sizeof (wFlags);
1311- if (RegGetValueW (pEntry->hkClass , wszKey, FlagsName, RRF_RT_REG_DWORD, NULL , &wFlags, &cbVerb) == ERROR_SUCCESS)
1312- {
1313- return wFlags;
1314- }
1315-
1316- return 0 ;
1318+ return RegGetDword (pEntry->hkClass , wszKey, FlagsName, 0 );
13171319}
13181320
13191321HRESULT
0 commit comments