Skip to content

Commit

Permalink
[SHELL32] Use FS compatible PIDL format for Recycle Bin items (reacto…
Browse files Browse the repository at this point in the history
…s#7532)

* [SHELL32] Use FS compatible PIDL format for Recycle Bin items

This allows SHChangeNotify to handle these items and DefView will correctly update the recycle folder.

CORE-18005 CORE-19239 CORE-13950 CORE-18435 CORE-18436 CORE-18437
  • Loading branch information
whindsaks authored Dec 19, 2024
1 parent a184242 commit 28399a2
Show file tree
Hide file tree
Showing 27 changed files with 1,141 additions and 941 deletions.
14 changes: 10 additions & 4 deletions dll/win32/shell32/CCopyAsPathMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ CCopyAsPathMenu::DoCopyAsPath(IDataObject *pdto)
return hr;
}

static const CMVERBMAP g_VerbMap[] =
{
{ "copyaspath", IDC_COPYASPATH },
{ NULL }
};

STDMETHODIMP
CCopyAsPathMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
Expand Down Expand Up @@ -133,7 +139,8 @@ CCopyAsPathMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
{
TRACE("CCopyAsPathMenu::InvokeCommand(%p %p)\n", this, lpcmi);

if (IS_INTRESOURCE(lpcmi->lpVerb) && LOWORD(lpcmi->lpVerb) == IDC_COPYASPATH)
int CmdId = SHELL_MapContextMenuVerbToCmdId(lpcmi, g_VerbMap);
if (CmdId == IDC_COPYASPATH)
return DoCopyAsPath(m_pDataObject);

return E_FAIL;
Expand All @@ -142,10 +149,9 @@ CCopyAsPathMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi)
STDMETHODIMP
CCopyAsPathMenu::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen)
{
FIXME("CCopyAsPathMenu::GetCommandString(%p %lu %u %p %p %u)\n", this,
TRACE("CCopyAsPathMenu::GetCommandString(%p %lu %u %p %p %u)\n", this,
idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);

return E_NOTIMPL;
return SHELL_GetCommandStringImpl(idCommand, uFlags, lpszName, uMaxNameLen, g_VerbMap);
}

STDMETHODIMP
Expand Down
33 changes: 20 additions & 13 deletions dll/win32/shell32/CDefView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,7 @@ int CDefView::LV_FindItemByPidl(PCUITEMID_CHILD pidl)
{
for (i = 0; i < cItems; i++)
{
//FIXME: ILIsEqual needs absolute pidls!
currentpidl = _PidlByItem(i);
if (ILIsEqual(pidl, currentpidl))
return i;
Expand Down Expand Up @@ -2848,29 +2849,35 @@ LRESULT CDefView::OnChangeNotify(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &
TRACE("(%p)(%p,%p,%p)\n", this, Pidls[0], Pidls[1], lParam);

if (_DoFolderViewCB(SFVM_FSNOTIFY, (WPARAM)Pidls, lEvent) == S_FALSE)
{
SHChangeNotification_Unlock(hLock);
return FALSE;
}

// Translate child IDLs.
// SHSimpleIDListFromPathW creates fake PIDLs (lacking some attributes)
lEvent &= ~SHCNE_INTERRUPT;
HRESULT hr;
PITEMID_CHILD child0 = NULL, child1 = NULL;
CComHeapPtr<ITEMIDLIST_RELATIVE> pidl0Temp, pidl1Temp;
if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]))
if (lEvent != SHCNE_UPDATEIMAGE && lEvent < SHCNE_EXTENDED_EVENT)
{
child0 = ILFindLastID(Pidls[0]);
hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp);
if (SUCCEEDED(hr))
child0 = pidl0Temp;
}
if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]))
{
child1 = ILFindLastID(Pidls[1]);
hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp);
if (SUCCEEDED(hr))
child1 = pidl1Temp;
if (_ILIsSpecialFolder(Pidls[0]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[0]))
{
child0 = ILFindLastID(Pidls[0]);
hr = SHGetRealIDL(m_pSFParent, child0, &pidl0Temp);
if (SUCCEEDED(hr))
child0 = pidl0Temp;
}
if (_ILIsSpecialFolder(Pidls[1]) || ILIsParentOrSpecialParent(m_pidlParent, Pidls[1]))
{
child1 = ILFindLastID(Pidls[1]);
hr = SHGetRealIDL(m_pSFParent, child1, &pidl1Temp);
if (SUCCEEDED(hr))
child1 = pidl1Temp;
}
}

lEvent &= ~SHCNE_INTERRUPT;
switch (lEvent)
{
case SHCNE_MKDIR:
Expand Down
37 changes: 34 additions & 3 deletions dll/win32/shell32/CDefaultContextMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,25 @@ UINT MapVerbToDfmCmd(_In_ LPCSTR verba)
return 0;
}

static HRESULT
MapVerbToCmdId(PVOID Verb, BOOL IsUnicode, IContextMenu *pCM, UINT idFirst, UINT idLast)
{
const UINT gcs = IsUnicode ? GCS_VERBW : GCS_VERBA;
for (UINT id = idFirst; id <= idLast; ++id)
{
WCHAR buf[MAX_PATH];
*buf = UNICODE_NULL;
HRESULT hr = pCM->GetCommandString(id, gcs, NULL, (LPSTR)buf, _countof(buf));
if (FAILED(hr) || !*buf)
continue;
else if (IsUnicode && !_wcsicmp((LPWSTR)Verb, buf))
return id;
else if (!IsUnicode && !lstrcmpiA((LPSTR)Verb, (LPSTR)buf))
return id;
}
return HRESULT_FROM_WIN32(ERROR_NOT_FOUND);
}

static inline bool IsVerbListSeparator(WCHAR Ch)
{
return Ch == L' ' || Ch == L','; // learn.microsoft.com/en-us/windows/win32/shell/context-menu-handlers
Expand Down Expand Up @@ -738,7 +757,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
return cIds;
}

void WINAPI _InsertMenuItemW(
BOOL WINAPI _InsertMenuItemW(
HMENU hMenu,
UINT indexMenu,
BOOL fByPosition,
Expand All @@ -764,7 +783,7 @@ void WINAPI _InsertMenuItemW(
else
{
ERR("failed to load string %p\n", dwTypeData);
return;
return FALSE;
}
}
else
Expand All @@ -774,7 +793,7 @@ void WINAPI _InsertMenuItemW(

mii.wID = wID;
mii.fType = fType;
InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
return InsertMenuItemW(hMenu, indexMenu, fByPosition, &mii);
}

void
Expand Down Expand Up @@ -1212,6 +1231,18 @@ CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
}
}

for (POSITION it = m_DynamicEntries.GetHeadPosition(); it != NULL;)
{
DynamicShellEntry& entry = m_DynamicEntries.GetNext(it);
if (!entry.NumIds)
continue;
HRESULT hr = ::MapVerbToCmdId(Verb, IsUnicode, entry.pCM, 0, entry.NumIds - 1);
if (SUCCEEDED(hr))
{
*idCmd = m_iIdSHEFirst + entry.iIdCmdFirst + hr;
return TRUE;
}
}
return FALSE;
}

Expand Down
8 changes: 1 addition & 7 deletions dll/win32/shell32/CFolderItemVerbs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,7 @@ CFolderItemVerbs::~CFolderItemVerbs()

HRESULT CFolderItemVerbs::Init(LPITEMIDLIST idlist)
{
CComPtr<IShellFolder> folder;
LPCITEMIDLIST child;
HRESULT hr = SHBindToParent(idlist, IID_PPV_ARG(IShellFolder, &folder), &child);
if (FAILED_UNEXPECTEDLY(hr))
return hr;

hr = folder->GetUIObjectOf(NULL, 1, &child, IID_IContextMenu, NULL, (PVOID*)&m_contextmenu);
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, idlist, IID_PPV_ARG(IContextMenu, &m_contextmenu));
if (FAILED_UNEXPECTEDLY(hr))
return hr;

Expand Down
20 changes: 17 additions & 3 deletions dll/win32/shell32/COpenWithMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1250,6 +1250,11 @@ VOID COpenWithMenu::AddApp(PVOID pApp)
m_idCmdLast++;
}

static const CMVERBMAP g_VerbMap[] = {
{ "openas", 0 },
{ NULL }
};

