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