1 /*
2 * Trash virtual folder support. The trashing engine is implemented in trash.c
3 *
4 * Copyright (C) 2006 Mikolaj Zalewski
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config.h"
22
23 #define COBJMACROS
24 #define NONAMELESSUNION
25
26 #include <stdarg.h>
27
28 #include "winerror.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winreg.h"
32 #include "winuser.h"
33 #include "ntquery.h"
34 #include "shlwapi.h"
35 #include "shlobj.h"
36 #include "shresdef.h"
37 #include "wine/debug.h"
38
39 #include "shell32_main.h"
40 #include "enumidlist.h"
41 #include "xdg.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
44
45 typedef struct
46 {
47 int column_name_id;
48 const GUID *fmtId;
49 DWORD pid;
50 int pcsFlags;
51 int fmt;
52 int cxChars;
53 } columninfo;
54
55 static const columninfo RecycleBinColumns[] =
56 {
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}, */
65 };
66
67 #define COLUMN_NAME 0
68 #define COLUMN_DELFROM 1
69 #define COLUMN_DATEDEL 2
70 #define COLUMN_SIZE 3
71 #define COLUMN_TYPE 4
72 #define COLUMN_MTIME 5
73
74 #define COLUMNS_COUNT 6
75
76 static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME ft)
77 {
78 FILETIME lft;
79 SYSTEMTIME time;
80 int ret;
81
82 FileTimeToLocalFileTime(&ft, &lft);
83 FileTimeToSystemTime(&lft, &time);
84
85 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size);
86 if (ret>0 && ret<size)
87 {
88 /* Append space + time without seconds */
89 buffer[ret-1] = ' ';
90 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret);
91 }
92
93 return (ret!=0 ? E_FAIL : S_OK);
94 }
95
96 /*
97 * Recycle Bin folder
98 */
99
100 typedef struct tagRecycleBin
101 {
102 const IShellFolder2Vtbl *lpVtbl;
103 const IPersistFolder2Vtbl *lpPersistFolderVtbl;
104 LONG refCount;
105
106 LPITEMIDLIST pidl;
107 } RecycleBin;
108
109 static const IShellFolder2Vtbl recycleBinVtbl;
110 static const IPersistFolder2Vtbl recycleBinPersistVtbl;
111
112 static RecycleBin *impl_from_IPersistFolder(IPersistFolder2 *iface)
113 {
114 return (RecycleBin *)((char *)iface - FIELD_OFFSET(RecycleBin, lpPersistFolderVtbl));
115 }
116
117 static void RecycleBin_Destructor(RecycleBin *This);
118
119 HRESULT WINAPI RecycleBin_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput)
120 {
121 RecycleBin *obj;
122 HRESULT ret;
123 if (pUnkOuter)
124 return CLASS_E_NOAGGREGATION;
125
126 obj = SHAlloc(sizeof(RecycleBin));
127 if (obj == NULL)
128 return E_OUTOFMEMORY;
129 ZeroMemory(obj, sizeof(RecycleBin));
130 obj->lpVtbl = &recycleBinVtbl;
131 obj->lpPersistFolderVtbl = &recycleBinPersistVtbl;
132 if (FAILED(ret = IUnknown_QueryInterface((IUnknown *)obj, riid, ppOutput)))
133 {
134 RecycleBin_Destructor(obj);
135 return ret;
136 }
137 /* InterlockedIncrement(&objCount);*/
138 return S_OK;
139 }
140
141 static void RecycleBin_Destructor(RecycleBin *This)
142 {
143 /* InterlockedDecrement(&objCount);*/
144 SHFree(This->pidl);
145 SHFree(This);
146 }
147
148 static HRESULT WINAPI RecycleBin_QueryInterface(IShellFolder2 *iface, REFIID riid, void **ppvObject)
149 {
150 RecycleBin *This = (RecycleBin *)iface;
151 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
152
153 *ppvObject = NULL;
154 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IShellFolder)
155 || IsEqualGUID(riid, &IID_IShellFolder2))
156 *ppvObject = This;
157
158 if (IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistFolder)
159 || IsEqualGUID(riid, &IID_IPersistFolder2))
160 *ppvObject = &This->lpPersistFolderVtbl;
161
162 if (*ppvObject != NULL)
163 {
164 IUnknown_AddRef((IUnknown *)*ppvObject);
165 return S_OK;
166 }
167 WARN("no interface %s\n", debugstr_guid(riid));
168 return E_NOINTERFACE;
169 }
170
171 static ULONG WINAPI RecycleBin_AddRef(IShellFolder2 *iface)
172 {
173 RecycleBin *This = (RecycleBin *)iface;
174 TRACE("(%p)\n", This);
175 return InterlockedIncrement(&This->refCount);
176 }
177
178 static ULONG WINAPI RecycleBin_Release(IShellFolder2 *iface)
179 {
180 RecycleBin *This = (RecycleBin *)iface;
181 LONG result;
182
183 TRACE("(%p)\n", This);
184 result = InterlockedDecrement(&This->refCount);
185 if (result == 0)
186 {
187 TRACE("Destroy object\n");
188 RecycleBin_Destructor(This);
189 }
190 return result;
191 }
192
193 static HRESULT WINAPI RecycleBin_ParseDisplayName(IShellFolder2 *This, HWND hwnd, LPBC pbc,
194 LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl,
195 ULONG *pdwAttributes)
196 {
197 FIXME("stub\n");
198 return E_NOTIMPL;
199 }
200
201 static HRESULT WINAPI RecycleBin_EnumObjects(IShellFolder2 *iface, HWND hwnd, SHCONTF grfFlags, IEnumIDList **ppenumIDList)
202 {
203 RecycleBin *This = (RecycleBin *)iface;
204 IEnumIDList *list;
205 LPITEMIDLIST *pidls;
206 HRESULT ret;
207 int pidls_count;
208 int i=0;
209
210 TRACE("(%p, %p, %x, %p)\n", This, hwnd, grfFlags, ppenumIDList);
211
212 if (grfFlags & SHCONTF_NONFOLDERS)
213 {
214 *ppenumIDList = NULL;
215 if (FAILED(ret = TRASH_EnumItems(&pidls, &pidls_count)))
216 return ret;
217
218 list = IEnumIDList_Constructor();
219 if (list == NULL)
220 goto failed;
221 for (i=0; i<pidls_count; i++)
222 if (!AddToEnumList(list, pidls[i]))
223 goto failed;
224 *ppenumIDList = list;
225 }
226 else
227 {
228 *ppenumIDList = IEnumIDList_Constructor();
229 if (*ppenumIDList == NULL)
230 return E_OUTOFMEMORY;
231 }
232
233 return S_OK;
234
235 failed:
236 if (list)
237 IEnumIDList_Release(list);
238 for (; i<pidls_count; i++)
239 ILFree(pidls[i]);
240 SHFree(pidls);
241 return E_OUTOFMEMORY;
242 }
243
244 static HRESULT WINAPI RecycleBin_BindToObject(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
245 {
246 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
247 return E_NOTIMPL;
248 }
249
250 static HRESULT WINAPI RecycleBin_BindToStorage(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
251 {
252 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
253 return E_NOTIMPL;
254 }
255
256 static HRESULT WINAPI RecycleBin_CompareIDs(IShellFolder2 *iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
257 {
258 RecycleBin *This = (RecycleBin *)iface;
259
260 /* TODO */
261 TRACE("(%p, %p, %p, %p)\n", This, (void *)lParam, pidl1, pidl2);
262 if (pidl1->mkid.cb != pidl2->mkid.cb)
263 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
264 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb));
265 }
266
267 static HRESULT WINAPI RecycleBin_CreateViewObject(IShellFolder2 *iface, HWND hwndOwner, REFIID riid, void **ppv)
268 {
269 RecycleBin *This = (RecycleBin *)iface;
270 HRESULT ret;
271 TRACE("(%p, %p, %s, %p)\n", This, hwndOwner, debugstr_guid(riid), ppv);
272
273 *ppv = NULL;
274 if (IsEqualGUID(riid, &IID_IShellView))
275 {
276 IShellView *tmp;
277 CSFV sfv;
278
279 ZeroMemory(&sfv, sizeof(sfv));
280 sfv.cbSize = sizeof(sfv);
281 sfv.pshf = (IShellFolder *)This;
282
283 TRACE("Calling SHCreateShellFolderViewEx\n");
284 ret = SHCreateShellFolderViewEx(&sfv, &tmp);
285 TRACE("Result: %08x, output: %p\n", (unsigned int)ret, tmp);
286 *ppv = tmp;
287 return ret;
288 }
289
290 return E_NOINTERFACE;
291 }
292
293 static HRESULT WINAPI RecycleBin_GetAttributesOf(IShellFolder2 *This, UINT cidl, LPCITEMIDLIST *apidl,
294 SFGAOF *rgfInOut)
295 {
296 TRACE("(%p, %d, {%p, ...}, {%x})\n", This, cidl, apidl[0], *rgfInOut);
297 *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM;
298 return S_OK;
299 }
300
301 static HRESULT WINAPI RecycleBin_GetUIObjectOf(IShellFolder2 *This, HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
302 REFIID riid, UINT *rgfReserved, void **ppv)
303 {
304 FIXME("(%p, %p, %d, {%p, ...}, %s, %p, %p): stub!\n", This, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
305 *ppv = NULL;
306 return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI RecycleBin_GetDisplayNameOf(IShellFolder2 *This, LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName)
310 {
311 WIN32_FIND_DATAW data;
312
313 TRACE("(%p, %p, %x, %p)\n", This, pidl, uFlags, pName);
314 TRASH_UnpackItemID(&pidl->mkid, &data);
315 pName->uType = STRRET_WSTR;
316 pName->u.pOleStr = StrDupW(PathFindFileNameW(data.cFileName));
317 if (pName->u.pOleStr == NULL)
318 return E_OUTOFMEMORY;
319
320 return S_OK;
321 }
322
323 static HRESULT WINAPI RecycleBin_SetNameOf(IShellFolder2 *This, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
324 SHGDNF uFlags, LPITEMIDLIST *ppidlOut)
325 {
326 TRACE("\n");
327 return E_FAIL; /* not supported */
328 }
329
330 static HRESULT WINAPI RecycleBin_GetClassID(IPersistFolder2 *This, CLSID *pClassID)
331 {
332 TRACE("(%p, %p)\n", This, pClassID);
333 if (This == NULL || pClassID == NULL)
334 return E_INVALIDARG;
335 *pClassID = CLSID_RecycleBin;
336 return S_OK;
337 }
338
339 static HRESULT WINAPI RecycleBin_Initialize(IPersistFolder2 *iface, LPCITEMIDLIST pidl)
340 {
341 RecycleBin *This = impl_from_IPersistFolder(iface);
342 TRACE("(%p, %p)\n", This, pidl);
343
344 This->pidl = ILClone(pidl);
345 if (This->pidl == NULL)
346 return E_OUTOFMEMORY;
347 return S_OK;
348 }
349
350 static HRESULT WINAPI RecycleBin_GetCurFolder(IPersistFolder2 *iface, LPITEMIDLIST *ppidl)
351 {
352 RecycleBin *This = impl_from_IPersistFolder(iface);
353 TRACE("\n");
354 *ppidl = ILClone(This->pidl);
355 return S_OK;
356 }
357
358 static HRESULT WINAPI RecycleBin_GetDefaultSearchGUID(IShellFolder2 *iface, GUID *pguid)
359 {
360 FIXME("stub\n");
361 return E_NOTIMPL;
362 }
363
364 static HRESULT WINAPI RecycleBin_EnumSearches(IShellFolder2 *iface, IEnumExtraSearch **ppEnum)
365 {
366 FIXME("stub\n");
367 *ppEnum = NULL;
368 return E_NOTIMPL;
369 }
370
371 static HRESULT WINAPI RecycleBin_GetDefaultColumn(IShellFolder2 *iface, DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
372 {
373 RecycleBin *This = (RecycleBin *)iface;
374 TRACE("(%p, %x, %p, %p)\n", This, dwReserved, pSort, pDisplay);
375 *pSort = 0;
376 *pDisplay = 0;
377 return S_OK;
378 }
379
380 static HRESULT WINAPI RecycleBin_GetDefaultColumnState(IShellFolder2 *iface, UINT iColumn, SHCOLSTATEF *pcsFlags)
381 {
382 RecycleBin *This = (RecycleBin *)iface;
383 TRACE("(%p, %d, %p)\n", This, iColumn, pcsFlags);
384 if (iColumn >= COLUMNS_COUNT)
385 return E_INVALIDARG;
386 *pcsFlags = RecycleBinColumns[iColumn].pcsFlags;
387 return S_OK;
388 }
389
390 static HRESULT WINAPI RecycleBin_GetDetailsEx(IShellFolder2 *iface, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
391 {
392 FIXME("stub\n");
393 return E_NOTIMPL;
394 }
395
396 static HRESULT WINAPI RecycleBin_GetDetailsOf(IShellFolder2 *iface, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
397 {
398 RecycleBin *This = (RecycleBin *)iface;
399 WIN32_FIND_DATAW data;
400 WCHAR buffer[MAX_PATH];
401
402 TRACE("(%p, %p, %d, %p)\n", This, pidl, iColumn, pDetails);
403 if (iColumn >= COLUMNS_COUNT)
404 return E_FAIL;
405 pDetails->fmt = RecycleBinColumns[iColumn].fmt;
406 pDetails->cxChar = RecycleBinColumns[iColumn].cxChars;
407 if (pidl == NULL)
408 {
409 pDetails->str.uType = STRRET_WSTR;
410 LoadStringW(shell32_hInstance, RecycleBinColumns[iColumn].column_name_id, buffer, MAX_PATH);
411 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
412 }
413
414 if (iColumn == COLUMN_NAME)
415 return RecycleBin_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL, &pDetails->str);
416
417 TRASH_UnpackItemID(&pidl->mkid, &data);
418 switch (iColumn)
419 {
420 case COLUMN_DATEDEL:
421 FormatDateTime(buffer, MAX_PATH, data.ftLastAccessTime);
422 break;
423 case COLUMN_DELFROM:
424 lstrcpyW(buffer, data.cFileName);
425 PathRemoveFileSpecW(buffer);
426 break;
427 case COLUMN_SIZE:
428 StrFormatKBSizeW(((LONGLONG)data.nFileSizeHigh<<32)|data.nFileSizeLow, buffer, MAX_PATH);
429 break;
430 case COLUMN_MTIME:
431 FormatDateTime(buffer, MAX_PATH, data.ftLastWriteTime);
432 break;
433 case COLUMN_TYPE:
434 /* TODO */
435 buffer[0] = 0;
436 break;
437 default:
438 return E_FAIL;
439 }
440
441 pDetails->str.uType = STRRET_WSTR;
442 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
443 }
444
445 static HRESULT WINAPI RecycleBin_MapColumnToSCID(IShellFolder2 *iface, UINT iColumn, SHCOLUMNID *pscid)
446 {
447 RecycleBin *This = (RecycleBin *)iface;
448 TRACE("(%p, %d, %p)\n", This, iColumn, pscid);
449 if (iColumn>=COLUMNS_COUNT)
450 return E_INVALIDARG;
451 pscid->fmtid = *RecycleBinColumns[iColumn].fmtId;
452 pscid->pid = RecycleBinColumns[iColumn].pid;
453 return S_OK;
454 }
455
456 static const IShellFolder2Vtbl recycleBinVtbl =
457 {
458 /* IUnknown */
459 RecycleBin_QueryInterface,
460 RecycleBin_AddRef,
461 RecycleBin_Release,
462
463 /* IShellFolder */
464 RecycleBin_ParseDisplayName,
465 RecycleBin_EnumObjects,
466 RecycleBin_BindToObject,
467 RecycleBin_BindToStorage,
468 RecycleBin_CompareIDs,
469 RecycleBin_CreateViewObject,
470 RecycleBin_GetAttributesOf,
471 RecycleBin_GetUIObjectOf,
472 RecycleBin_GetDisplayNameOf,
473 RecycleBin_SetNameOf,
474
475 /* IShellFolder2 */
476 RecycleBin_GetDefaultSearchGUID,
477 RecycleBin_EnumSearches,
478 RecycleBin_GetDefaultColumn,
479 RecycleBin_GetDefaultColumnState,
480 RecycleBin_GetDetailsEx,
481 RecycleBin_GetDetailsOf,
482 RecycleBin_MapColumnToSCID
483 };
484
485 static HRESULT WINAPI RecycleBin_IPersistFolder2_QueryInterface(IPersistFolder2 *This, REFIID riid, void **ppvObject)
486 {
487 return RecycleBin_QueryInterface((IShellFolder2 *)impl_from_IPersistFolder(This), riid, ppvObject);
488 }
489
490 static ULONG WINAPI RecycleBin_IPersistFolder2_AddRef(IPersistFolder2 *This)
491 {
492 return RecycleBin_AddRef((IShellFolder2 *)impl_from_IPersistFolder(This));
493 }
494
495 static ULONG WINAPI RecycleBin_IPersistFolder2_Release(IPersistFolder2 *This)
496 {
497 return RecycleBin_Release((IShellFolder2 *)impl_from_IPersistFolder(This));
498 }
499
500 static const IPersistFolder2Vtbl recycleBinPersistVtbl =
501 {
502 /* IUnknown */
503 RecycleBin_IPersistFolder2_QueryInterface,
504 RecycleBin_IPersistFolder2_AddRef,
505 RecycleBin_IPersistFolder2_Release,
506
507 /* IPersist */
508 RecycleBin_GetClassID,
509 /* IPersistFolder */
510 RecycleBin_Initialize,
511 /* IPersistFolder2 */
512 RecycleBin_GetCurFolder
513 };
514
515 /*************************************************************************
516 * SHUpdateRecycleBinIcon [SHELL32.@]
517 *
518 * Undocumented
519 */
520 HRESULT WINAPI SHUpdateRecycleBinIcon(void)
521 {
522 FIXME("stub\n");
523 return S_OK;
524 }
525
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.