@@ -210,12 +210,6 @@ static HRESULT GetItemTypeName(PCUITEMID_CHILD pidl, const BBITEMDATA &Data, SHF
210210 return E_FAIL;
211211}
212212
213- static HDELFILE GetRecycleBinFileHandleFromItem (const BBITEMDATA &Data)
214- {
215- RECYCLEBINFILEIDENTITY identity = { Data.DeletionTime , GetItemRecycledFullPath (Data) };
216- return GetRecycleBinFileHandle (NULL , &identity);
217- }
218-
219213/*
220214 * Recycle Bin folder
221215 */
@@ -285,14 +279,6 @@ EXTERN_C void CRecycleBin_NotifyRecycled(LPCWSTR OrigPath, const WIN32_FIND_DATA
285279static void CRecycleBin_NotifyRemovedFromRecycleBin (LPCITEMIDLIST BBItem)
286280{
287281 CRecycleBin_ChangeNotifyBBItem (IsFolder (BBItem) ? SHCNE_RMDIR : SHCNE_DELETE, BBItem);
288-
289- CComHeapPtr<ITEMIDLIST> pidlBB (SHCloneSpecialIDList (NULL , CSIDL_BITBUCKET, FALSE ));
290- CComPtr<IShellFolder> pSF;
291- if (pidlBB && SUCCEEDED (SHBindToObject (NULL , pidlBB, IID_PPV_ARG (IShellFolder, &pSF))))
292- {
293- if (IsRecycleBinEmpty (pSF))
294- SHUpdateRecycleBinIcon ();
295- }
296282}
297283
298284static HRESULT CRecyclerExtractIcon_CreateInstance (
@@ -316,11 +302,12 @@ class CRecycleBinItemContextMenu :
316302 public IContextMenu2
317303{
318304 private:
319- LPITEMIDLIST apidl;
305+ PITEMID_CHILD* m_apidl;
306+ UINT m_cidl;
320307 public:
321308 CRecycleBinItemContextMenu ();
322- ~CRecycleBinItemContextMenu ();
323- HRESULT WINAPI Initialize (LPCITEMIDLIST pidl );
309+ virtual ~CRecycleBinItemContextMenu ();
310+ HRESULT WINAPI Initialize (UINT cidl, PCUITEMID_CHILD_ARRAY apidl );
324311
325312 // IContextMenu
326313 STDMETHOD (QueryContextMenu)(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) override ;
@@ -411,19 +398,21 @@ BOOL CRecycleBinEnum::CBEnumRecycleBin(IN HDELFILE hDeletedFile)
411398
412399CRecycleBinItemContextMenu::CRecycleBinItemContextMenu ()
413400{
414- apidl = NULL ;
401+ m_apidl = NULL ;
402+ m_cidl = 0 ;
415403}
416404
417405CRecycleBinItemContextMenu::~CRecycleBinItemContextMenu ()
418406{
419- ILFree (apidl );
407+ _ILFreeaPidl (m_apidl, m_cidl );
420408}
421409
422- HRESULT WINAPI CRecycleBinItemContextMenu::Initialize (LPCITEMIDLIST pidl )
410+ HRESULT WINAPI CRecycleBinItemContextMenu::Initialize (UINT cidl, PCUITEMID_CHILD_ARRAY apidl )
423411{
424- apidl = ILClone (pidl );
425- if (apidl == NULL )
412+ m_apidl = _ILCopyaPidl (apidl, cidl );
413+ if (m_apidl == NULL )
426414 return E_OUTOFMEMORY;
415+ m_cidl = cidl;
427416 return S_OK;
428417}
429418
@@ -473,22 +462,93 @@ HRESULT WINAPI CRecycleBinItemContextMenu::QueryContextMenu(HMENU hMenu, UINT in
473462 return idHigh ? MAKE_HRESULT (SEVERITY_SUCCESS, 0 , idHigh - idCmdFirst + 1 ) : S_OK;
474463}
475464
476- static BOOL ConfirmDelete (LPCMINVOKECOMMANDINFO lpcmi, UINT cidl, LPCITEMIDLIST pidl, const BBITEMDATA &Data )
465+ static BOOL ConfirmDelete (LPCMINVOKECOMMANDINFO lpcmi, UINT cidl, LPCITEMIDLIST pidl)
477466{
467+ BBITEMDATA *pData;
478468 if (lpcmi->fMask & CMIC_MASK_FLAG_NO_UI)
479469 {
480470 return TRUE ;
481471 }
482- else if (cidl == 1 )
472+ else if (cidl == 1 && (pData = ValidateItem (pidl)) != NULL )
483473 {
484474 const UINT ask = IsFolder (pidl) ? ASK_DELETE_FOLDER : ASK_DELETE_FILE;
485- return SHELL_ConfirmYesNoW (lpcmi->hwnd , ask, GetItemOriginalFileName (Data ));
475+ return SHELL_ConfirmYesNoW (lpcmi->hwnd , ask, GetItemOriginalFileName (*pData ));
486476 }
487- WCHAR buf[MAX_PATH ];
477+ WCHAR buf[42 ];
488478 wsprintfW (buf, L" %d" , cidl);
489479 return SHELL_ConfirmYesNoW (lpcmi->hwnd , ASK_DELETE_MULTIPLE_ITEM, buf);
490480}
491481
482+ static LPWSTR CreateFileOpStrings (UINT cidl, PCUITEMID_CHILD_ARRAY apidl, BOOL RecycledPath)
483+ {
484+ PWSTR mem = NULL , newmem;
485+ for (SIZE_T i = 0 , cb = 0 , cb2, cbPath; i < cidl; ++i, cb = cb2)
486+ {
487+ BBITEMDATA *pData = ValidateItem (apidl[i]);
488+ if (!pData)
489+ {
490+ fail:
491+ LocalFree (mem);
492+ return NULL ;
493+ }
494+ LPCWSTR path = RecycledPath ? GetItemRecycledFullPath (*pData) : GetItemOriginalFullPath (*pData);
495+ cbPath = (lstrlenW (path) + 1 ) * sizeof (WCHAR);
496+ cb2 = cb + cbPath;
497+ SIZE_T cbTot = cb2 + sizeof (WCHAR); // \0\0 termination
498+ newmem = (PWSTR)(i ? LocalReAlloc (mem, cbTot, LMEM_MOVEABLE) : LocalAlloc (LPTR, cbTot));
499+ if (!newmem)
500+ goto fail;
501+ mem = newmem;
502+ CopyMemory ((char *)mem + cb, path, cbPath);
503+ *(PWSTR)((char *)mem + cb + cbPath) = UNICODE_NULL;
504+ }
505+ return mem;
506+ }
507+
508+ typedef struct
509+ {
510+ PCUITEMID_CHILD_ARRAY apidl;
511+ UINT cidl, index;
512+ BBITEMDATA *pItem;
513+ } FILEOPDATA;
514+
515+ static HRESULT CALLBACK FileOpCallback (FILEOPCALLBACKEVENT Event, LPCWSTR Src, LPCWSTR Dst, UINT Attrib, HRESULT hrOp, void *CallerData)
516+ {
517+ FILEOPDATA &data = *(FILEOPDATA*)CallerData;
518+ if (Event == FOCE_PREMOVEITEM || Event == FOCE_PREDELETEITEM)
519+ {
520+ data.pItem = NULL ;
521+ for (UINT i = 0 ; i < data.cidl ; ++i)
522+ {
523+ BBITEMDATA *pItem = ValidateItem (data.apidl [i]);
524+ if (pItem && !_wcsicmp (Src, GetItemRecycledFullPath (*pItem)))
525+ {
526+ data.pItem = pItem;
527+ data.index = i;
528+ break ;
529+ }
530+ }
531+ }
532+ else if ((Event == FOCE_POSTDELETEITEM || Event == FOCE_POSTMOVEITEM) && SUCCEEDED (hrOp) && data.pItem )
533+ {
534+ RECYCLEBINFILEIDENTITY identity = { data.pItem ->DeletionTime , GetItemRecycledFullPath (*data.pItem ) };
535+ RemoveFromRecycleBinDatabase (&identity);
536+ CRecycleBin_NotifyRemovedFromRecycleBin (data.apidl [data.index ]);
537+ data.pItem = NULL ;
538+ }
539+ else if (Event == FOCE_FINISHOPERATIONS)
540+ {
541+ CComHeapPtr<ITEMIDLIST> pidlBB (SHCloneSpecialIDList (NULL , CSIDL_BITBUCKET, FALSE ));
542+ CComPtr<IShellFolder> pSF;
543+ if (pidlBB && SUCCEEDED (SHBindToObject (NULL , pidlBB, IID_PPV_ARG (IShellFolder, &pSF))))
544+ {
545+ if (IsRecycleBinEmpty (pSF))
546+ SHUpdateRecycleBinIcon ();
547+ }
548+ }
549+ return S_OK;
550+ }
551+
492552HRESULT WINAPI CRecycleBinItemContextMenu::InvokeCommand (LPCMINVOKECOMMANDINFO lpcmi)
493553{
494554 TRACE (" (%p)->(invcom=%p verb=%p wnd=%p)\n " , this , lpcmi, lpcmi->lpVerb , lpcmi->hwnd );
@@ -505,35 +565,51 @@ HRESULT WINAPI CRecycleBinItemContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO l
505565
506566 if (CmdId == IDC_BB_RESTORE || CmdId == IDC_BB_DELETE)
507567 {
508- BBITEMDATA *pData = ValidateItem (apidl);
509- if (!pData && FAILED_UNEXPECTEDLY (E_FAIL))
510- return E_FAIL;
511- HDELFILE hDelFile = GetRecycleBinFileHandleFromItem (*pData);
512- if (!hDelFile && FAILED_UNEXPECTEDLY (E_FAIL))
513- return E_FAIL;
568+ HRESULT hr = S_OK;
569+ if (CmdId == IDC_BB_DELETE && !ConfirmDelete (lpcmi, m_cidl, m_apidl[0 ]))
570+ return S_OK;
514571
515- HRESULT hr = S_FALSE;
572+ LPWSTR pszzDst = NULL ;
573+ LPWSTR pszzSrc = CreateFileOpStrings (m_cidl, m_apidl, TRUE );
574+ if (!pszzSrc)
575+ return E_OUTOFMEMORY;
576+ SHFILEOPSTRUCTW shfos = { lpcmi->hwnd , FO_DELETE, pszzSrc, NULL , FOF_NOCONFIRMMKDIR };
516577 if (CmdId == IDC_BB_RESTORE)
517- hr = RestoreFileFromRecycleBin (hDelFile) ? S_OK : E_FAIL;
518- else if (ConfirmDelete (lpcmi, 1 , apidl, *pData))
519- hr = DeleteFileInRecycleBin (hDelFile) ? S_OK : E_FAIL;
520-
521- if (hr == S_OK)
522- CRecycleBin_NotifyRemovedFromRecycleBin (apidl);
523-
524- CloseRecycleBinHandle (hDelFile);
578+ {
579+ pszzDst = CreateFileOpStrings (m_cidl, m_apidl, FALSE );
580+ if (!pszzDst)
581+ hr = E_OUTOFMEMORY;
582+ shfos.wFunc = FO_MOVE;
583+ shfos.pTo = pszzDst;
584+ shfos.fFlags |= FOF_MULTIDESTFILES;
585+ }
586+ else // IDC_BB_DELETE
587+ {
588+ shfos.fFlags |= FOF_NOCONFIRMATION;
589+ }
590+ if (SUCCEEDED (hr))
591+ {
592+ if (lpcmi->fMask & CMIC_MASK_FLAG_NO_UI)
593+ shfos.fFlags |= FOF_SILENT | FOF_NOERRORUI | FOF_NOCONFIRMATION;
594+ FILEOPDATA data = { m_apidl, m_cidl };
595+ int res = SHELL32_FileOperation (&shfos, FileOpCallback, &data);
596+ if (res && res != DE_OPCANCELLED && res != ERROR_CANCELLED)
597+ hr = SHELL_ErrorBox (*lpcmi, E_FAIL);
598+ }
599+ LocalFree (pszzDst);
600+ LocalFree (pszzSrc);
525601 return hr;
526602 }
527603 else if (CmdId == IDC_BB_CUT)
528604 {
529605 FIXME (" implement cut\n " );
530- SHELL_ErrorBox (lpcmi-> hwnd , ERROR_NOT_SUPPORTED);
606+ SHELL_ErrorBox (* lpcmi, ERROR_NOT_SUPPORTED);
531607 return E_NOTIMPL;
532608 }
533609 else if (CmdId == IDC_BB_PROPERTIES)
534610 {
535611 FIXME (" implement properties\n " );
536- SHELL_ErrorBox (lpcmi-> hwnd , ERROR_NOT_SUPPORTED);
612+ SHELL_ErrorBox (* lpcmi, ERROR_NOT_SUPPORTED);
537613 return E_NOTIMPL;
538614 }
539615 return E_UNEXPECTED;
@@ -814,8 +890,7 @@ HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_C
814890
815891 if ((IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2)) && (cidl >= 1 ))
816892 {
817- // FIXME: Handle multiple items
818- hr = ShellObjectCreatorInit<CRecycleBinItemContextMenu>(apidl[0 ], riid, &pObj);
893+ hr = ShellObjectCreatorInit<CRecycleBinItemContextMenu>(cidl, apidl, riid, &pObj);
819894 }
820895 else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1 ))
821896 {
0 commit comments