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