2 * Trash virtual folder support. The trashing engine is implemented in trash.c
4 * Copyright (C) 2006 Mikolaj Zalewski
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define NONAMELESSUNION
37 #include "wine/debug.h"
39 #include "shell32_main.h"
40 #include "enumidlist.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
55 static const columninfo RecycleBinColumns[] =
57 {IDS_SHV_COLUMN1, &FMTID_Storage, PID_STG_NAME, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
58 {IDS_SHV_COLUMN_DELFROM, &FMTID_Displaced, PID_DISPLACED_FROM, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
59 {IDS_SHV_COLUMN_DELDATE, &FMTID_Displaced, PID_DISPLACED_DATE, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
60 {IDS_SHV_COLUMN2, &FMTID_Storage, PID_STG_SIZE, SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20},
61 {IDS_SHV_COLUMN3, &FMTID_Storage, PID_STG_STORAGETYPE,SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
62 {IDS_SHV_COLUMN4, &FMTID_Storage, PID_STG_WRITETIME, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
63 /* {"creation time", &FMTID_Storage, PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE, LVCFMT_LEFT, 20}, */
64 /* {"attribs", &FMTID_Storage, PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 20}, */
68 #define COLUMN_DELFROM 1
69 #define COLUMN_DATEDEL 2
72 #define COLUMN_MTIME 5
74 #define COLUMNS_COUNT 6
76 static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME ft)
82 FileTimeToLocalFileTime(&ft, &lft);
83 FileTimeToSystemTime(&lft, &time);
85 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size);
86 if (ret>0 && ret<size)
88 /* Append space + time without seconds */
90 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret);
93 return (ret!=0 ? E_FAIL : S_OK);
100 typedef struct tagRecycleBin
102 IShellFolder2 IShellFolder2_iface;
103 IPersistFolder2 IPersistFolder2_iface;
109 static const IShellFolder2Vtbl recycleBinVtbl;
110 static const IPersistFolder2Vtbl recycleBinPersistVtbl;
112 static inline RecycleBin *impl_from_IShellFolder2(IShellFolder2 *iface)
114 return CONTAINING_RECORD(iface, RecycleBin, IShellFolder2_iface);
117 static RecycleBin *impl_from_IPersistFolder2(IPersistFolder2 *iface)
119 return CONTAINING_RECORD(iface, RecycleBin, IPersistFolder2_iface);
122 static void RecycleBin_Destructor(RecycleBin *This);
124 HRESULT WINAPI RecycleBin_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput)
129 return CLASS_E_NOAGGREGATION;
131 obj = SHAlloc(sizeof(RecycleBin));
133 return E_OUTOFMEMORY;
134 ZeroMemory(obj, sizeof(RecycleBin));
135 obj->IShellFolder2_iface.lpVtbl = &recycleBinVtbl;
136 obj->IPersistFolder2_iface.lpVtbl = &recycleBinPersistVtbl;
137 if (FAILED(ret = IPersistFolder2_QueryInterface(&obj->IPersistFolder2_iface, riid, ppOutput)))
139 RecycleBin_Destructor(obj);
142 /* InterlockedIncrement(&objCount);*/
146 static void RecycleBin_Destructor(RecycleBin *This)
148 /* InterlockedDecrement(&objCount);*/
153 static HRESULT WINAPI RecycleBin_QueryInterface(IShellFolder2 *iface, REFIID riid, void **ppvObject)
155 RecycleBin *This = impl_from_IShellFolder2(iface);
156 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
159 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IShellFolder)
160 || IsEqualGUID(riid, &IID_IShellFolder2))
163 if (IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistFolder)
164 || IsEqualGUID(riid, &IID_IPersistFolder2))
165 *ppvObject = &This->IPersistFolder2_iface;
167 if (*ppvObject != NULL)
169 IUnknown_AddRef((IUnknown *)*ppvObject);
172 WARN("no interface %s\n", debugstr_guid(riid));
173 return E_NOINTERFACE;
176 static ULONG WINAPI RecycleBin_AddRef(IShellFolder2 *iface)
178 RecycleBin *This = impl_from_IShellFolder2(iface);
179 TRACE("(%p)\n", This);
180 return InterlockedIncrement(&This->refCount);
183 static ULONG WINAPI RecycleBin_Release(IShellFolder2 *iface)
185 RecycleBin *This = impl_from_IShellFolder2(iface);
188 TRACE("(%p)\n", This);
189 result = InterlockedDecrement(&This->refCount);
192 TRACE("Destroy object\n");
193 RecycleBin_Destructor(This);
198 static HRESULT WINAPI RecycleBin_ParseDisplayName(IShellFolder2 *This, HWND hwnd, LPBC pbc,
199 LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl,
200 ULONG *pdwAttributes)
206 static HRESULT WINAPI RecycleBin_EnumObjects(IShellFolder2 *iface, HWND hwnd, SHCONTF grfFlags, IEnumIDList **ppenumIDList)
208 RecycleBin *This = impl_from_IShellFolder2(iface);
215 TRACE("(%p, %p, %x, %p)\n", This, hwnd, grfFlags, ppenumIDList);
217 if (grfFlags & SHCONTF_NONFOLDERS)
219 *ppenumIDList = NULL;
220 if (FAILED(ret = TRASH_EnumItems(&pidls, &pidls_count)))
223 list = IEnumIDList_Constructor();
226 for (i=0; i<pidls_count; i++)
227 if (!AddToEnumList(list, pidls[i]))
229 *ppenumIDList = list;
233 *ppenumIDList = IEnumIDList_Constructor();
234 if (*ppenumIDList == NULL)
235 return E_OUTOFMEMORY;
242 IEnumIDList_Release(list);
243 for (; i<pidls_count; i++)
246 return E_OUTOFMEMORY;
249 static HRESULT WINAPI RecycleBin_BindToObject(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
251 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
255 static HRESULT WINAPI RecycleBin_BindToStorage(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
257 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
261 static HRESULT WINAPI RecycleBin_CompareIDs(IShellFolder2 *iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
263 RecycleBin *This = impl_from_IShellFolder2(iface);
266 TRACE("(%p, %p, %p, %p)\n", This, (void *)lParam, pidl1, pidl2);
267 if (pidl1->mkid.cb != pidl2->mkid.cb)
268 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
269 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb));
272 static HRESULT WINAPI RecycleBin_CreateViewObject(IShellFolder2 *iface, HWND hwndOwner, REFIID riid, void **ppv)
274 RecycleBin *This = impl_from_IShellFolder2(iface);
276 TRACE("(%p, %p, %s, %p)\n", This, hwndOwner, debugstr_guid(riid), ppv);
279 if (IsEqualGUID(riid, &IID_IShellView))
284 ZeroMemory(&sfv, sizeof(sfv));
285 sfv.cbSize = sizeof(sfv);
286 sfv.pshf = (IShellFolder *)This;
288 TRACE("Calling SHCreateShellFolderViewEx\n");
289 ret = SHCreateShellFolderViewEx(&sfv, &tmp);
290 TRACE("Result: %08x, output: %p\n", (unsigned int)ret, tmp);
295 return E_NOINTERFACE;
298 static HRESULT WINAPI RecycleBin_GetAttributesOf(IShellFolder2 *This, UINT cidl, LPCITEMIDLIST *apidl,
301 TRACE("(%p, %d, {%p, ...}, {%x})\n", This, cidl, apidl[0], *rgfInOut);
302 *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM;
306 static HRESULT WINAPI RecycleBin_GetUIObjectOf(IShellFolder2 *This, HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
307 REFIID riid, UINT *rgfReserved, void **ppv)
309 FIXME("(%p, %p, %d, {%p, ...}, %s, %p, %p): stub!\n", This, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
314 static HRESULT WINAPI RecycleBin_GetDisplayNameOf(IShellFolder2 *This, LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName)
316 WIN32_FIND_DATAW data;
318 TRACE("(%p, %p, %x, %p)\n", This, pidl, uFlags, pName);
319 TRASH_UnpackItemID(&pidl->mkid, &data);
320 pName->uType = STRRET_WSTR;
321 pName->u.pOleStr = StrDupW(PathFindFileNameW(data.cFileName));
322 if (pName->u.pOleStr == NULL)
323 return E_OUTOFMEMORY;
328 static HRESULT WINAPI RecycleBin_SetNameOf(IShellFolder2 *This, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
329 SHGDNF uFlags, LPITEMIDLIST *ppidlOut)
332 return E_FAIL; /* not supported */
335 static HRESULT WINAPI RecycleBin_GetClassID(IPersistFolder2 *This, CLSID *pClassID)
337 TRACE("(%p, %p)\n", This, pClassID);
338 if (This == NULL || pClassID == NULL)
340 *pClassID = CLSID_RecycleBin;
344 static HRESULT WINAPI RecycleBin_Initialize(IPersistFolder2 *iface, LPCITEMIDLIST pidl)
346 RecycleBin *This = impl_from_IPersistFolder2(iface);
347 TRACE("(%p, %p)\n", This, pidl);
349 This->pidl = ILClone(pidl);
350 if (This->pidl == NULL)
351 return E_OUTOFMEMORY;
355 static HRESULT WINAPI RecycleBin_GetCurFolder(IPersistFolder2 *iface, LPITEMIDLIST *ppidl)
357 RecycleBin *This = impl_from_IPersistFolder2(iface);
359 *ppidl = ILClone(This->pidl);
363 static HRESULT WINAPI RecycleBin_GetDefaultSearchGUID(IShellFolder2 *iface, GUID *pguid)
369 static HRESULT WINAPI RecycleBin_EnumSearches(IShellFolder2 *iface, IEnumExtraSearch **ppEnum)
376 static HRESULT WINAPI RecycleBin_GetDefaultColumn(IShellFolder2 *iface, DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
378 RecycleBin *This = impl_from_IShellFolder2(iface);
379 TRACE("(%p, %x, %p, %p)\n", This, dwReserved, pSort, pDisplay);
385 static HRESULT WINAPI RecycleBin_GetDefaultColumnState(IShellFolder2 *iface, UINT iColumn, SHCOLSTATEF *pcsFlags)
387 RecycleBin *This = impl_from_IShellFolder2(iface);
388 TRACE("(%p, %d, %p)\n", This, iColumn, pcsFlags);
389 if (iColumn >= COLUMNS_COUNT)
391 *pcsFlags = RecycleBinColumns[iColumn].pcsFlags;
395 static HRESULT WINAPI RecycleBin_GetDetailsEx(IShellFolder2 *iface, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
401 static HRESULT WINAPI RecycleBin_GetDetailsOf(IShellFolder2 *iface, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
403 RecycleBin *This = impl_from_IShellFolder2(iface);
404 WIN32_FIND_DATAW data;
405 WCHAR buffer[MAX_PATH];
407 TRACE("(%p, %p, %d, %p)\n", This, pidl, iColumn, pDetails);
408 if (iColumn >= COLUMNS_COUNT)
410 pDetails->fmt = RecycleBinColumns[iColumn].fmt;
411 pDetails->cxChar = RecycleBinColumns[iColumn].cxChars;
414 pDetails->str.uType = STRRET_WSTR;
415 LoadStringW(shell32_hInstance, RecycleBinColumns[iColumn].column_name_id, buffer, MAX_PATH);
416 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
419 if (iColumn == COLUMN_NAME)
420 return RecycleBin_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL, &pDetails->str);
422 TRASH_UnpackItemID(&pidl->mkid, &data);
426 FormatDateTime(buffer, MAX_PATH, data.ftLastAccessTime);
429 lstrcpyW(buffer, data.cFileName);
430 PathRemoveFileSpecW(buffer);
433 StrFormatKBSizeW(((LONGLONG)data.nFileSizeHigh<<32)|data.nFileSizeLow, buffer, MAX_PATH);
436 FormatDateTime(buffer, MAX_PATH, data.ftLastWriteTime);
446 pDetails->str.uType = STRRET_WSTR;
447 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
450 static HRESULT WINAPI RecycleBin_MapColumnToSCID(IShellFolder2 *iface, UINT iColumn, SHCOLUMNID *pscid)
452 RecycleBin *This = impl_from_IShellFolder2(iface);
453 TRACE("(%p, %d, %p)\n", This, iColumn, pscid);
454 if (iColumn>=COLUMNS_COUNT)
456 pscid->fmtid = *RecycleBinColumns[iColumn].fmtId;
457 pscid->pid = RecycleBinColumns[iColumn].pid;
461 static const IShellFolder2Vtbl recycleBinVtbl =
464 RecycleBin_QueryInterface,
469 RecycleBin_ParseDisplayName,
470 RecycleBin_EnumObjects,
471 RecycleBin_BindToObject,
472 RecycleBin_BindToStorage,
473 RecycleBin_CompareIDs,
474 RecycleBin_CreateViewObject,
475 RecycleBin_GetAttributesOf,
476 RecycleBin_GetUIObjectOf,
477 RecycleBin_GetDisplayNameOf,
478 RecycleBin_SetNameOf,
481 RecycleBin_GetDefaultSearchGUID,
482 RecycleBin_EnumSearches,
483 RecycleBin_GetDefaultColumn,
484 RecycleBin_GetDefaultColumnState,
485 RecycleBin_GetDetailsEx,
486 RecycleBin_GetDetailsOf,
487 RecycleBin_MapColumnToSCID
490 static HRESULT WINAPI RecycleBin_IPersistFolder2_QueryInterface(IPersistFolder2 *iface, REFIID riid,
493 RecycleBin *This = impl_from_IPersistFolder2(iface);
495 return RecycleBin_QueryInterface(&This->IShellFolder2_iface, riid, ppvObject);
498 static ULONG WINAPI RecycleBin_IPersistFolder2_AddRef(IPersistFolder2 *iface)
500 RecycleBin *This = impl_from_IPersistFolder2(iface);
502 return RecycleBin_AddRef(&This->IShellFolder2_iface);
505 static ULONG WINAPI RecycleBin_IPersistFolder2_Release(IPersistFolder2 *iface)
507 RecycleBin *This = impl_from_IPersistFolder2(iface);
509 return RecycleBin_Release(&This->IShellFolder2_iface);
512 static const IPersistFolder2Vtbl recycleBinPersistVtbl =
515 RecycleBin_IPersistFolder2_QueryInterface,
516 RecycleBin_IPersistFolder2_AddRef,
517 RecycleBin_IPersistFolder2_Release,
520 RecycleBin_GetClassID,
522 RecycleBin_Initialize,
523 /* IPersistFolder2 */
524 RecycleBin_GetCurFolder
527 /*************************************************************************
528 * SHUpdateRecycleBinIcon [SHELL32.@]
532 HRESULT WINAPI SHUpdateRecycleBinIcon(void)