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