From eca272bd003e3c1ccf87f6cefa9c8852b8d02d7b Mon Sep 17 00:00:00 2001 From: Johannes Anderwald Date: Thu, 11 Oct 2007 23:45:36 +0000 Subject: [PATCH] - start implementing recyclebin (based on Wine's recycle bin implemenation) svn path=/trunk/; revision=29526 --- reactos/dll/win32/shell32/recyclebin.c | 570 +++++++++++++++++++++++ reactos/dll/win32/shell32/regsvr.c | 2 +- reactos/dll/win32/shell32/shell32.rbuild | 3 + reactos/dll/win32/shell32/shellole.c | 2 +- reactos/dll/win32/shell32/shlfileop.c | 4 +- 5 files changed, 578 insertions(+), 3 deletions(-) create mode 100644 reactos/dll/win32/shell32/recyclebin.c diff --git a/reactos/dll/win32/shell32/recyclebin.c b/reactos/dll/win32/shell32/recyclebin.c new file mode 100644 index 00000000000..ec6f724fbfa --- /dev/null +++ b/reactos/dll/win32/shell32/recyclebin.c @@ -0,0 +1,570 @@ +/* + * Trash virtual folder support. The trashing engine is implemented in trash.c + * + * Copyright (C) 2006 Mikolaj Zalewski + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" +#define YDEBUG +#define COBJMACROS +#define NONAMELESSUNION + +#include + +#include "winerror.h" +#include "windef.h" +#include "winbase.h" +#include "winreg.h" +#include "winuser.h" +#include "ntquery.h" +#include "shlwapi.h" +#include "shlobj.h" +#include "shresdef.h" +#include "wine/debug.h" + +#include "shell32_main.h" +#include "enumidlist.h" +#include "xdg.h" +#include "recyclebin.h" + +WINE_DEFAULT_DEBUG_CHANNEL(recyclebin); + +typedef struct +{ + int column_name_id; + const GUID *fmtId; + DWORD pid; + int pcsFlags; + int fmt; + int cxChars; +} columninfo; + +static const columninfo RecycleBinColumns[] = +{ + {IDS_SHV_COLUMN1, &FMTID_Storage, PID_STG_NAME, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30}, + {IDS_SHV_COLUMN_DELFROM, &FMTID_Displaced, PID_DISPLACED_FROM, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30}, + {IDS_SHV_COLUMN_DELDATE, &FMTID_Displaced, PID_DISPLACED_DATE, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20}, + {IDS_SHV_COLUMN2, &FMTID_Storage, PID_STG_SIZE, SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20}, + {IDS_SHV_COLUMN3, &FMTID_Storage, PID_STG_STORAGETYPE,SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20}, + {IDS_SHV_COLUMN4, &FMTID_Storage, PID_STG_WRITETIME, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20}, +/* {"creation time", &FMTID_Storage, PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE, LVCFMT_LEFT, 20}, */ +/* {"attribs", &FMTID_Storage, PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 20}, */ +}; + +#define COLUMN_NAME 0 +#define COLUMN_DELFROM 1 +#define COLUMN_DATEDEL 2 +#define COLUMN_SIZE 3 +#define COLUMN_TYPE 4 +#define COLUMN_MTIME 5 + +#define COLUMNS_COUNT 6 + +static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME ft) +{ + FILETIME lft; + SYSTEMTIME time; + int ret; + + FileTimeToLocalFileTime(&ft, &lft); + FileTimeToSystemTime(&lft, &time); + + ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size); + if (ret>0 && retlpVtbl = &recycleBinVtbl; + obj->lpPersistFolderVtbl = &recycleBinPersistVtbl; + if (FAILED(ret = IUnknown_QueryInterface((IUnknown *)obj, riid, ppOutput))) + { + RecycleBin_Destructor(obj); + return ret; + } +/* InterlockedIncrement(&objCount);*/ + return S_OK; +} + +static void RecycleBin_Destructor(RecycleBin *This) +{ +/* InterlockedDecrement(&objCount);*/ + SHFree(This->pidl); + SHFree(This); +} + +static HRESULT WINAPI RecycleBin_QueryInterface(IShellFolder2 *iface, REFIID riid, void **ppvObject) +{ + RecycleBin *This = (RecycleBin *)iface; + TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject); + + *ppvObject = NULL; + if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IShellFolder) + || IsEqualGUID(riid, &IID_IShellFolder2)) + *ppvObject = This; + + if (IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistFolder) + || IsEqualGUID(riid, &IID_IPersistFolder2)) + *ppvObject = &This->lpPersistFolderVtbl; + + if (*ppvObject != NULL) + { + IUnknown_AddRef((IUnknown *)*ppvObject); + return S_OK; + } + WARN("no interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI RecycleBin_AddRef(IShellFolder2 *iface) +{ + RecycleBin *This = (RecycleBin *)iface; + TRACE("(%p)\n", This); + return InterlockedIncrement(&This->refCount); +} + +static ULONG WINAPI RecycleBin_Release(IShellFolder2 *iface) +{ + RecycleBin *This = (RecycleBin *)iface; + LONG result; + + TRACE("(%p)\n", This); + result = InterlockedDecrement(&This->refCount); + if (result == 0) + { + TRACE("Destroy object\n"); + RecycleBin_Destructor(This); + } + return result; +} + +static HRESULT WINAPI RecycleBin_ParseDisplayName(IShellFolder2 *This, HWND hwnd, LPBC pbc, + LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, + ULONG *pdwAttributes) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +BOOL +WINAPI +CBEnumBitBucket(IN PVOID Context, IN HANDLE hDeletedFile) +{ + PDELETED_FILE_DETAILS_W pFileDetails; + DWORD dwSize = 0; + LPITEMIDLIST pidl = NULL; + BOOL ret; + + TRACE("CBEnumBitBucket entered\n"); + GetDeletedFileDetailsW(hDeletedFile, + 0, + NULL, + &dwSize); + + if (!dwSize) + { + ERR("GetDeletedFileDetailsW failed\n"); + return FALSE; + } + + pidl = SHAlloc(dwSize); + if (!pidl) + { + ERR("No memory\n"); + return FALSE; + } + + pidl->mkid.cb = dwSize; + pidl->mkid.abID[0] = 0; + pFileDetails = (PDELETED_FILE_DETAILS_W) &pidl->mkid.abID[1]; + + if (!GetDeletedFileDetailsW(hDeletedFile, + dwSize, + pFileDetails, + NULL)) + { + ERR("GetDeletedFileDetailsW failed\n"); + SHFree(pidl); + return FALSE; + } + + ret = AddToEnumList((IEnumIDList*)Context, pidl); + return ret; +} + +PDELETED_FILE_DETAILS_W +UnpackDetailsFromPidl(LPITEMIDLIST pidl) +{ + return (PDELETED_FILE_DETAILS_W)&pidl->mkid.abID[1]; +} + +static HRESULT WINAPI RecycleBin_EnumObjects(IShellFolder2 *iface, HWND hwnd, SHCONTF grfFlags, IEnumIDList **ppenumIDList) +{ + RecycleBin *This = (RecycleBin *)iface; + IEnumIDList *list; + static const WCHAR szDrive = L'C'; + + TRACE("(%p, %p, %x, %p)\n", This, hwnd, (unsigned int)grfFlags, ppenumIDList); + + if (grfFlags & SHCONTF_NONFOLDERS) + { + TRACE("Starting Enumeration\n"); + *ppenumIDList = NULL; + list = IEnumIDList_Constructor(); + if (list == NULL) + return E_OUTOFMEMORY; + + if (!EnumerateRecycleBinW(szDrive, //FIXME + CBEnumBitBucket, + (PVOID)list)) + { + WARN("Error: EnumerateRecycleBinW failed\n"); + } + *ppenumIDList = list; + } + else + { + *ppenumIDList = IEnumIDList_Constructor(); + if (*ppenumIDList == NULL) + return E_OUTOFMEMORY; + } + + return S_OK; + +} + +static HRESULT WINAPI RecycleBin_BindToObject(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv) +{ + FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecycleBin_BindToStorage(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv) +{ + FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecycleBin_CompareIDs(IShellFolder2 *iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2) +{ + RecycleBin *This = (RecycleBin *)iface; + + /* TODO */ + TRACE("(%p, %p, %p, %p)\n", This, (void *)lParam, pidl1, pidl2); + if (pidl1->mkid.cb != pidl2->mkid.cb) + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb); + return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb)); +} + +static HRESULT WINAPI RecycleBin_CreateViewObject(IShellFolder2 *iface, HWND hwndOwner, REFIID riid, void **ppv) +{ + RecycleBin *This = (RecycleBin *)iface; + HRESULT ret; + TRACE("(%p, %p, %s, %p)\n", This, hwndOwner, debugstr_guid(riid), ppv); + + *ppv = NULL; + if (IsEqualGUID(riid, &IID_IShellView)) + { + IShellView *tmp; + CSFV sfv; + + ZeroMemory(&sfv, sizeof(sfv)); + sfv.cbSize = sizeof(sfv); + sfv.pshf = (IShellFolder *)This; + + TRACE("Calling SHCreateShellFolderViewEx\n"); + ret = SHCreateShellFolderViewEx(&sfv, &tmp); + TRACE("Result: %08x, output: %p\n", (unsigned int)ret, tmp); + *ppv = tmp; + return ret; + } + + return E_NOINTERFACE; +} + +static HRESULT WINAPI RecycleBin_GetAttributesOf(IShellFolder2 *This, UINT cidl, LPCITEMIDLIST *apidl, + SFGAOF *rgfInOut) +{ + TRACE("(%p, %d, {%p, ...}, {%x})\n", This, cidl, apidl[0], (unsigned int)*rgfInOut); + *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM; + return S_OK; +} + +static HRESULT WINAPI RecycleBin_GetUIObjectOf(IShellFolder2 *This, HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl, + REFIID riid, UINT *rgfReserved, void **ppv) +{ + FIXME("(%p, %p, %d, {%p, ...}, %s, %p, %p): stub!\n", This, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv); + *ppv = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI RecycleBin_GetDisplayNameOf(IShellFolder2 *This, LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName) +{ + PDELETED_FILE_DETAILS_W pFileDetails; + TRACE("(%p, %p, %x, %p)\n", This, pidl, (unsigned int)uFlags, pName); + + pFileDetails = UnpackDetailsFromPidl(pidl); + pName->uType = STRRET_WSTR; + pName->u.pOleStr = StrDupW(&pFileDetails->FileName[0]); + if (pName->u.pOleStr == NULL) + return E_OUTOFMEMORY; + + return S_OK; +} + +static HRESULT WINAPI RecycleBin_SetNameOf(IShellFolder2 *This, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, + SHGDNF uFlags, LPITEMIDLIST *ppidlOut) +{ + TRACE("\n"); + return E_FAIL; /* not supported */ +} + +static HRESULT WINAPI RecycleBin_GetClassID(IPersistFolder2 *This, CLSID *pClassID) +{ + TRACE("(%p, %p)\n", This, pClassID); + if (This == NULL || pClassID == NULL) + return E_INVALIDARG; + memcpy(pClassID, &CLSID_RecycleBin, sizeof(CLSID)); + return S_OK; +} + +static HRESULT WINAPI RecycleBin_Initialize(IPersistFolder2 *iface, LPCITEMIDLIST pidl) +{ + RecycleBin *This = impl_from_IPersistFolder(iface); + TRACE("(%p, %p)\n", This, pidl); + + This->pidl = ILClone(pidl); + if (This->pidl == NULL) + return E_OUTOFMEMORY; + return S_OK; +} + +static HRESULT WINAPI RecycleBin_GetCurFolder(IPersistFolder2 *iface, LPITEMIDLIST *ppidl) +{ + RecycleBin *This = impl_from_IPersistFolder(iface); + TRACE("\n"); + *ppidl = ILClone(This->pidl); + return S_OK; +} + +static HRESULT WINAPI RecycleBin_GetDefaultSearchGUID(IShellFolder2 *iface, GUID *pguid) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecycleBin_EnumSearches(IShellFolder2 *iface, IEnumExtraSearch **ppEnum) +{ + FIXME("stub\n"); + *ppEnum = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI RecycleBin_GetDefaultColumn(IShellFolder2 *iface, DWORD dwReserved, ULONG *pSort, ULONG *pDisplay) +{ + RecycleBin *This = (RecycleBin *)iface; + TRACE("(%p, %x, %p, %p)\n", This, (unsigned int)dwReserved, pSort, pDisplay); + *pSort = 0; + *pDisplay = 0; + return S_OK; +} + +static HRESULT WINAPI RecycleBin_GetDefaultColumnState(IShellFolder2 *iface, UINT iColumn, SHCOLSTATEF *pcsFlags) +{ + RecycleBin *This = (RecycleBin *)iface; + TRACE("(%p, %d, %p)\n", This, iColumn, pcsFlags); + if (iColumn < 0 || iColumn >= COLUMNS_COUNT) + return E_INVALIDARG; + *pcsFlags = RecycleBinColumns[iColumn].pcsFlags; + return S_OK; +} + +static HRESULT WINAPI RecycleBin_GetDetailsEx(IShellFolder2 *iface, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) +{ + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI RecycleBin_GetDetailsOf(IShellFolder2 *iface, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails) +{ + RecycleBin *This = (RecycleBin *)iface; + PDELETED_FILE_DETAILS_W pFileDetails; + WCHAR buffer[MAX_PATH]; + + TRACE("(%p, %p, %d, %p)\n", This, pidl, iColumn, pDetails); + if (iColumn < 0 || iColumn >= COLUMNS_COUNT) + return E_FAIL; + pDetails->fmt = RecycleBinColumns[iColumn].fmt; + pDetails->cxChar = RecycleBinColumns[iColumn].cxChars; + if (pidl == NULL) + { + pDetails->str.uType = STRRET_WSTR; + LoadStringW(shell32_hInstance, RecycleBinColumns[iColumn].column_name_id, buffer, MAX_PATH); + return SHStrDupW(buffer, &pDetails->str.u.pOleStr); + } + + if (iColumn == COLUMN_NAME) + return RecycleBin_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL, &pDetails->str); + + pFileDetails = UnpackDetailsFromPidl(pidl); + switch (iColumn) + { + case COLUMN_DATEDEL: + FormatDateTime(buffer, MAX_PATH, pFileDetails->DeletionTime); + break; + case COLUMN_DELFROM: + lstrcpyW(buffer, &pFileDetails->FileName[0]); + PathRemoveFileSpecW(buffer); + break; + case COLUMN_SIZE: + StrFormatKBSizeW(pFileDetails->FileSize.QuadPart, buffer, MAX_PATH); + break; + case COLUMN_MTIME: + FormatDateTime(buffer, MAX_PATH, pFileDetails->LastModification); + break; + case COLUMN_TYPE: + /* TODO */ + buffer[0] = 0; + break; + default: + return E_FAIL; + } + + pDetails->str.uType = STRRET_WSTR; + pDetails->str.u.pOleStr = StrDupW(buffer); + return (pDetails->str.u.pOleStr != NULL ? S_OK : E_OUTOFMEMORY); +} + +static HRESULT WINAPI RecycleBin_MapColumnToSCID(IShellFolder2 *iface, UINT iColumn, SHCOLUMNID *pscid) +{ + RecycleBin *This = (RecycleBin *)iface; + TRACE("(%p, %d, %p)\n", This, iColumn, pscid); + if (iColumn<0 || iColumn>=COLUMNS_COUNT) + return E_INVALIDARG; + pscid->fmtid = *RecycleBinColumns[iColumn].fmtId; + pscid->pid = RecycleBinColumns[iColumn].pid; + return S_OK; +} + +static const IShellFolder2Vtbl recycleBinVtbl = +{ + /* IUnknown */ + RecycleBin_QueryInterface, + RecycleBin_AddRef, + RecycleBin_Release, + + /* IShellFolder */ + RecycleBin_ParseDisplayName, + RecycleBin_EnumObjects, + RecycleBin_BindToObject, + RecycleBin_BindToStorage, + RecycleBin_CompareIDs, + RecycleBin_CreateViewObject, + RecycleBin_GetAttributesOf, + RecycleBin_GetUIObjectOf, + RecycleBin_GetDisplayNameOf, + RecycleBin_SetNameOf, + + /* IShellFolder2 */ + RecycleBin_GetDefaultSearchGUID, + RecycleBin_EnumSearches, + RecycleBin_GetDefaultColumn, + RecycleBin_GetDefaultColumnState, + RecycleBin_GetDetailsEx, + RecycleBin_GetDetailsOf, + RecycleBin_MapColumnToSCID +}; + +static HRESULT WINAPI RecycleBin_IPersistFolder2_QueryInterface(IPersistFolder2 *This, REFIID riid, void **ppvObject) +{ + return RecycleBin_QueryInterface((IShellFolder2 *)impl_from_IPersistFolder(This), riid, ppvObject); +} + +static ULONG WINAPI RecycleBin_IPersistFolder2_AddRef(IPersistFolder2 *This) +{ + return RecycleBin_AddRef((IShellFolder2 *)impl_from_IPersistFolder(This)); +} + +static ULONG WINAPI RecycleBin_IPersistFolder2_Release(IPersistFolder2 *This) +{ + return RecycleBin_Release((IShellFolder2 *)impl_from_IPersistFolder(This)); +} + +static const IPersistFolder2Vtbl recycleBinPersistVtbl = +{ + /* IUnknown */ + RecycleBin_IPersistFolder2_QueryInterface, + RecycleBin_IPersistFolder2_AddRef, + RecycleBin_IPersistFolder2_Release, + + /* IPersist */ + RecycleBin_GetClassID, + /* IPersistFolder */ + RecycleBin_Initialize, + /* IPersistFolder2 */ + RecycleBin_GetCurFolder +}; + +/************************************************************************* + * SHUpdateRecycleBinIcon [SHELL32.@] + * + * Undocumented + */ +HRESULT WINAPI SHUpdateRecycleBinIcon(void) +{ + FIXME("stub\n"); + return S_OK; +} diff --git a/reactos/dll/win32/shell32/regsvr.c b/reactos/dll/win32/shell32/regsvr.c index d8761b4af22..6489b61fa3d 100644 --- a/reactos/dll/win32/shell32/regsvr.c +++ b/reactos/dll/win32/shell32/regsvr.c @@ -680,12 +680,12 @@ static struct regsvr_namespace const namespace_extensions_list[] = { wszDesktop, wszMyDocuments }, +#endif { &CLSID_RecycleBin, wszDesktop, wszRecycleBin }, -#endif { NULL } }; diff --git a/reactos/dll/win32/shell32/shell32.rbuild b/reactos/dll/win32/shell32/shell32.rbuild index ee8811dda5b..4d14ef99e2e 100644 --- a/reactos/dll/win32/shell32/shell32.rbuild +++ b/reactos/dll/win32/shell32/shell32.rbuild @@ -2,6 +2,7 @@ . + . include/reactos/wine 0x600 @@ -11,6 +12,7 @@ wine uuid + recyclebin ntdll kernel32 advapi32 @@ -64,4 +66,5 @@ shell32.spec fprop.c drive.c + recyclebin.c diff --git a/reactos/dll/win32/shell32/shellole.c b/reactos/dll/win32/shell32/shellole.c index d8493bd476e..2f01ab5e69f 100644 --- a/reactos/dll/win32/shell32/shellole.c +++ b/reactos/dll/win32/shell32/shellole.c @@ -74,8 +74,8 @@ static const struct { {&CLSID_UnixDosFolder, &UnixDosFolder_Constructor}, {&CLSID_FolderShortcut, &FolderShortcut_Constructor}, {&CLSID_MyDocuments, &MyDocuments_Constructor}, - {&CLSID_RecycleBin, &RecycleBin_Constructor}, #endif + {&CLSID_RecycleBin, &RecycleBin_Constructor}, {NULL,NULL} }; diff --git a/reactos/dll/win32/shell32/shlfileop.c b/reactos/dll/win32/shell32/shlfileop.c index ec2793fadbc..94c5546ab54 100644 --- a/reactos/dll/win32/shell32/shlfileop.c +++ b/reactos/dll/win32/shell32/shlfileop.c @@ -1304,7 +1304,9 @@ static HRESULT delete_files(LPSHFILEOPSTRUCTW lpFileOp, FILE_LIST *flFrom) /* Windows also checks only the first item */ bTrash = (lpFileOp->fFlags & FOF_ALLOWUNDO); - //&& TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath); +#if 0 + && TRASH_CanTrashFile(flFrom->feFiles[0].szFullPath); +#endif if (!(lpFileOp->fFlags & FOF_NOCONFIRMATION) || (!bTrash && lpFileOp->fFlags & FOF_WANTNUKEWARNING)) if (!confirm_delete_list(lpFileOp->hwnd, lpFileOp->fFlags, bTrash, flFrom))