[SHELL32] Implement the desktop folder menu for Explorer tree (#7026)

Enumerates but does not actually allow you to get CF_HDROP if the desktop PIDL is present in the dataobject.
This commit is contained in:
Whindmar Saksit 2024-06-21 19:19:49 +02:00 committed by GitHub
parent 674136bcd0
commit 63935f857f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 57 additions and 24 deletions

View file

@ -207,6 +207,11 @@ CDefaultContextMenu::CDefaultContextMenu() :
CDefaultContextMenu::~CDefaultContextMenu() CDefaultContextMenu::~CDefaultContextMenu()
{ {
for (POSITION it = m_DynamicEntries.GetHeadPosition(); it != NULL;)
{
const DynamicShellEntry& info = m_DynamicEntries.GetNext(it);
IUnknown_SetSite(info.pCM.p, NULL);
}
m_DynamicEntries.RemoveAll(); m_DynamicEntries.RemoveAll();
m_StaticEntries.RemoveAll(); m_StaticEntries.RemoveAll();
@ -389,7 +394,7 @@ CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, REFCLSID clsid)
return hr; return hr;
} }
hr = pExtInit->Initialize(m_pidlFolder, m_pDataObj, hKey); hr = pExtInit->Initialize(m_pDataObj ? NULL : m_pidlFolder, m_pDataObj, hKey);
if (FAILED(hr)) if (FAILED(hr))
{ {
WARN("IShellExtInit::Initialize failed.clsid %s hr 0x%x\n", wine_dbgstr_guid(&clsid), hr); WARN("IShellExtInit::Initialize failed.clsid %s hr 0x%x\n", wine_dbgstr_guid(&clsid), hr);
@ -459,7 +464,7 @@ CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey)
} }
} }
hr = LoadDynamicContextMenuHandler(hKey, clsid); hr = LoadDynamicContextMenuHandler(hRootKey, clsid);
if (FAILED(hr)) if (FAILED(hr))
WARN("Failed to get context menu entires from shell extension! clsid: %S\n", pwszClsid); WARN("Failed to get context menu entires from shell extension! clsid: %S\n", pwszClsid);
} }

View file

@ -140,6 +140,7 @@ private:
CSimpleArray<STGMEDIUM> m_Storage; CSimpleArray<STGMEDIUM> m_Storage;
UINT m_cfShellIDList; UINT m_cfShellIDList;
BOOL m_doasync; BOOL m_doasync;
bool m_FailGetHDrop;
public: public:
CIDLDataObj(); CIDLDataObj();
~CIDLDataObj(); ~CIDLDataObj();
@ -173,6 +174,7 @@ CIDLDataObj::CIDLDataObj()
{ {
m_cfShellIDList = 0; m_cfShellIDList = 0;
m_doasync = FALSE; m_doasync = FALSE;
m_FailGetHDrop = false;
} }
CIDLDataObj::~CIDLDataObj() CIDLDataObj::~CIDLDataObj()
@ -205,6 +207,15 @@ HRESULT WINAPI CIDLDataObj::Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl
HRESULT hr = SetData(&Format, &medium, TRUE); HRESULT hr = SetData(&Format, &medium, TRUE);
if (!FAILED_UNEXPECTEDLY(hr) && bAddAdditionalFormats) if (!FAILED_UNEXPECTEDLY(hr) && bAddAdditionalFormats)
{ {
/* The Windows default shell IDataObject::GetData fails with DV_E_CLIPFORMAT if the desktop is present.
* Windows does return HDROP in EnumFormatEtc and does not fail until GetData is called.
* Failing GetData causes 7-Zip 23.01 to not add its menu to the desktop folder. */
for (UINT i = 0; i < cidlx; ++i)
{
if (ILIsEmpty(apidlx[i]) && ILIsEmpty(pMyPidl))
m_FailGetHDrop = true;
}
Format.cfFormat = CF_HDROP; Format.cfFormat = CF_HDROP;
medium.hGlobal = RenderHDROP((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx); medium.hGlobal = RenderHDROP((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx);
hr = SetData(&Format, &medium, TRUE); hr = SetData(&Format, &medium, TRUE);
@ -245,6 +256,9 @@ HRESULT WINAPI CIDLDataObj::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium
fmt.dwAspect == pformatetcIn->dwAspect && fmt.dwAspect == pformatetcIn->dwAspect &&
fmt.tymed == pformatetcIn->tymed) fmt.tymed == pformatetcIn->tymed)
{ {
if (m_FailGetHDrop && fmt.cfFormat == CF_HDROP)
return DV_E_CLIPFORMAT;
if (pformatetcIn->tymed != TYMED_HGLOBAL) if (pformatetcIn->tymed != TYMED_HGLOBAL)
{ {
UNIMPLEMENTED; UNIMPLEMENTED;

View file

@ -945,7 +945,7 @@ BrFolder_OnContextMenu(BrFolder &info, LPARAM lParam)
return; return;
info.pContextMenu = pcm; info.pContextMenu = pcm;
UINT cmf = ((GetKeyState(VK_SHIFT) < 0) ? CMF_EXTENDEDVERBS : 0) | CMF_CANRENAME; UINT cmf = ((GetKeyState(VK_SHIFT) < 0) ? CMF_EXTENDEDVERBS : 0) | CMF_CANRENAME;
hr = pcm->QueryContextMenu(hMenu, 0, ID_FIRSTCMD, ID_LASTCMD, CMF_NODEFAULT | cmf); hr = pcm->QueryContextMenu(hMenu, 0, ID_FIRSTCMD, ID_LASTCMD, CMF_EXPLORE | cmf);
if (hr > 0) if (hr > 0)
_InsertMenuItemW(hMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, 0); _InsertMenuItemW(hMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, 0);
_InsertMenuItemW(hMenu, 0, TRUE, IDC_TOGGLE, MFT_STRING, _InsertMenuItemW(hMenu, 0, TRUE, IDC_TOGGLE, MFT_STRING,
@ -961,8 +961,7 @@ BrFolder_OnContextMenu(BrFolder &info, LPARAM lParam)
} }
else if (cmd != 0 && GetDfmCmd(pcm, ici.lpVerb) == DFM_CMD_RENAME) else if (cmd != 0 && GetDfmCmd(pcm, ici.lpVerb) == DFM_CMD_RENAME)
{ {
TreeView_SelectItem(info.hwndTreeView, hSelected); BrFolder_Rename(&info, hSelected);
TreeView_EditLabel(info.hwndTreeView, hSelected);
} }
else if (cmd != 0) else if (cmd != 0)
{ {

View file

@ -25,6 +25,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell); WINE_DEFAULT_DEBUG_CHANNEL(shell);
static BOOL IsSelf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
{
return cidl == 0 || (cidl == 1 && apidl && _ILIsEmpty(apidl[0]));
}
STDMETHODIMP STDMETHODIMP
CDesktopFolder::ShellUrlParseDisplayName( CDesktopFolder::ShellUrlParseDisplayName(
HWND hwndOwner, HWND hwndOwner,
@ -810,10 +815,10 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
if (!ppvOut) if (!ppvOut)
return hr; return hr;
*ppvOut = NULL; *ppvOut = NULL;
if (cidl == 1 && !_ILIsSpecialFolder(apidl[0])) BOOL self = IsSelf(cidl, apidl);
if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]) && !self)
{ {
CComPtr<IShellFolder2> psf; CComPtr<IShellFolder2> psf;
HRESULT hr = _GetSFFromPidl(apidl[0], &psf); HRESULT hr = _GetSFFromPidl(apidl[0], &psf);
@ -825,7 +830,8 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
if (IsEqualIID (riid, IID_IContextMenu)) if (IsEqualIID (riid, IID_IContextMenu))
{ {
if (cidl > 0 && _ILIsSpecialFolder(apidl[0])) // FIXME: m_regFolder vs AddFSClassKeysToArray is incorrect when the selection includes both regitems and FS items
if (!self && cidl > 0 && _ILIsSpecialFolder(apidl[0]))
{ {
hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj); hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
} }
@ -836,7 +842,12 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
/* Otherwise operations like that involve items from both user and shared desktop will not work */ /* Otherwise operations like that involve items from both user and shared desktop will not work */
HKEY hKeys[16]; HKEY hKeys[16];
UINT cKeys = 0; UINT cKeys = 0;
if (cidl > 0) if (self)
{
AddClsidKeyToArray(CLSID_ShellDesktop, hKeys, &cKeys);
AddClassKeyToArray(L"Folder", hKeys, &cKeys);
}
else if (cidl > 0)
{ {
AddFSClassKeysToArray(cidl, apidl, hKeys, &cKeys); AddFSClassKeysToArray(cidl, apidl, hKeys, &cKeys);
} }
@ -1075,22 +1086,18 @@ HRESULT WINAPI CDesktopFolder::GetCurFolder(PIDLIST_ABSOLUTE * pidl)
HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam) HRESULT WINAPI CDesktopFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
{ {
enum { IDC_PROPERTIES }; enum { IDC_PROPERTIES };
/* no data object means no selection */ if (uMsg == DFM_INVOKECOMMAND && wParam == (pdtobj ? DFM_CMD_PROPERTIES : IDC_PROPERTIES))
if (!pdtobj)
{ {
if (uMsg == DFM_INVOKECOMMAND && wParam == IDC_PROPERTIES) return SHELL_ExecuteControlPanelCPL(hwndOwner, L"desk.cpl") ? S_OK : E_FAIL;
{ }
return SHELL_ExecuteControlPanelCPL(hwndOwner, L"desk.cpl") ? S_OK : E_FAIL; else if (uMsg == DFM_MERGECONTEXTMENU && !pdtobj) // Add Properties item when called for directory background
} {
else if (uMsg == DFM_MERGECONTEXTMENU) QCMINFO *pqcminfo = (QCMINFO *)lParam;
{ HMENU hpopup = CreatePopupMenu();
QCMINFO *pqcminfo = (QCMINFO *)lParam; _InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
HMENU hpopup = CreatePopupMenu(); pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
_InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); DestroyMenu(hpopup);
pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR); return S_OK;
DestroyMenu(hpopup);
return S_OK;
}
} }
return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg); return SHELL32_DefaultContextMenuCallBack(psf, pdtobj, uMsg);
} }

View file

@ -113,6 +113,7 @@ void SHELL_FS_ProcessDisplayFilename(LPWSTR szPath, DWORD dwFlags);
BOOL SHELL_FS_HideExtension(LPCWSTR pwszPath); BOOL SHELL_FS_HideExtension(LPCWSTR pwszPath);
LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys); LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys);
LSTATUS AddClsidKeyToArray(REFCLSID clsid, HKEY* array, UINT* cKeys);
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -289,6 +289,13 @@ LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys)
return result; return result;
} }
LSTATUS AddClsidKeyToArray(REFCLSID clsid, HKEY* array, UINT* cKeys)
{
WCHAR path[6 + 38 + 1] = L"CLSID\\";
StringFromGUID2(clsid, path + 6, 38 + 1);
return AddClassKeyToArray(path, array, cKeys);
}
void AddFSClassKeysToArray(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, HKEY* array, UINT* cKeys) void AddFSClassKeysToArray(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, HKEY* array, UINT* cKeys)
{ {
// This function opens the association array keys in canonical order for filesystem items. // This function opens the association array keys in canonical order for filesystem items.