Revert an unwanted change from r66575.
[reactos.git] / reactos / dll / win32 / shell32 / shfldr_recyclebin.c
1 /*
2 * Trash virtual folder support. The trashing engine is implemented in trash.c
3 *
4 * Copyright (C) 2006 Mikolaj Zalewski
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #define MAX_PROPERTY_SHEET_PAGE 32
22
23 #include <precomp.h>
24
25 WINE_DEFAULT_DEBUG_CHANNEL(recyclebin);
26
27 typedef struct
28 {
29 int column_name_id;
30 const GUID *fmtId;
31 DWORD pid;
32 int pcsFlags;
33 int fmt;
34 int cxChars;
35 } columninfo;
36
37 static const columninfo RecycleBinColumns[] =
38 {
39 {IDS_SHV_COLUMN1, &FMTID_Storage, PID_STG_NAME, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
40 {IDS_SHV_COLUMN_DELFROM, &FMTID_Displaced, PID_DISPLACED_FROM, SHCOLSTATE_TYPE_STR|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 30},
41 {IDS_SHV_COLUMN_DELDATE, &FMTID_Displaced, PID_DISPLACED_DATE, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
42 {IDS_SHV_COLUMN2, &FMTID_Storage, PID_STG_SIZE, SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20},
43 {IDS_SHV_COLUMN3, &FMTID_Storage, PID_STG_STORAGETYPE,SHCOLSTATE_TYPE_INT|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
44 {IDS_SHV_COLUMN4, &FMTID_Storage, PID_STG_WRITETIME, SHCOLSTATE_TYPE_DATE|SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20},
45 /* {"creation time", &FMTID_Storage, PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE, LVCFMT_LEFT, 20}, */
46 /* {"attribs", &FMTID_Storage, PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 20}, */
47 };
48
49 #define COLUMN_NAME 0
50 #define COLUMN_DELFROM 1
51 #define COLUMN_DATEDEL 2
52 #define COLUMN_SIZE 3
53 #define COLUMN_TYPE 4
54 #define COLUMN_MTIME 5
55
56 #define COLUMNS_COUNT 6
57
58 /*
59 * Recycle Bin folder
60 */
61
62 typedef struct tagRecycleBin
63 {
64 const IShellFolder2Vtbl *lpVtbl;
65 const IPersistFolder2Vtbl *lpPersistFolderVtbl;
66 const IContextMenu2Vtbl *lpContextMenu2;
67 const IShellExtInitVtbl *lpSEI;
68 LONG refCount;
69 INT iIdEmpty;
70 LPITEMIDLIST pidl;
71 LPCITEMIDLIST apidl;
72 } RecycleBin, *LPRecycleBin;
73
74 typedef struct
75 {
76 PIDLRecycleStruct *pFileDetails;
77 HANDLE hDeletedFile;
78 BOOL bFound;
79 }SEARCH_CONTEXT, *PSEARCH_CONTEXT;
80
81 typedef struct
82 {
83 DWORD dwNukeOnDelete;
84 DWORD dwSerial;
85 DWORD dwMaxCapacity;
86 }DRIVE_ITEM_CONTEXT, *PDRIVE_ITEM_CONTEXT;
87
88
89 static const IContextMenu2Vtbl recycleBincmVtblFolder;
90 static const IContextMenu2Vtbl recycleBincmVtblBitbucketItem;
91 static const IShellFolder2Vtbl recycleBinVtbl;
92 static const IPersistFolder2Vtbl recycleBinPersistVtbl;
93 static const IShellExtInitVtbl eivt;
94
95 static LPRecycleBin __inline impl_from_IContextMenu2(IContextMenu2 *iface)
96 {
97 return (RecycleBin *)((char *)iface - FIELD_OFFSET(RecycleBin, lpContextMenu2));
98 }
99
100 static LPRecycleBin __inline impl_from_IPersistFolder(IPersistFolder2 *iface)
101 {
102 return (RecycleBin *)((char *)iface - FIELD_OFFSET(RecycleBin, lpPersistFolderVtbl));
103 }
104
105 static LPRecycleBin __inline impl_from_IShellExtInit( IShellExtInit *iface )
106 {
107 return (RecycleBin *)((char*)iface - FIELD_OFFSET(RecycleBin, lpSEI));
108 }
109
110 static void RecycleBin_Destructor(RecycleBin *This);
111
112 HRESULT WINAPI RecycleBin_Constructor(IUnknown *pUnkOuter, REFIID riid, LPVOID *ppOutput)
113 {
114 RecycleBin *obj;
115 HRESULT ret;
116 if (pUnkOuter)
117 return CLASS_E_NOAGGREGATION;
118
119 obj = SHAlloc(sizeof(RecycleBin));
120 if (obj == NULL)
121 return E_OUTOFMEMORY;
122 ZeroMemory(obj, sizeof(RecycleBin));
123 obj->lpVtbl = &recycleBinVtbl;
124 obj->lpSEI = &eivt;
125 obj->lpPersistFolderVtbl = &recycleBinPersistVtbl;
126 obj->lpContextMenu2 = NULL;
127 if (FAILED(ret = IUnknown_QueryInterface((IUnknown *)obj, riid, ppOutput)))
128 {
129 RecycleBin_Destructor(obj);
130 return ret;
131 }
132 /* InterlockedIncrement(&objCount);*/
133 return S_OK;
134 }
135
136 static void RecycleBin_Destructor(RecycleBin *This)
137 {
138 /* InterlockedDecrement(&objCount);*/
139 SHFree(This->pidl);
140 SHFree(This);
141 }
142
143 static HRESULT WINAPI RecycleBin_QueryInterface(IShellFolder2 *iface, REFIID riid, void **ppvObject)
144 {
145 RecycleBin *This = (RecycleBin *)iface;
146 TRACE("(%p, %s, %p)\n", This, debugstr_guid(riid), ppvObject);
147
148 *ppvObject = NULL;
149 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IShellFolder)
150 || IsEqualGUID(riid, &IID_IShellFolder2))
151 *ppvObject = This;
152
153 if (IsEqualGUID(riid, &IID_IPersist) || IsEqualGUID(riid, &IID_IPersistFolder)
154 || IsEqualGUID(riid, &IID_IPersistFolder2))
155 *ppvObject = (void *)&This->lpPersistFolderVtbl;
156
157 else if (IsEqualIID(riid, &IID_IContextMenu) || IsEqualGUID(riid, &IID_IContextMenu2))
158 {
159 This->lpContextMenu2 = &recycleBincmVtblFolder;
160 *ppvObject = (void *)&This->lpContextMenu2;
161 }
162 else if(IsEqualIID(riid, &IID_IShellExtInit))
163 {
164 *ppvObject = (void *)&(This->lpSEI);
165 }
166
167 if (*ppvObject != NULL)
168 {
169 IUnknown_AddRef((IUnknown *)*ppvObject);
170 return S_OK;
171 }
172 WARN("no interface %s\n", debugstr_guid(riid));
173 return E_NOINTERFACE;
174 }
175
176 static ULONG WINAPI RecycleBin_AddRef(IShellFolder2 *iface)
177 {
178 RecycleBin *This = (RecycleBin *)iface;
179 TRACE("(%p)\n", This);
180 return InterlockedIncrement(&This->refCount);
181 }
182
183 static ULONG WINAPI RecycleBin_Release(IShellFolder2 *iface)
184 {
185 RecycleBin *This = (RecycleBin *)iface;
186 LONG result;
187
188 TRACE("(%p)\n", This);
189 result = InterlockedDecrement(&This->refCount);
190 if (result == 0)
191 {
192 TRACE("Destroy object\n");
193 RecycleBin_Destructor(This);
194 }
195 return result;
196 }
197
198 static HRESULT WINAPI RecycleBin_ParseDisplayName(IShellFolder2 *This, HWND hwnd, LPBC pbc,
199 LPOLESTR pszDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl,
200 ULONG *pdwAttributes)
201 {
202 FIXME("stub\n");
203 return E_NOTIMPL;
204 }
205
206
207 PDELETED_FILE_DETAILS_W
208 UnpackDetailsFromPidl(LPCITEMIDLIST pidl)
209 {
210 return (PDELETED_FILE_DETAILS_W)&pidl->mkid.abID;
211 }
212
213 static LPITEMIDLIST _ILCreateRecycleItem(PDELETED_FILE_DETAILS_W pFileDetails)
214 {
215 PIDLDATA tmp;
216 LPITEMIDLIST pidl;
217 PIDLRecycleStruct * p;
218 int size0 = (char*)&tmp.u.crecycle.szName-(char*)&tmp.u.crecycle;
219 int size = size0;
220
221 tmp.type = 0x00;
222 size += (wcslen(pFileDetails->FileName) + 1) * sizeof(WCHAR);
223
224 pidl = (LPITEMIDLIST)SHAlloc(size + 4);
225 if (!pidl)
226 return pidl;
227
228 pidl->mkid.cb = size+2;
229 memcpy(pidl->mkid.abID, &tmp, 2+size0);
230
231 p = &((PIDLDATA*)pidl->mkid.abID)->u.crecycle;
232 RtlCopyMemory(p, pFileDetails, sizeof(DELETED_FILE_DETAILS_W));
233 wcscpy(p->szName, pFileDetails->FileName);
234 *(WORD*)((char*)pidl+(size+2)) = 0;
235 return pidl;
236 }
237
238 static PIDLRecycleStruct * _ILGetRecycleStruct(LPCITEMIDLIST pidl)
239 {
240 LPPIDLDATA pdata = _ILGetDataPointer(pidl);
241
242 if (pdata && pdata->type==0x00)
243 return (PIDLRecycleStruct*)&(pdata->u.crecycle);
244
245 return NULL;
246 }
247
248 BOOL
249 WINAPI
250 CBSearchBitBucket(IN PVOID Context, IN HANDLE hDeletedFile)
251 {
252 PSEARCH_CONTEXT pContext = (PSEARCH_CONTEXT)Context;
253
254 PDELETED_FILE_DETAILS_W pFileDetails;
255 DWORD dwSize;
256 BOOL ret;
257
258 if (!GetDeletedFileDetailsW(hDeletedFile,
259 0,
260 NULL,
261 &dwSize) &&
262 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
263 {
264 ERR("GetDeletedFileDetailsW failed\n");
265 return FALSE;
266 }
267
268 pFileDetails = SHAlloc(dwSize);
269 if (!pFileDetails)
270 {
271 ERR("No memory\n");
272 return FALSE;
273 }
274
275 if (!GetDeletedFileDetailsW(hDeletedFile,
276 dwSize,
277 pFileDetails,
278 NULL))
279 {
280 ERR("GetDeletedFileDetailsW failed\n");
281 SHFree(pFileDetails);
282 return FALSE;
283 }
284
285 ret = memcmp(pFileDetails, pContext->pFileDetails, dwSize);
286 if (!ret)
287 {
288 pContext->hDeletedFile = hDeletedFile;
289 pContext->bFound = TRUE;
290 }
291 else
292 CloseRecycleBinHandle(hDeletedFile);
293
294 SHFree(pFileDetails);
295 return ret;
296 }
297
298
299
300 BOOL
301 WINAPI
302 CBEnumBitBucket(IN PVOID Context, IN HANDLE hDeletedFile)
303 {
304 PDELETED_FILE_DETAILS_W pFileDetails;
305 DWORD dwSize;
306 LPITEMIDLIST pidl = NULL;
307 BOOL ret;
308
309 if (!GetDeletedFileDetailsW(hDeletedFile,
310 0,
311 NULL,
312 &dwSize) &&
313 GetLastError() != ERROR_INSUFFICIENT_BUFFER)
314 {
315 ERR("GetDeletedFileDetailsW failed\n");
316 return FALSE;
317 }
318
319 pFileDetails = SHAlloc(dwSize);
320 if (!pFileDetails)
321 {
322 ERR("No memory\n");
323 return FALSE;
324 }
325
326 if (!GetDeletedFileDetailsW(hDeletedFile,
327 dwSize,
328 pFileDetails,
329 NULL))
330 {
331 ERR("GetDeletedFileDetailsW failed\n");
332 SHFree(pFileDetails);
333 return FALSE;
334 }
335
336 pidl = _ILCreateRecycleItem(pFileDetails);
337 if (!pidl)
338 {
339 SHFree(pFileDetails);
340 return FALSE;
341 }
342
343 ret = AddToEnumList((IEnumIDList*)Context, pidl);
344
345 if (!ret)
346 SHFree(pidl);
347 SHFree(pFileDetails);
348 TRACE("Returning %d\n", ret);
349 CloseRecycleBinHandle(hDeletedFile);
350 return ret;
351 }
352
353 static HRESULT WINAPI RecycleBin_EnumObjects(IShellFolder2 *iface, HWND hwnd, SHCONTF grfFlags, IEnumIDList **ppenumIDList)
354 {
355 RecycleBin *This = (RecycleBin *)iface;
356 IEnumIDList *list;
357 static LPCWSTR szDrive = L"C:\\";
358
359 TRACE("(%p, %p, %x, %p)\n", This, hwnd, (unsigned int)grfFlags, ppenumIDList);
360
361 if (grfFlags & SHCONTF_NONFOLDERS)
362 {
363 TRACE("Starting Enumeration\n");
364 *ppenumIDList = NULL;
365 list = IEnumIDList_Constructor();
366 if (list == NULL)
367 return E_OUTOFMEMORY;
368
369 if (!EnumerateRecycleBinW(szDrive, //FIXME
370 CBEnumBitBucket,
371 (PVOID)list))
372 {
373 WARN("Error: EnumerateRecycleBinW failed\n");
374 }
375 *ppenumIDList = list;
376 }
377 else
378 {
379 *ppenumIDList = IEnumIDList_Constructor();
380 if (*ppenumIDList == NULL)
381 return E_OUTOFMEMORY;
382 }
383
384 return S_OK;
385
386 }
387
388 static HRESULT WINAPI RecycleBin_BindToObject(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
389 {
390 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
391 return E_NOTIMPL;
392 }
393
394 static HRESULT WINAPI RecycleBin_BindToStorage(IShellFolder2 *This, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
395 {
396 FIXME("(%p, %p, %p, %s, %p) - stub\n", This, pidl, pbc, debugstr_guid(riid), ppv);
397 return E_NOTIMPL;
398 }
399
400 static HRESULT WINAPI RecycleBin_CompareIDs(IShellFolder2 *iface, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
401 {
402 RecycleBin *This = (RecycleBin *)iface;
403
404 /* TODO */
405 TRACE("(%p, %p, %p, %p)\n", This, (void *)lParam, pidl1, pidl2);
406 if (pidl1->mkid.cb != pidl2->mkid.cb)
407 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
408 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb));
409 }
410
411 static HRESULT WINAPI RecycleBin_CreateViewObject(IShellFolder2 *iface, HWND hwndOwner, REFIID riid, void **ppv)
412 {
413 RecycleBin *This = (RecycleBin *)iface;
414 LPSHELLVIEW pShellView;
415 HRESULT hr = E_NOINTERFACE;
416
417 TRACE("(%p, %p, %s, %p)\n", This, hwndOwner, debugstr_guid(riid), ppv);
418
419 if (!ppv)
420 return hr;
421
422 *ppv = NULL;
423
424 if (IsEqualIID (riid, &IID_IDropTarget))
425 {
426 WARN ("IDropTarget not implemented\n");
427 hr = E_NOTIMPL;
428 }
429 else if (IsEqualIID (riid, &IID_IContextMenu) || IsEqualIID (riid, &IID_IContextMenu2))
430 {
431 This->lpContextMenu2 = &recycleBincmVtblFolder;
432 *ppv = (void *)&This->lpContextMenu2;
433 This->refCount++;
434 hr = S_OK;
435 }
436 else if (IsEqualIID (riid, &IID_IShellView))
437 {
438 pShellView = IShellView_Constructor ((IShellFolder *) iface);
439 if (pShellView)
440 {
441 hr = IShellView_QueryInterface (pShellView, riid, ppv);
442 IShellView_Release (pShellView);
443 }
444 }
445 else
446 return hr;
447 TRACE ("-- (%p)->(interface=%p)\n", This, ppv);
448 return hr;
449
450 }
451
452 static HRESULT WINAPI RecycleBin_GetAttributesOf(IShellFolder2 *This, UINT cidl, LPCITEMIDLIST *apidl,
453 SFGAOF *rgfInOut)
454 {
455 TRACE("(%p, %d, {%p, ...}, {%x})\n", This, cidl, apidl[0], (unsigned int)*rgfInOut);
456 *rgfInOut &= SFGAO_CANMOVE|SFGAO_CANDELETE|SFGAO_HASPROPSHEET|SFGAO_FILESYSTEM;
457 return S_OK;
458 }
459
460 static HRESULT WINAPI RecycleBin_GetUIObjectOf(IShellFolder2 *iface, HWND hwndOwner, UINT cidl, LPCITEMIDLIST *apidl,
461 REFIID riid, UINT *prgfInOut, void **ppv)
462 {
463 IUnknown *pObj = NULL;
464 HRESULT hr = E_INVALIDARG;
465 RecycleBin * This = (RecycleBin*)iface;
466
467 TRACE ("(%p)->(%p,%u,apidl=%p, %p %p)\n", This,
468 hwndOwner, cidl, apidl, prgfInOut, ppv);
469
470 if (!ppv)
471 return hr;
472
473 *ppv = NULL;
474
475 if ((IsEqualIID (riid, &IID_IContextMenu) || IsEqualIID(riid, &IID_IContextMenu2)) && (cidl >= 1))
476 {
477 This->lpContextMenu2 = &recycleBincmVtblBitbucketItem;
478 pObj = (IUnknown*)(&This->lpContextMenu2);
479 This->apidl = apidl[0];
480 IUnknown_AddRef(pObj);
481 hr = S_OK;
482 }
483 else if (IsEqualIID (riid, &IID_IDropTarget) && (cidl >= 1))
484 {
485 hr = IShellFolder_QueryInterface (iface, &IID_IDropTarget, (LPVOID *) & pObj);
486 }
487 else
488 hr = E_NOINTERFACE;
489
490 if (SUCCEEDED(hr) && !pObj)
491 hr = E_OUTOFMEMORY;
492
493 *ppv = pObj;
494 TRACE ("(%p)->hr=0x%08x\n", This, hr);
495 return hr;
496 }
497
498 static HRESULT WINAPI RecycleBin_GetDisplayNameOf(IShellFolder2 *This, LPCITEMIDLIST pidl, SHGDNF uFlags, STRRET *pName)
499 {
500 PIDLRecycleStruct *pFileDetails;
501 LPWSTR pFileName;
502
503 TRACE("(%p, %p, %x, %p)\n", This, pidl, (unsigned int)uFlags, pName);
504
505
506 if (_ILIsBitBucket (pidl))
507 {
508 WCHAR pszPath[100];
509
510 if (HCR_GetClassNameW(&CLSID_RecycleBin, pszPath, MAX_PATH))
511 {
512 pName->uType = STRRET_WSTR;
513 pName->u.pOleStr = StrDupW(pszPath);
514 return S_OK;
515 }
516 }
517
518 pFileDetails = _ILGetRecycleStruct(pidl);
519 if (!pFileDetails)
520 {
521 pName->u.cStr[0] = 0;
522 pName->uType = STRRET_CSTR;
523 return E_INVALIDARG;
524 }
525
526 pFileName = wcsrchr(pFileDetails->szName, L'\\');
527 if (!pFileName)
528 {
529 pName->u.cStr[0] = 0;
530 pName->uType = STRRET_CSTR;
531 return E_UNEXPECTED;
532 }
533
534 pName->u.pOleStr = StrDupW(pFileName + 1);
535 if (pName->u.pOleStr == NULL)
536 return E_OUTOFMEMORY;
537
538 pName->uType = STRRET_WSTR;
539 return S_OK;
540 }
541
542 static HRESULT WINAPI RecycleBin_SetNameOf(IShellFolder2 *This, HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
543 SHGDNF uFlags, LPITEMIDLIST *ppidlOut)
544 {
545 TRACE("\n");
546 return E_FAIL; /* not supported */
547 }
548
549 static HRESULT WINAPI RecycleBin_GetDefaultSearchGUID(IShellFolder2 *iface, GUID *pguid)
550 {
551 FIXME("stub\n");
552 return E_NOTIMPL;
553 }
554
555 static HRESULT WINAPI RecycleBin_EnumSearches(IShellFolder2 *iface, IEnumExtraSearch **ppEnum)
556 {
557 FIXME("stub\n");
558 *ppEnum = NULL;
559 return E_NOTIMPL;
560 }
561
562 static HRESULT WINAPI RecycleBin_GetDefaultColumn(IShellFolder2 *iface, DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
563 {
564 RecycleBin *This = (RecycleBin *)iface;
565 TRACE("(%p, %x, %p, %p)\n", This, (unsigned int)dwReserved, pSort, pDisplay);
566 *pSort = 0;
567 *pDisplay = 0;
568 return S_OK;
569 }
570
571 static HRESULT WINAPI RecycleBin_GetDefaultColumnState(IShellFolder2 *iface, UINT iColumn, SHCOLSTATEF *pcsFlags)
572 {
573 RecycleBin *This = (RecycleBin *)iface;
574 TRACE("(%p, %d, %p)\n", This, iColumn, pcsFlags);
575 if (iColumn >= COLUMNS_COUNT)
576 return E_INVALIDARG;
577 *pcsFlags = RecycleBinColumns[iColumn].pcsFlags;
578 return S_OK;
579 }
580
581 static HRESULT WINAPI RecycleBin_GetDetailsEx(IShellFolder2 *iface, LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
582 {
583 FIXME("stub\n");
584 return E_NOTIMPL;
585 }
586
587 static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME * ft)
588 {
589 FILETIME lft;
590 SYSTEMTIME time;
591 int ret;
592
593 FileTimeToLocalFileTime(ft, &lft);
594 FileTimeToSystemTime(&lft, &time);
595
596 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size);
597 if (ret>0 && ret<size)
598 {
599 /* Append space + time without seconds */
600 buffer[ret-1] = ' ';
601 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret);
602 }
603
604 return (ret!=0 ? E_FAIL : S_OK);
605 }
606
607 static HRESULT WINAPI RecycleBin_GetDetailsOf(IShellFolder2 *iface, LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS pDetails)
608 {
609 RecycleBin *This = (RecycleBin *)iface;
610 PIDLRecycleStruct * pFileDetails;
611 WCHAR buffer[MAX_PATH];
612 WCHAR szTypeName[100];
613 LPWSTR pszBackslash;
614 UINT Length;
615
616 TRACE("(%p, %p, %d, %p)\n", This, pidl, iColumn, pDetails);
617 if (iColumn >= COLUMNS_COUNT)
618 return E_FAIL;
619 pDetails->fmt = RecycleBinColumns[iColumn].fmt;
620 pDetails->cxChar = RecycleBinColumns[iColumn].cxChars;
621 if (pidl == NULL)
622 {
623 pDetails->str.uType = STRRET_WSTR;
624 LoadStringW(shell32_hInstance, RecycleBinColumns[iColumn].column_name_id, buffer, MAX_PATH);
625 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
626 }
627
628 if (iColumn == COLUMN_NAME)
629 return RecycleBin_GetDisplayNameOf(iface, pidl, SHGDN_NORMAL, &pDetails->str);
630
631 pFileDetails = _ILGetRecycleStruct(pidl);
632 switch (iColumn)
633 {
634 case COLUMN_DATEDEL:
635 FormatDateTime(buffer, MAX_PATH, &pFileDetails->DeletionTime);
636 break;
637 case COLUMN_DELFROM:
638 pszBackslash = wcsrchr(pFileDetails->szName, L'\\');
639 Length = (pszBackslash - pFileDetails->szName);
640 memcpy((LPVOID)buffer, pFileDetails->szName, Length * sizeof(WCHAR));
641 buffer[Length] = L'\0';
642 break;
643 case COLUMN_SIZE:
644 StrFormatKBSizeW(pFileDetails->FileSize.QuadPart, buffer, MAX_PATH);
645 break;
646 case COLUMN_MTIME:
647 FormatDateTime(buffer, MAX_PATH, &pFileDetails->LastModification);
648 break;
649 case COLUMN_TYPE:
650 szTypeName[0] = L'\0';
651 wcscpy(buffer,PathFindExtensionW(pFileDetails->szName));
652 if (!( HCR_MapTypeToValueW(buffer, buffer, sizeof(buffer)/sizeof(WCHAR), TRUE) &&
653 HCR_MapTypeToValueW(buffer, szTypeName, sizeof(szTypeName)/sizeof(WCHAR), FALSE )))
654 {
655 wcscpy (szTypeName, PathFindExtensionW(pFileDetails->szName));
656 wcscat(szTypeName, L"-");
657 Length = wcslen(szTypeName);
658 if (LoadStringW(shell32_hInstance, IDS_SHV_COLUMN1, &szTypeName[Length], (sizeof(szTypeName)/sizeof(WCHAR))- Length))
659 szTypeName[(sizeof(szTypeName)/sizeof(WCHAR))-1] = L'\0';
660 }
661 pDetails->str.uType = STRRET_WSTR;
662 return SHStrDupW(szTypeName, &pDetails->str.u.pOleStr);
663 break;
664 default:
665 return E_FAIL;
666 }
667
668 pDetails->str.uType = STRRET_WSTR;
669 return SHStrDupW(buffer, &pDetails->str.u.pOleStr);
670 }
671
672 static HRESULT WINAPI RecycleBin_MapColumnToSCID(IShellFolder2 *iface, UINT iColumn, SHCOLUMNID *pscid)
673 {
674 RecycleBin *This = (RecycleBin *)iface;
675 TRACE("(%p, %d, %p)\n", This, iColumn, pscid);
676 if (iColumn>=COLUMNS_COUNT)
677 return E_INVALIDARG;
678 pscid->fmtid = *RecycleBinColumns[iColumn].fmtId;
679 pscid->pid = RecycleBinColumns[iColumn].pid;
680 return S_OK;
681 }
682
683 static const IShellFolder2Vtbl recycleBinVtbl =
684 {
685 /* IUnknown */
686 RecycleBin_QueryInterface,
687 RecycleBin_AddRef,
688 RecycleBin_Release,
689
690 /* IShellFolder */
691 RecycleBin_ParseDisplayName,
692 RecycleBin_EnumObjects,
693 RecycleBin_BindToObject,
694 RecycleBin_BindToStorage,
695 RecycleBin_CompareIDs,
696 RecycleBin_CreateViewObject,
697 RecycleBin_GetAttributesOf,
698 RecycleBin_GetUIObjectOf,
699 RecycleBin_GetDisplayNameOf,
700 RecycleBin_SetNameOf,
701
702 /* IShellFolder2 */
703 RecycleBin_GetDefaultSearchGUID,
704 RecycleBin_EnumSearches,
705 RecycleBin_GetDefaultColumn,
706 RecycleBin_GetDefaultColumnState,
707 RecycleBin_GetDetailsEx,
708 RecycleBin_GetDetailsOf,
709 RecycleBin_MapColumnToSCID
710 };
711
712 static HRESULT WINAPI RecycleBin_IPersistFolder2_GetClassID(IPersistFolder2 *This, CLSID *pClassID)
713 {
714 TRACE("(%p, %p)\n", This, pClassID);
715 if (This == NULL || pClassID == NULL)
716 return E_INVALIDARG;
717 memcpy(pClassID, &CLSID_RecycleBin, sizeof(CLSID));
718 return S_OK;
719 }
720
721 static HRESULT WINAPI RecycleBin_IPersistFolder2_Initialize(IPersistFolder2 *iface, LPCITEMIDLIST pidl)
722 {
723 RecycleBin *This = impl_from_IPersistFolder(iface);
724 TRACE("(%p, %p)\n", This, pidl);
725
726 SHFree((LPVOID)This->pidl);
727 This->pidl = ILClone(pidl);
728 if (This->pidl == NULL)
729 return E_OUTOFMEMORY;
730 return S_OK;
731 }
732
733 static HRESULT WINAPI RecycleBin_IPersistFolder2_GetCurFolder(IPersistFolder2 *iface, LPITEMIDLIST *ppidl)
734 {
735 RecycleBin *This = impl_from_IPersistFolder(iface);
736 TRACE("\n");
737 *ppidl = ILClone(This->pidl);
738 return S_OK;
739 }
740
741 static HRESULT WINAPI RecycleBin_IPersistFolder2_QueryInterface(IPersistFolder2 *This, REFIID riid, void **ppvObject)
742 {
743 return RecycleBin_QueryInterface((IShellFolder2 *)impl_from_IPersistFolder(This), riid, ppvObject);
744 }
745
746 static ULONG WINAPI RecycleBin_IPersistFolder2_AddRef(IPersistFolder2 *This)
747 {
748 return RecycleBin_AddRef((IShellFolder2 *)impl_from_IPersistFolder(This));
749 }
750
751 static ULONG WINAPI RecycleBin_IPersistFolder2_Release(IPersistFolder2 *This)
752 {
753 return RecycleBin_Release((IShellFolder2 *)impl_from_IPersistFolder(This));
754 }
755
756 static const IPersistFolder2Vtbl recycleBinPersistVtbl =
757 {
758 /* IUnknown */
759 RecycleBin_IPersistFolder2_QueryInterface,
760 RecycleBin_IPersistFolder2_AddRef,
761 RecycleBin_IPersistFolder2_Release,
762
763 /* IPersist */
764 RecycleBin_IPersistFolder2_GetClassID,
765 /* IPersistFolder */
766 RecycleBin_IPersistFolder2_Initialize,
767 /* IPersistFolder2 */
768 RecycleBin_IPersistFolder2_GetCurFolder
769 };
770
771 /*************************************************************************
772 * BitBucket IShellExtInit interface
773 */
774
775 static HRESULT WINAPI
776 RecycleBin_ExtInit_QueryInterface( IShellExtInit* iface, REFIID riid, void** ppvObject )
777 {
778 return RecycleBin_QueryInterface((IShellFolder2 *)impl_from_IShellExtInit(iface), riid, ppvObject);
779 }
780
781 static ULONG WINAPI
782 RecycleBin_ExtInit_AddRef( IShellExtInit* iface )
783 {
784 return RecycleBin_AddRef((IShellFolder2 *)impl_from_IShellExtInit(iface));
785 }
786
787 static ULONG WINAPI
788 RecycleBin_ExtInit_Release( IShellExtInit* iface )
789 {
790 return RecycleBin_Release((IShellFolder2 *)impl_from_IShellExtInit(iface));
791 }
792
793 static HRESULT WINAPI
794 RecycleBin_ExtInit_Initialize( IShellExtInit* iface, LPCITEMIDLIST pidlFolder,
795 IDataObject *pdtobj, HKEY hkeyProgID )
796 {
797 RecycleBin *This = impl_from_IShellExtInit(iface);
798
799 TRACE("%p %p %p %p\n", This, pidlFolder, pdtobj, hkeyProgID );
800 return S_OK;
801 }
802
803
804 static const IShellExtInitVtbl eivt =
805 {
806 RecycleBin_ExtInit_QueryInterface,
807 RecycleBin_ExtInit_AddRef,
808 RecycleBin_ExtInit_Release,
809 RecycleBin_ExtInit_Initialize
810 };
811
812
813 /*************************************************************************
814 * BitBucket context menu
815 *
816 */
817
818 static HRESULT WINAPI
819 RecycleBin_IContextMenu2Folder_QueryInterface( IContextMenu2* iface, REFIID riid, void** ppvObject )
820 {
821 return RecycleBin_QueryInterface((IShellFolder2 *)impl_from_IContextMenu2(iface), riid, ppvObject);
822 }
823
824 static ULONG WINAPI
825 RecycleBin_IContextMenu2Folder_AddRef( IContextMenu2* iface )
826 {
827 return RecycleBin_AddRef((IShellFolder2 *)impl_from_IContextMenu2(iface));
828 }
829
830 static ULONG WINAPI
831 RecycleBin_IContextMenu2Folder_Release( IContextMenu2* iface )
832 {
833 return RecycleBin_Release((IShellFolder2 *)impl_from_IContextMenu2(iface));
834 }
835
836 static HRESULT WINAPI
837 RecycleBin_IContextMenu2Folder_QueryContextMenu( IContextMenu2* iface, HMENU hmenu, UINT indexMenu,
838 UINT idCmdFirst, UINT idCmdLast, UINT uFlags )
839 {
840 WCHAR szBuffer[100];
841 MENUITEMINFOW mii;
842 int id = 1;
843 RecycleBin * This = impl_from_IContextMenu2(iface);
844
845 TRACE("%p %p %u %u %u %u\n", This,
846 hmenu, indexMenu, idCmdFirst, idCmdLast, uFlags );
847
848 if ( !hmenu )
849 return E_INVALIDARG;
850
851 memset( &mii, 0, sizeof(mii) );
852 mii.cbSize = sizeof(mii);
853 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
854 mii.fState = MFS_ENABLED;
855 szBuffer[0] = L'\0';
856 LoadStringW(shell32_hInstance, IDS_EMPTY_BITBUCKET, szBuffer, sizeof(szBuffer)/sizeof(WCHAR));
857 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
858 mii.dwTypeData = szBuffer;
859 mii.cch = wcslen( mii.dwTypeData );
860 mii.wID = idCmdFirst + id++;
861 mii.fType = MFT_STRING;
862 This->iIdEmpty = 1;
863
864 if (!InsertMenuItemW( hmenu, indexMenu, TRUE, &mii ))
865 return E_FAIL;
866
867 return MAKE_HRESULT( SEVERITY_SUCCESS, 0, id );
868 }
869
870 static HRESULT WINAPI
871 RecycleBin_IContextMenu2Folder_InvokeCommand( IContextMenu2* iface, LPCMINVOKECOMMANDINFO lpici )
872 {
873 HRESULT hr;
874 LPSHELLBROWSER lpSB;
875 LPSHELLVIEW lpSV = NULL;
876 RecycleBin * This = impl_from_IContextMenu2(iface);
877
878 TRACE("%p %p verb %p\n", This, lpici, lpici->lpVerb);
879
880 if ( LOWORD(lpici->lpVerb) == This->iIdEmpty)
881 {
882 // FIXME
883 // path & flags
884 hr = SHEmptyRecycleBinW(lpici->hwnd, L"C:\\", 0);
885 TRACE("result %x\n", hr);
886 if (hr != S_OK)
887 {
888 return hr;
889 }
890
891 if((lpSB = (LPSHELLBROWSER)SendMessageA(lpici->hwnd, CWM_GETISHELLBROWSER,0,0)))
892 {
893 if(SUCCEEDED(IShellBrowser_QueryActiveShellView(lpSB, &lpSV)))
894 {
895 IShellView_Refresh(lpSV);
896 }
897 }
898 }
899 return S_OK;
900 }
901
902 static HRESULT WINAPI
903 RecycleBin_IContextMenu2Folder_GetCommandString( IContextMenu2* iface, UINT_PTR idCmd, UINT uType,
904 UINT* pwReserved, LPSTR pszName, UINT cchMax )
905 {
906 RecycleBin * This = impl_from_IContextMenu2(iface);
907
908 FIXME("%p %lu %u %p %p %u\n", This,
909 idCmd, uType, pwReserved, pszName, cchMax );
910
911 return E_NOTIMPL;
912 }
913
914 /**************************************************************************
915 * RecycleBin_IContextMenu2Item_HandleMenuMsg()
916 */
917 static HRESULT WINAPI RecycleBin_IContextMenu2Folder_HandleMenuMsg(
918 IContextMenu2 *iface,
919 UINT uMsg,
920 WPARAM wParam,
921 LPARAM lParam)
922 {
923 RecycleBin * This = impl_from_IContextMenu2(iface);
924
925 TRACE("RecycleBin_IContextMenu2Item_IContextMenu2Folder_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam);
926
927 return E_NOTIMPL;
928 }
929
930
931 static const IContextMenu2Vtbl recycleBincmVtblFolder =
932 {
933 RecycleBin_IContextMenu2Folder_QueryInterface,
934 RecycleBin_IContextMenu2Folder_AddRef,
935 RecycleBin_IContextMenu2Folder_Release,
936 RecycleBin_IContextMenu2Folder_QueryContextMenu,
937 RecycleBin_IContextMenu2Folder_InvokeCommand,
938 RecycleBin_IContextMenu2Folder_GetCommandString,
939 RecycleBin_IContextMenu2Folder_HandleMenuMsg
940 };
941
942
943 /**************************************************************************
944 * IContextMenu2 Bitbucket Item Implementation
945 */
946
947 /************************************************************************
948 * RecycleBin_IContextMenu2Item_QueryInterface
949 */
950 static HRESULT WINAPI RecycleBin_IContextMenu2Item_QueryInterface(IContextMenu2 * iface, REFIID iid, LPVOID * ppvObject)
951 {
952 RecycleBin * This = impl_from_IContextMenu2(iface);
953
954 TRACE("(%p)\n", This);
955
956 return RecycleBin_QueryInterface((IShellFolder2*)This, iid, ppvObject);
957 }
958
959 /************************************************************************
960 * RecycleBin_IContextMenu2Item_AddRef
961 */
962 static ULONG WINAPI RecycleBin_IContextMenu2Item_AddRef(IContextMenu2 * iface)
963 {
964 RecycleBin * This = impl_from_IContextMenu2(iface);
965
966 TRACE("(%p)->(count=%u)\n", This, This->refCount);
967
968 return RecycleBin_AddRef((IShellFolder2*)This);
969 }
970
971 /************************************************************************
972 * RecycleBin_IContextMenu2Item_Release
973 */
974 static ULONG WINAPI RecycleBin_IContextMenu2Item_Release(IContextMenu2 * iface)
975 {
976 RecycleBin * This = impl_from_IContextMenu2(iface);
977
978 TRACE("(%p)->(count=%u)\n", This, This->refCount);
979
980 return RecycleBin_Release((IShellFolder2*)This);
981 }
982
983 /**************************************************************************
984 * RecycleBin_IContextMenu2Item_QueryContextMenu()
985 */
986 static HRESULT WINAPI RecycleBin_IContextMenu2Item_QueryContextMenu(
987 IContextMenu2 *iface,
988 HMENU hMenu,
989 UINT indexMenu,
990 UINT idCmdFirst,
991 UINT idCmdLast,
992 UINT uFlags)
993 {
994 WCHAR szBuffer[30] = {0};
995 ULONG Count = 1;
996
997 RecycleBin * This = impl_from_IContextMenu2(iface);
998
999 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n",
1000 This, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
1001
1002 if (LoadStringW(shell32_hInstance, IDS_RESTORE, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
1003 {
1004 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
1005 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED);
1006 Count++;
1007 }
1008
1009 if (LoadStringW(shell32_hInstance, IDS_CUT, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
1010 {
1011 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
1012 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
1013 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
1014 }
1015
1016 if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
1017 {
1018 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
1019 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
1020 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
1021 }
1022
1023 if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer)/sizeof(WCHAR)))
1024 {
1025 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
1026 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
1027 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT);
1028 }
1029
1030 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count);
1031 }
1032
1033
1034 /**************************************************************************
1035 * RecycleBin_IContextMenu2Item_InvokeCommand()
1036 */
1037 static HRESULT WINAPI RecycleBin_IContextMenu2Item_InvokeCommand(
1038 IContextMenu2 *iface,
1039 LPCMINVOKECOMMANDINFO lpcmi)
1040 {
1041
1042 SEARCH_CONTEXT Context;
1043 RecycleBin * This = impl_from_IContextMenu2(iface);
1044 static LPCWSTR szDrive = L"C:\\";
1045
1046 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n",This,lpcmi,lpcmi->lpVerb, lpcmi->hwnd);
1047
1048 if (lpcmi->lpVerb == MAKEINTRESOURCEA(1) || lpcmi->lpVerb == MAKEINTRESOURCEA(5))
1049 {
1050 Context.pFileDetails = _ILGetRecycleStruct(This->apidl);
1051 Context.bFound = FALSE;
1052
1053 EnumerateRecycleBinW(szDrive, CBSearchBitBucket, (PVOID)&Context);
1054 if (!Context.bFound)
1055 return E_FAIL;
1056
1057 if (lpcmi->lpVerb == MAKEINTRESOURCEA(1))
1058 {
1059 /* restore file */
1060 if (RestoreFile(Context.hDeletedFile))
1061 return S_OK;
1062 else
1063 return E_FAIL;
1064 }
1065 else
1066 {
1067 DeleteFileHandleToRecycleBin(Context.hDeletedFile);
1068 return E_NOTIMPL;
1069 }
1070 }
1071 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(3))
1072 {
1073 FIXME("implement cut\n");
1074 return E_NOTIMPL;
1075 }
1076 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7))
1077 {
1078 FIXME("implement properties\n");
1079 return E_NOTIMPL;
1080 }
1081
1082 return S_OK;
1083 }
1084
1085 /**************************************************************************
1086 * RecycleBin_IContextMenu2Item_GetCommandString()
1087 *
1088 */
1089 static HRESULT WINAPI RecycleBin_IContextMenu2Item_GetCommandString(
1090 IContextMenu2 *iface,
1091 UINT_PTR idCommand,
1092 UINT uFlags,
1093 UINT* lpReserved,
1094 LPSTR lpszName,
1095 UINT uMaxNameLen)
1096 {
1097 RecycleBin * This = impl_from_IContextMenu2(iface);
1098
1099 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n",This, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen);
1100
1101
1102 return E_FAIL;
1103 }
1104
1105
1106
1107 /**************************************************************************
1108 * RecycleBin_IContextMenu2Item_HandleMenuMsg()
1109 */
1110 static HRESULT WINAPI RecycleBin_IContextMenu2Item_HandleMenuMsg(
1111 IContextMenu2 *iface,
1112 UINT uMsg,
1113 WPARAM wParam,
1114 LPARAM lParam)
1115 {
1116 RecycleBin * This = impl_from_IContextMenu2(iface);
1117
1118 TRACE("RecycleBin_IContextMenu2Item_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n",This, uMsg, wParam, lParam);
1119
1120 return E_NOTIMPL;
1121 }
1122
1123 static const IContextMenu2Vtbl recycleBincmVtblBitbucketItem =
1124 {
1125 RecycleBin_IContextMenu2Item_QueryInterface,
1126 RecycleBin_IContextMenu2Item_AddRef,
1127 RecycleBin_IContextMenu2Item_Release,
1128 RecycleBin_IContextMenu2Item_QueryContextMenu,
1129 RecycleBin_IContextMenu2Item_InvokeCommand,
1130 RecycleBin_IContextMenu2Item_GetCommandString,
1131 RecycleBin_IContextMenu2Item_HandleMenuMsg
1132 };
1133
1134
1135 void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable)
1136 {
1137 if (bEnable)
1138 {
1139 SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_UNCHECKED, 0);
1140 EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
1141 SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0);
1142 }
1143 else
1144 {
1145 SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_CHECKED, 0);
1146 EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE);
1147 SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0);
1148 }
1149 }
1150
1151
1152 void
1153 InitializeBitBucketDlg(HWND hwndDlg, WCHAR DefaultDrive)
1154 {
1155 WCHAR CurDrive = L'A';
1156 WCHAR szDrive[] = L"A:\\";
1157 DWORD dwDrives;
1158 WCHAR szName[100];
1159 WCHAR szVolume[100];
1160 DWORD MaxComponent, Flags;
1161 DWORD dwSerial;
1162 LVCOLUMNW lc;
1163 HWND hDlgCtrl;
1164 LVITEMW li;
1165 INT itemCount;
1166 ULARGE_INTEGER TotalNumberOfFreeBytes, TotalNumberOfBytes, FreeBytesAvailable;
1167 RECT rect;
1168 int columnSize;
1169 int defIndex = 0;
1170 DWORD dwSize;
1171 PDRIVE_ITEM_CONTEXT pItem = NULL, pDefault = NULL, pFirst = NULL;
1172
1173 hDlgCtrl = GetDlgItem(hwndDlg, 14000);
1174
1175 if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_LOCATION, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
1176 szVolume[0] = 0;
1177
1178 GetClientRect(hDlgCtrl, &rect);
1179
1180 memset(&lc, 0, sizeof(LV_COLUMN) );
1181 lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
1182
1183 columnSize = 140; //FIXME
1184 lc.iSubItem = 0;
1185 lc.fmt = LVCFMT_FIXED_WIDTH;
1186 lc.cx = columnSize;
1187 lc.cchTextMax = wcslen(szVolume);
1188 lc.pszText = szVolume;
1189 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&lc);
1190
1191 if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_DISKSPACE, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
1192 szVolume[0] = 0;
1193
1194 lc.iSubItem = 1;
1195 lc.cx = rect.right - rect.left - columnSize;
1196 lc.cchTextMax = wcslen(szVolume);
1197 lc.pszText = szVolume;
1198 (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&lc);
1199
1200 dwDrives = GetLogicalDrives();
1201 itemCount = 0;
1202 do
1203 {
1204 if ((dwDrives & 0x1))
1205 {
1206 UINT Type = GetDriveTypeW(szDrive);
1207 if (Type == DRIVE_FIXED) //FIXME
1208 {
1209 if (!GetVolumeInformationW(szDrive, szName, sizeof(szName) / sizeof(WCHAR), &dwSerial, &MaxComponent, &Flags, NULL, 0))
1210 {
1211 szName[0] = 0;
1212 dwSerial = -1;
1213 }
1214
1215 swprintf(szVolume, L"%s (%c)", szName, szDrive[0]);
1216 memset(&li, 0x0, sizeof(LVITEMW));
1217 li.mask = LVIF_TEXT | LVIF_PARAM;
1218 li.iSubItem = 0;
1219 li.pszText = szVolume;
1220 li.iItem = itemCount;
1221 (void)SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
1222 if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable , &TotalNumberOfBytes, &TotalNumberOfFreeBytes))
1223 {
1224 if (StrFormatByteSizeW(TotalNumberOfFreeBytes.QuadPart, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
1225 {
1226
1227 pItem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DRIVE_ITEM_CONTEXT));
1228 if (pItem)
1229 {
1230 swprintf(szName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\%04X-%04X", LOWORD(dwSerial), HIWORD(dwSerial));
1231 dwSize = sizeof(DWORD);
1232 RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize);
1233 dwSize = sizeof(DWORD);
1234 RegGetValueW(HKEY_CURRENT_USER, szName, L"NukeOnDelete", RRF_RT_DWORD, NULL, &pItem->dwNukeOnDelete, &dwSize);
1235 pItem->dwSerial = dwSerial;
1236 li.mask = LVIF_PARAM;
1237 li.lParam = (LPARAM)pItem;
1238 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
1239 if (CurDrive == DefaultDrive)
1240 {
1241 defIndex = itemCount;
1242 pDefault = pItem;
1243 }
1244 }
1245 if (!pFirst)
1246 pFirst = pItem;
1247
1248 li.mask = LVIF_TEXT;
1249 li.iSubItem = 1;
1250 li.pszText = szVolume;
1251 li.iItem = itemCount;
1252 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
1253 }
1254 }
1255 itemCount++;
1256 }
1257 }
1258 CurDrive++;
1259 szDrive[0] = CurDrive;
1260 dwDrives = (dwDrives >> 1);
1261 }while(dwDrives);
1262
1263 if (!pDefault)
1264 pDefault = pFirst;
1265 if (pDefault)
1266 {
1267 toggleNukeOnDeleteOption(hwndDlg, pDefault->dwNukeOnDelete);
1268 SetDlgItemInt(hwndDlg, 14002, pDefault->dwMaxCapacity, FALSE);
1269 }
1270 ZeroMemory(&li, sizeof(li));
1271 li.mask = LVIF_STATE;
1272 li.stateMask = (UINT)-1;
1273 li.state = LVIS_FOCUSED|LVIS_SELECTED;
1274 li.iItem = defIndex;
1275 (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
1276
1277 }
1278
1279 static BOOL StoreDriveSettings(HWND hwndDlg)
1280 {
1281 int iCount, iIndex;
1282 HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
1283 LVITEMW li;
1284 PDRIVE_ITEM_CONTEXT pItem;
1285 HKEY hKey, hSubKey;
1286 WCHAR szSerial[20];
1287 DWORD dwSize;
1288
1289
1290 if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume", 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
1291 return FALSE;
1292
1293 iCount = ListView_GetItemCount(hDlgCtrl);
1294
1295 ZeroMemory(&li, sizeof(li));
1296 li.mask = LVIF_PARAM;
1297
1298 for(iIndex = 0; iIndex < iCount; iIndex++)
1299 {
1300 li.iItem = iIndex;
1301 if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
1302 {
1303 pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
1304 swprintf(szSerial, L"%04X-%04X", LOWORD(pItem->dwSerial), HIWORD(pItem->dwSerial));
1305 if (RegCreateKeyExW(hKey, szSerial, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
1306 {
1307 dwSize = sizeof(DWORD);
1308 RegSetValueExW(hSubKey, L"NukeOnDelete", 0, REG_DWORD, (LPVOID)&pItem->dwNukeOnDelete, dwSize);
1309 dwSize = sizeof(DWORD);
1310 RegSetValueExW(hSubKey, L"MaxCapacity", 0, REG_DWORD, (LPVOID)&pItem->dwMaxCapacity, dwSize);
1311 RegCloseKey(hSubKey);
1312 }
1313 }
1314 }
1315 RegCloseKey(hKey);
1316 return TRUE;
1317
1318 }
1319
1320 static VOID FreeDriveItemContext(HWND hwndDlg)
1321 {
1322 int iCount, iIndex;
1323 HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
1324 LVITEMW li;
1325
1326 iCount = ListView_GetItemCount(hDlgCtrl);
1327
1328 ZeroMemory(&li, sizeof(li));
1329 li.mask = LVIF_PARAM;
1330
1331 for(iIndex = 0; iIndex < iCount; iIndex++)
1332 {
1333 li.iItem = iIndex;
1334 if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
1335 {
1336 HeapFree(GetProcessHeap(), 0, (LPVOID)li.lParam);
1337 }
1338 }
1339 }
1340
1341 INT
1342 GetDefaultItem(HWND hwndDlg, LVITEMW * li)
1343 {
1344 HWND hDlgCtrl;
1345 UINT iItemCount, iIndex;
1346
1347 hDlgCtrl = GetDlgItem(hwndDlg, 14000);
1348 if (!hDlgCtrl)
1349 return -1;
1350
1351 iItemCount = ListView_GetItemCount(hDlgCtrl);
1352 if (!iItemCount)
1353 return -1;
1354
1355 ZeroMemory(li, sizeof(LVITEMW));
1356 li->mask = LVIF_PARAM | LVIF_STATE;
1357 li->stateMask = (UINT)-1;
1358 for (iIndex = 0; iIndex < iItemCount; iIndex++)
1359 {
1360 li->iItem = iIndex;
1361 if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)li))
1362 {
1363 if (li->state & LVIS_SELECTED)
1364 return iIndex;
1365 }
1366 }
1367 return -1;
1368
1369 }
1370
1371 INT_PTR
1372 CALLBACK
1373 BitBucketDlg(
1374 HWND hwndDlg,
1375 UINT uMsg,
1376 WPARAM wParam,
1377 LPARAM lParam
1378 )
1379 {
1380 LPPSHNOTIFY lppsn;
1381 LPNMLISTVIEW lppl;
1382 LVITEMW li;
1383 PDRIVE_ITEM_CONTEXT pItem;
1384 BOOL bSuccess;
1385 UINT uResult;
1386 PROPSHEETPAGE * page;
1387 DWORD dwStyle;
1388
1389 switch(uMsg)
1390 {
1391 case WM_INITDIALOG:
1392 page = (PROPSHEETPAGE*)lParam;
1393 InitializeBitBucketDlg(hwndDlg, (WCHAR)page->lParam);
1394 dwStyle = (DWORD) SendDlgItemMessage(hwndDlg, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
1395 dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
1396 SendDlgItemMessage(hwndDlg, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
1397 if (GetDlgCtrlID((HWND)wParam) != 14000)
1398 {
1399 SetFocus(GetDlgItem(hwndDlg, 14000));
1400 return FALSE;
1401 }
1402 return TRUE;
1403 case WM_COMMAND:
1404 switch(LOWORD(wParam))
1405 {
1406 case 14001:
1407 toggleNukeOnDeleteOption(hwndDlg, FALSE);
1408 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1409 break;
1410 case 14003:
1411 toggleNukeOnDeleteOption(hwndDlg, TRUE);
1412 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1413 break;
1414 case 14004:
1415 PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
1416 break;
1417 }
1418 break;
1419 case WM_NOTIFY:
1420 lppsn = (LPPSHNOTIFY) lParam;
1421 lppl = (LPNMLISTVIEW) lParam;
1422 if (lppsn->hdr.code == PSN_APPLY)
1423 {
1424 if (GetDefaultItem(hwndDlg, &li) > -1)
1425 {
1426 pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
1427 if (pItem)
1428 {
1429 uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
1430 if (bSuccess)
1431 pItem->dwMaxCapacity = uResult;
1432 if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
1433 pItem->dwNukeOnDelete = TRUE;
1434 else
1435 pItem->dwNukeOnDelete = FALSE;
1436 }
1437 }
1438 if (StoreDriveSettings(hwndDlg))
1439 {
1440 SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
1441 return TRUE;
1442 }
1443 }
1444 else if (lppl->hdr.code == LVN_ITEMCHANGING)
1445 {
1446 ZeroMemory(&li, sizeof(li));
1447 li.mask = LVIF_PARAM;
1448 li.iItem = lppl->iItem;
1449 if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&li))
1450 return TRUE;
1451
1452 pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
1453 if (!pItem)
1454 return TRUE;
1455
1456 if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
1457 {
1458 /* new focused item */
1459 toggleNukeOnDeleteOption(lppl->hdr.hwndFrom, pItem->dwNukeOnDelete);
1460 SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
1461 }
1462 else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED))
1463 {
1464 /* kill focus */
1465 uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
1466 if (bSuccess)
1467 pItem->dwMaxCapacity = uResult;
1468 if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
1469 pItem->dwNukeOnDelete = TRUE;
1470 else
1471 pItem->dwNukeOnDelete = FALSE;
1472 }
1473 return TRUE;
1474
1475 }
1476 break;
1477 case WM_DESTROY:
1478 FreeDriveItemContext(hwndDlg);
1479 break;
1480 }
1481 return FALSE;
1482 }
1483
1484 BOOL SH_ShowRecycleBinProperties(WCHAR sDrive)
1485 {
1486 HPROPSHEETPAGE hpsp[1];
1487 PROPSHEETHEADERW psh;
1488 HPROPSHEETPAGE hprop;
1489
1490 BOOL ret;
1491
1492
1493 ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
1494 psh.dwSize = sizeof(PROPSHEETHEADERW);
1495 psh.dwFlags = PSP_DEFAULT | PSH_PROPTITLE;
1496 psh.pszCaption = MAKEINTRESOURCEW(IDS_RECYCLEBIN_FOLDER_NAME);
1497 psh.hwndParent = NULL;
1498 psh.u3.phpage = hpsp;
1499 psh.hInstance = shell32_hInstance;
1500
1501 hprop = SH_CreatePropertySheetPage("BITBUCKET_PROPERTIES_DLG", BitBucketDlg, (LPARAM)sDrive, NULL);
1502 if (!hprop)
1503 {
1504 ERR("Failed to create property sheet\n");
1505 return FALSE;
1506 }
1507 hpsp[psh.nPages] = hprop;
1508 psh.nPages++;
1509
1510
1511 ret = PropertySheetW(&psh);
1512 if (ret < 0)
1513 return FALSE;
1514 else
1515 return TRUE;
1516 }
1517
1518 BOOL
1519 TRASH_CanTrashFile(LPCWSTR wszPath)
1520 {
1521 LONG ret;
1522 DWORD dwNukeOnDelete, dwType, VolSerialNumber, MaxComponentLength;
1523 DWORD FileSystemFlags, dwSize, dwDisposition;
1524 HKEY hKey;
1525 WCHAR szBuffer[10];
1526 WCHAR szKey[150] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\";
1527
1528 if (wszPath[1] != L':')
1529 {
1530 /* path is UNC */
1531 return FALSE;
1532 }
1533
1534 if (GetDriveTypeW(wszPath) != DRIVE_FIXED)
1535 {
1536 /* no bitbucket on removable media */
1537 return FALSE;
1538 }
1539
1540 if (!GetVolumeInformationW(wszPath, NULL, 0, &VolSerialNumber, &MaxComponentLength, &FileSystemFlags, NULL, 0))
1541 {
1542 ERR("GetVolumeInformationW failed with %u\n", GetLastError());
1543 return FALSE;
1544 }
1545
1546 swprintf(szBuffer, L"%04X-%04X", LOWORD(VolSerialNumber), HIWORD(VolSerialNumber));
1547 wcscat(szKey, szBuffer);
1548
1549 if (RegCreateKeyExW(HKEY_CURRENT_USER, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS)
1550 {
1551 ERR("RegCreateKeyExW failed\n");
1552 return FALSE;
1553 }
1554
1555 if (dwDisposition & REG_CREATED_NEW_KEY)
1556 {
1557 /* per default move to bitbucket */
1558 dwNukeOnDelete = 0;
1559 RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD));
1560 /* per default unlimited size */
1561 dwSize = -1;
1562 RegSetValueExW(hKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD));
1563 RegCloseKey(hKey);
1564 return TRUE;
1565 }
1566 else
1567 {
1568 dwSize = sizeof(dwNukeOnDelete);
1569 ret = RegQueryValueExW(hKey, L"NukeOnDelete", NULL, &dwType, (LPBYTE)&dwNukeOnDelete, &dwSize);
1570 if (ret != ERROR_SUCCESS)
1571 {
1572 if (ret == ERROR_FILE_NOT_FOUND)
1573 {
1574 /* restore key and enable bitbucket */
1575 dwNukeOnDelete = 0;
1576 RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD));
1577 }
1578 RegCloseKey(hKey);
1579 return TRUE;
1580 }
1581 else if (dwNukeOnDelete)
1582 {
1583 /* do not delete to bitbucket */
1584 RegCloseKey(hKey);
1585 return FALSE;
1586 }
1587 /* FIXME
1588 * check if bitbucket is full
1589 */
1590 RegCloseKey(hKey);
1591 return TRUE;
1592 }
1593 }
1594
1595 BOOL
1596 TRASH_TrashFile(LPCWSTR wszPath)
1597 {
1598 TRACE("(%s)\n", debugstr_w(wszPath));
1599 return DeleteFileToRecycleBinW(wszPath);
1600 }
1601
1602 /*************************************************************************
1603 * SHUpdateRecycleBinIcon [SHELL32.@]
1604 *
1605 * Undocumented
1606 */
1607 HRESULT WINAPI SHUpdateRecycleBinIcon(void)
1608 {
1609 FIXME("stub\n");
1610
1611
1612
1613 return S_OK;
1614 }