shell32: Remove outdated dll names from comments.
[wine] / dlls / shell32 / recyclebin.c
1 /*
2  * Trash virtual folder support. The trashing engine is implemented in trash.c
3  *
4  * Copyright (C) 2006 Mikolaj Zalewski
5  * Copyright 2011 Jay Yang
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23
24 #define COBJMACROS
25 #define NONAMELESSUNION
26
27 #include <stdarg.h>
28
29 #include "winerror.h"
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.h"
33 #include "winuser.h"
34 #include "shlwapi.h"
35 #include "ntquery.h"
36 #include "shlobj.h"
37 #include "shresdef.h"
38 #include "shellfolder.h"
39 #include "shellapi.h"
40 #include "knownfolders.h"
41 #include "wine/debug.h"
42
43 #include "shell32_main.h"
44 #include "xdg.h"
45 #include "pidl.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
48
49 typedef struct
50 {
51     int column_name_id;
52     const GUID *fmtId;
53     DWORD pid;
54     int pcsFlags;
55     int fmt;
56     int cxChars;
57 } columninfo;
58
59 static const columninfo RecycleBinColumns[] =
60 {
61     {IDS_SHV_COLUMN1,        &FMTID_Storage,   PID_STG_NAME,       SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  30},
62     {IDS_SHV_COLUMN_DELFROM, &FMTID_Displaced, PID_DISPLACED_FROM, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  30},
63     {IDS_SHV_COLUMN_DELDATE, &FMTID_Displaced, PID_DISPLACED_DATE, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT,  20},
64     {IDS_SHV_COLUMN2,        &FMTID_Storage,   PID_STG_SIZE,       SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT,  LVCFMT_RIGHT, 20},
65     {IDS_SHV_COLUMN3,        &FMTID_Storage,   PID_STG_STORAGETYPE,SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  20},
66     {IDS_SHV_COLUMN4,        &FMTID_Storage,   PID_STG_WRITETIME,  SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT,  20},
67 /*    {"creation time",  &FMTID_Storage,   PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE,                        LVCFMT_LEFT,  20}, */
68 /*    {"attribs",        &FMTID_Storage,   PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR,                         LVCFMT_LEFT,  20},       */
69 };
70
71 #define COLUMN_NAME    0
72 #define COLUMN_DELFROM 1
73 #define COLUMN_DATEDEL 2
74 #define COLUMN_SIZE    3
75 #define COLUMN_TYPE    4
76 #define COLUMN_MTIME   5
77
78 #define COLUMNS_COUNT  6
79
80 static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME ft)
81 {
82     FILETIME lft;
83     SYSTEMTIME time;
84     int ret;
85
86     FileTimeToLocalFileTime(&ft, &lft);
87     FileTimeToSystemTime(&lft, &time);
88
89     ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size);
90     if (ret>0 && ret<size)
91     {
92         /* Append space + time without seconds */
93         buffer[ret-1] = ' ';
94         GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret);
95     }
96
97     return (ret!=0 ? E_FAIL : S_OK);
98 }
99
100 typedef struct tagRecycleBinMenu
101 {
102     IContextMenu2 IContextMenu2_iface;
103     LONG refCount;
104
105     UINT cidl;
106     LPITEMIDLIST *apidl;
107     IShellFolder2 *folder;
108 } RecycleBinMenu;
109
110 static const IContextMenu2Vtbl recycleBinMenuVtbl;
111
112 static RecycleBinMenu *impl_from_IContextMenu2(IContextMenu2 *iface)
113 {
114     return CONTAINING_RECORD(iface, RecycleBinMenu, IContextMenu2_iface);
115 }
116
117 static IContextMenu2* RecycleBinMenu_Constructor(UINT cidl, LPCITEMIDLIST *apidl, IShellFolder2 *folder)
118 {
119     RecycleBinMenu *This = SHAlloc(sizeof(RecycleBinMenu));
120     TRACE("(%u,%p)\n",cidl,apidl);
121     This->IContextMenu2_iface.lpVtbl = &recycleBinMenuVtbl;
122     This->cidl = cidl;
123     This->apidl = _ILCopyaPidl(apidl,cidl);
124     IShellFolder2_AddRef(folder);
125     This->folder = folder;
126     This->refCount = 1;
127     return &This->IContextMenu2_iface;
128 }
129
130 static HRESULT WINAPI RecycleBinMenu_QueryInterface(IContextMenu2 *iface,
131                                                     REFIID riid,
132                                                     void **ppvObject)
133 {
134     RecycleBinMenu *This = impl_from_IContextMenu2(iface);
135     TRACE("(%p, %s, %p) - stub\n", This, debugstr_guid(riid), ppvObject);
136     return E_NOTIMPL;
137 }
138
139 static ULONG WINAPI RecycleBinMenu_AddRef(IContextMenu2 *iface)
140 {
141     RecycleBinMenu *This = impl_from_IContextMenu2(iface);
142     TRACE("(%p)\n", This);
143     return InterlockedIncrement(&This->refCount);
144
145 }
146
147 static ULONG WINAPI RecycleBinMenu_Release(IContextMenu2 *iface)
148 {
149     RecycleBinMenu *This = impl_from_IContextMenu2(iface);
150     UINT result;
151     TRACE("(%p)\n", This);
152     result = InterlockedDecrement(&This->refCount);
153     if (result == 0)
154     {
155         TRACE("Destroying object\n");
156         _ILFreeaPidl(This->apidl,This->cidl);
157         IShellFolder_Release(This->folder);
158         SHFree(This);
159     }
160     return result;
161 }
162
163 static HRESULT WINAPI RecycleBinMenu_QueryContextMenu(IContextMenu2 *iface,
164                                                       HMENU hmenu,
165                                                       UINT indexMenu,
166                                                       UINT idCmdFirst,
167                                                       UINT idCmdLast,
168                                                       UINT uFlags)
169 {
170     HMENU menures = LoadMenuW(shell32_hInstance,MAKEINTRESOURCEW(MENU_RECYCLEBIN));
171     if(uFlags & CMF_DEFAULTONLY)
172         return E_NOTIMPL;
173     else{
174         UINT idMax = Shell_MergeMenus(hmenu,GetSubMenu(menures,0),indexMenu,idCmdFirst,idCmdLast,MM_SUBMENUSHAVEIDS);
175         TRACE("Added %d id(s)\n",idMax-idCmdFirst);
176         return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst+1);
177     }
178 }
179
180 static void DoErase(RecycleBinMenu *This)
181 {
182     ISFHelper *helper;
183     IShellFolder2_QueryInterface(This->folder,&IID_ISFHelper,(void**)&helper);
184     if(helper)
185         ISFHelper_DeleteItems(helper,This->cidl,(LPCITEMIDLIST*)This->apidl);
186 }
187
188 static void DoRestore(RecycleBinMenu *This)
189 {
190
191     /*TODO add prompts*/
192     UINT i;
193     for(i=0;i<This->cidl;i++)
194     {
195         WIN32_FIND_DATAW data;
196         TRASH_UnpackItemID(&((This->apidl[i])->mkid),&data);
197         if(PathFileExistsW(data.cFileName))
198         {
199             PIDLIST_ABSOLUTE dest_pidl = ILCreateFromPathW(data.cFileName);
200             WCHAR message[100];
201             WCHAR caption[50];
202             if(_ILIsFolder(ILFindLastID(dest_pidl)))
203                 LoadStringW(shell32_hInstance,IDS_RECYCLEBIN_OVERWRITEFOLDER,
204                             message,sizeof(message)/sizeof(WCHAR));
205             else
206                 LoadStringW(shell32_hInstance,IDS_RECYCLEBIN_OVERWRITEFILE,
207                             message,sizeof(message)/sizeof(WCHAR));
208             LoadStringW(shell32_hInstance,IDS_RECYCLEBIN_OVERWRITE_CAPTION,
209                         caption,sizeof(caption)/sizeof(WCHAR));
210
211             if(ShellMessageBoxW(shell32_hInstance,GetActiveWindow(),message,
212                                 caption,MB_YESNO|MB_ICONEXCLAMATION,
213                                 data.cFileName)!=IDYES)
214                 continue;
215         }
216         if(SUCCEEDED(TRASH_RestoreItem(This->apidl[i])))
217         {
218             IPersistFolder2 *persist;
219             LPITEMIDLIST root_pidl;
220             PIDLIST_ABSOLUTE dest_pidl = ILCreateFromPathW(data.cFileName);
221             BOOL is_folder = _ILIsFolder(ILFindLastID(dest_pidl));
222             IShellFolder2_QueryInterface(This->folder,&IID_IPersistFolder2,
223                                          (void**)&persist);
224             IPersistFolder2_GetCurFolder(persist,&root_pidl);
225             SHChangeNotify(is_folder ? SHCNE_RMDIR : SHCNE_DELETE,
226                            SHCNF_IDLIST,ILCombine(root_pidl,This->apidl[i]),0);
227             SHChangeNotify(is_folder ? SHCNE_MKDIR : SHCNE_CREATE,
228                            SHCNF_IDLIST,dest_pidl,0);
229             ILFree(dest_pidl);
230             ILFree(root_pidl);
231         }
232     }
233 }
234
235 static HRESULT WINAPI RecycleBinMenu_InvokeCommand(IContextMenu2 *iface,
236                                                    LPCMINVOKECOMMANDINFO pici)
237 {
238     RecycleBinMenu *This = impl_from_IContextMenu2(iface);
239     LPCSTR verb = pici->lpVerb;
240     if(IS_INTRESOURCE(verb))
241     {
242         switch(LOWORD(verb))
243         {
244         case IDM_RECYCLEBIN_ERASE:
245             DoErase(This);
246             break;
247         case IDM_RECYCLEBIN_RESTORE:
248             DoRestore(This);
249             break;
250         default:
251             return E_NOTIMPL;
252         }
253     }
254     return S_OK;
255 }
256
257 static HRESULT WINAPI RecycleBinMenu_GetCommandString(IContextMenu2 *iface,
258                                                       UINT_PTR idCmd,
259                                                       UINT uType,
260                                                       UINT *pwReserved,
261                                                       LPSTR pszName,
262                                                       UINT cchMax)
263 {
264     TRACE("(%p, %lu, %u, %p, %s, %u) - stub\n",iface,idCmd,uType,pwReserved,debugstr_a(pszName),cchMax);
265     return E_NOTIMPL;
266 }
267
268 static HRESULT WINAPI RecycleBinMenu_HandleMenuMsg(IContextMenu2 *iface,
269                                                    UINT uMsg, WPARAM wParam,
270                                                    LPARAM lParam)
271 {
272     TRACE("(%p, %u, 0x%lx, 0x%lx) - stub\n",iface,uMsg,wParam,lParam);
273     return E_NOTIMPL;
274 }
275
276
277 static const IContextMenu2Vtbl recycleBinMenuVtbl =
278 {
279     RecycleBinMenu_QueryInterface,
280     RecycleBinMenu_AddRef,
281     RecycleBinMenu_Release,
282     RecycleBinMenu_QueryContextMenu,
283     RecycleBinMenu_InvokeCommand,
284     RecycleBinMenu_GetCommandString,
285     RecycleBinMenu_HandleMenuMsg,
286 };
287
288 /*
289  * Recycle Bin folder
290  */
291
292 typedef struct tagRecycleBin
293 {
294     IShellFolder2 IShellFolder2_iface;
295     IPersistFolder2 IPersistFolder2_iface;
296     ISFHelper ISFHelper_iface;
297     LONG refCount;
298
299     LPITEMIDLIST pidl;
300 } RecycleBin;
301
302 static const IShellFolder2Vtbl recycleBinVtbl;
303 static const IPersistFolder2Vtbl recycleBinPersistVtbl;
304 static const ISFHelperVtbl sfhelperVtbl;
305
306 static inline RecycleBin *impl_from_IShellFolder2(IShellFolder2 *iface)
307 {
308     return CONTAINING_RECORD(iface, RecycleBin, IShellFolder2_iface);
309 }
310
311 static RecycleBin *impl_from_IPersistFolder2(IPersistFolder2 *iface)
312 {
313     return CONTAINING_RECORD(iface, RecycleBin, IPersistFolder2_iface);
314 }
315
316 static RecycleBin *impl_from_ISFHelper(ISFHelper *iface)
317 {
318     return CONTAINING_RECORD(iface, RecycleBin, ISFHelper_iface);
319 }
320
321 static void RecycleBin_Destructor(RecycleBin *This);
322
323 HRESULT WINAPI RecycleBin_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput)
324 {
325     RecycleBin *obj;
326     HRESULT ret;
327     if (pUnkOuter)
328         return CLASS_E_NOAGGREGATION;
329
330     obj = SHAlloc(sizeof(RecycleBin));
331     if (obj == NULL)
332         return E_OUTOFMEMORY;
333     ZeroMemory(obj, sizeof(RecycleBin));
334     obj->IShellFolder2_iface.lpVtbl = &recycleBinVtbl;
335     obj->IPersistFolder2_iface.lpVtbl = &recycleBinPersistVtbl;
336     obj->ISFHelper_iface.lpVtbl = &sfhelperVtbl;
337     if (FAILED(ret = IPersistFolder2_QueryInterface(&obj->IPersistFolder2_iface, riid, ppOutput)))
338     {
339         RecycleBin_Destructor(obj);
340         return ret;
341     }
342 /*    InterlockedIncrement(&objCount);*/
343     return S_OK;
344 }
345
346 static void RecycleBin_Destructor(RecycleBin *This)
347 {
348 /*    InterlockedDecrement(&objCount);*/
349     SHFree(This->pidl);
350     SHFree(This);
351 }
352
353 static HRESULT WINAPI RecycleBin_QueryInterface(IShellFolder2 *iface, REFIID riid, void **ppvObject)
354 {
355     RecycleBin *This = impl_from_IShellFolder2(iface);
356     TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
357
358     *ppvObject = NULL;
359     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IShellFolder)
360             || IsEqualGUID(riid, &IID_IShellFolder2))
361         *ppvObject = This;
362
363     if (IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistFolder)
364             || IsEqualGUID(riid, &IID_IPersistFolder2))
365         *ppvObject = &This->IPersistFolder2_iface;
366     if (IsEqualGUID(riid, &IID_ISFHelper))
367         *ppvObject = &This->ISFHelper_iface;
368
369     if (*ppvObject != NULL)
370     {
371         IUnknown_AddRef((IUnknown *)*ppvObject);
372         return S_OK;
373     }
374     WARN("no interface %s\n", debugstr_guid(riid));
375     return E_NOINTERFACE;
376 }
377
378 static ULONG WINAPI RecycleBin_AddRef(IShellFolder2 *iface)
379 {
380     RecycleBin *This = impl_from_IShellFolder2(iface);
381     TRACE("(%p)\n", This);
382     return InterlockedIncrement(&This->refCount);
383 }
384
385 static ULONG WINAPI RecycleBin_Release(IShellFolder2 *iface)
386 {
387     RecycleBin *This = impl_from_IShellFolder2(iface);
388     LONG result;
389
390     TRACE("(%p)\n", This);
391     result = InterlockedDecrement(&This->refCount);
392     if (result == 0)
393     {
394         TRACE("Destroy object\n");
395         RecycleBin_Destructor(This);
396     }
397     return result;
398 }
399
400 static HRESULT WINAPI RecycleBin_ParseDisplayName(IShellFolder2 *This, HWND hwnd, LPBC pbc,
401             LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl,
402             ULONG *pdwAttributes)
403 {
404     FIXME("stub\n");
405     return E_NOTIMPL;
406 }
407
408 static HRESULT WINAPI RecycleBin_EnumObjects(IShellFolder2 *iface, HWND hwnd, SHCONTF grfFlags, IEnumIDList **ppenumIDList)
409 {
410     RecycleBin *This = impl_from_IShellFolder2(iface);
411     IEnumIDListImpl *list;
412     LPITEMIDLIST *pidls;
413     HRESULT ret = E_OUTOFMEMORY;
414     int pidls_count;
415     int i=0;
416
417     TRACE("(%p, %p, %x, %p)\n", This, hwnd, grfFlags, ppenumIDList);
418
419     *ppenumIDList = NULL;
420     list = IEnumIDList_Constructor();
421     if (!list)
422         return E_OUTOFMEMORY;
423
424     if (grfFlags & SHCONTF_NONFOLDERS)
425     {
426         if (FAILED(ret = TRASH_EnumItems(&pidls, &pidls_count)))
427             goto failed;
428         for (i=0; i<pidls_count; i++)
429             if (!AddToEnumList(list, pidls[i]))
430                 goto failed;
431     }
432
433     *ppenumIDList = &list->IEnumIDList_iface;
434     return S_OK;
435
436 failed:
437     if (list)
438         IEnumIDList_Release(&list->IEnumIDList_iface);
439     for (; i<pidls_count; i++)
440         ILFree(pidls[i]);
441     SHFree(pidls);
442     return ret;
443 }
444
445 static HRESULT WINAPI RecycleBin_BindToObject(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
446 {
447     FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
448     return E_NOTIMPL;
449 }
450
451 static HRESULT WINAPI RecycleBin_BindToStorage(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
452 {
453     FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
454     return E_NOTIMPL;
455 }
456
457 static HRESULT WINAPI RecycleBin_CompareIDs(IShellFolder2 *iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
458 {
459     RecycleBin *This = impl_from_IShellFolder2(iface);
460
461     /* TODO */
462     TRACE("(%p, %p, %p, %p)\n", This, (void *)lParam, pidl1, pidl2);
463     if (pidl1->mkid.cb != pidl2->mkid.cb)
464         return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
465     return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb));
466 }
467
468 static HRESULT WINAPI RecycleBin_CreateViewObject(IShellFolder2 *iface, HWND hwndOwner, REFIID riid, void **ppv)
469 {
470     RecycleBin *This = impl_from_IShellFolder2(iface);
471     HRESULT ret;
472     TRACE("(%p, %p, %s, %p)\n", This, hwndOwner, debugstr_guid(riid), ppv);
473
474     *ppv = NULL;
475     if (IsEqualGUID(riid, &IID_IShellView))
476     {
477         IShellView *tmp;
478         CSFV sfv;
479
480         ZeroMemory(&sfv, sizeof(sfv));
481         sfv.cbSize = sizeof(sfv);
482         sfv.pshf = (IShellFolder *)This;
483
484         TRACE("Calling SHCreateShellFolderViewEx\n");
485         ret = SHCreateShellFolderViewEx(&sfv, &tmp);
486         TRACE("Result: %08x, output: %p\n", (unsigned int)ret, tmp);
487         *ppv = tmp;
488         return ret;
489     }
490
491     return E_NOINTERFACE;
492 }
493
494 static HRESULT WINAPI RecycleBin_GetAttributesOf(IShellFolder2 *This, UINT cidl, LPCITEMIDLIST *apidl,
495                                    SFGAOF *rgfInOut)
496 {
497     TRACE("(%p, %d, {%p, ...}, {%x})\n", This, cidl, apidl[0], *rgfInOut);
498     *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM;
499     return S_OK;
500 }
501
502 static HRESULT WINAPI RecycleBin_GetUIObjectOf(IShellFolder2 *iface, HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
503                       REFIID riid, UINT *rgfReserved, void **ppv)
504 {
505     RecycleBin *This = impl_from_IShellFolder2(iface);
506     *ppv = NULL;
507     if(IsEqualGUID(riid, &IID_IContextMenu) || IsEqualGUID(riid, &IID_IContextMenu2))
508     {
509         TRACE("(%p, %p, %d, {%p, ...}, %s, %p, %p)\n", This, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
510         *ppv = RecycleBinMenu_Constructor(cidl,apidl,&(This->IShellFolder2_iface));
511         return S_OK;
512     }
513     FIXME("(%p, %p, %d, {%p, ...}, %s, %p, %p): stub!\n", iface, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
514
515     return E_NOTIMPL;
516 }
517
518 static HRESULT WINAPI RecycleBin_GetDisplayNameOf(IShellFolder2 *This, LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName)
519 {
520     WIN32_FIND_DATAW data;
521
522     TRACE("(%p, %p, %x, %p)\n", This, pidl, uFlags, pName);
523     TRASH_UnpackItemID(&pidl->mkid, &data);
524     pName->uType = STRRET_WSTR;
525     pName->u.pOleStr = StrDupW(PathFindFileNameW(data.cFileName));
526     if (pName->u.pOleStr == NULL)
527         return E_OUTOFMEMORY;
528
529     return S_OK;
530 }
531
532 static HRESULT WINAPI RecycleBin_SetNameOf(IShellFolder2 *This, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
533             SHGDNF uFlags, LPITEMIDLIST *ppidlOut)
534 {
535     TRACE("\n");
536     return E_FAIL; /* not supported */
537 }
538
539 static HRESULT WINAPI RecycleBin_GetClassID(IPersistFolder2 *This, CLSID *pClassID)
540 {
541     TRACE("(%p, %p)\n", This, pClassID);
542     if (This == NULL || pClassID == NULL)
543         return E_INVALIDARG;
544     *pClassID = CLSID_RecycleBin;
545     return S_OK;
546 }
547
548 static HRESULT WINAPI RecycleBin_Initialize(IPersistFolder2 *iface, LPCITEMIDLIST pidl)
549 {
550     RecycleBin *This = impl_from_IPersistFolder2(iface);
551     TRACE("(%p, %p)\n", This, pidl);
552
553     This->pidl = ILClone(pidl);
554     if (This->pidl == NULL)
555         return E_OUTOFMEMORY;
556     return S_OK;
557 }
558
559 static HRESULT WINAPI RecycleBin_GetCurFolder(IPersistFolder2 *iface, LPITEMIDLIST *ppidl)
560 {
561     RecycleBin *This = impl_from_IPersistFolder2(iface);
562     TRACE("\n");
563     *ppidl = ILClone(This->pidl);
564     return S_OK;
565 }
566
567 static HRESULT WINAPI RecycleBin_GetDefaultSearchGUID(IShellFolder2 *iface, GUID *pguid)
568 {
569     FIXME("stub\n");
570     return E_NOTIMPL;
571 }
572
573 static HRESULT WINAPI RecycleBin_EnumSearches(IShellFolder2 *iface, IEnumExtraSearch **ppEnum)
574 {
575     FIXME("stub\n");
576     *ppEnum = NULL;
577     return E_NOTIMPL;
578 }
579
580 static HRESULT WINAPI RecycleBin_GetDefaultColumn(IShellFolder2 *iface, DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
581 {
582     RecycleBin *This = impl_from_IShellFolder2(iface);
583     TRACE("(%p, %x, %p, %p)\n", This, dwReserved, pSort, pDisplay);
584     *pSort = 0;
585     *pDisplay = 0;
586     return S_OK;
587 }
588
589 static HRESULT WINAPI RecycleBin_GetDefaultColumnState(IShellFolder2 *iface, UINT iColumn, SHCOLSTATEF *pcsFlags)
590 {
591     RecycleBin *This = impl_from_IShellFolder2(iface);
592     TRACE("(%p, %d, %p)\n", This, iColumn, pcsFlags);
593     if (iColumn >= COLUMNS_COUNT)
594         return E_INVALIDARG;
595     *pcsFlags = RecycleBinColumns[iColumn].pcsFlags;
596     return S_OK;
597 }
598
599 static HRESULT WINAPI RecycleBin_GetDetailsEx(IShellFolder2 *iface, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
600 {
601     FIXME("stub\n");
602     return E_NOTIMPL;
603 }
604
605 static HRESULT WINAPI RecycleBin_GetDetailsOf(IShellFolder2 *iface, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
606 {
607     RecycleBin *This = impl_from_IShellFolder2(iface);
608     WIN32_FIND_DATAW data;
609     WCHAR buffer[MAX_PATH];
610
611     TRACE("(%p, %p, %d, %p)\n", This, pidl, iColumn, pDetails);
612     if (iColumn >= COLUMNS_COUNT)
613         return E_FAIL;
614     pDetails->fmt = RecycleBinColumns[iColumn].fmt;
615     pDetails->cxChar = RecycleBinColumns[iColumn].cxChars;
616     if (pidl == NULL)
617     {
618         pDetails->str.uType = STRRET_WSTR;
619         LoadStringW(shell32_hInstance, RecycleBinColumns[iColumn].column_name_id, buffer, MAX_PATH);
620         return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
621     }
622
623     if (iColumn == COLUMN_NAME)
624         return RecycleBin_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL, &pDetails->str);
625
626     TRASH_UnpackItemID(&pidl->mkid, &data);
627     switch (iColumn)
628     {
629         case COLUMN_DATEDEL:
630             FormatDateTime(buffer, MAX_PATH, data.ftLastAccessTime);
631             break;
632         case COLUMN_DELFROM:
633             lstrcpyW(buffer, data.cFileName);
634             PathRemoveFileSpecW(buffer);
635             break;
636         case COLUMN_SIZE:
637             StrFormatKBSizeW(((LONGLONG)data.nFileSizeHigh<<32)|data.nFileSizeLow, buffer, MAX_PATH);
638             break;
639         case COLUMN_MTIME:
640             FormatDateTime(buffer, MAX_PATH, data.ftLastWriteTime);
641             break;
642         case COLUMN_TYPE:
643             /* TODO */
644             buffer[0] = 0;
645             break;
646         default:
647             return E_FAIL;
648     }
649     
650     pDetails->str.uType = STRRET_WSTR;
651     return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
652 }
653
654 static HRESULT WINAPI RecycleBin_MapColumnToSCID(IShellFolder2 *iface, UINT iColumn, SHCOLUMNID *pscid)
655 {
656     RecycleBin *This = impl_from_IShellFolder2(iface);
657     TRACE("(%p, %d, %p)\n", This, iColumn, pscid);
658     if (iColumn>=COLUMNS_COUNT)
659         return E_INVALIDARG;
660     pscid->fmtid = *RecycleBinColumns[iColumn].fmtId;
661     pscid->pid = RecycleBinColumns[iColumn].pid;
662     return S_OK;
663 }
664
665 static const IShellFolder2Vtbl recycleBinVtbl = 
666 {
667     /* IUnknown */
668     RecycleBin_QueryInterface,
669     RecycleBin_AddRef,
670     RecycleBin_Release,
671
672     /* IShellFolder */
673     RecycleBin_ParseDisplayName,
674     RecycleBin_EnumObjects,
675     RecycleBin_BindToObject,
676     RecycleBin_BindToStorage,
677     RecycleBin_CompareIDs,
678     RecycleBin_CreateViewObject,
679     RecycleBin_GetAttributesOf,
680     RecycleBin_GetUIObjectOf,
681     RecycleBin_GetDisplayNameOf,
682     RecycleBin_SetNameOf,
683
684     /* IShellFolder2 */
685     RecycleBin_GetDefaultSearchGUID,
686     RecycleBin_EnumSearches,
687     RecycleBin_GetDefaultColumn,
688     RecycleBin_GetDefaultColumnState,
689     RecycleBin_GetDetailsEx,
690     RecycleBin_GetDetailsOf,
691     RecycleBin_MapColumnToSCID
692 };
693
694 static HRESULT WINAPI RecycleBin_IPersistFolder2_QueryInterface(IPersistFolder2 *iface, REFIID riid,
695         void **ppvObject)
696 {
697     RecycleBin *This = impl_from_IPersistFolder2(iface);
698
699     return RecycleBin_QueryInterface(&This->IShellFolder2_iface, riid, ppvObject);
700 }
701
702 static ULONG WINAPI RecycleBin_IPersistFolder2_AddRef(IPersistFolder2 *iface)
703 {
704     RecycleBin *This = impl_from_IPersistFolder2(iface);
705
706     return RecycleBin_AddRef(&This->IShellFolder2_iface);
707 }
708
709 static ULONG WINAPI RecycleBin_IPersistFolder2_Release(IPersistFolder2 *iface)
710 {
711     RecycleBin *This = impl_from_IPersistFolder2(iface);
712
713     return RecycleBin_Release(&This->IShellFolder2_iface);
714 }
715
716 static const IPersistFolder2Vtbl recycleBinPersistVtbl =
717 {
718     /* IUnknown */
719     RecycleBin_IPersistFolder2_QueryInterface,
720     RecycleBin_IPersistFolder2_AddRef,
721     RecycleBin_IPersistFolder2_Release,
722
723     /* IPersist */
724     RecycleBin_GetClassID,
725     /* IPersistFolder */
726     RecycleBin_Initialize,
727     /* IPersistFolder2 */
728     RecycleBin_GetCurFolder
729 };
730
731 static HRESULT WINAPI RecycleBin_ISFHelper_QueryInterface(ISFHelper *iface, REFIID riid,
732         void **ppvObject)
733 {
734     RecycleBin *This = impl_from_ISFHelper(iface);
735
736     return RecycleBin_QueryInterface(&This->IShellFolder2_iface, riid, ppvObject);
737 }
738
739 static ULONG WINAPI RecycleBin_ISFHelper_AddRef(ISFHelper *iface)
740 {
741     RecycleBin *This = impl_from_ISFHelper(iface);
742
743     return RecycleBin_AddRef(&This->IShellFolder2_iface);
744 }
745
746 static ULONG WINAPI RecycleBin_ISFHelper_Release(ISFHelper *iface)
747 {
748     RecycleBin *This = impl_from_ISFHelper(iface);
749
750     return RecycleBin_Release(&This->IShellFolder2_iface);
751 }
752
753 static HRESULT WINAPI RecycleBin_GetUniqueName(ISFHelper *iface,LPWSTR lpName,
754                                                UINT  uLen)
755 {
756     return E_NOTIMPL;
757 }
758
759 static HRESULT WINAPI RecycleBin_AddFolder(ISFHelper * iface, HWND hwnd,
760                                            LPCWSTR pwszName,
761                                            LPITEMIDLIST * ppidlOut)
762 {
763     /*Adding folders doesn't make sense in the recycle bin*/
764     return E_NOTIMPL;
765 }
766
767 static HRESULT erase_items(HWND parent,const LPCITEMIDLIST * apidl, UINT cidl, BOOL confirm)
768 {
769     UINT i=0;
770     HRESULT ret = S_OK;
771     LPITEMIDLIST recyclebin;
772
773     if(confirm)
774     {
775         WCHAR arg[MAX_PATH];
776         WCHAR message[100];
777         WCHAR caption[50];
778         switch(cidl)
779         {
780         case 0:
781             return S_OK;
782         case 1:
783             {
784                 WIN32_FIND_DATAW data;
785                 TRASH_UnpackItemID(&((*apidl)->mkid),&data);
786                 lstrcpynW(arg,data.cFileName,MAX_PATH);
787                 LoadStringW(shell32_hInstance,IDS_RECYCLEBIN_ERASEITEM,message,
788                             sizeof(message)/sizeof(WCHAR));
789                 break;
790             }
791         default:
792             {
793                 static const WCHAR format[]={'%','u','\0'};
794                 LoadStringW(shell32_hInstance,IDS_RECYCLEBIN_ERASEMULTIPLE,
795                             message,sizeof(message)/sizeof(WCHAR));
796                 sprintfW(arg,format,cidl);
797                 break;
798             }
799
800         }
801         LoadStringW(shell32_hInstance,IDS_RECYCLEBIN_ERASE_CAPTION,caption,
802                     sizeof(caption)/sizeof(WCHAR));
803         if(ShellMessageBoxW(shell32_hInstance,parent,message,caption,
804                             MB_YESNO|MB_ICONEXCLAMATION,arg)!=IDYES)
805             return ret;
806
807     }
808     SHGetFolderLocation(parent,CSIDL_BITBUCKET,0,0,&recyclebin);
809     for (; i<cidl; i++)
810     {
811         if(SUCCEEDED(TRASH_EraseItem(apidl[i])))
812             SHChangeNotify(SHCNE_DELETE,SHCNF_IDLIST,
813                            ILCombine(recyclebin,apidl[i]),0);
814     }
815     ILFree(recyclebin);
816     return S_OK;
817 }
818
819 static HRESULT WINAPI RecycleBin_DeleteItems(ISFHelper * iface, UINT cidl,
820                                              LPCITEMIDLIST * apidl)
821 {
822     TRACE("(%p,%u,%p)\n",iface,cidl,apidl);
823     return erase_items(GetActiveWindow(),apidl,cidl,TRUE);
824 }
825
826 static HRESULT WINAPI RecycleBin_CopyItems(ISFHelper * iface,
827                                            IShellFolder * pSFFrom,
828                                            UINT cidl, LPCITEMIDLIST * apidl)
829 {
830     return E_NOTIMPL;
831 }
832
833 static const ISFHelperVtbl sfhelperVtbl =
834 {
835     RecycleBin_ISFHelper_QueryInterface,
836     RecycleBin_ISFHelper_AddRef,
837     RecycleBin_ISFHelper_Release,
838     RecycleBin_GetUniqueName,
839     RecycleBin_AddFolder,
840     RecycleBin_DeleteItems,
841     RecycleBin_CopyItems
842 };
843
844 HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
845 {
846     WCHAR wszRootPath[MAX_PATH];
847     MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, wszRootPath, MAX_PATH);
848     return SHQueryRecycleBinW(wszRootPath, pSHQueryRBInfo);
849 }
850
851 HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
852 {
853     LPITEMIDLIST *apidl;
854     INT cidl;
855     INT i=0;
856     TRACE("(%s, %p)\n", debugstr_w(pszRootPath), pSHQueryRBInfo);
857     FIXME("Ignoring pszRootPath=%s\n",debugstr_w(pszRootPath));
858
859     TRASH_EnumItems(&apidl,&cidl);
860     pSHQueryRBInfo->i64NumItems = cidl;
861     pSHQueryRBInfo->i64Size = 0;
862     for (; i<cidl; i++)
863     {
864         WIN32_FIND_DATAW data;
865         TRASH_UnpackItemID(&((apidl[i])->mkid),&data);
866         pSHQueryRBInfo->i64Size += ((DWORDLONG)data.nFileSizeHigh << 32) + data.nFileSizeLow;
867         ILFree(apidl[i]);
868     }
869     SHFree(apidl);
870     return S_OK;
871 }
872
873 HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
874 {
875     WCHAR wszRootPath[MAX_PATH];
876     MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, wszRootPath, MAX_PATH);
877     return SHEmptyRecycleBinW(hwnd, wszRootPath, dwFlags);
878 }
879
880 #define SHERB_NOCONFIRMATION 1
881 #define SHERB_NOPROGRESSUI   2
882 #define SHERB_NOSOUND        4
883
884 HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
885 {
886     LPITEMIDLIST *apidl;
887     INT cidl;
888     INT i=0;
889     HRESULT ret;
890     TRACE("(%p, %s, 0x%08x)\n", hwnd, debugstr_w(pszRootPath) , dwFlags);
891     FIXME("Ignoring pszRootPath=%s\n",debugstr_w(pszRootPath));
892     TRASH_EnumItems(&apidl,&cidl);
893     ret = erase_items(hwnd,(const LPCITEMIDLIST*)apidl,cidl,!(dwFlags & SHERB_NOCONFIRMATION));
894     for (;i<cidl;i++)
895         ILFree(apidl[i]);
896     SHFree(apidl);
897     return ret;
898 }
899
900 /*************************************************************************
901  * SHUpdateRecycleBinIcon                                [SHELL32.@]
902  *
903  * Undocumented
904  */
905 HRESULT WINAPI SHUpdateRecycleBinIcon(void)
906 {
907     FIXME("stub\n");
908     return S_OK;
909 }