mfmediaengine: Remove unnecessary import library.
[wine.git] / dlls / shell32 / recyclebin.c
blob8cfc1042fe7a37b2aad4077d61040c9a1515aa4d
1 /*
2 * Trash virtual folder support
4 * Copyright (C) 2006 Mikolaj Zalewski
5 * Copyright 2011 Jay Yang
6 * Copyright 2021 Alexandre Julliard
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define COBJMACROS
24 #define NONAMELESSUNION
26 #include <stdarg.h>
28 #include "winerror.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winternl.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"
43 #include "shell32_main.h"
44 #include "pidl.h"
45 #include "shfldr.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
49 static const shvheader RecycleBinColumns[] =
51 {&FMTID_Storage, PID_STG_NAME, IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
52 {&FMTID_Displaced, PID_DISPLACED_FROM, IDS_SHV_COLUMN_DELFROM, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
53 {&FMTID_Displaced, PID_DISPLACED_DATE, IDS_SHV_COLUMN_DELDATE, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
54 {&FMTID_Storage, PID_STG_SIZE, IDS_SHV_COLUMN2, SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20},
55 {&FMTID_Storage, PID_STG_STORAGETYPE,IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
56 {&FMTID_Storage, PID_STG_WRITETIME, IDS_SHV_COLUMN4, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
57 /* {&FMTID_Storage, PID_STG_CREATETIME, "creation time", SHCOLSTATE_TYPE_DATE, LVCFMT_LEFT, 20}, */
58 /* {&FMTID_Storage, PID_STG_ATTRIBUTES, "attribs", SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 20}, */
61 #define COLUMN_NAME 0
62 #define COLUMN_DELFROM 1
63 #define COLUMN_DATEDEL 2
64 #define COLUMN_SIZE 3
65 #define COLUMN_TYPE 4
66 #define COLUMN_MTIME 5
68 #define COLUMNS_COUNT 6
70 static const WIN32_FIND_DATAW *get_trash_item_data( LPCITEMIDLIST id )
72 if (id->mkid.cb < 2 + 1 + sizeof(WIN32_FIND_DATAW) + 2) return NULL;
73 if (id->mkid.abID[0] != 0) return NULL;
74 return (const WIN32_FIND_DATAW *)(id->mkid.abID + 1);
77 static INIT_ONCE trash_dir_once;
78 static WCHAR *trash_dir;
79 static WCHAR *trash_info_dir;
80 static ULONG random_seed;
82 extern void CDECL wine_get_host_version( const char **sysname, const char **release );
84 static BOOL is_macos(void)
86 const char *sysname;
88 wine_get_host_version( &sysname, NULL );
89 return !strcmp( sysname, "Darwin" );
92 static BOOL WINAPI init_trash_dirs( INIT_ONCE *once, void *param, void **context )
94 const WCHAR *home = _wgetenv( L"WINEHOMEDIR" );
95 WCHAR *info = NULL, *files = NULL;
96 ULONG len;
98 if (!home) return TRUE;
99 if (is_macos())
101 files = heap_alloc( (lstrlenW(home) + lstrlenW(L"\\.Trash") + 1) * sizeof(WCHAR) );
102 lstrcpyW( files, home );
103 lstrcatW( files, L"\\.Trash" );
104 files[1] = '\\'; /* change \??\ to \\?\ */
106 else
108 const WCHAR *data_home = _wgetenv( L"XDG_DATA_HOME" );
109 const WCHAR *fmt = L"%s/.local/share/Trash";
110 WCHAR *p;
112 if (data_home && data_home[0] == '/')
114 home = data_home;
115 fmt = L"\\??\\unix%s/Trash";
117 len = lstrlenW(home) + lstrlenW(fmt) + 7;
118 files = heap_alloc( len * sizeof(WCHAR) );
119 swprintf( files, len, fmt, home );
120 files[1] = '\\'; /* change \??\ to \\?\ */
121 for (p = files; *p; p++) if (*p == '/') *p = '\\';
122 CreateDirectoryW( files, NULL );
123 info = heap_alloc( len * sizeof(WCHAR) );
124 lstrcpyW( info, files );
125 lstrcatW( files, L"\\files" );
126 lstrcatW( info, L"\\info" );
127 if (!CreateDirectoryW( info, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS) goto done;
128 trash_info_dir = info;
131 if (!CreateDirectoryW( files, NULL ) && GetLastError() != ERROR_ALREADY_EXISTS) goto done;
132 trash_dir = files;
133 random_seed = GetTickCount();
134 return TRUE;
136 done:
137 heap_free( files );
138 heap_free( info );
139 return TRUE;
142 BOOL is_trash_available(void)
144 InitOnceExecuteOnce( &trash_dir_once, init_trash_dirs, NULL, NULL );
145 return trash_dir != NULL;
148 static void encode( const char *src, char *dst )
150 static const char escape_chars[] = "^&`{}|[]'<>\\#%\"+";
151 static const char hexchars[] = "0123456789ABCDEF";
153 for ( ; *src; src++)
155 if (*src <= 0x20 || *src >= 0x7f || strchr( escape_chars, *src ))
157 *dst++ = '%';
158 *dst++ = hexchars[(unsigned char)*src / 16];
159 *dst++ = hexchars[(unsigned char)*src % 16];
161 else *dst++ = *src;
163 *dst = 0;
166 static char *decode( char *buf )
168 const char *src = buf;
169 char *dst = buf; /* decode in place */
171 while (*src)
173 if (*src == '%')
175 unsigned char v;
177 if (src[1] >= '0' && src[1] <= '9') v = src[1] - '0';
178 else if (src[1] >= 'A' && src[1] <= 'F') v = src[1] - 'A' + 10;
179 else if (src[1] >= 'a' && src[1] <= 'f') v = src[1] - 'a' + 10;
180 else goto next;
181 v <<= 4;
182 if (src[2] >= '0' && src[2] <= '9') v += src[2] - '0';
183 else if (src[2] >= 'A' && src[2] <= 'F') v += src[2] - 'A' + 10;
184 else if (src[2] >= 'a' && src[2] <= 'f') v += src[2] - 'a' + 10;
185 else goto next;
186 *dst++ = v;
187 next:
188 if (src[1] && src[2]) src += 3;
189 else break;
191 else *dst++ = *src++;
193 *dst = 0;
194 return buf;
197 static BOOL write_trashinfo_file( HANDLE handle, const WCHAR *orig_path )
199 char *path, *buffer;
200 SYSTEMTIME now;
202 if (!(path = wine_get_unix_file_name( orig_path ))) return FALSE;
203 GetLocalTime( &now );
205 buffer = heap_alloc( strlen(path) * 3 + 128 );
206 strcpy( buffer, "[Trash Info]\nPath=" );
207 encode( path, buffer + strlen(buffer) );
208 sprintf( buffer + strlen(buffer), "\nDeletionDate=%04u-%02u-%02uT%02u:%02u:%02u\n",
209 now.wYear, now.wMonth, now.wDay, now.wHour, now.wMinute, now.wSecond);
210 WriteFile( handle, buffer, strlen(buffer), NULL, NULL );
211 heap_free( path );
212 heap_free( buffer );
213 return TRUE;
216 static void read_trashinfo_file( HANDLE handle, WIN32_FIND_DATAW *data )
218 ULONG size;
219 WCHAR *path;
220 char *buffer, *next, *p;
221 int header = 0;
223 size = GetFileSize( handle, NULL );
224 if (!(buffer = heap_alloc( size + 1 ))) return;
225 if (!ReadFile( handle, buffer, size, &size, NULL )) size = 0;
226 buffer[size] = 0;
227 next = buffer;
228 while (next)
230 p = next;
231 if ((next = strchr( next, '\n' ))) *next++ = 0;
232 while (*p == ' ' || *p == '\t') p++;
233 if (!strncmp( p, "[Trash Info]", 12 ))
235 header++;
236 continue;
238 if (header && !strncmp( p, "Path=", 5 ))
240 p += 5;
241 if ((path = wine_get_dos_file_name( decode( p ))))
243 lstrcpynW( data->cFileName, path, MAX_PATH );
244 heap_free( path );
246 else
248 /* show only the file name */
249 char *file = strrchr( p, '/' );
250 if (!file) file = p;
251 else file++;
252 MultiByteToWideChar( CP_UNIXCP, 0, file, -1, data->cFileName, MAX_PATH );
254 continue;
256 if (header && !strncmp( p, "DeletionDate=", 13 ))
258 int year, mon, day, hour, min, sec;
259 if (sscanf( p + 13, "%d-%d-%dT%d:%d:%d", &year, &mon, &day, &hour, &min, &sec ) == 6)
261 SYSTEMTIME time = { year, mon, 0, day, hour, min, sec };
262 FILETIME ft;
263 if (SystemTimeToFileTime( &time, &ft ))
264 LocalFileTimeToFileTime( &ft, &data->ftLastAccessTime );
268 heap_free( buffer );
272 BOOL trash_file( const WCHAR *path )
274 WCHAR *dest = NULL, *file = PathFindFileNameW( path );
275 BOOL ret = TRUE;
276 ULONG i, len;
278 InitOnceExecuteOnce( &trash_dir_once, init_trash_dirs, NULL, NULL );
279 if (!trash_dir) return FALSE;
281 len = lstrlenW(trash_dir) + lstrlenW(file) + 11;
282 dest = heap_alloc( len * sizeof(WCHAR) );
284 if (trash_info_dir)
286 HANDLE handle;
287 ULONG infolen = lstrlenW(trash_info_dir) + lstrlenW(file) + 21;
288 WCHAR *info = heap_alloc( infolen * sizeof(WCHAR) );
290 swprintf( info, infolen, L"%s\\%s.trashinfo", trash_info_dir, file );
291 for (i = 0; i < 1000; i++)
293 handle = CreateFileW( info, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, 0 );
294 if (handle != INVALID_HANDLE_VALUE) break;
295 swprintf( info, infolen, L"%s\\%s-%08x.trashinfo", trash_info_dir, file, RtlRandom( &random_seed ));
297 if (handle != INVALID_HANDLE_VALUE)
299 if ((ret = write_trashinfo_file( handle, path )))
301 ULONG namelen = lstrlenW(info) - lstrlenW(trash_info_dir) - 10 /* .trashinfo */;
302 swprintf( dest, len, L"%s%.*s", trash_dir, namelen, info + lstrlenW(trash_info_dir) );
303 ret = MoveFileW( path, dest );
305 CloseHandle( handle );
306 if (!ret) DeleteFileW( info );
309 else
311 swprintf( dest, len, L"%s\\%s", trash_dir, file );
312 for (i = 0; i < 1000; i++)
314 ret = MoveFileW( path, dest );
315 if (ret || GetLastError() != ERROR_ALREADY_EXISTS) break;
316 swprintf( dest, len, L"%s\\%s-%08x", trash_dir, file, RtlRandom( &random_seed ));
319 if (ret) TRACE( "%s -> %s\n", debugstr_w(path), debugstr_w(dest) );
320 heap_free( dest );
321 return ret;
324 static BOOL get_trash_item_info( const WCHAR *filename, WIN32_FIND_DATAW *data )
326 if (!trash_info_dir)
328 return !!wcscmp( filename, L".DS_Store" );
330 else
332 HANDLE handle;
333 ULONG len = lstrlenW(trash_info_dir) + lstrlenW(filename) + 12;
334 WCHAR *info = heap_alloc( len * sizeof(WCHAR) );
336 swprintf( info, len, L"%s\\%s.trashinfo", trash_info_dir, filename );
337 handle = CreateFileW( info, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
338 heap_free( info );
339 if (handle == INVALID_HANDLE_VALUE) return FALSE;
340 read_trashinfo_file( handle, data );
341 CloseHandle( handle );
342 return TRUE;
346 static HRESULT add_trash_item( WIN32_FIND_DATAW *orig_data, LPITEMIDLIST **pidls,
347 ULONG *count, ULONG *size )
349 ITEMIDLIST *pidl;
350 WIN32_FIND_DATAW *data;
351 const WCHAR *filename = orig_data->cFileName;
352 ULONG len = offsetof( ITEMIDLIST, mkid.abID[1 + sizeof(*data) + (lstrlenW(filename)+1) * sizeof(WCHAR)]);
354 if (!(pidl = SHAlloc( len + 2 ))) return E_OUTOFMEMORY;
355 pidl->mkid.cb = len;
356 pidl->mkid.abID[0] = 0;
357 data = (WIN32_FIND_DATAW *)(pidl->mkid.abID + 1);
358 memcpy( data, orig_data, sizeof(*data) );
359 lstrcpyW( (WCHAR *)(data + 1), filename );
360 *(USHORT *)((char *)pidl + len) = 0;
362 if (get_trash_item_info( filename, data ))
364 if (*count == *size)
366 LPITEMIDLIST *new;
368 *size = max( *size * 2, 32 );
369 new = heap_realloc( *pidls, *size * sizeof(**pidls) );
370 if (!new)
372 SHFree( pidl );
373 return E_OUTOFMEMORY;
375 *pidls = new;
377 (*pidls)[(*count)++] = pidl;
379 else SHFree( pidl ); /* ignore it */
380 return S_OK;
383 static HRESULT enum_trash_items( LPITEMIDLIST **pidls, int *ret_count )
385 HANDLE handle;
386 WCHAR *file;
387 WIN32_FIND_DATAW data;
388 LPITEMIDLIST *ret = NULL;
389 ULONG count = 0, size = 0;
390 HRESULT hr = S_OK;
392 InitOnceExecuteOnce( &trash_dir_once, init_trash_dirs, NULL, NULL );
393 if (!trash_dir) return E_FAIL;
395 file = heap_alloc( (lstrlenW(trash_dir) + lstrlenW(L"\\*") + 1) * sizeof(WCHAR) );
396 lstrcpyW( file, trash_dir );
397 lstrcatW( file, L"\\*" );
398 handle = FindFirstFileW( file, &data );
399 if (handle != INVALID_HANDLE_VALUE)
403 if (!wcscmp( data.cFileName, L"." )) continue;
404 if (!wcscmp( data.cFileName, L".." )) continue;
405 hr = add_trash_item( &data, &ret, &count, &size );
406 } while (hr == S_OK && FindNextFileW( handle, &data ));
407 FindClose( handle );
410 if (FAILED(hr)) while (count) SHFree( &ret[--count] );
411 else if (count)
413 *pidls = SHAlloc( count * sizeof(**pidls) );
414 memcpy( *pidls, ret, count * sizeof(**pidls) );
416 heap_free( ret );
417 *ret_count = count;
418 return hr;
421 static void remove_trashinfo( const WCHAR *filename )
423 WCHAR *info;
424 ULONG len;
426 if (!trash_info_dir) return;
427 len = lstrlenW(trash_info_dir) + lstrlenW(filename) + 12;
428 info = heap_alloc( len * sizeof(WCHAR) );
429 swprintf( info, len, L"%s\\%s.trashinfo", trash_info_dir, filename );
430 DeleteFileW( info );
431 heap_free( info );
434 static HRESULT restore_trash_item( LPCITEMIDLIST pidl )
436 const WIN32_FIND_DATAW *data = get_trash_item_data( pidl );
437 WCHAR *from, *filename = (WCHAR *)(data + 1);
438 ULONG len;
440 if (!wcschr( data->cFileName, '\\' ))
442 FIXME( "original name for %s not available\n", debugstr_w(data->cFileName) );
443 return E_NOTIMPL;
445 len = lstrlenW(trash_dir) + lstrlenW(filename) + 2;
446 from = heap_alloc( len * sizeof(WCHAR) );
447 swprintf( from, len, L"%s\\%s", trash_dir, filename );
448 if (MoveFileW( from, data->cFileName )) remove_trashinfo( filename );
449 else WARN( "failed to restore %s to %s\n", debugstr_w(from), debugstr_w(data->cFileName) );
450 heap_free( from );
451 return S_OK;
454 static HRESULT erase_trash_item( LPCITEMIDLIST pidl )
456 const WIN32_FIND_DATAW *data = get_trash_item_data( pidl );
457 WCHAR *from, *filename = (WCHAR *)(data + 1);
458 ULONG len = lstrlenW(trash_dir) + lstrlenW(filename) + 2;
460 from = heap_alloc( len * sizeof(WCHAR) );
461 swprintf( from, len, L"%s\\%s", trash_dir, filename );
462 if (DeleteFileW( from )) remove_trashinfo( filename );
463 heap_free( from );
464 return S_OK;
468 static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME ft)
470 FILETIME lft;
471 SYSTEMTIME time;
472 int ret;
474 FileTimeToLocalFileTime(&ft, &lft);
475 FileTimeToSystemTime(&lft, &time);
477 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size);
478 if (ret>0 && ret<size)
480 /* Append space + time without seconds */
481 buffer[ret-1] = ' ';
482 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret);
485 return (ret!=0 ? E_FAIL : S_OK);
488 typedef struct tagRecycleBinMenu
490 IContextMenu2 IContextMenu2_iface;
491 LONG refCount;
493 UINT cidl;
494 LPITEMIDLIST *apidl;
495 IShellFolder2 *folder;
496 } RecycleBinMenu;
498 static const IContextMenu2Vtbl recycleBinMenuVtbl;
500 static RecycleBinMenu *impl_from_IContextMenu2(IContextMenu2 *iface)
502 return CONTAINING_RECORD(iface, RecycleBinMenu, IContextMenu2_iface);
505 static IContextMenu2* RecycleBinMenu_Constructor(UINT cidl, LPCITEMIDLIST *apidl, IShellFolder2 *folder)
507 RecycleBinMenu *This = SHAlloc(sizeof(RecycleBinMenu));
508 TRACE("(%u,%p)\n",cidl,apidl);
509 This->IContextMenu2_iface.lpVtbl = &recycleBinMenuVtbl;
510 This->cidl = cidl;
511 This->apidl = _ILCopyaPidl(apidl,cidl);
512 IShellFolder2_AddRef(folder);
513 This->folder = folder;
514 This->refCount = 1;
515 return &This->IContextMenu2_iface;
518 static HRESULT WINAPI RecycleBinMenu_QueryInterface(IContextMenu2 *iface,
519 REFIID riid,
520 void **ppvObject)
522 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
523 TRACE("(%p, %s, %p) - stub\n", This, debugstr_guid(riid), ppvObject);
524 return E_NOTIMPL;
527 static ULONG WINAPI RecycleBinMenu_AddRef(IContextMenu2 *iface)
529 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
530 TRACE("(%p)\n", This);
531 return InterlockedIncrement(&This->refCount);
535 static ULONG WINAPI RecycleBinMenu_Release(IContextMenu2 *iface)
537 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
538 UINT result;
539 TRACE("(%p)\n", This);
540 result = InterlockedDecrement(&This->refCount);
541 if (result == 0)
543 TRACE("Destroying object\n");
544 _ILFreeaPidl(This->apidl,This->cidl);
545 IShellFolder2_Release(This->folder);
546 SHFree(This);
548 return result;
551 static HRESULT WINAPI RecycleBinMenu_QueryContextMenu(IContextMenu2 *iface,
552 HMENU hmenu,
553 UINT indexMenu,
554 UINT idCmdFirst,
555 UINT idCmdLast,
556 UINT uFlags)
558 HMENU menures = LoadMenuW(shell32_hInstance,MAKEINTRESOURCEW(MENU_RECYCLEBIN));
559 if(uFlags & CMF_DEFAULTONLY)
560 return E_NOTIMPL;
561 else{
562 UINT idMax = Shell_MergeMenus(hmenu,GetSubMenu(menures,0),indexMenu,idCmdFirst,idCmdLast,MM_SUBMENUSHAVEIDS);
563 TRACE("Added %d id(s)\n",idMax-idCmdFirst);
564 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst+1);
568 static void DoErase(RecycleBinMenu *This)
570 ISFHelper *helper;
571 IShellFolder2_QueryInterface(This->folder,&IID_ISFHelper,(void**)&helper);
572 if(helper)
573 ISFHelper_DeleteItems(helper,This->cidl,(LPCITEMIDLIST*)This->apidl);
576 static void DoRestore(RecycleBinMenu *This)
579 /*TODO add prompts*/
580 UINT i;
581 for(i=0;i<This->cidl;i++)
583 const WIN32_FIND_DATAW *data = get_trash_item_data( This->apidl[i] );
585 if(PathFileExistsW(data->cFileName))
587 PIDLIST_ABSOLUTE dest_pidl = ILCreateFromPathW(data->cFileName);
588 WCHAR message[100];
589 WCHAR caption[50];
590 if(_ILIsFolder(ILFindLastID(dest_pidl)))
591 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_OVERWRITEFOLDER, message, ARRAY_SIZE(message));
592 else
593 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_OVERWRITEFILE, message, ARRAY_SIZE(message));
594 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_OVERWRITE_CAPTION, caption, ARRAY_SIZE(caption));
596 if(ShellMessageBoxW(shell32_hInstance,GetActiveWindow(),message,
597 caption,MB_YESNO|MB_ICONEXCLAMATION,
598 data->cFileName)!=IDYES)
599 continue;
601 if(SUCCEEDED(restore_trash_item(This->apidl[i])))
603 IPersistFolder2 *persist;
604 LPITEMIDLIST root_pidl;
605 PIDLIST_ABSOLUTE dest_pidl = ILCreateFromPathW(data->cFileName);
606 BOOL is_folder = _ILIsFolder(ILFindLastID(dest_pidl));
607 IShellFolder2_QueryInterface(This->folder,&IID_IPersistFolder2,
608 (void**)&persist);
609 IPersistFolder2_GetCurFolder(persist,&root_pidl);
610 SHChangeNotify(is_folder ? SHCNE_RMDIR : SHCNE_DELETE,
611 SHCNF_IDLIST,ILCombine(root_pidl,This->apidl[i]),0);
612 SHChangeNotify(is_folder ? SHCNE_MKDIR : SHCNE_CREATE,
613 SHCNF_IDLIST,dest_pidl,0);
614 ILFree(dest_pidl);
615 ILFree(root_pidl);
620 static HRESULT WINAPI RecycleBinMenu_InvokeCommand(IContextMenu2 *iface,
621 LPCMINVOKECOMMANDINFO pici)
623 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
624 LPCSTR verb = pici->lpVerb;
625 if(IS_INTRESOURCE(verb))
627 switch(LOWORD(verb))
629 case IDM_RECYCLEBIN_ERASE:
630 DoErase(This);
631 break;
632 case IDM_RECYCLEBIN_RESTORE:
633 DoRestore(This);
634 break;
635 default:
636 return E_NOTIMPL;
639 return S_OK;
642 static HRESULT WINAPI RecycleBinMenu_GetCommandString(IContextMenu2 *iface,
643 UINT_PTR idCmd,
644 UINT uType,
645 UINT *pwReserved,
646 LPSTR pszName,
647 UINT cchMax)
649 TRACE("(%p, %lu, %u, %p, %s, %u) - stub\n",iface,idCmd,uType,pwReserved,debugstr_a(pszName),cchMax);
650 return E_NOTIMPL;
653 static HRESULT WINAPI RecycleBinMenu_HandleMenuMsg(IContextMenu2 *iface,
654 UINT uMsg, WPARAM wParam,
655 LPARAM lParam)
657 TRACE("(%p, %u, 0x%lx, 0x%lx) - stub\n",iface,uMsg,wParam,lParam);
658 return E_NOTIMPL;
662 static const IContextMenu2Vtbl recycleBinMenuVtbl =
664 RecycleBinMenu_QueryInterface,
665 RecycleBinMenu_AddRef,
666 RecycleBinMenu_Release,
667 RecycleBinMenu_QueryContextMenu,
668 RecycleBinMenu_InvokeCommand,
669 RecycleBinMenu_GetCommandString,
670 RecycleBinMenu_HandleMenuMsg,
674 * Recycle Bin folder
677 typedef struct tagRecycleBin
679 IShellFolder2 IShellFolder2_iface;
680 IPersistFolder2 IPersistFolder2_iface;
681 ISFHelper ISFHelper_iface;
682 LONG refCount;
684 LPITEMIDLIST pidl;
685 } RecycleBin;
687 static const IShellFolder2Vtbl recycleBinVtbl;
688 static const IPersistFolder2Vtbl recycleBinPersistVtbl;
689 static const ISFHelperVtbl sfhelperVtbl;
691 static inline RecycleBin *impl_from_IShellFolder2(IShellFolder2 *iface)
693 return CONTAINING_RECORD(iface, RecycleBin, IShellFolder2_iface);
696 static RecycleBin *impl_from_IPersistFolder2(IPersistFolder2 *iface)
698 return CONTAINING_RECORD(iface, RecycleBin, IPersistFolder2_iface);
701 static RecycleBin *impl_from_ISFHelper(ISFHelper *iface)
703 return CONTAINING_RECORD(iface, RecycleBin, ISFHelper_iface);
706 static void RecycleBin_Destructor(RecycleBin *This);
708 HRESULT WINAPI RecycleBin_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput)
710 RecycleBin *obj;
711 HRESULT ret;
712 if (pUnkOuter)
713 return CLASS_E_NOAGGREGATION;
715 obj = SHAlloc(sizeof(RecycleBin));
716 if (obj == NULL)
717 return E_OUTOFMEMORY;
718 ZeroMemory(obj, sizeof(RecycleBin));
719 obj->IShellFolder2_iface.lpVtbl = &recycleBinVtbl;
720 obj->IPersistFolder2_iface.lpVtbl = &recycleBinPersistVtbl;
721 obj->ISFHelper_iface.lpVtbl = &sfhelperVtbl;
722 if (FAILED(ret = IPersistFolder2_QueryInterface(&obj->IPersistFolder2_iface, riid, ppOutput)))
724 RecycleBin_Destructor(obj);
725 return ret;
727 /* InterlockedIncrement(&objCount);*/
728 return S_OK;
731 static void RecycleBin_Destructor(RecycleBin *This)
733 /* InterlockedDecrement(&objCount);*/
734 SHFree(This->pidl);
735 SHFree(This);
738 static HRESULT WINAPI RecycleBin_QueryInterface(IShellFolder2 *iface, REFIID riid, void **ppvObject)
740 RecycleBin *This = impl_from_IShellFolder2(iface);
741 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
743 *ppvObject = NULL;
744 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IShellFolder)
745 || IsEqualGUID(riid, &IID_IShellFolder2))
746 *ppvObject = &This->IShellFolder2_iface;
748 if (IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistFolder)
749 || IsEqualGUID(riid, &IID_IPersistFolder2))
750 *ppvObject = &This->IPersistFolder2_iface;
751 if (IsEqualGUID(riid, &IID_ISFHelper))
752 *ppvObject = &This->ISFHelper_iface;
754 if (*ppvObject != NULL)
756 IUnknown_AddRef((IUnknown *)*ppvObject);
757 return S_OK;
759 WARN("no interface %s\n", debugstr_guid(riid));
760 return E_NOINTERFACE;
763 static ULONG WINAPI RecycleBin_AddRef(IShellFolder2 *iface)
765 RecycleBin *This = impl_from_IShellFolder2(iface);
766 TRACE("(%p)\n", This);
767 return InterlockedIncrement(&This->refCount);
770 static ULONG WINAPI RecycleBin_Release(IShellFolder2 *iface)
772 RecycleBin *This = impl_from_IShellFolder2(iface);
773 LONG result;
775 TRACE("(%p)\n", This);
776 result = InterlockedDecrement(&This->refCount);
777 if (result == 0)
779 TRACE("Destroy object\n");
780 RecycleBin_Destructor(This);
782 return result;
785 static HRESULT WINAPI RecycleBin_ParseDisplayName(IShellFolder2 *This, HWND hwnd, LPBC pbc,
786 LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl,
787 ULONG *pdwAttributes)
789 FIXME("stub\n");
790 return E_NOTIMPL;
793 static HRESULT WINAPI RecycleBin_EnumObjects(IShellFolder2 *iface, HWND hwnd, SHCONTF grfFlags, IEnumIDList **ppenumIDList)
795 RecycleBin *This = impl_from_IShellFolder2(iface);
796 IEnumIDListImpl *list;
797 LPITEMIDLIST *pidls;
798 HRESULT ret = E_OUTOFMEMORY;
799 int pidls_count = 0;
800 int i=0;
802 TRACE("(%p, %p, %x, %p)\n", This, hwnd, grfFlags, ppenumIDList);
804 *ppenumIDList = NULL;
805 list = IEnumIDList_Constructor();
806 if (!list)
807 return E_OUTOFMEMORY;
809 if (grfFlags & SHCONTF_NONFOLDERS)
811 if (FAILED(ret = enum_trash_items(&pidls, &pidls_count)))
812 goto failed;
813 for (i=0; i<pidls_count; i++)
814 if (!AddToEnumList(list, pidls[i]))
815 goto failed;
818 *ppenumIDList = &list->IEnumIDList_iface;
819 return S_OK;
821 failed:
822 IEnumIDList_Release(&list->IEnumIDList_iface);
823 for (; i<pidls_count; i++)
824 ILFree(pidls[i]);
825 SHFree(pidls);
826 return ret;
829 static HRESULT WINAPI RecycleBin_BindToObject(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
831 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
832 return E_NOTIMPL;
835 static HRESULT WINAPI RecycleBin_BindToStorage(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
837 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
838 return E_NOTIMPL;
841 static HRESULT WINAPI RecycleBin_CompareIDs(IShellFolder2 *iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
843 RecycleBin *This = impl_from_IShellFolder2(iface);
844 int ret;
846 /* TODO */
847 TRACE("(%p, %p, %p, %p)\n", This, (void *)lParam, pidl1, pidl2);
848 if (pidl1->mkid.cb != pidl2->mkid.cb)
849 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
850 /* Looks too complicated, but in optimized memcpy we might get
851 * a 32bit wide difference and would truncate it to 16 bit, so
852 * erroneously returning equality. */
853 ret = memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb);
854 if (ret < 0) ret = -1;
855 if (ret > 0) ret = 1;
856 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)ret);
859 static HRESULT WINAPI RecycleBin_CreateViewObject(IShellFolder2 *iface, HWND hwndOwner, REFIID riid, void **ppv)
861 RecycleBin *This = impl_from_IShellFolder2(iface);
862 HRESULT ret;
863 TRACE("(%p, %p, %s, %p)\n", This, hwndOwner, debugstr_guid(riid), ppv);
865 *ppv = NULL;
866 if (IsEqualGUID(riid, &IID_IShellView))
868 IShellView *tmp;
869 CSFV sfv;
871 ZeroMemory(&sfv, sizeof(sfv));
872 sfv.cbSize = sizeof(sfv);
873 sfv.pshf = (IShellFolder *)&This->IShellFolder2_iface;
875 TRACE("Calling SHCreateShellFolderViewEx\n");
876 ret = SHCreateShellFolderViewEx(&sfv, &tmp);
877 TRACE("Result: %08x, output: %p\n", (unsigned int)ret, tmp);
878 *ppv = tmp;
879 return ret;
881 else
882 FIXME("invalid/unsupported interface %s\n", debugstr_guid(riid));
884 return E_NOINTERFACE;
887 static HRESULT WINAPI RecycleBin_GetAttributesOf(IShellFolder2 *This, UINT cidl, LPCITEMIDLIST *apidl,
888 SFGAOF *rgfInOut)
890 TRACE("(%p, %d, {%p, ...}, {%x})\n", This, cidl, apidl[0], *rgfInOut);
891 *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM;
892 return S_OK;
895 static HRESULT WINAPI RecycleBin_GetUIObjectOf(IShellFolder2 *iface, HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
896 REFIID riid, UINT *rgfReserved, void **ppv)
898 RecycleBin *This = impl_from_IShellFolder2(iface);
899 *ppv = NULL;
900 if(IsEqualGUID(riid, &IID_IContextMenu) || IsEqualGUID(riid, &IID_IContextMenu2))
902 TRACE("(%p, %p, %d, {%p, ...}, %s, %p, %p)\n", This, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
903 *ppv = RecycleBinMenu_Constructor(cidl,apidl,&(This->IShellFolder2_iface));
904 return S_OK;
906 FIXME("(%p, %p, %d, {%p, ...}, %s, %p, %p): stub!\n", iface, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
908 return E_NOTIMPL;
911 static HRESULT WINAPI RecycleBin_GetDisplayNameOf(IShellFolder2 *This, LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName)
913 const WIN32_FIND_DATAW *data = get_trash_item_data( pidl );
915 TRACE("(%p, %p, %x, %p)\n", This, pidl, uFlags, pName);
916 pName->uType = STRRET_WSTR;
917 return SHStrDupW(PathFindFileNameW(data->cFileName), &pName->u.pOleStr);
920 static HRESULT WINAPI RecycleBin_SetNameOf(IShellFolder2 *This, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
921 SHGDNF uFlags, LPITEMIDLIST *ppidlOut)
923 TRACE("\n");
924 return E_FAIL; /* not supported */
927 static HRESULT WINAPI RecycleBin_GetClassID(IPersistFolder2 *This, CLSID *pClassID)
929 TRACE("(%p, %p)\n", This, pClassID);
930 if (This == NULL || pClassID == NULL)
931 return E_INVALIDARG;
932 *pClassID = CLSID_RecycleBin;
933 return S_OK;
936 static HRESULT WINAPI RecycleBin_Initialize(IPersistFolder2 *iface, LPCITEMIDLIST pidl)
938 RecycleBin *This = impl_from_IPersistFolder2(iface);
939 TRACE("(%p, %p)\n", This, pidl);
941 This->pidl = ILClone(pidl);
942 if (This->pidl == NULL)
943 return E_OUTOFMEMORY;
944 return S_OK;
947 static HRESULT WINAPI RecycleBin_GetCurFolder(IPersistFolder2 *iface, LPITEMIDLIST *ppidl)
949 RecycleBin *This = impl_from_IPersistFolder2(iface);
950 TRACE("\n");
951 *ppidl = ILClone(This->pidl);
952 return S_OK;
955 static HRESULT WINAPI RecycleBin_GetDefaultSearchGUID(IShellFolder2 *iface, GUID *guid)
957 RecycleBin *This = impl_from_IShellFolder2(iface);
958 TRACE("(%p)->(%p)\n", This, guid);
959 return E_NOTIMPL;
962 static HRESULT WINAPI RecycleBin_EnumSearches(IShellFolder2 *iface, IEnumExtraSearch **ppEnum)
964 FIXME("stub\n");
965 *ppEnum = NULL;
966 return E_NOTIMPL;
969 static HRESULT WINAPI RecycleBin_GetDefaultColumn(IShellFolder2 *iface, DWORD reserved, ULONG *sort, ULONG *display)
971 RecycleBin *This = impl_from_IShellFolder2(iface);
973 TRACE("(%p)->(%#x, %p, %p)\n", This, reserved, sort, display);
975 return E_NOTIMPL;
978 static HRESULT WINAPI RecycleBin_GetDefaultColumnState(IShellFolder2 *iface, UINT iColumn, SHCOLSTATEF *pcsFlags)
980 RecycleBin *This = impl_from_IShellFolder2(iface);
981 TRACE("(%p, %d, %p)\n", This, iColumn, pcsFlags);
982 if (iColumn >= COLUMNS_COUNT)
983 return E_INVALIDARG;
984 *pcsFlags = RecycleBinColumns[iColumn].pcsFlags;
985 return S_OK;
988 static HRESULT WINAPI RecycleBin_GetDetailsEx(IShellFolder2 *iface, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
990 FIXME("stub\n");
991 return E_NOTIMPL;
994 static HRESULT WINAPI RecycleBin_GetDetailsOf(IShellFolder2 *iface, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
996 RecycleBin *This = impl_from_IShellFolder2(iface);
997 const WIN32_FIND_DATAW *data;
998 WCHAR buffer[MAX_PATH];
1000 TRACE("(%p, %p, %d, %p)\n", This, pidl, iColumn, pDetails);
1001 if (iColumn >= COLUMNS_COUNT)
1002 return E_FAIL;
1004 if (!pidl) return SHELL32_GetColumnDetails( RecycleBinColumns, iColumn, pDetails );
1006 if (iColumn == COLUMN_NAME)
1007 return RecycleBin_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL, &pDetails->str);
1009 data = get_trash_item_data( pidl );
1010 switch (iColumn)
1012 case COLUMN_DATEDEL:
1013 FormatDateTime(buffer, MAX_PATH, data->ftLastAccessTime);
1014 break;
1015 case COLUMN_DELFROM:
1016 lstrcpyW(buffer, data->cFileName);
1017 PathRemoveFileSpecW(buffer);
1018 break;
1019 case COLUMN_SIZE:
1020 StrFormatKBSizeW(((LONGLONG)data->nFileSizeHigh<<32)|data->nFileSizeLow, buffer, MAX_PATH);
1021 break;
1022 case COLUMN_MTIME:
1023 FormatDateTime(buffer, MAX_PATH, data->ftLastWriteTime);
1024 break;
1025 case COLUMN_TYPE:
1026 /* TODO */
1027 buffer[0] = 0;
1028 break;
1029 default:
1030 return E_FAIL;
1033 pDetails->str.uType = STRRET_WSTR;
1034 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
1037 static HRESULT WINAPI RecycleBin_MapColumnToSCID(IShellFolder2 *iface, UINT iColumn, SHCOLUMNID *pscid)
1039 RecycleBin *This = impl_from_IShellFolder2(iface);
1040 TRACE("(%p, %d, %p)\n", This, iColumn, pscid);
1041 if (iColumn>=COLUMNS_COUNT)
1042 return E_INVALIDARG;
1044 return shellfolder_map_column_to_scid(RecycleBinColumns, iColumn, pscid);
1047 static const IShellFolder2Vtbl recycleBinVtbl =
1049 /* IUnknown */
1050 RecycleBin_QueryInterface,
1051 RecycleBin_AddRef,
1052 RecycleBin_Release,
1054 /* IShellFolder */
1055 RecycleBin_ParseDisplayName,
1056 RecycleBin_EnumObjects,
1057 RecycleBin_BindToObject,
1058 RecycleBin_BindToStorage,
1059 RecycleBin_CompareIDs,
1060 RecycleBin_CreateViewObject,
1061 RecycleBin_GetAttributesOf,
1062 RecycleBin_GetUIObjectOf,
1063 RecycleBin_GetDisplayNameOf,
1064 RecycleBin_SetNameOf,
1066 /* IShellFolder2 */
1067 RecycleBin_GetDefaultSearchGUID,
1068 RecycleBin_EnumSearches,
1069 RecycleBin_GetDefaultColumn,
1070 RecycleBin_GetDefaultColumnState,
1071 RecycleBin_GetDetailsEx,
1072 RecycleBin_GetDetailsOf,
1073 RecycleBin_MapColumnToSCID
1076 static HRESULT WINAPI RecycleBin_IPersistFolder2_QueryInterface(IPersistFolder2 *iface, REFIID riid,
1077 void **ppvObject)
1079 RecycleBin *This = impl_from_IPersistFolder2(iface);
1081 return IShellFolder2_QueryInterface(&This->IShellFolder2_iface, riid, ppvObject);
1084 static ULONG WINAPI RecycleBin_IPersistFolder2_AddRef(IPersistFolder2 *iface)
1086 RecycleBin *This = impl_from_IPersistFolder2(iface);
1088 return IShellFolder2_AddRef(&This->IShellFolder2_iface);
1091 static ULONG WINAPI RecycleBin_IPersistFolder2_Release(IPersistFolder2 *iface)
1093 RecycleBin *This = impl_from_IPersistFolder2(iface);
1095 return IShellFolder2_Release(&This->IShellFolder2_iface);
1098 static const IPersistFolder2Vtbl recycleBinPersistVtbl =
1100 /* IUnknown */
1101 RecycleBin_IPersistFolder2_QueryInterface,
1102 RecycleBin_IPersistFolder2_AddRef,
1103 RecycleBin_IPersistFolder2_Release,
1105 /* IPersist */
1106 RecycleBin_GetClassID,
1107 /* IPersistFolder */
1108 RecycleBin_Initialize,
1109 /* IPersistFolder2 */
1110 RecycleBin_GetCurFolder
1113 static HRESULT WINAPI RecycleBin_ISFHelper_QueryInterface(ISFHelper *iface, REFIID riid,
1114 void **ppvObject)
1116 RecycleBin *This = impl_from_ISFHelper(iface);
1118 return IShellFolder2_QueryInterface(&This->IShellFolder2_iface, riid, ppvObject);
1121 static ULONG WINAPI RecycleBin_ISFHelper_AddRef(ISFHelper *iface)
1123 RecycleBin *This = impl_from_ISFHelper(iface);
1125 return IShellFolder2_AddRef(&This->IShellFolder2_iface);
1128 static ULONG WINAPI RecycleBin_ISFHelper_Release(ISFHelper *iface)
1130 RecycleBin *This = impl_from_ISFHelper(iface);
1132 return IShellFolder2_Release(&This->IShellFolder2_iface);
1135 static HRESULT WINAPI RecycleBin_GetUniqueName(ISFHelper *iface,LPWSTR lpName,
1136 UINT uLen)
1138 return E_NOTIMPL;
1141 static HRESULT WINAPI RecycleBin_AddFolder(ISFHelper * iface, HWND hwnd,
1142 LPCWSTR pwszName,
1143 LPITEMIDLIST * ppidlOut)
1145 /*Adding folders doesn't make sense in the recycle bin*/
1146 return E_NOTIMPL;
1149 static HRESULT erase_items(HWND parent,const LPCITEMIDLIST * apidl, UINT cidl, BOOL confirm)
1151 UINT i=0;
1152 HRESULT ret = S_OK;
1153 LPITEMIDLIST recyclebin;
1155 if(confirm)
1157 WCHAR arg[MAX_PATH];
1158 WCHAR message[100];
1159 WCHAR caption[50];
1160 switch(cidl)
1162 case 0:
1163 return S_OK;
1164 case 1:
1166 const WIN32_FIND_DATAW *data = get_trash_item_data( apidl[0] );
1167 lstrcpynW(arg,data->cFileName,MAX_PATH);
1168 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_ERASEITEM, message, ARRAY_SIZE(message));
1169 break;
1171 default:
1173 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_ERASEMULTIPLE, message, ARRAY_SIZE(message));
1174 swprintf(arg, ARRAY_SIZE(arg), L"%u", cidl);
1175 break;
1179 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_ERASE_CAPTION, caption, ARRAY_SIZE(caption));
1180 if(ShellMessageBoxW(shell32_hInstance,parent,message,caption,
1181 MB_YESNO|MB_ICONEXCLAMATION,arg)!=IDYES)
1182 return ret;
1185 SHGetFolderLocation(parent,CSIDL_BITBUCKET,0,0,&recyclebin);
1186 for (; i<cidl; i++)
1188 if(SUCCEEDED(erase_trash_item(apidl[i])))
1189 SHChangeNotify(SHCNE_DELETE,SHCNF_IDLIST,
1190 ILCombine(recyclebin,apidl[i]),0);
1192 ILFree(recyclebin);
1193 return S_OK;
1196 static HRESULT WINAPI RecycleBin_DeleteItems(ISFHelper * iface, UINT cidl,
1197 LPCITEMIDLIST * apidl)
1199 TRACE("(%p,%u,%p)\n",iface,cidl,apidl);
1200 return erase_items(GetActiveWindow(),apidl,cidl,TRUE);
1203 static HRESULT WINAPI RecycleBin_CopyItems(ISFHelper * iface,
1204 IShellFolder * pSFFrom,
1205 UINT cidl, LPCITEMIDLIST * apidl)
1207 return E_NOTIMPL;
1210 static const ISFHelperVtbl sfhelperVtbl =
1212 RecycleBin_ISFHelper_QueryInterface,
1213 RecycleBin_ISFHelper_AddRef,
1214 RecycleBin_ISFHelper_Release,
1215 RecycleBin_GetUniqueName,
1216 RecycleBin_AddFolder,
1217 RecycleBin_DeleteItems,
1218 RecycleBin_CopyItems
1221 HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
1223 WCHAR wszRootPath[MAX_PATH];
1224 MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, wszRootPath, MAX_PATH);
1225 return SHQueryRecycleBinW(wszRootPath, pSHQueryRBInfo);
1228 HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
1230 LPITEMIDLIST *apidl;
1231 INT cidl;
1232 INT i=0;
1233 HRESULT hr;
1235 TRACE("(%s, %p)\n", debugstr_w(pszRootPath), pSHQueryRBInfo);
1237 hr = enum_trash_items(&apidl, &cidl);
1238 if (FAILED(hr))
1239 return hr;
1240 pSHQueryRBInfo->i64NumItems = cidl;
1241 pSHQueryRBInfo->i64Size = 0;
1242 for (; i<cidl; i++)
1244 const WIN32_FIND_DATAW *data = get_trash_item_data( apidl[i] );
1245 pSHQueryRBInfo->i64Size += ((DWORDLONG)data->nFileSizeHigh << 32) + data->nFileSizeLow;
1246 ILFree(apidl[i]);
1248 SHFree(apidl);
1249 return S_OK;
1252 HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
1254 WCHAR wszRootPath[MAX_PATH];
1255 MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, wszRootPath, MAX_PATH);
1256 return SHEmptyRecycleBinW(hwnd, wszRootPath, dwFlags);
1259 #define SHERB_NOCONFIRMATION 1
1260 #define SHERB_NOPROGRESSUI 2
1261 #define SHERB_NOSOUND 4
1263 HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
1265 LPITEMIDLIST *apidl;
1266 INT cidl;
1267 INT i=0;
1268 HRESULT ret;
1270 TRACE("(%p, %s, 0x%08x)\n", hwnd, debugstr_w(pszRootPath) , dwFlags);
1272 ret = enum_trash_items(&apidl, &cidl);
1273 if (FAILED(ret))
1274 return ret;
1276 ret = erase_items(hwnd,(const LPCITEMIDLIST*)apidl,cidl,!(dwFlags & SHERB_NOCONFIRMATION));
1277 for (;i<cidl;i++)
1278 ILFree(apidl[i]);
1279 SHFree(apidl);
1280 return ret;
1283 /*************************************************************************
1284 * SHUpdateRecycleBinIcon [SHELL32.@]
1286 * Undocumented
1288 HRESULT WINAPI SHUpdateRecycleBinIcon(void)
1290 FIXME("stub\n");
1291 return S_OK;