[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()
{
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_StaticEntries.RemoveAll();
@ -389,7 +394,7 @@ CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey, REFCLSID clsid)
return hr;
}
hr = pExtInit->Initialize(m_pidlFolder, m_pDataObj, hKey);
hr = pExtInit->Initialize(m_pDataObj ? NULL : m_pidlFolder, m_pDataObj, hKey);
if (FAILED(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))
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;
UINT m_cfShellIDList;
BOOL m_doasync;
bool m_FailGetHDrop;
public:
CIDLDataObj();
~CIDLDataObj();
@ -173,6 +174,7 @@ CIDLDataObj::CIDLDataObj()
{
m_cfShellIDList = 0;
m_doasync = FALSE;
m_FailGetHDrop = false;
}
CIDLDataObj::~CIDLDataObj()
@ -205,6 +207,15 @@ HRESULT WINAPI CIDLDataObj::Initialize(HWND hwndOwner, PCIDLIST_ABSOLUTE pMyPidl
HRESULT hr = SetData(&Format, &medium, TRUE);
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;
medium.hGlobal = RenderHDROP((LPITEMIDLIST)pMyPidl, (LPITEMIDLIST*)apidlx, cidlx);
hr = SetData(&Format, &medium, TRUE);
@ -245,6 +256,9 @@ HRESULT WINAPI CIDLDataObj::GetData(LPFORMATETC pformatetcIn, STGMEDIUM *pmedium
fmt.dwAspect == pformatetcIn->dwAspect &&
fmt.tymed == pformatetcIn->tymed)
{
if (m_FailGetHDrop && fmt.cfFormat == CF_HDROP)
return DV_E_CLIPFORMAT;
if (pformatetcIn->tymed != TYMED_HGLOBAL)
{
UNIMPLEMENTED;

View file

@ -945,7 +945,7 @@ BrFolder_OnContextMenu(BrFolder &info, LPARAM lParam)
return;
info.pContextMenu = pcm;
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)
_InsertMenuItemW(hMenu, 0, TRUE, 0, MFT_SEPARATOR, NULL, 0);
_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)
{
TreeView_SelectItem(info.hwndTreeView, hSelected);
TreeView_EditLabel(info.hwndTreeView, hSelected);
BrFolder_Rename(&info, hSelected);
}
else if (cmd != 0)
{

View file

@ -25,6 +25,11 @@
WINE_DEFAULT_DEBUG_CHANNEL(shell);
static BOOL IsSelf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl)
{
return cidl == 0 || (cidl == 1 && apidl && _ILIsEmpty(apidl[0]));
}
STDMETHODIMP
CDesktopFolder::ShellUrlParseDisplayName(
HWND hwndOwner,
@ -810,10 +815,10 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
if (!ppvOut)
return hr;
*ppvOut = NULL;
if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]))
BOOL self = IsSelf(cidl, apidl);
if (cidl == 1 && !_ILIsSpecialFolder(apidl[0]) && !self)
{
CComPtr<IShellFolder2> psf;
HRESULT hr = _GetSFFromPidl(apidl[0], &psf);
@ -825,7 +830,8 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
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);
}
@ -836,7 +842,12 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
/* Otherwise operations like that involve items from both user and shared desktop will not work */
HKEY hKeys[16];
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);
}
@ -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)
{
enum { IDC_PROPERTIES };
/* no data object means no selection */
if (!pdtobj)
if (uMsg == DFM_INVOKECOMMAND && wParam == (pdtobj ? DFM_CMD_PROPERTIES : IDC_PROPERTIES))
{
if (uMsg == DFM_INVOKECOMMAND && wParam == IDC_PROPERTIES)
{
return SHELL_ExecuteControlPanelCPL(hwndOwner, L"desk.cpl") ? S_OK : E_FAIL;
}
else if (uMsg == DFM_MERGECONTEXTMENU)
{
QCMINFO *pqcminfo = (QCMINFO *)lParam;
HMENU hpopup = CreatePopupMenu();
_InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
DestroyMenu(hpopup);
return S_OK;
}
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
{
QCMINFO *pqcminfo = (QCMINFO *)lParam;
HMENU hpopup = CreatePopupMenu();
_InsertMenuItemW(hpopup, 0, TRUE, IDC_PROPERTIES, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED);
pqcminfo->idCmdFirst = Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
DestroyMenu(hpopup);
return S_OK;
}
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);
LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys);
LSTATUS AddClsidKeyToArray(REFCLSID clsid, HKEY* array, UINT* cKeys);
#ifdef __cplusplus

View file

@ -289,6 +289,13 @@ LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys)
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)
{
// This function opens the association array keys in canonical order for filesystem items.