mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 18:33:10 +00:00
[SHELL32] CDefaultContextMenu must respect the default verb list (#7090)
This commit is contained in:
parent
5b78381a53
commit
2e08238c7c
2 changed files with 75 additions and 18 deletions
|
@ -14,6 +14,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
|
||||||
|
|
||||||
// FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
|
// FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
|
||||||
#define MAX_VERB 260
|
#define MAX_VERB 260
|
||||||
|
#define VERBKEY_CCHMAX 64 // Note: 63+\0 seems to be the limit on XP
|
||||||
|
|
||||||
static HRESULT
|
static HRESULT
|
||||||
SHELL_GetRegCLSID(HKEY hKey, LPCWSTR SubKey, LPCWSTR Value, CLSID &clsid)
|
SHELL_GetRegCLSID(HKEY hKey, LPCWSTR SubKey, LPCWSTR Value, CLSID &clsid)
|
||||||
|
@ -90,6 +91,27 @@ UINT MapVerbToDfmCmd(_In_ LPCSTR verba)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool IsVerbListSeparator(WCHAR Ch)
|
||||||
|
{
|
||||||
|
return Ch == L' ' || Ch == L','; // learn.microsoft.com/en-us/windows/win32/shell/context-menu-handlers
|
||||||
|
}
|
||||||
|
|
||||||
|
static int FindVerbInDefaultVerbList(LPCWSTR List, LPCWSTR Verb)
|
||||||
|
{
|
||||||
|
for (UINT index = 0; *List; ++index)
|
||||||
|
{
|
||||||
|
while (IsVerbListSeparator(*List))
|
||||||
|
List++;
|
||||||
|
LPCWSTR Start = List;
|
||||||
|
while (*List && !IsVerbListSeparator(*List))
|
||||||
|
List++;
|
||||||
|
// "List > Start" to verify that the list item is non-empty to avoid the edge case where Verb is "" and the list contains ",,"
|
||||||
|
if (!_wcsnicmp(Verb, Start, List - Start) && List > Start)
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
class CDefaultContextMenu :
|
class CDefaultContextMenu :
|
||||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
public IContextMenu3,
|
public IContextMenu3,
|
||||||
|
@ -119,6 +141,7 @@ class CDefaultContextMenu :
|
||||||
UINT m_iIdDfltFirst; /* first default part id */
|
UINT m_iIdDfltFirst; /* first default part id */
|
||||||
UINT m_iIdDfltLast; /* last default part id */
|
UINT m_iIdDfltLast; /* last default part id */
|
||||||
HWND m_hwnd; /* window passed to callback */
|
HWND m_hwnd; /* window passed to callback */
|
||||||
|
WCHAR m_DefVerbs[MAX_PATH];
|
||||||
|
|
||||||
HRESULT _DoCallback(UINT uMsg, WPARAM wParam, LPVOID lParam);
|
HRESULT _DoCallback(UINT uMsg, WPARAM wParam, LPVOID lParam);
|
||||||
void AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb, UINT uFlags);
|
void AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb, UINT uFlags);
|
||||||
|
@ -203,6 +226,7 @@ CDefaultContextMenu::CDefaultContextMenu() :
|
||||||
m_iIdDfltLast(0),
|
m_iIdDfltLast(0),
|
||||||
m_hwnd(NULL)
|
m_hwnd(NULL)
|
||||||
{
|
{
|
||||||
|
*m_DefVerbs = UNICODE_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
CDefaultContextMenu::~CDefaultContextMenu()
|
CDefaultContextMenu::~CDefaultContextMenu()
|
||||||
|
@ -314,7 +338,7 @@ void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVe
|
||||||
|
|
||||||
void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey, UINT uFlags)
|
void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey, UINT uFlags)
|
||||||
{
|
{
|
||||||
WCHAR wszName[40];
|
WCHAR wszName[VERBKEY_CCHMAX];
|
||||||
DWORD cchName, dwIndex = 0;
|
DWORD cchName, dwIndex = 0;
|
||||||
HKEY hShellKey;
|
HKEY hShellKey;
|
||||||
|
|
||||||
|
@ -322,6 +346,12 @@ void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey, UINT uFlags)
|
||||||
if (lres != STATUS_SUCCESS)
|
if (lres != STATUS_SUCCESS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!*m_DefVerbs)
|
||||||
|
{
|
||||||
|
DWORD cb = sizeof(m_DefVerbs);
|
||||||
|
RegGetValueW(hShellKey, NULL, NULL, RRF_RT_REG_SZ, NULL, m_DefVerbs, &cb);
|
||||||
|
}
|
||||||
|
|
||||||
while(TRUE)
|
while(TRUE)
|
||||||
{
|
{
|
||||||
cchName = _countof(wszName);
|
cchName = _countof(wszName);
|
||||||
|
@ -513,9 +543,10 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
||||||
UINT ntver = RosGetProcessEffectiveVersion();
|
UINT ntver = RosGetProcessEffectiveVersion();
|
||||||
MENUITEMINFOW mii = { sizeof(mii) };
|
MENUITEMINFOW mii = { sizeof(mii) };
|
||||||
UINT idResource;
|
UINT idResource;
|
||||||
WCHAR wszVerb[40];
|
WCHAR wszDispVerb[80]; // The limit on XP. If the friendly string is longer, it falls back to the verb key.
|
||||||
UINT fState;
|
UINT fState;
|
||||||
UINT cIds = 0, indexFirst = *pIndexMenu;
|
UINT cIds = 0, indexFirst = *pIndexMenu, indexDefault;
|
||||||
|
int iDefVerbIndex = -1;
|
||||||
|
|
||||||
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
|
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
|
||||||
mii.fType = MFT_STRING;
|
mii.fType = MFT_STRING;
|
||||||
|
@ -582,8 +613,8 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
||||||
{
|
{
|
||||||
if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
|
if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
|
||||||
{
|
{
|
||||||
if (LoadStringW(shell32_hInstance, idResource, wszVerb, _countof(wszVerb)))
|
if (LoadStringW(shell32_hInstance, idResource, wszDispVerb, _countof(wszDispVerb)))
|
||||||
mii.dwTypeData = wszVerb; /* use translated verb */
|
mii.dwTypeData = wszDispVerb; /* use translated verb */
|
||||||
else
|
else
|
||||||
ERR("Failed to load string\n");
|
ERR("Failed to load string\n");
|
||||||
}
|
}
|
||||||
|
@ -597,16 +628,15 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
||||||
{
|
{
|
||||||
if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
|
if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
|
||||||
{
|
{
|
||||||
DWORD cbVerb = sizeof(wszVerb);
|
DWORD cbVerb = sizeof(wszDispVerb);
|
||||||
|
LONG res = RegLoadMUIStringW(hkVerb, L"MUIVerb", wszDispVerb, cbVerb, NULL, 0, NULL);
|
||||||
|
if (res || !*wszDispVerb)
|
||||||
|
res = RegLoadMUIStringW(hkVerb, NULL, wszDispVerb, cbVerb, NULL, 0, NULL);
|
||||||
|
|
||||||
LONG res = RegLoadMUIStringW(hkVerb, L"MUIVerb", wszVerb, cbVerb, NULL, 0, NULL);
|
if (res == ERROR_SUCCESS && *wszDispVerb)
|
||||||
if (res || !*wszVerb)
|
|
||||||
res = RegLoadMUIStringW(hkVerb, NULL, wszVerb, cbVerb, NULL, 0, NULL);
|
|
||||||
|
|
||||||
if (res == ERROR_SUCCESS && *wszVerb)
|
|
||||||
{
|
{
|
||||||
/* use description for the menu entry */
|
/* use description for the menu entry */
|
||||||
mii.dwTypeData = wszVerb;
|
mii.dwTypeData = wszDispVerb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -652,9 +682,33 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
||||||
(*pIndexMenu)++;
|
(*pIndexMenu)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UINT pos = *pIndexMenu;
|
||||||
|
int verbIndex = hkVerb ? FindVerbInDefaultVerbList(m_DefVerbs, info.Verb) : -1;
|
||||||
|
if (verbIndex >= 0)
|
||||||
|
{
|
||||||
|
if (verbIndex < iDefVerbIndex || iDefVerbIndex < 0)
|
||||||
|
{
|
||||||
|
iDefVerbIndex = verbIndex;
|
||||||
|
fState |= MFS_DEFAULT;
|
||||||
|
forceFirstPos = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fState &= ~MFS_DEFAULT; // We have already set a better default
|
||||||
|
pos = indexDefault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (iDefVerbIndex >= 0)
|
||||||
|
{
|
||||||
|
fState &= ~MFS_DEFAULT; // We have already set the default
|
||||||
|
if (forceFirstPos)
|
||||||
|
pos = indexDefault;
|
||||||
|
forceFirstPos = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
mii.fState = fState;
|
mii.fState = fState;
|
||||||
mii.wID = iIdCmdFirst + cIds;
|
mii.wID = iIdCmdFirst + cIds;
|
||||||
if (InsertMenuItemW(hMenu, forceFirstPos ? indexFirst : *pIndexMenu, TRUE, &mii))
|
if (InsertMenuItemW(hMenu, forceFirstPos ? indexFirst : pos, TRUE, &mii))
|
||||||
(*pIndexMenu)++;
|
(*pIndexMenu)++;
|
||||||
|
|
||||||
if (cmdFlags & ECF_SEPARATORAFTER)
|
if (cmdFlags & ECF_SEPARATORAFTER)
|
||||||
|
@ -662,6 +716,9 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
||||||
if (InsertMenuItemAt(hMenu, *pIndexMenu, MF_SEPARATOR))
|
if (InsertMenuItemAt(hMenu, *pIndexMenu, MF_SEPARATOR))
|
||||||
(*pIndexMenu)++;
|
(*pIndexMenu)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fState & MFS_DEFAULT)
|
||||||
|
indexDefault = *pIndexMenu; // This is where we want to insert "high priority" verbs
|
||||||
}
|
}
|
||||||
cIds++; // Always increment the id because it acts as the index into m_StaticEntries
|
cIds++; // Always increment the id because it acts as the index into m_StaticEntries
|
||||||
|
|
||||||
|
|
|
@ -1222,7 +1222,6 @@ VOID COpenWithMenu::AddApp(PVOID pApp)
|
||||||
mii.fState = MFS_ENABLED;
|
mii.fState = MFS_ENABLED;
|
||||||
mii.wID = m_idCmdLast;
|
mii.wID = m_idCmdLast;
|
||||||
mii.dwTypeData = const_cast<LPWSTR>(pwszName);
|
mii.dwTypeData = const_cast<LPWSTR>(pwszName);
|
||||||
mii.cch = wcslen(mii.dwTypeData);
|
|
||||||
mii.dwItemData = (ULONG_PTR)pApp;
|
mii.dwItemData = (ULONG_PTR)pApp;
|
||||||
|
|
||||||
HICON hIcon = m_pAppList->GetIcon((COpenWithList::SApp*)pApp);
|
HICON hIcon = m_pAppList->GetIcon((COpenWithList::SApp*)pApp);
|
||||||
|
@ -1259,7 +1258,7 @@ HRESULT WINAPI COpenWithMenu::QueryContextMenu(
|
||||||
m_idCmdFirst = m_idCmdLast = idCmdFirst;
|
m_idCmdFirst = m_idCmdLast = idCmdFirst;
|
||||||
m_hSubMenu = NULL;
|
m_hSubMenu = NULL;
|
||||||
|
|
||||||
/* If we are going to be default item, we shouldn't be submenu */
|
/* We can only be a submenu if we are not the default */
|
||||||
if (DefaultPos != -1)
|
if (DefaultPos != -1)
|
||||||
{
|
{
|
||||||
/* Load applications list */
|
/* Load applications list */
|
||||||
|
@ -1298,13 +1297,14 @@ HRESULT WINAPI COpenWithMenu::QueryContextMenu(
|
||||||
|
|
||||||
mii.fType = MFT_STRING;
|
mii.fType = MFT_STRING;
|
||||||
mii.dwTypeData = (LPWSTR)wszName;
|
mii.dwTypeData = (LPWSTR)wszName;
|
||||||
mii.cch = wcslen(wszName);
|
|
||||||
|
|
||||||
mii.fState = MFS_ENABLED;
|
mii.fState = MFS_ENABLED;
|
||||||
if (DefaultPos == -1)
|
if (DefaultPos == -1)
|
||||||
|
{
|
||||||
mii.fState |= MFS_DEFAULT;
|
mii.fState |= MFS_DEFAULT;
|
||||||
|
indexMenu = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!InsertMenuItemW(hMenu, DefaultPos + 1, TRUE, &mii))
|
if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii))
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
|
||||||
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, m_idCmdLast - m_idCmdFirst + 1);
|
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, m_idCmdLast - m_idCmdFirst + 1);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue