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)