vbscript: Handle index read access to array properties.
[wine.git] / dlls / shell32 / recyclebin.c
blobcc3c6a3654ca0aafca1eb2dff2b43bfa763f29fe
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 *pidls = NULL;
396 file = heap_alloc( (lstrlenW(trash_dir) + lstrlenW(L"\\*") + 1) * sizeof(WCHAR) );
397 lstrcpyW( file, trash_dir );
398 lstrcatW( file, L"\\*" );
399 handle = FindFirstFileW( file, &data );
400 if (handle != INVALID_HANDLE_VALUE)
404 if (!wcscmp( data.cFileName, L"." )) continue;
405 if (!wcscmp( data.cFileName, L".." )) continue;
406 hr = add_trash_item( &data, &ret, &count, &size );
407 } while (hr == S_OK && FindNextFileW( handle, &data ));
408 FindClose( handle );
411 if (FAILED(hr)) while (count) SHFree( &ret[--count] );
412 else if (count)
414 *pidls = SHAlloc( count * sizeof(**pidls) );
415 memcpy( *pidls, ret, count * sizeof(**pidls) );
417 heap_free( ret );
418 *ret_count = count;
419 return hr;
422 static void remove_trashinfo( const WCHAR *filename )
424 WCHAR *info;
425 ULONG len;
427 if (!trash_info_dir) return;
428 len = lstrlenW(trash_info_dir) + lstrlenW(filename) + 12;
429 info = heap_alloc( len * sizeof(WCHAR) );
430 swprintf( info, len, L"%s\\%s.trashinfo", trash_info_dir, filename );
431 DeleteFileW( info );
432 heap_free( info );
435 static HRESULT restore_trash_item( LPCITEMIDLIST pidl )
437 const WIN32_FIND_DATAW *data = get_trash_item_data( pidl );
438 WCHAR *from, *filename = (WCHAR *)(data + 1);
439 ULONG len;
441 if (!wcschr( data->cFileName, '\\' ))
443 FIXME( "original name for %s not available\n", debugstr_w(data->cFileName) );
444 return E_NOTIMPL;
446 len = lstrlenW(trash_dir) + lstrlenW(filename) + 2;
447 from = heap_alloc( len * sizeof(WCHAR) );
448 swprintf( from, len, L"%s\\%s", trash_dir, filename );
449 if (MoveFileW( from, data->cFileName )) remove_trashinfo( filename );
450 else WARN( "failed to restore %s to %s\n", debugstr_w(from), debugstr_w(data->cFileName) );
451 heap_free( from );
452 return S_OK;
455 static HRESULT erase_trash_item( LPCITEMIDLIST pidl )
457 const WIN32_FIND_DATAW *data = get_trash_item_data( pidl );
458 WCHAR *from, *filename = (WCHAR *)(data + 1);
459 ULONG len = lstrlenW(trash_dir) + lstrlenW(filename) + 2;
461 from = heap_alloc( len * sizeof(WCHAR) );
462 swprintf( from, len, L"%s\\%s", trash_dir, filename );
463 if (DeleteFileW( from )) remove_trashinfo( filename );
464 heap_free( from );
465 return S_OK;
469 static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME ft)
471 FILETIME lft;
472 SYSTEMTIME time;
473 int ret;
475 FileTimeToLocalFileTime(&ft, &lft);
476 FileTimeToSystemTime(&lft, &time);
478 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size);
479 if (ret>0 && ret<size)
481 /* Append space + time without seconds */
482 buffer[ret-1] = ' ';
483 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret);
486 return (ret!=0 ? E_FAIL : S_OK);
489 typedef struct tagRecycleBinMenu
491 IContextMenu2 IContextMenu2_iface;
492 LONG refCount;
494 UINT cidl;
495 LPITEMIDLIST *apidl;
496 IShellFolder2 *folder;
497 } RecycleBinMenu;
499 static const IContextMenu2Vtbl recycleBinMenuVtbl;
501 static RecycleBinMenu *impl_from_IContextMenu2(IContextMenu2 *iface)
503 return CONTAINING_RECORD(iface, RecycleBinMenu, IContextMenu2_iface);
506 static IContextMenu2* RecycleBinMenu_Constructor(UINT cidl, LPCITEMIDLIST *apidl, IShellFolder2 *folder)
508 RecycleBinMenu *This = SHAlloc(sizeof(RecycleBinMenu));
509 TRACE("(%u,%p)\n",cidl,apidl);
510 This->IContextMenu2_iface.lpVtbl = &recycleBinMenuVtbl;
511 This->cidl = cidl;
512 This->apidl = _ILCopyaPidl(apidl,cidl);
513 IShellFolder2_AddRef(folder);
514 This->folder = folder;
515 This->refCount = 1;
516 return &This->IContextMenu2_iface;
519 static HRESULT WINAPI RecycleBinMenu_QueryInterface(IContextMenu2 *iface,
520 REFIID riid,
521 void **ppvObject)
523 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
524 TRACE("(%p, %s, %p) - stub\n", This, debugstr_guid(riid), ppvObject);
525 return E_NOTIMPL;
528 static ULONG WINAPI RecycleBinMenu_AddRef(IContextMenu2 *iface)
530 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
531 TRACE("(%p)\n", This);
532 return InterlockedIncrement(&This->refCount);
536 static ULONG WINAPI RecycleBinMenu_Release(IContextMenu2 *iface)
538 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
539 UINT result;
540 TRACE("(%p)\n", This);
541 result = InterlockedDecrement(&This->refCount);
542 if (result == 0)
544 TRACE("Destroying object\n");
545 _ILFreeaPidl(This->apidl,This->cidl);
546 IShellFolder2_Release(This->folder);
547 SHFree(This);
549 return result;
552 static HRESULT WINAPI RecycleBinMenu_QueryContextMenu(IContextMenu2 *iface,
553 HMENU hmenu,
554 UINT indexMenu,
555 UINT idCmdFirst,
556 UINT idCmdLast,
557 UINT uFlags)
559 HMENU menures = LoadMenuW(shell32_hInstance,MAKEINTRESOURCEW(MENU_RECYCLEBIN));
560 if(uFlags & CMF_DEFAULTONLY)
561 return E_NOTIMPL;
562 else{
563 UINT idMax = Shell_MergeMenus(hmenu,GetSubMenu(menures,0),indexMenu,idCmdFirst,idCmdLast,MM_SUBMENUSHAVEIDS);
564 TRACE("Added %d id(s)\n",idMax-idCmdFirst);
565 return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, idMax-idCmdFirst+1);
569 static void DoErase(RecycleBinMenu *This)
571 ISFHelper *helper;
572 IShellFolder2_QueryInterface(This->folder,&IID_ISFHelper,(void**)&helper);
573 if(helper)
574 ISFHelper_DeleteItems(helper,This->cidl,(LPCITEMIDLIST*)This->apidl);
577 static void DoRestore(RecycleBinMenu *This)
580 /*TODO add prompts*/
581 UINT i;
582 for(i=0;i<This->cidl;i++)
584 const WIN32_FIND_DATAW *data = get_trash_item_data( This->apidl[i] );
586 if(PathFileExistsW(data->cFileName))
588 PIDLIST_ABSOLUTE dest_pidl = ILCreateFromPathW(data->cFileName);
589 WCHAR message[100];
590 WCHAR caption[50];
591 if(_ILIsFolder(ILFindLastID(dest_pidl)))
592 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_OVERWRITEFOLDER, message, ARRAY_SIZE(message));
593 else
594 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_OVERWRITEFILE, message, ARRAY_SIZE(message));
595 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_OVERWRITE_CAPTION, caption, ARRAY_SIZE(caption));
597 if(ShellMessageBoxW(shell32_hInstance,GetActiveWindow(),message,
598 caption,MB_YESNO|MB_ICONEXCLAMATION,
599 data->cFileName)!=IDYES)
600 continue;
602 if(SUCCEEDED(restore_trash_item(This->apidl[i])))
604 IPersistFolder2 *persist;
605 LPITEMIDLIST root_pidl;
606 PIDLIST_ABSOLUTE dest_pidl = ILCreateFromPathW(data->cFileName);
607 BOOL is_folder = _ILIsFolder(ILFindLastID(dest_pidl));
608 IShellFolder2_QueryInterface(This->folder,&IID_IPersistFolder2,
609 (void**)&persist);
610 IPersistFolder2_GetCurFolder(persist,&root_pidl);
611 SHChangeNotify(is_folder ? SHCNE_RMDIR : SHCNE_DELETE,
612 SHCNF_IDLIST,ILCombine(root_pidl,This->apidl[i]),0);
613 SHChangeNotify(is_folder ? SHCNE_MKDIR : SHCNE_CREATE,
614 SHCNF_IDLIST,dest_pidl,0);
615 ILFree(dest_pidl);
616 ILFree(root_pidl);
621 static HRESULT WINAPI RecycleBinMenu_InvokeCommand(IContextMenu2 *iface,
622 LPCMINVOKECOMMANDINFO pici)
624 RecycleBinMenu *This = impl_from_IContextMenu2(iface);
625 LPCSTR verb = pici->lpVerb;
626 if(IS_INTRESOURCE(verb))
628 switch(LOWORD(verb))
630 case IDM_RECYCLEBIN_ERASE:
631 DoErase(This);
632 break;
633 case IDM_RECYCLEBIN_RESTORE:
634 DoRestore(This);
635 break;
636 default:
637 return E_NOTIMPL;
640 return S_OK;
643 static HRESULT WINAPI RecycleBinMenu_GetCommandString(IContextMenu2 *iface,
644 UINT_PTR idCmd,
645 UINT uType,
646 UINT *pwReserved,
647 LPSTR pszName,
648 UINT cchMax)
650 TRACE("(%p, %Iu, %u, %p, %s, %u) - stub\n",iface,idCmd,uType,pwReserved,debugstr_a(pszName),cchMax);
651 return E_NOTIMPL;
654 static HRESULT WINAPI RecycleBinMenu_HandleMenuMsg(IContextMenu2 *iface,
655 UINT uMsg, WPARAM wParam,
656 LPARAM lParam)
658 TRACE("(%p, %u, 0x%Ix, 0x%Ix) - stub\n",iface,uMsg,wParam,lParam);
659 return E_NOTIMPL;
663 static const IContextMenu2Vtbl recycleBinMenuVtbl =
665 RecycleBinMenu_QueryInterface,
666 RecycleBinMenu_AddRef,
667 RecycleBinMenu_Release,
668 RecycleBinMenu_QueryContextMenu,
669 RecycleBinMenu_InvokeCommand,
670 RecycleBinMenu_GetCommandString,
671 RecycleBinMenu_HandleMenuMsg,
675 * Recycle Bin folder
678 typedef struct tagRecycleBin
680 IShellFolder2 IShellFolder2_iface;
681 IPersistFolder2 IPersistFolder2_iface;
682 ISFHelper ISFHelper_iface;
683 LONG refCount;
685 LPITEMIDLIST pidl;
686 } RecycleBin;
688 static const IShellFolder2Vtbl recycleBinVtbl;
689 static const IPersistFolder2Vtbl recycleBinPersistVtbl;
690 static const ISFHelperVtbl sfhelperVtbl;
692 static inline RecycleBin *impl_from_IShellFolder2(IShellFolder2 *iface)
694 return CONTAINING_RECORD(iface, RecycleBin, IShellFolder2_iface);
697 static RecycleBin *impl_from_IPersistFolder2(IPersistFolder2 *iface)
699 return CONTAINING_RECORD(iface, RecycleBin, IPersistFolder2_iface);
702 static RecycleBin *impl_from_ISFHelper(ISFHelper *iface)
704 return CONTAINING_RECORD(iface, RecycleBin, ISFHelper_iface);
707 static void RecycleBin_Destructor(RecycleBin *This);
709 HRESULT WINAPI RecycleBin_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput)
711 RecycleBin *obj;
712 HRESULT ret;
713 if (pUnkOuter)
714 return CLASS_E_NOAGGREGATION;
716 obj = SHAlloc(sizeof(RecycleBin));
717 if (obj == NULL)
718 return E_OUTOFMEMORY;
719 ZeroMemory(obj, sizeof(RecycleBin));
720 obj->IShellFolder2_iface.lpVtbl = &recycleBinVtbl;
721 obj->IPersistFolder2_iface.lpVtbl = &recycleBinPersistVtbl;
722 obj->ISFHelper_iface.lpVtbl = &sfhelperVtbl;
723 if (FAILED(ret = IPersistFolder2_QueryInterface(&obj->IPersistFolder2_iface, riid, ppOutput)))
725 RecycleBin_Destructor(obj);
726 return ret;
728 /* InterlockedIncrement(&objCount);*/
729 return S_OK;
732 static void RecycleBin_Destructor(RecycleBin *This)
734 /* InterlockedDecrement(&objCount);*/
735 SHFree(This->pidl);
736 SHFree(This);
739 static HRESULT WINAPI RecycleBin_QueryInterface(IShellFolder2 *iface, REFIID riid, void **ppvObject)
741 RecycleBin *This = impl_from_IShellFolder2(iface);
742 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
744 *ppvObject = NULL;
745 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IShellFolder)
746 || IsEqualGUID(riid, &IID_IShellFolder2))
747 *ppvObject = &This->IShellFolder2_iface;
749 if (IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistFolder)
750 || IsEqualGUID(riid, &IID_IPersistFolder2))
751 *ppvObject = &This->IPersistFolder2_iface;
752 if (IsEqualGUID(riid, &IID_ISFHelper))
753 *ppvObject = &This->ISFHelper_iface;
755 if (*ppvObject != NULL)
757 IUnknown_AddRef((IUnknown *)*ppvObject);
758 return S_OK;
760 WARN("no interface %s\n", debugstr_guid(riid));
761 return E_NOINTERFACE;
764 static ULONG WINAPI RecycleBin_AddRef(IShellFolder2 *iface)
766 RecycleBin *This = impl_from_IShellFolder2(iface);
767 TRACE("(%p)\n", This);
768 return InterlockedIncrement(&This->refCount);
771 static ULONG WINAPI RecycleBin_Release(IShellFolder2 *iface)
773 RecycleBin *This = impl_from_IShellFolder2(iface);
774 LONG result;
776 TRACE("(%p)\n", This);
777 result = InterlockedDecrement(&This->refCount);
778 if (result == 0)
780 TRACE("Destroy object\n");
781 RecycleBin_Destructor(This);
783 return result;
786 static HRESULT WINAPI RecycleBin_ParseDisplayName(IShellFolder2 *This, HWND hwnd, LPBC pbc,
787 LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl,
788 ULONG *pdwAttributes)
790 FIXME("stub\n");
791 return E_NOTIMPL;
794 static HRESULT WINAPI RecycleBin_EnumObjects(IShellFolder2 *iface, HWND hwnd, SHCONTF grfFlags, IEnumIDList **ppenumIDList)
796 RecycleBin *This = impl_from_IShellFolder2(iface);
797 IEnumIDListImpl *list;
798 LPITEMIDLIST *pidls;
799 HRESULT ret = E_OUTOFMEMORY;
800 int pidls_count = 0;
801 int i=0;
803 TRACE("(%p, %p, %lx, %p)\n", This, hwnd, grfFlags, ppenumIDList);
805 *ppenumIDList = NULL;
806 list = IEnumIDList_Constructor();
807 if (!list)
808 return E_OUTOFMEMORY;
810 if (grfFlags & SHCONTF_NONFOLDERS)
812 if (FAILED(ret = enum_trash_items(&pidls, &pidls_count)))
813 goto failed;
814 for (i=0; i<pidls_count; i++)
815 if (!AddToEnumList(list, pidls[i]))
816 goto failed;
819 *ppenumIDList = &list->IEnumIDList_iface;
820 return S_OK;
822 failed:
823 IEnumIDList_Release(&list->IEnumIDList_iface);
824 for (; i<pidls_count; i++)
825 ILFree(pidls[i]);
826 SHFree(pidls);
827 return ret;
830 static HRESULT WINAPI RecycleBin_BindToObject(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
832 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
833 return E_NOTIMPL;
836 static HRESULT WINAPI RecycleBin_BindToStorage(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
838 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
839 return E_NOTIMPL;
842 static HRESULT WINAPI RecycleBin_CompareIDs(IShellFolder2 *iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
844 RecycleBin *This = impl_from_IShellFolder2(iface);
845 int ret;
847 /* TODO */
848 TRACE("(%p, %p, %p, %p)\n", This, (void *)lParam, pidl1, pidl2);
849 if (pidl1->mkid.cb != pidl2->mkid.cb)
850 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
851 /* Looks too complicated, but in optimized memcpy we might get
852 * a 32bit wide difference and would truncate it to 16 bit, so
853 * erroneously returning equality. */
854 ret = memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb);
855 if (ret < 0) ret = -1;
856 if (ret > 0) ret = 1;
857 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)ret);
860 static HRESULT WINAPI RecycleBin_CreateViewObject(IShellFolder2 *iface, HWND hwndOwner, REFIID riid, void **ppv)
862 RecycleBin *This = impl_from_IShellFolder2(iface);
863 HRESULT ret;
864 TRACE("(%p, %p, %s, %p)\n", This, hwndOwner, debugstr_guid(riid), ppv);
866 *ppv = NULL;
867 if (IsEqualGUID(riid, &IID_IShellView))
869 IShellView *tmp;
870 CSFV sfv;
872 ZeroMemory(&sfv, sizeof(sfv));
873 sfv.cbSize = sizeof(sfv);
874 sfv.pshf = (IShellFolder *)&This->IShellFolder2_iface;
876 TRACE("Calling SHCreateShellFolderViewEx\n");
877 ret = SHCreateShellFolderViewEx(&sfv, &tmp);
878 TRACE("Result: %08x, output: %p\n", (unsigned int)ret, tmp);
879 *ppv = tmp;
880 return ret;
882 else
883 FIXME("invalid/unsupported interface %s\n", debugstr_guid(riid));
885 return E_NOINTERFACE;
888 static HRESULT WINAPI RecycleBin_GetAttributesOf(IShellFolder2 *This, UINT cidl, LPCITEMIDLIST *apidl,
889 SFGAOF *rgfInOut)
891 TRACE("(%p, %d, {%p, ...}, {%lx})\n", This, cidl, apidl[0], *rgfInOut);
892 *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM;
893 return S_OK;
896 static HRESULT WINAPI RecycleBin_GetUIObjectOf(IShellFolder2 *iface, HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
897 REFIID riid, UINT *rgfReserved, void **ppv)
899 RecycleBin *This = impl_from_IShellFolder2(iface);
900 *ppv = NULL;
901 if(IsEqualGUID(riid, &IID_IContextMenu) || IsEqualGUID(riid, &IID_IContextMenu2))
903 TRACE("(%p, %p, %d, {%p, ...}, %s, %p, %p)\n", This, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
904 *ppv = RecycleBinMenu_Constructor(cidl,apidl,&(This->IShellFolder2_iface));
905 return S_OK;
907 FIXME("(%p, %p, %d, {%p, ...}, %s, %p, %p): stub!\n", iface, hwndOwner, cidl, apidl[0], debugstr_guid(riid), rgfReserved, ppv);
909 return E_NOTIMPL;
912 static HRESULT WINAPI RecycleBin_GetDisplayNameOf(IShellFolder2 *This, LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName)
914 const WIN32_FIND_DATAW *data = get_trash_item_data( pidl );
916 TRACE("(%p, %p, %lx, %p)\n", This, pidl, uFlags, pName);
917 pName->uType = STRRET_WSTR;
918 return SHStrDupW(PathFindFileNameW(data->cFileName), &pName->u.pOleStr);
921 static HRESULT WINAPI RecycleBin_SetNameOf(IShellFolder2 *This, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
922 SHGDNF uFlags, LPITEMIDLIST *ppidlOut)
924 TRACE("\n");
925 return E_FAIL; /* not supported */
928 static HRESULT WINAPI RecycleBin_GetClassID(IPersistFolder2 *This, CLSID *pClassID)
930 TRACE("(%p, %p)\n", This, pClassID);
931 if (This == NULL || pClassID == NULL)
932 return E_INVALIDARG;
933 *pClassID = CLSID_RecycleBin;
934 return S_OK;
937 static HRESULT WINAPI RecycleBin_Initialize(IPersistFolder2 *iface, LPCITEMIDLIST pidl)
939 RecycleBin *This = impl_from_IPersistFolder2(iface);
940 TRACE("(%p, %p)\n", This, pidl);
942 This->pidl = ILClone(pidl);
943 if (This->pidl == NULL)
944 return E_OUTOFMEMORY;
945 return S_OK;
948 static HRESULT WINAPI RecycleBin_GetCurFolder(IPersistFolder2 *iface, LPITEMIDLIST *ppidl)
950 RecycleBin *This = impl_from_IPersistFolder2(iface);
951 TRACE("\n");
952 *ppidl = ILClone(This->pidl);
953 return S_OK;
956 static HRESULT WINAPI RecycleBin_GetDefaultSearchGUID(IShellFolder2 *iface, GUID *guid)
958 RecycleBin *This = impl_from_IShellFolder2(iface);
959 TRACE("(%p)->(%p)\n", This, guid);
960 return E_NOTIMPL;
963 static HRESULT WINAPI RecycleBin_EnumSearches(IShellFolder2 *iface, IEnumExtraSearch **ppEnum)
965 FIXME("stub\n");
966 *ppEnum = NULL;
967 return E_NOTIMPL;
970 static HRESULT WINAPI RecycleBin_GetDefaultColumn(IShellFolder2 *iface, DWORD reserved, ULONG *sort, ULONG *display)
972 RecycleBin *This = impl_from_IShellFolder2(iface);
974 TRACE("(%p)->(%#lx, %p, %p)\n", This, reserved, sort, display);
976 return E_NOTIMPL;
979 static HRESULT WINAPI RecycleBin_GetDefaultColumnState(IShellFolder2 *iface, UINT iColumn, SHCOLSTATEF *pcsFlags)
981 RecycleBin *This = impl_from_IShellFolder2(iface);
982 TRACE("(%p, %d, %p)\n", This, iColumn, pcsFlags);
983 if (iColumn >= COLUMNS_COUNT)
984 return E_INVALIDARG;
985 *pcsFlags = RecycleBinColumns[iColumn].pcsFlags;
986 return S_OK;
989 static HRESULT WINAPI RecycleBin_GetDetailsEx(IShellFolder2 *iface, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
991 FIXME("stub\n");
992 return E_NOTIMPL;
995 static HRESULT WINAPI RecycleBin_GetDetailsOf(IShellFolder2 *iface, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
997 RecycleBin *This = impl_from_IShellFolder2(iface);
998 const WIN32_FIND_DATAW *data;
999 WCHAR buffer[MAX_PATH];
1001 TRACE("(%p, %p, %d, %p)\n", This, pidl, iColumn, pDetails);
1002 if (iColumn >= COLUMNS_COUNT)
1003 return E_FAIL;
1005 if (!pidl) return SHELL32_GetColumnDetails( RecycleBinColumns, iColumn, pDetails );
1007 if (iColumn == COLUMN_NAME)
1008 return RecycleBin_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL, &pDetails->str);
1010 data = get_trash_item_data( pidl );
1011 switch (iColumn)
1013 case COLUMN_DATEDEL:
1014 FormatDateTime(buffer, MAX_PATH, data->ftLastAccessTime);
1015 break;
1016 case COLUMN_DELFROM:
1017 lstrcpyW(buffer, data->cFileName);
1018 PathRemoveFileSpecW(buffer);
1019 break;
1020 case COLUMN_SIZE:
1021 StrFormatKBSizeW(((LONGLONG)data->nFileSizeHigh<<32)|data->nFileSizeLow, buffer, MAX_PATH);
1022 break;
1023 case COLUMN_MTIME:
1024 FormatDateTime(buffer, MAX_PATH, data->ftLastWriteTime);
1025 break;
1026 case COLUMN_TYPE:
1027 /* TODO */
1028 buffer[0] = 0;
1029 break;
1030 default:
1031 return E_FAIL;
1034 pDetails->str.uType = STRRET_WSTR;
1035 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
1038 static HRESULT WINAPI RecycleBin_MapColumnToSCID(IShellFolder2 *iface, UINT iColumn, SHCOLUMNID *pscid)
1040 RecycleBin *This = impl_from_IShellFolder2(iface);
1041 TRACE("(%p, %d, %p)\n", This, iColumn, pscid);
1042 if (iColumn>=COLUMNS_COUNT)
1043 return E_INVALIDARG;
1045 return shellfolder_map_column_to_scid(RecycleBinColumns, iColumn, pscid);
1048 static const IShellFolder2Vtbl recycleBinVtbl =
1050 /* IUnknown */
1051 RecycleBin_QueryInterface,
1052 RecycleBin_AddRef,
1053 RecycleBin_Release,
1055 /* IShellFolder */
1056 RecycleBin_ParseDisplayName,
1057 RecycleBin_EnumObjects,
1058 RecycleBin_BindToObject,
1059 RecycleBin_BindToStorage,
1060 RecycleBin_CompareIDs,
1061 RecycleBin_CreateViewObject,
1062 RecycleBin_GetAttributesOf,
1063 RecycleBin_GetUIObjectOf,
1064 RecycleBin_GetDisplayNameOf,
1065 RecycleBin_SetNameOf,
1067 /* IShellFolder2 */
1068 RecycleBin_GetDefaultSearchGUID,
1069 RecycleBin_EnumSearches,
1070 RecycleBin_GetDefaultColumn,
1071 RecycleBin_GetDefaultColumnState,
1072 RecycleBin_GetDetailsEx,
1073 RecycleBin_GetDetailsOf,
1074 RecycleBin_MapColumnToSCID
1077 static HRESULT WINAPI RecycleBin_IPersistFolder2_QueryInterface(IPersistFolder2 *iface, REFIID riid,
1078 void **ppvObject)
1080 RecycleBin *This = impl_from_IPersistFolder2(iface);
1082 return IShellFolder2_QueryInterface(&This->IShellFolder2_iface, riid, ppvObject);
1085 static ULONG WINAPI RecycleBin_IPersistFolder2_AddRef(IPersistFolder2 *iface)
1087 RecycleBin *This = impl_from_IPersistFolder2(iface);
1089 return IShellFolder2_AddRef(&This->IShellFolder2_iface);
1092 static ULONG WINAPI RecycleBin_IPersistFolder2_Release(IPersistFolder2 *iface)
1094 RecycleBin *This = impl_from_IPersistFolder2(iface);
1096 return IShellFolder2_Release(&This->IShellFolder2_iface);
1099 static const IPersistFolder2Vtbl recycleBinPersistVtbl =
1101 /* IUnknown */
1102 RecycleBin_IPersistFolder2_QueryInterface,
1103 RecycleBin_IPersistFolder2_AddRef,
1104 RecycleBin_IPersistFolder2_Release,
1106 /* IPersist */
1107 RecycleBin_GetClassID,
1108 /* IPersistFolder */
1109 RecycleBin_Initialize,
1110 /* IPersistFolder2 */
1111 RecycleBin_GetCurFolder
1114 static HRESULT WINAPI RecycleBin_ISFHelper_QueryInterface(ISFHelper *iface, REFIID riid,
1115 void **ppvObject)
1117 RecycleBin *This = impl_from_ISFHelper(iface);
1119 return IShellFolder2_QueryInterface(&This->IShellFolder2_iface, riid, ppvObject);
1122 static ULONG WINAPI RecycleBin_ISFHelper_AddRef(ISFHelper *iface)
1124 RecycleBin *This = impl_from_ISFHelper(iface);
1126 return IShellFolder2_AddRef(&This->IShellFolder2_iface);
1129 static ULONG WINAPI RecycleBin_ISFHelper_Release(ISFHelper *iface)
1131 RecycleBin *This = impl_from_ISFHelper(iface);
1133 return IShellFolder2_Release(&This->IShellFolder2_iface);
1136 static HRESULT WINAPI RecycleBin_GetUniqueName(ISFHelper *iface,LPWSTR lpName,
1137 UINT uLen)
1139 return E_NOTIMPL;
1142 static HRESULT WINAPI RecycleBin_AddFolder(ISFHelper * iface, HWND hwnd,
1143 LPCWSTR pwszName,
1144 LPITEMIDLIST * ppidlOut)
1146 /*Adding folders doesn't make sense in the recycle bin*/
1147 return E_NOTIMPL;
1150 static HRESULT erase_items(HWND parent,const LPCITEMIDLIST * apidl, UINT cidl, BOOL confirm)
1152 UINT i=0;
1153 HRESULT ret = S_OK;
1154 LPITEMIDLIST recyclebin;
1156 if(confirm)
1158 WCHAR arg[MAX_PATH];
1159 WCHAR message[100];
1160 WCHAR caption[50];
1161 switch(cidl)
1163 case 0:
1164 return S_OK;
1165 case 1:
1167 const WIN32_FIND_DATAW *data = get_trash_item_data( apidl[0] );
1168 lstrcpynW(arg,data->cFileName,MAX_PATH);
1169 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_ERASEITEM, message, ARRAY_SIZE(message));
1170 break;
1172 default:
1174 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_ERASEMULTIPLE, message, ARRAY_SIZE(message));
1175 swprintf(arg, ARRAY_SIZE(arg), L"%u", cidl);
1176 break;
1180 LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_ERASE_CAPTION, caption, ARRAY_SIZE(caption));
1181 if(ShellMessageBoxW(shell32_hInstance,parent,message,caption,
1182 MB_YESNO|MB_ICONEXCLAMATION,arg)!=IDYES)
1183 return ret;
1186 SHGetFolderLocation(parent,CSIDL_BITBUCKET,0,0,&recyclebin);
1187 for (; i<cidl; i++)
1189 if(SUCCEEDED(erase_trash_item(apidl[i])))
1190 SHChangeNotify(SHCNE_DELETE,SHCNF_IDLIST,
1191 ILCombine(recyclebin,apidl[i]),0);
1193 ILFree(recyclebin);
1194 return S_OK;
1197 static HRESULT WINAPI RecycleBin_DeleteItems(ISFHelper * iface, UINT cidl,
1198 LPCITEMIDLIST * apidl)
1200 TRACE("(%p,%u,%p)\n",iface,cidl,apidl);
1201 return erase_items(GetActiveWindow(),apidl,cidl,TRUE);
1204 static HRESULT WINAPI RecycleBin_CopyItems(ISFHelper * iface,
1205 IShellFolder * pSFFrom,
1206 UINT cidl, LPCITEMIDLIST * apidl)
1208 return E_NOTIMPL;
1211 static const ISFHelperVtbl sfhelperVtbl =
1213 RecycleBin_ISFHelper_QueryInterface,
1214 RecycleBin_ISFHelper_AddRef,
1215 RecycleBin_ISFHelper_Release,
1216 RecycleBin_GetUniqueName,
1217 RecycleBin_AddFolder,
1218 RecycleBin_DeleteItems,
1219 RecycleBin_CopyItems
1222 HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
1224 WCHAR wszRootPath[MAX_PATH];
1225 MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, wszRootPath, MAX_PATH);
1226 return SHQueryRecycleBinW(wszRootPath, pSHQueryRBInfo);
1229 HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
1231 LPITEMIDLIST *apidl;
1232 INT cidl;
1233 INT i=0;
1234 HRESULT hr;
1236 TRACE("(%s, %p)\n", debugstr_w(pszRootPath), pSHQueryRBInfo);
1238 hr = enum_trash_items(&apidl, &cidl);
1239 if (FAILED(hr))
1240 return hr;
1241 pSHQueryRBInfo->i64NumItems = cidl;
1242 pSHQueryRBInfo->i64Size = 0;
1243 for (; i<cidl; i++)
1245 const WIN32_FIND_DATAW *data = get_trash_item_data( apidl[i] );
1246 pSHQueryRBInfo->i64Size += ((DWORDLONG)data->nFileSizeHigh << 32) + data->nFileSizeLow;
1247 ILFree(apidl[i]);
1249 SHFree(apidl);
1250 return S_OK;
1253 HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
1255 WCHAR wszRootPath[MAX_PATH];
1256 MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, wszRootPath, MAX_PATH);
1257 return SHEmptyRecycleBinW(hwnd, wszRootPath, dwFlags);
1260 #define SHERB_NOCONFIRMATION 1
1261 #define SHERB_NOPROGRESSUI 2
1262 #define SHERB_NOSOUND 4
1264 HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
1266 LPITEMIDLIST *apidl;
1267 INT cidl;
1268 INT i=0;
1269 HRESULT ret;
1271 TRACE("(%p, %s, 0x%08lx)\n", hwnd, debugstr_w(pszRootPath) , dwFlags);
1273 ret = enum_trash_items(&apidl, &cidl);
1274 if (FAILED(ret))
1275 return ret;
1277 ret = erase_items(hwnd,(const LPCITEMIDLIST*)apidl,cidl,!(dwFlags & SHERB_NOCONFIRMATION));
1278 for (;i<cidl;i++)
1279 ILFree(apidl[i]);
1280 SHFree(apidl);
1281 return ret;
1284 /*************************************************************************
1285 * SHUpdateRecycleBinIcon [SHELL32.@]
1287 * Undocumented
1289 HRESULT WINAPI SHUpdateRecycleBinIcon(void)
1291 FIXME("stub\n");
1292 return S_OK;