HRESULT WINAPI COpenWithMenu::QueryContextMenu(
HMENU hMenu,
UINT indexMenu,
Expand Down Expand Up @@ -1328,14 +1333,19 @@ HRESULT WINAPI COpenWithMenu::QueryContextMenu(
HRESULT WINAPI
COpenWithMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
{
const SIZE_T idChooseApp = m_idCmdLast;
HRESULT hr = E_FAIL;

TRACE("This %p idFirst %u idLast %u idCmd %u\n", this, m_idCmdFirst, m_idCmdLast, m_idCmdFirst + LOWORD(lpici->lpVerb));

if (HIWORD(lpici->lpVerb) == 0 && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast)
if (!IS_INTRESOURCE(lpici->lpVerb) && SHELL_MapContextMenuVerbToCmdId(lpici, g_VerbMap) == 0)
goto DoChooseApp;

if (IS_INTRESOURCE(lpici->lpVerb) && m_idCmdFirst + LOWORD(lpici->lpVerb) <= m_idCmdLast)
{
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == m_idCmdLast)
if (m_idCmdFirst + LOWORD(lpici->lpVerb) == idChooseApp)
{
DoChooseApp:
OPENASINFO info;
LPCWSTR pwszExt = PathFindExtensionW(m_wszPath);

Expand Down Expand Up @@ -1371,9 +1381,13 @@ HRESULT WINAPI
COpenWithMenu::GetCommandString(UINT_PTR idCmd, UINT uType,
UINT* pwReserved, LPSTR pszName, UINT cchMax )
{
FIXME("%p %lu %u %p %p %u\n", this,
TRACE("%p %lu %u %p %p %u\n", this,
idCmd, uType, pwReserved, pszName, cchMax );

const SIZE_T idChooseApp = m_idCmdLast;
if (m_idCmdFirst + idCmd == idChooseApp)
return SHELL_GetCommandStringImpl(0, uType, pszName, cchMax, g_VerbMap);

return E_NOTIMPL;
}

Expand Down
9 changes: 1 addition & 8 deletions dll/win32/shell32/CSendToMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,7 @@ HRESULT CSendToMenu::GetUIObjectFromPidl(HWND hwnd, PIDLIST_ABSOLUTE pidl,
REFIID riid, LPVOID *ppvOut)
{
*ppvOut = NULL;

PCITEMID_CHILD pidlLast;
CComPtr<IShellFolder> pFolder;
HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &pFolder), &pidlLast);
if (FAILED_UNEXPECTEDLY(hr))
return hr;

hr = pFolder->GetUIObjectOf(hwnd, 1, &pidlLast, riid, NULL, ppvOut);
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(hwnd, pidl, riid, ppvOut);
if (FAILED_UNEXPECTEDLY(hr))
return hr;

Expand Down
25 changes: 3 additions & 22 deletions dll/win32/shell32/CShellLink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1729,18 +1729,10 @@ HRESULT STDMETHODCALLTYPE CShellLink::GetIconLocation(LPWSTR pszIconPath, INT cc
static HRESULT SHELL_PidlGetIconLocationW(PCIDLIST_ABSOLUTE pidl,
UINT uFlags, PWSTR pszIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
{
LPCITEMIDLIST pidlLast;
CComPtr<IShellFolder> psf;

HRESULT hr = SHBindToParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
if (FAILED_UNEXPECTEDLY(hr))
return hr;

CComPtr<IExtractIconW> pei;
hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IExtractIconW, &pei));
HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, pidl, IID_PPV_ARG(IExtractIconW, &pei));
if (FAILED_UNEXPECTEDLY(hr))
return hr;

hr = pei->GetIconLocation(uFlags, pszIconFile, cchMax, piIndex, pwFlags);
if (FAILED_UNEXPECTEDLY(hr))
return hr;
Expand Down Expand Up @@ -3142,20 +3134,9 @@ HRESULT STDMETHODCALLTYPE CShellLink::DragEnter(IDataObject *pDataObject,
if (*pdwEffect == DROPEFFECT_NONE)
return S_OK;

LPCITEMIDLIST pidlLast;
CComPtr<IShellFolder> psf;

HRESULT hr = SHBindToParent(m_pPidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);

HRESULT hr = SHELL_GetUIObjectOfAbsoluteItem(NULL, m_pPidl, IID_PPV_ARG(IDropTarget, &m_DropTarget));
if (SUCCEEDED(hr))
{
hr = psf->GetUIObjectOf(0, 1, &pidlLast, IID_NULL_PPV_ARG(IDropTarget, &m_DropTarget));

if (SUCCEEDED(hr))
hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
else
*pdwEffect = DROPEFFECT_NONE;
}
hr = m_DropTarget->DragEnter(pDataObject, dwKeyState, pt, pdwEffect);
else
*pdwEffect = DROPEFFECT_NONE;

Expand Down
Loading

0 comments on commit 28399a2

Please sign in to comment.