https://git.reactos.org/?p=reactos.git;a=commitdiff;h=7fb91d98f92d0600b0173…
commit 7fb91d98f92d0600b0173b6fe1d6be8dda4066f8
Author: Whindmar Saksit <whindsaks(a)proton.me>
AuthorDate: Mon Nov 13 16:21:13 2023 +0100
Commit: GitHub <noreply(a)github.com>
CommitDate: Mon Nov 13 16:21:13 2023 +0100
[SHELL32] Add support for more registry verb flags and CMF flags (#5785)
- Adds support for registry controlled menu separators and the documented
values to turn off verbs.
- Adds support for CMF_OPTIMIZEFORINVOKE, CMF_NODEFAULT, CMF_DONOTPICKDEFAULT,
CMF_EXPLORE and CMF_DISABLEDVERBS.
Bugs fixed:
- A verb with "Extended" set in the registry could cause the menu to invoke
the incorrect command! This happened because skipping InsertMenuItemW
caused InvokeCommand to use the wrong index with m_StaticEntries.
- Uses IS_INTRESOURCE instead of HIWORD to check if something is a string
(only matters on 64-bit).
- TryToBrowse leaking a PIDL when calling ILCombine.
Notes:
- This PR introduces the RosGetProcessEffectiveVersion() helper function
discussed in chat.
- Relaxed FAILED_UNEXPECTEDLY to FAILED in two places because IContextMenu
cannot assume that it has a site that leads to IShellBrowser.
---
dll/win32/shell32/CDefaultContextMenu.cpp | 345 ++++++++++++++++++++----------
sdk/include/psdk/shobjidl.idl | 25 ++-
sdk/include/reactos/compat_undoc.h | 11 +
sdk/include/reactos/shellutils.h | 12 ++
4 files changed, 270 insertions(+), 123 deletions(-)
diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp
b/dll/win32/shell32/CDefaultContextMenu.cpp
index 577e93d332e..af57d92d3bb 100644
--- a/dll/win32/shell32/CDefaultContextMenu.cpp
+++ b/dll/win32/shell32/CDefaultContextMenu.cpp
@@ -7,9 +7,24 @@
*/
#include "precomp.h"
+#include <compat_undoc.h>
WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
+static inline bool RegValueExists(HKEY hKey, LPCWSTR Name)
+{
+ return RegQueryValueExW(hKey, Name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
+}
+
+static BOOL InsertMenuItemAt(HMENU hMenu, UINT Pos, UINT Flags)
+{
+ MENUITEMINFOW mii;
+ mii.cbSize = FIELD_OFFSET(MENUITEMINFOW, hbmpItem); // USER32 version agnostic
+ mii.fMask = MIIM_TYPE;
+ mii.fType = Flags;
+ return InsertMenuItemW(hMenu, Pos, TRUE, &mii);
+}
+
typedef struct _DynamicShellEntry_
{
UINT iIdCmdFirst;
@@ -24,30 +39,32 @@ typedef struct _StaticShellEntry_
HKEY hkClass;
} StaticShellEntry, *PStaticShellEntry;
+#define DCM_FCIDM_SHVIEW_OFFSET 0x7000 // Offset from the menu ids in the menu resource
to FCIDM_SHVIEW_*
//
// verbs for InvokeCommandInfo
//
-struct _StaticInvokeCommandMap_
+static const struct _StaticInvokeCommandMap_
{
LPCSTR szStringVerb;
- UINT IntVerb;
+ WORD IntVerb;
+ SHORT DfmCmd;
} g_StaticInvokeCmdMap[] =
{
{ "RunAs", 0 }, // Unimplemented
{ "Print", 0 }, // Unimplemented
{ "Preview", 0 }, // Unimplemented
- { "Open", FCIDM_SHVIEW_OPEN },
- { CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER },
- { "cut", FCIDM_SHVIEW_CUT},
- { "copy", FCIDM_SHVIEW_COPY},
- { "paste", FCIDM_SHVIEW_INSERT},
- { "link", FCIDM_SHVIEW_CREATELINK},
- { "delete", FCIDM_SHVIEW_DELETE},
- { "properties", FCIDM_SHVIEW_PROPERTIES},
- { "rename", FCIDM_SHVIEW_RENAME},
- { "copyto", FCIDM_SHVIEW_COPYTO },
- { "moveto", FCIDM_SHVIEW_MOVETO },
+ { "Open", FCIDM_SHVIEW_OPEN },
+ { CMDSTR_NEWFOLDERA, FCIDM_SHVIEW_NEWFOLDER, (SHORT)DFM_CMD_NEWFOLDER },
+ { "cut", FCIDM_SHVIEW_CUT, /* ? */ },
+ { "copy", FCIDM_SHVIEW_COPY, (SHORT)DFM_CMD_COPY },
+ { "paste", FCIDM_SHVIEW_INSERT, (SHORT)DFM_CMD_PASTE },
+ { "link", FCIDM_SHVIEW_CREATELINK, (SHORT)DFM_CMD_LINK },
+ { "delete", FCIDM_SHVIEW_DELETE, (SHORT)DFM_CMD_DELETE },
+ { "properties", FCIDM_SHVIEW_PROPERTIES, (SHORT)DFM_CMD_PROPERTIES },
+ { "rename", FCIDM_SHVIEW_RENAME, (SHORT)DFM_CMD_RENAME },
+ { "copyto", FCIDM_SHVIEW_COPYTO },
+ { "moveto", FCIDM_SHVIEW_MOVETO },
};
class CDefaultContextMenu :
@@ -79,13 +96,14 @@ class CDefaultContextMenu :
UINT m_iIdDfltLast; /* last default part id */
HRESULT _DoCallback(UINT uMsg, WPARAM wParam, LPVOID lParam);
- void AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb);
- void AddStaticEntriesForKey(HKEY hKey);
+ void AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb, UINT uFlags);
+ void AddStaticEntriesForKey(HKEY hKey, UINT uFlags);
+ void TryPickDefault(HMENU hMenu, UINT idCmdFirst, UINT DfltOffset, UINT uFlags);
BOOL IsShellExtensionAlreadyLoaded(REFCLSID clsid);
HRESULT LoadDynamicContextMenuHandler(HKEY hKey, REFCLSID clsid);
BOOL EnumerateDynamicContextHandlerForKey(HKEY hRootKey);
UINT AddShellExtensionsToMenu(HMENU hMenu, UINT* pIndexMenu, UINT idCmdFirst,
UINT idCmdLast, UINT uFlags);
- UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT* IndexMenu, UINT iIdCmdFirst,
UINT iIdCmdLast);
+ UINT AddStaticContextMenusToMenu(HMENU hMenu, UINT* IndexMenu, UINT iIdCmdFirst,
UINT iIdCmdLast, UINT uFlags);
HRESULT DoPaste(LPCMINVOKECOMMANDINFOEX lpcmi, BOOL bLink);
HRESULT DoOpenOrExplore(LPCMINVOKECOMMANDINFOEX lpcmi);
HRESULT DoCreateLink(LPCMINVOKECOMMANDINFOEX lpcmi);
@@ -229,7 +247,7 @@ HRESULT CDefaultContextMenu::_DoCallback(UINT uMsg, WPARAM wParam,
LPVOID lParam
return E_FAIL;
}
-void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb)
+void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass, const WCHAR *szVerb, UINT
uFlags)
{
POSITION it = m_StaticEntries.GetHeadPosition();
while (it != NULL)
@@ -244,7 +262,7 @@ void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass, const
WCHAR *szVe
TRACE("adding verb %s\n", debugstr_w(szVerb));
- if (!wcsicmp(szVerb, L"open"))
+ if (!wcsicmp(szVerb, L"open") && !(uFlags & CMF_NODEFAULT))
{
/* open verb is always inserted in front */
m_StaticEntries.AddHead({ szVerb, hkeyClass });
@@ -255,7 +273,7 @@ void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass, const
WCHAR *szVe
}
}
-void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey)
+void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey, UINT uFlags)
{
WCHAR wszName[40];
DWORD cchName, dwIndex = 0;
@@ -271,7 +289,7 @@ void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey)
if (RegEnumKeyExW(hShellKey, dwIndex++, wszName, &cchName, NULL, NULL, NULL,
NULL) != ERROR_SUCCESS)
break;
- AddStaticEntry(hKey, wszName);
+ AddStaticEntry(hKey, wszName, uFlags);
}
RegCloseKey(hShellKey);
@@ -450,13 +468,15 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
HMENU hMenu,
UINT* pIndexMenu,
UINT iIdCmdFirst,
- UINT iIdCmdLast)
+ UINT iIdCmdLast,
+ UINT uFlags)
{
+ UINT ntver = RosGetProcessEffectiveVersion();
MENUITEMINFOW mii;
UINT idResource;
WCHAR wszVerb[40];
UINT fState;
- UINT cIds = 0;
+ UINT cIds = 0, indexFirst = *pIndexMenu;
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE | MIIM_DATA;
@@ -468,6 +488,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
while (it != NULL)
{
StaticShellEntry& info = m_StaticEntries.GetNext(it);
+ BOOL forceFirstPos = FALSE;
fState = MFS_ENABLED;
mii.dwTypeData = NULL;
@@ -481,12 +502,19 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
if (info.Verb.CompareNoCase(L"open") == 0)
{
- /* override default when open verb is found */
- fState |= MFS_DEFAULT;
idResource = IDS_OPEN_VERB;
+ fState |= MFS_DEFAULT; /* override default when open verb is found */
+ forceFirstPos++;
}
else if (info.Verb.CompareNoCase(L"explore") == 0)
+ {
idResource = IDS_EXPLORE_VERB;
+ if (uFlags & CMF_EXPLORE)
+ {
+ fState |= MFS_DEFAULT;
+ forceFirstPos++;
+ }
+ }
else if (info.Verb.CompareNoCase(L"runas") == 0)
idResource = IDS_RUNAS_VERB;
else if (info.Verb.CompareNoCase(L"edit") == 0)
@@ -496,9 +524,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
else if (info.Verb.CompareNoCase(L"print") == 0)
idResource = IDS_PRINT_VERB;
else if (info.Verb.CompareNoCase(L"printto") == 0)
- {
continue;
- }
else
idResource = 0;
@@ -513,53 +539,96 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
continue;
}
- BOOL Extended = FALSE;
+ UINT cmdFlags = 0;
+ BOOL hide = FALSE;
HKEY hkVerb;
if (idResource > 0)
{
- if (LoadStringW(shell32_hInstance, idResource, wszVerb, _countof(wszVerb)))
- mii.dwTypeData = wszVerb; /* use translated verb */
- else
- ERR("Failed to load string\n");
-
- LONG res = RegOpenKeyW(info.hkClass, wszKey, &hkVerb);
- if (res == ERROR_SUCCESS)
+ if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
{
- res = RegQueryValueExW(hkVerb, L"Extended", NULL, NULL, NULL,
NULL);
- Extended = (res == ERROR_SUCCESS);
-
- RegCloseKey(hkVerb);
+ if (LoadStringW(shell32_hInstance, idResource, wszVerb,
_countof(wszVerb)))
+ mii.dwTypeData = wszVerb; /* use translated verb */
+ else
+ ERR("Failed to load string\n");
}
+
+ if (RegOpenKeyW(info.hkClass, wszKey, &hkVerb) != ERROR_SUCCESS)
+ hkVerb = NULL;
}
else
{
- LONG res = RegOpenKeyW(info.hkClass, wszKey, &hkVerb);
- if (res == ERROR_SUCCESS)
+ if (RegOpenKeyW(info.hkClass, wszKey, &hkVerb) == ERROR_SUCCESS)
{
- DWORD cbVerb = sizeof(wszVerb);
- res = RegLoadMUIStringW(hkVerb, NULL, wszVerb, cbVerb, NULL, 0, NULL);
- if (res == ERROR_SUCCESS)
+ if (!(uFlags & CMF_OPTIMIZEFORINVOKE))
{
- /* use description for the menu entry */
- mii.dwTypeData = wszVerb;
- }
+ DWORD cbVerb = sizeof(wszVerb);
- res = RegQueryValueExW(hkVerb, L"Extended", NULL, NULL, NULL,
NULL);
- Extended = (res == ERROR_SUCCESS);
+ LONG res = RegLoadMUIStringW(hkVerb, L"MUIVerb", wszVerb,
cbVerb, NULL, 0, NULL);
+ if (res || !*wszVerb)
+ res = RegLoadMUIStringW(hkVerb, NULL, wszVerb, cbVerb, NULL, 0,
NULL);
- RegCloseKey(hkVerb);
+ if (res == ERROR_SUCCESS && *wszVerb)
+ {
+ /* use description for the menu entry */
+ mii.dwTypeData = wszVerb;
+ }
+ }
+ }
+ else
+ {
+ hkVerb = NULL;
}
}
- if (!Extended || GetAsyncKeyState(VK_SHIFT) < 0)
+ if (hkVerb)
{
- mii.cch = wcslen(mii.dwTypeData);
+ // FIXME: GetAsyncKeyState should not be called here, clients
+ // need to be updated to set the CMF_EXTENDEDVERBS flag.
+ if (!(uFlags & CMF_EXTENDEDVERBS) && GetAsyncKeyState(VK_SHIFT)
>= 0)
+ hide |= RegValueExists(hkVerb, L"Extended");
+
+ hide |= RegValueExists(hkVerb, L"ProgrammaticAccessOnly");
+
+ if (!(uFlags & CMF_DISABLEDVERBS))
+ hide |= RegValueExists(hkVerb, L"LegacyDisable");
+
+ if (RegValueExists(hkVerb, L"NeverDefault"))
+ fState &= ~MFS_DEFAULT;
+
+ if (RegValueExists(hkVerb, L"SeparatorBefore"))
+ cmdFlags |= ECF_SEPARATORBEFORE;
+ if (RegValueExists(hkVerb, L"SeparatorAfter"))
+ cmdFlags |= ECF_SEPARATORAFTER;
+
+ RegCloseKey(hkVerb);
+ }
+
+ if (((uFlags & CMF_NODEFAULT) && ntver >= _WIN32_WINNT_VISTA) ||
+ ((uFlags & CMF_DONOTPICKDEFAULT) && ntver >=
_WIN32_WINNT_WIN7))
+ {
+ fState &= ~MFS_DEFAULT;
+ }
+
+ if (!hide)
+ {
+ if (cmdFlags & ECF_SEPARATORBEFORE)
+ {
+ if (InsertMenuItemAt(hMenu, *pIndexMenu, MF_SEPARATOR))
+ (*pIndexMenu)++;
+ }
+
mii.fState = fState;
mii.wID = iIdCmdFirst + cIds;
- InsertMenuItemW(hMenu, *pIndexMenu, TRUE, &mii);
- (*pIndexMenu)++;
- cIds++;
+ if (InsertMenuItemW(hMenu, forceFirstPos ? indexFirst : *pIndexMenu, TRUE,
&mii))
+ (*pIndexMenu)++;
+
+ if (cmdFlags & ECF_SEPARATORAFTER)
+ {
+ if (InsertMenuItemAt(hMenu, *pIndexMenu, MF_SEPARATOR))
+ (*pIndexMenu)++;
+ }
}
+ cIds++; // Always increment the id because it acts as the index into
m_StaticEntries
if (mii.wID >= iIdCmdLast)
break;
@@ -587,7 +656,7 @@ void WINAPI _InsertMenuItemW(
else if (fType == MFT_STRING)
{
mii.fMask = MIIM_ID | MIIM_TYPE | MIIM_STATE;
- if ((ULONG_PTR)HIWORD((ULONG_PTR)dwTypeData) == 0)
+ if (IS_INTRESOURCE(dwTypeData))
{
if (LoadStringW(shell32_hInstance, LOWORD((ULONG_PTR)dwTypeData), wszText,
_countof(wszText)))
mii.dwTypeData = wszText;
@@ -607,6 +676,42 @@ void WINAPI _InsertMenuItemW(
InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
}
+void
+CDefaultContextMenu::TryPickDefault(HMENU hMenu, UINT idCmdFirst, UINT DfltOffset, UINT
uFlags)
+{
+ // Are we allowed to pick a default?
+ UINT ntver = RosGetProcessEffectiveVersion();
+ if (((uFlags & CMF_NODEFAULT) && ntver >= _WIN32_WINNT_VISTA) ||
+ ((uFlags & CMF_DONOTPICKDEFAULT) && ntver >= _WIN32_WINNT_WIN7))
+ {
+ return;
+ }
+
+ // Do we already have a default?
+ if ((int)GetMenuDefaultItem(hMenu, MF_BYPOSITION, 0) != -1)
+ return;
+
+ // Does the view want to pick one?
+ INT_PTR forceDfm = 0;
+ if (_DoCallback(DFM_GETDEFSTATICID, 0, &forceDfm) == S_OK && forceDfm)
+ {
+ for (UINT i = 0; i < _countof(g_StaticInvokeCmdMap); ++i)
+ {
+ UINT menuItemId = g_StaticInvokeCmdMap[i].IntVerb + DfltOffset -
DCM_FCIDM_SHVIEW_OFFSET;
+ if (g_StaticInvokeCmdMap[i].DfmCmd == forceDfm &&
+ SetMenuDefaultItem(hMenu, menuItemId, MF_BYCOMMAND))
+ {
+ return;
+ }
+ }
+ }
+
+ // Don't want to pick something like cut or delete as the default but
+ // a static or dynamic verb is a good default.
+ if (m_iIdSCMLast > m_iIdSCMFirst || m_iIdSHELast > m_iIdSHEFirst)
+ SetMenuDefaultItem(hMenu, idCmdFirst, MF_BYCOMMAND);
+}
+
HRESULT
WINAPI
CDefaultContextMenu::QueryContextMenu(
@@ -623,15 +728,15 @@ CDefaultContextMenu::QueryContextMenu(
TRACE("BuildShellItemContextMenu entered\n");
/* Load static verbs and shell extensions from registry */
- for (UINT i = 0; i < m_cKeys; i++)
+ for (UINT i = 0; i < m_cKeys && !(uFlags & CMF_NOVERBS); i++)
{
- AddStaticEntriesForKey(m_aKeys[i]);
+ AddStaticEntriesForKey(m_aKeys[i], uFlags);
EnumerateDynamicContextHandlerForKey(m_aKeys[i]);
}
/* Add static context menu handlers */
- cIds = AddStaticContextMenusToMenu(hMenu, &IndexMenu, idCmdFirst, idCmdLast);
- m_iIdSCMFirst = 0;
+ cIds = AddStaticContextMenusToMenu(hMenu, &IndexMenu, idCmdFirst, idCmdLast,
uFlags);
+ m_iIdSCMFirst = 0; // FIXME: This should be = idCmdFirst?
m_iIdSCMLast = cIds;
idCmdNext = idCmdFirst + cIds;
@@ -654,44 +759,49 @@ CDefaultContextMenu::QueryContextMenu(
idCmdNext = idCmdFirst + cIds;
}
- if (uFlags & CMF_VERBSONLY)
- return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cIds);
+ //TODO: DFM_MERGECONTEXTMENU_BOTTOM
+
+ UINT idDefaultOffset = 0;
+ BOOL isBackgroundMenu = !m_cidl;
+ if (!(uFlags & CMF_VERBSONLY) && !isBackgroundMenu)
+ {
+ /* Get the attributes of the items */
+ SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE |
SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
+ hr = m_psf->GetAttributesOf(m_cidl, m_apidl, &rfg);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cIds);
+
+ /* Add the default part of the menu */
+ HMENU hmenuDefault = LoadMenu(_AtlBaseModule.GetResourceInstance(),
L"MENU_SHV_FILE");
+
+ /* Remove uneeded entries */
+ if (!(rfg & SFGAO_CANMOVE))
+ DeleteMenu(hmenuDefault, IDM_CUT, MF_BYCOMMAND);
+ if (!(rfg & SFGAO_CANCOPY))
+ DeleteMenu(hmenuDefault, IDM_COPY, MF_BYCOMMAND);
+ if (!((rfg & SFGAO_FILESYSTEM) && HasClipboardData()))
+ DeleteMenu(hmenuDefault, IDM_INSERT, MF_BYCOMMAND);
+ if (!(rfg & SFGAO_CANLINK))
+ DeleteMenu(hmenuDefault, IDM_CREATELINK, MF_BYCOMMAND);
+ if (!(rfg & SFGAO_CANDELETE))
+ DeleteMenu(hmenuDefault, IDM_DELETE, MF_BYCOMMAND);
+ if (!(rfg & SFGAO_CANRENAME))
+ DeleteMenu(hmenuDefault, IDM_RENAME, MF_BYCOMMAND);
+ if (!(rfg & SFGAO_HASPROPSHEET))
+ DeleteMenu(hmenuDefault, IDM_PROPERTIES, MF_BYCOMMAND);
+
+ idDefaultOffset = idCmdNext;
+ UINT idMax = Shell_MergeMenus(hMenu, GetSubMenu(hmenuDefault, 0), IndexMenu,
idCmdNext, idCmdLast, 0);
+ m_iIdDfltFirst = cIds;
+ cIds += idMax - idCmdNext;
+ m_iIdDfltLast = cIds;
+
+ DestroyMenu(hmenuDefault);
+ }
- /* If this is a background context menu we are done */
- if (!m_cidl)
- return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cIds);
+ TryPickDefault(hMenu, idCmdFirst, idDefaultOffset, uFlags);
- /* Get the attributes of the items */
- SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE |
SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
- hr = m_psf->GetAttributesOf(m_cidl, m_apidl, &rfg);
- if (FAILED_UNEXPECTEDLY(hr))
- return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cIds);
-
- /* Add the default part of the menu */
- HMENU hmenuDefault = LoadMenu(_AtlBaseModule.GetResourceInstance(),
L"MENU_SHV_FILE");
-
- /* Remove uneeded entries */
- if (!(rfg & SFGAO_CANMOVE))
- DeleteMenu(hmenuDefault, IDM_CUT, MF_BYCOMMAND);
- if (!(rfg & SFGAO_CANCOPY))
- DeleteMenu(hmenuDefault, IDM_COPY, MF_BYCOMMAND);
- if (!((rfg & SFGAO_FILESYSTEM) && HasClipboardData()))
- DeleteMenu(hmenuDefault, IDM_INSERT, MF_BYCOMMAND);
- if (!(rfg & SFGAO_CANLINK))
- DeleteMenu(hmenuDefault, IDM_CREATELINK, MF_BYCOMMAND);
- if (!(rfg & SFGAO_CANDELETE))
- DeleteMenu(hmenuDefault, IDM_DELETE, MF_BYCOMMAND);
- if (!(rfg & SFGAO_CANRENAME))
- DeleteMenu(hmenuDefault, IDM_RENAME, MF_BYCOMMAND);
- if (!(rfg & SFGAO_HASPROPSHEET))
- DeleteMenu(hmenuDefault, IDM_PROPERTIES, MF_BYCOMMAND);
-
- UINT idMax = Shell_MergeMenus(hMenu, GetSubMenu(hmenuDefault, 0), IndexMenu,
idCmdNext, idCmdLast, 0);
- m_iIdDfltFirst = cIds;
- cIds += idMax - idCmdNext;
- m_iIdDfltLast = cIds;
-
- DestroyMenu(hmenuDefault);
+ // TODO: DFM_MERGECONTEXTMENU_TOP
return MAKE_HRESULT(SEVERITY_SUCCESS, 0, cIds);
}
@@ -1040,7 +1150,7 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX
lpcmi, PStatic
/* Get a pointer to the shell browser */
hr = IUnknown_QueryService(m_site, SID_IShellBrowser, IID_PPV_ARG(IShellBrowser,
&psb));
- if (FAILED_UNEXPECTEDLY(hr))
+ if (FAILED(hr))
return 0;
/* See if we are in Explore or Browse mode. If the browser's tree is present, we
are in Explore mode.*/
@@ -1065,7 +1175,7 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX
lpcmi, PStatic
HRESULT
CDefaultContextMenu::TryToBrowse(
- LPCMINVOKECOMMANDINFOEX lpcmi, LPCITEMIDLIST pidl, DWORD wFlags)
+ LPCMINVOKECOMMANDINFOEX lpcmi, LPCITEMIDLIST pidlChild, DWORD wFlags)
{
CComPtr<IShellBrowser> psb;
HRESULT hr;
@@ -1075,10 +1185,17 @@ CDefaultContextMenu::TryToBrowse(
/* Get a pointer to the shell browser */
hr = IUnknown_QueryService(m_site, SID_IShellBrowser, IID_PPV_ARG(IShellBrowser,
&psb));
- if (FAILED_UNEXPECTEDLY(hr))
- return 0;
+ if (FAILED(hr))
+ return hr;
- return psb->BrowseObject(ILCombine(m_pidlFolder, pidl), wFlags);
+ PIDLIST_ABSOLUTE pidl;
+ hr = SHILCombine(m_pidlFolder, pidlChild, &pidl);
+ if (FAILED_UNEXPECTEDLY(hr))
+ return hr;
+
+ hr = psb->BrowseObject(pidl, wFlags & ~SBSP_RELATIVE);
+ ILFree(pidl);
+ return hr;
}
HRESULT
@@ -1101,7 +1218,8 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFOEX lpcmi,
LPCITEMIDLIST pid
}
else
{
- SHGetPathFromIDListW(m_pidlFolder, wszDir);
+ if (!SHGetPathFromIDListW(m_pidlFolder, wszDir))
+ *wszDir = UNICODE_NULL;
}
SHELLEXECUTEINFOW sei;
@@ -1143,23 +1261,24 @@ CDefaultContextMenu::InvokeRegVerb(
/* Get the browse flags to see if we need to browse */
DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
- BOOL bBrowsed = FALSE;
for (i=0; i < m_cidl; i++)
{
/* Check if we need to browse */
- if (wFlags > 0)
+ if (wFlags)
{
- /* In xp if we have browsed, we don't open any more folders.
- * In win7 we browse to the first folder we find and
- * open new windows for each of the rest of the folders */
- if (bBrowsed)
- continue;
-
hr = TryToBrowse(lpcmi, m_apidl[i], wFlags);
if (SUCCEEDED(hr))
{
- bBrowsed = TRUE;
+ /* In WinXP if we have browsed, we don't open any more folders.
+ * In Win7 we browse to the first folder we find and
+ * open new windows for each of the rest of the folders */
+ UINT ntver = RosGetProcessEffectiveVersion();
+ if (ntver >= _WIN32_WINNT_VISTA)
+ wFlags = 0; // FIXME: = SBSP_NEWBROWSER | (wFlags &
~SBSP_SAMEBROWSER);
+ else
+ i = m_cidl;
+
continue;
}
}
@@ -1184,7 +1303,7 @@ CDefaultContextMenu::InvokeCommand(
memcpy(&LocalInvokeInfo, lpcmi, min(sizeof(LocalInvokeInfo), lpcmi->cbSize));
/* Check if this is a string verb */
- if (HIWORD(LocalInvokeInfo.lpVerb))
+ if (!IS_INTRESOURCE(LocalInvokeInfo.lpVerb))
{
/* Get the ID which corresponds to this verb, and update our local copy */
if (MapVerbToCmdId((LPVOID)LocalInvokeInfo.lpVerb, &CmdId, FALSE))
@@ -1217,7 +1336,7 @@ CDefaultContextMenu::InvokeCommand(
{
CmdId -= m_iIdDfltFirst;
/* See the definitions of IDM_CUT and co to see how this works */
- CmdId += 0x7000;
+ CmdId += DCM_FCIDM_SHVIEW_OFFSET;
}
if (LocalInvokeInfo.cbSize >= sizeof(CMINVOKECOMMANDINFOEX) &&
(LocalInvokeInfo.fMask & CMIC_MASK_PTINVOKE))
@@ -1344,7 +1463,7 @@ CDefaultContextMenu::GetCommandString(
{
CmdId -= m_iIdDfltFirst;
/* See the definitions of IDM_CUT and co to see how this works */
- CmdId += 0x7000;
+ CmdId += DCM_FCIDM_SHVIEW_OFFSET;
}
/* Loop looking for a matching Id */
diff --git a/sdk/include/psdk/shobjidl.idl b/sdk/include/psdk/shobjidl.idl
index 54bf45a34c2..ef9e51d16e1 100644
--- a/sdk/include/psdk/shobjidl.idl
+++ b/sdk/include/psdk/shobjidl.idl
@@ -1596,16 +1596,21 @@ interface IDropTargetHelper : IUnknown
]
interface IContextMenu : IUnknown
{
-cpp_quote("#define CMF_NORMAL 0x00000000")
-cpp_quote("#define CMF_DEFAULTONLY 0x00000001")
-cpp_quote("#define CMF_VERBSONLY 0x00000002")
-cpp_quote("#define CMF_EXPLORE 0x00000004")
-cpp_quote("#define CMF_NOVERBS 0x00000008")
-cpp_quote("#define CMF_CANRENAME 0x00000010")
-cpp_quote("#define CMF_NODEFAULT 0x00000020")
-cpp_quote("#define CMF_INCLUDESTATIC 0x00000040")
-cpp_quote("#define CMF_EXTENDEDVERBS 0x00000100")
-cpp_quote("#define CMF_RESERVED 0xffff0000")
+cpp_quote("#define CMF_NORMAL 0x00000000")
+cpp_quote("#define CMF_DEFAULTONLY 0x00000001")
+cpp_quote("#define CMF_VERBSONLY 0x00000002")
+cpp_quote("#define CMF_EXPLORE 0x00000004")
+cpp_quote("#define CMF_NOVERBS 0x00000008")
+cpp_quote("#define CMF_CANRENAME 0x00000010")
+cpp_quote("#define CMF_NODEFAULT 0x00000020")
+cpp_quote("#define CMF_INCLUDESTATIC 0x00000040")
+cpp_quote("#define CMF_EXTENDEDVERBS 0x00000100")
+cpp_quote("#define CMF_DISABLEDVERBS 0x00000200")
+cpp_quote("#define CMF_ASYNCVERBSTATE 0x00000400")
+cpp_quote("#define CMF_OPTIMIZEFORINVOKE 0x00000800")
+cpp_quote("#define CMF_SYNCCASCADEMENU 0x00001000")
+cpp_quote("#define CMF_DONOTPICKDEFAULT 0x00002000")
+cpp_quote("#define CMF_RESERVED 0xffff0000")
cpp_quote("#define GCS_VERBA 0x00000000")
cpp_quote("#define GCS_HELPTEXTA 0x00000001")
diff --git a/sdk/include/reactos/compat_undoc.h b/sdk/include/reactos/compat_undoc.h
index 44212efb2d2..b0516322a37 100644
--- a/sdk/include/reactos/compat_undoc.h
+++ b/sdk/include/reactos/compat_undoc.h
@@ -34,5 +34,16 @@ DWORD RosGetProcessCompatVersion(VOID)
return g_CompatVersion < REACTOS_COMPATVERSION_UNINITIALIZED ? g_CompatVersion :
0;
}
+static
+inline
+UINT RosGetProcessEffectiveVersion(VOID)
+{
+ PPEB peb = NtCurrentPeb();
+ UINT shimVer = RosGetProcessCompatVersion();
+ if (shimVer)
+ return shimVer;
+ else
+ return (peb->OSMajorVersion << 8) | (peb->OSMinorVersion);
+}
#endif // COMPAT_UNDOC_H
diff --git a/sdk/include/reactos/shellutils.h b/sdk/include/reactos/shellutils.h
index 9ccce4d3373..226de2ee325 100644
--- a/sdk/include/reactos/shellutils.h
+++ b/sdk/include/reactos/shellutils.h
@@ -410,6 +410,18 @@ HRESULT inline ShellObjectCreatorInit(T1 initArg1, T2 initArg2, T3
initArg3, T4
return hResult;
}
+template<class P, class R> static HRESULT SHILClone(P pidl, R *ppOut)
+{
+ R r = *ppOut = (R)ILClone((PIDLIST_RELATIVE)pidl);
+ return r ? S_OK : E_OUTOFMEMORY;
+}
+
+template<class B, class R> static HRESULT SHILCombine(B base, PCUIDLIST_RELATIVE
sub, R *ppOut)
+{
+ R r = *ppOut = (R)ILCombine((PCIDLIST_ABSOLUTE)base, sub);
+ return r ? S_OK : E_OUTOFMEMORY;
+}
+
HRESULT inline SHSetStrRet(LPSTRRET pStrRet, LPCSTR pstrValue)
{
pStrRet->uType = STRRET_CSTR;