2 * Trash virtual folder support. The trashing engine is implemented in trash.c
4 * Copyright (C) 2006 Mikolaj Zalewski
5 * Copyright (C) 2009 Andrew Hill
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.
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.
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
27 #define MAX_PROPERTY_SHEET_PAGE 32
29 WINE_DEFAULT_DEBUG_CHANNEL(CRecycleBin
);
41 static const columninfo RecycleBinColumns
[] =
43 {IDS_SHV_COLUMN1
, &FMTID_Storage
, PID_STG_NAME
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 30},
44 {IDS_SHV_COLUMN_DELFROM
, &FMTID_Displaced
, PID_DISPLACED_FROM
, SHCOLSTATE_TYPE_STR
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 30},
45 {IDS_SHV_COLUMN_DELDATE
, &FMTID_Displaced
, PID_DISPLACED_DATE
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 20},
46 {IDS_SHV_COLUMN2
, &FMTID_Storage
, PID_STG_SIZE
, SHCOLSTATE_TYPE_INT
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_RIGHT
, 20},
47 {IDS_SHV_COLUMN3
, &FMTID_Storage
, PID_STG_STORAGETYPE
, SHCOLSTATE_TYPE_INT
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 20},
48 {IDS_SHV_COLUMN4
, &FMTID_Storage
, PID_STG_WRITETIME
, SHCOLSTATE_TYPE_DATE
| SHCOLSTATE_ONBYDEFAULT
, LVCFMT_LEFT
, 20},
49 /* {"creation time", &FMTID_Storage, PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE, LVCFMT_LEFT, 20}, */
50 /* {"attribs", &FMTID_Storage, PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 20}, */
54 #define COLUMN_DELFROM 1
55 #define COLUMN_DATEDEL 2
58 #define COLUMN_MTIME 5
60 #define COLUMNS_COUNT 6
66 class CRecycleBinEnum
:
67 public CEnumIDListBase
73 HRESULT WINAPI
Initialize(DWORD dwFlags
);
74 static BOOL WINAPI
CBEnumRecycleBin(IN PVOID Context
, IN HANDLE hDeletedFile
);
75 BOOL WINAPI
CBEnumRecycleBin(IN HANDLE hDeletedFile
);
77 BEGIN_COM_MAP(CRecycleBinEnum
)
78 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList
, IEnumIDList
)
82 class CRecycleBinItemContextMenu
:
83 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
89 CRecycleBinItemContextMenu();
90 ~CRecycleBinItemContextMenu();
91 HRESULT WINAPI
Initialize(LPCITEMIDLIST pidl
);
94 virtual HRESULT WINAPI
QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
);
95 virtual HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
);
96 virtual HRESULT WINAPI
GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
);
99 virtual HRESULT WINAPI
HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
101 BEGIN_COM_MAP(CRecycleBinItemContextMenu
)
102 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
103 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
109 PIDLRecycleStruct
*pFileDetails
;
112 } SEARCH_CONTEXT
, *PSEARCH_CONTEXT
;
116 DWORD dwNukeOnDelete
;
119 } DRIVE_ITEM_CONTEXT
, *PDRIVE_ITEM_CONTEXT
;
121 BOOL WINAPI
CBSearchRecycleBin(IN PVOID Context
, IN HANDLE hDeletedFile
)
123 PSEARCH_CONTEXT pContext
= (PSEARCH_CONTEXT
)Context
;
125 PDELETED_FILE_DETAILS_W pFileDetails
;
129 if (!GetDeletedFileDetailsW(hDeletedFile
,
133 GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
135 ERR("GetDeletedFileDetailsW failed\n");
139 pFileDetails
= (DELETED_FILE_DETAILS_W
*)SHAlloc(dwSize
);
146 if (!GetDeletedFileDetailsW(hDeletedFile
,
151 ERR("GetDeletedFileDetailsW failed\n");
152 SHFree(pFileDetails
);
156 ret
= memcmp(pFileDetails
, pContext
->pFileDetails
, dwSize
);
159 pContext
->hDeletedFile
= hDeletedFile
;
160 pContext
->bFound
= TRUE
;
163 CloseRecycleBinHandle(hDeletedFile
);
165 SHFree(pFileDetails
);
169 static PIDLRecycleStruct
* _ILGetRecycleStruct(LPCITEMIDLIST pidl
)
171 LPPIDLDATA pdata
= _ILGetDataPointer(pidl
);
173 if (pdata
&& pdata
->type
== 0x00)
174 return (PIDLRecycleStruct
*) & (pdata
->u
.crecycle
);
179 CRecycleBinEnum::CRecycleBinEnum()
183 CRecycleBinEnum::~CRecycleBinEnum()
187 HRESULT WINAPI
CRecycleBinEnum::Initialize(DWORD dwFlags
)
189 static LPCWSTR szDrive
= L
"C:\\";
191 if (dwFlags
& SHCONTF_NONFOLDERS
)
193 TRACE("Starting Enumeration\n");
195 if (!EnumerateRecycleBinW(szDrive
/* FIXME */ , CBEnumRecycleBin
, (PVOID
)this))
197 WARN("Error: EnumerateCRecycleBinW failed\n");
208 static LPITEMIDLIST
_ILCreateRecycleItem(PDELETED_FILE_DETAILS_W pFileDetails
)
212 PIDLRecycleStruct
* p
;
213 int size0
= (char*)&tmp
.u
.crecycle
.szName
- (char*)&tmp
.u
.crecycle
;
217 size
+= (wcslen(pFileDetails
->FileName
) + 1) * sizeof(WCHAR
);
219 pidl
= (LPITEMIDLIST
)SHAlloc(size
+ 4);
223 pidl
->mkid
.cb
= size
+ 2;
224 memcpy(pidl
->mkid
.abID
, &tmp
, 2 + size0
);
226 p
= &((PIDLDATA
*)pidl
->mkid
.abID
)->u
.crecycle
;
227 RtlCopyMemory(p
, pFileDetails
, sizeof(DELETED_FILE_DETAILS_W
));
228 wcscpy(p
->szName
, pFileDetails
->FileName
);
229 *(WORD
*)((char*)pidl
+ (size
+ 2)) = 0;
233 BOOL WINAPI
CRecycleBinEnum::CBEnumRecycleBin(IN PVOID Context
, IN HANDLE hDeletedFile
)
235 return static_cast<CRecycleBinEnum
*>(Context
)->CBEnumRecycleBin(hDeletedFile
);
238 BOOL WINAPI
CRecycleBinEnum::CBEnumRecycleBin(IN HANDLE hDeletedFile
)
240 PDELETED_FILE_DETAILS_W pFileDetails
;
242 LPITEMIDLIST pidl
= NULL
;
245 if (!GetDeletedFileDetailsW(hDeletedFile
,
249 GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
251 ERR("GetDeletedFileDetailsW failed\n");
255 pFileDetails
= (DELETED_FILE_DETAILS_W
*)SHAlloc(dwSize
);
262 if (!GetDeletedFileDetailsW(hDeletedFile
,
267 ERR("GetDeletedFileDetailsW failed\n");
268 SHFree(pFileDetails
);
272 pidl
= _ILCreateRecycleItem(pFileDetails
);
275 SHFree(pFileDetails
);
279 ret
= AddToEnumList(pidl
);
283 SHFree(pFileDetails
);
284 TRACE("Returning %d\n", ret
);
285 CloseRecycleBinHandle(hDeletedFile
);
289 /**************************************************************************
290 * IContextMenu2 Bitbucket Item Implementation
293 CRecycleBinItemContextMenu::CRecycleBinItemContextMenu()
298 CRecycleBinItemContextMenu::~CRecycleBinItemContextMenu()
303 HRESULT WINAPI
CRecycleBinItemContextMenu::Initialize(LPCITEMIDLIST pidl
)
305 apidl
= ILClone(pidl
);
307 return E_OUTOFMEMORY
;
311 HRESULT WINAPI
CRecycleBinItemContextMenu::QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
313 WCHAR szBuffer
[30] = {0};
316 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", this, hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
318 if (LoadStringW(shell32_hInstance
, IDS_RESTORE
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
320 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
321 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
, MFT_STRING
, szBuffer
, MFS_ENABLED
);
325 if (LoadStringW(shell32_hInstance
, IDS_CUT
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
327 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
328 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
329 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_STRING
, szBuffer
, MFS_ENABLED
);
332 if (LoadStringW(shell32_hInstance
, IDS_DELETE
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
334 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
335 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
336 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_STRING
, szBuffer
, MFS_ENABLED
);
339 if (LoadStringW(shell32_hInstance
, IDS_PROPERTIES
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
341 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
342 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
343 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
, MFT_STRING
, szBuffer
, MFS_DEFAULT
);
346 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Count
);
349 HRESULT WINAPI
CRecycleBinItemContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
351 SEARCH_CONTEXT Context
;
352 static LPCWSTR szDrive
= L
"C:\\";
354 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi
, lpcmi
->lpVerb
, lpcmi
->hwnd
);
356 if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(1) || lpcmi
->lpVerb
== MAKEINTRESOURCEA(5))
358 Context
.pFileDetails
= _ILGetRecycleStruct(apidl
);
359 Context
.bFound
= FALSE
;
361 EnumerateRecycleBinW(szDrive
, CBSearchRecycleBin
, (PVOID
)&Context
);
365 if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(1))
368 if (RestoreFile(Context
.hDeletedFile
))
375 DeleteFileHandleToRecycleBin(Context
.hDeletedFile
);
379 else if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(3))
381 FIXME("implement cut\n");
384 else if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(7))
386 FIXME("implement properties\n");
393 HRESULT WINAPI
CRecycleBinItemContextMenu::GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
)
395 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
400 HRESULT WINAPI
CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
402 TRACE("CRecycleBin_IContextMenu2Item_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg
, wParam
, lParam
);
407 /**************************************************************************
408 * registers clipboardformat once
410 void CRecycleBin::SF_RegisterClipFmt()
412 TRACE ("(%p)\n", this);
415 cfShellIDList
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
418 CRecycleBin::CRecycleBin()
423 SF_RegisterClipFmt();
427 CRecycleBin::~CRecycleBin()
429 /* InterlockedDecrement(&objCount);*/
433 /*************************************************************************
434 * RecycleBin IPersistFolder2 interface
437 HRESULT WINAPI
CRecycleBin::GetClassID(CLSID
*pClassID
)
439 TRACE("(%p, %p)\n", this, pClassID
);
440 if (pClassID
== NULL
)
442 memcpy(pClassID
, &CLSID_RecycleBin
, sizeof(CLSID
));
446 HRESULT WINAPI
CRecycleBin::Initialize(LPCITEMIDLIST pidl
)
448 TRACE("(%p, %p)\n", this, pidl
);
450 SHFree((LPVOID
)this->pidl
);
451 this->pidl
= ILClone(pidl
);
452 if (this->pidl
== NULL
)
453 return E_OUTOFMEMORY
;
457 HRESULT WINAPI
CRecycleBin::GetCurFolder(LPITEMIDLIST
*ppidl
)
460 *ppidl
= ILClone(pidl
);
464 /*************************************************************************
465 * RecycleBin IShellFolder2 interface
468 HRESULT WINAPI
CRecycleBin::ParseDisplayName(HWND hwnd
, LPBC pbc
,
469 LPOLESTR pszDisplayName
, ULONG
*pchEaten
, PIDLIST_RELATIVE
*ppidl
,
470 ULONG
*pdwAttributes
)
477 PDELETED_FILE_DETAILS_W
478 UnpackDetailsFromPidl(LPCITEMIDLIST pidl
)
480 return (PDELETED_FILE_DETAILS_W
)&pidl
->mkid
.abID
;
483 HRESULT WINAPI
CRecycleBin::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
485 return ShellObjectCreatorInit
<CRecycleBinEnum
>(dwFlags
, IID_IEnumIDList
, ppEnumIDList
);
488 HRESULT WINAPI
CRecycleBin::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbc
, REFIID riid
, void **ppv
)
490 FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl
, pbc
, debugstr_guid(&riid
), ppv
);
494 HRESULT WINAPI
CRecycleBin::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbc
, REFIID riid
, void **ppv
)
496 FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl
, pbc
, debugstr_guid(&riid
), ppv
);
500 HRESULT WINAPI
CRecycleBin::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
503 TRACE("(%p, %p, %p, %p)\n", this, (void *)lParam
, pidl1
, pidl2
);
504 if (pidl1
->mkid
.cb
!= pidl2
->mkid
.cb
)
505 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, pidl1
->mkid
.cb
- pidl2
->mkid
.cb
);
506 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, (unsigned short)memcmp(pidl1
->mkid
.abID
, pidl2
->mkid
.abID
, pidl1
->mkid
.cb
));
509 HRESULT WINAPI
CRecycleBin::CreateViewObject(HWND hwndOwner
, REFIID riid
, void **ppv
)
511 CComPtr
<IShellView
> pShellView
;
512 HRESULT hr
= E_NOINTERFACE
;
514 TRACE("(%p, %p, %s, %p)\n", this, hwndOwner
, debugstr_guid(&riid
), ppv
);
521 if (IsEqualIID (riid
, IID_IDropTarget
))
523 hr
= this->QueryInterface (IID_IDropTarget
, ppv
);
525 else if (IsEqualIID (riid
, IID_IContextMenu
) || IsEqualIID (riid
, IID_IContextMenu2
))
527 hr
= this->QueryInterface(riid
, ppv
);
529 else if (IsEqualIID (riid
, IID_IShellView
))
531 hr
= IShellView_Constructor ((IShellFolder
*)this, &pShellView
);
534 hr
= pShellView
->QueryInterface(riid
, ppv
);
539 TRACE ("-- (%p)->(interface=%p)\n", this, ppv
);
544 HRESULT WINAPI
CRecycleBin::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
547 TRACE("(%p, %d, {%p, ...}, {%x})\n", this, cidl
, apidl
? apidl
[0] : NULL
, (unsigned int)*rgfInOut
);
548 *rgfInOut
&= SFGAO_FOLDER
|SFGAO_DROPTARGET
|SFGAO_HASPROPSHEET
|SFGAO_CANLINK
;
552 HRESULT WINAPI
CRecycleBin::GetUIObjectOf(HWND hwndOwner
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
553 REFIID riid
, UINT
*prgfInOut
, void **ppv
)
555 IUnknown
*pObj
= NULL
;
556 HRESULT hr
= E_INVALIDARG
;
558 TRACE ("(%p)->(%p,%u,apidl=%p, %p %p)\n", this,
559 hwndOwner
, cidl
, apidl
, prgfInOut
, ppv
);
566 if ((IsEqualIID (riid
, IID_IContextMenu
) || IsEqualIID(riid
, IID_IContextMenu2
)) && (cidl
>= 1))
568 hr
= ShellObjectCreatorInit
<CRecycleBinItemContextMenu
>(apidl
[0], riid
, &pObj
);
570 else if (IsEqualIID (riid
, IID_IDropTarget
) && (cidl
== 1))
572 IDropTarget
* pDt
= NULL
;
573 hr
= QueryInterface(IID_PPV_ARG(IDropTarget
, &pDt
));
576 else if(IsEqualIID(riid
, IID_IExtractIconA
) && (cidl
== 1))
578 // FIXME: This is not correct, it does not show the right icons
579 LPITEMIDLIST pidlItem
= ILCombine(pidl
, apidl
[0]);
580 pObj
= IExtractIconA_Constructor(pidlItem
);
584 else if (IsEqualIID(riid
, IID_IExtractIconW
) && (cidl
== 1))
586 // FIXME: This is not correct, it does not show the right icons
587 LPITEMIDLIST pidlItem
= ILCombine(pidl
, apidl
[0]);
588 pObj
= IExtractIconW_Constructor(pidlItem
);
595 if (SUCCEEDED(hr
) && !pObj
)
599 TRACE ("(%p)->hr=0x%08x\n", this, hr
);
603 HRESULT WINAPI
CRecycleBin::GetDisplayNameOf(PCUITEMID_CHILD pidl
, SHGDNF uFlags
, STRRET
*pName
)
605 PIDLRecycleStruct
*pFileDetails
;
608 TRACE("(%p, %p, %x, %p)\n", this, pidl
, (unsigned int)uFlags
, pName
);
611 if (_ILIsBitBucket (pidl
))
615 if (HCR_GetClassNameW(CLSID_RecycleBin
, pszPath
, MAX_PATH
))
617 pName
->uType
= STRRET_WSTR
;
618 pName
->pOleStr
= StrDupW(pszPath
);
623 pFileDetails
= _ILGetRecycleStruct(pidl
);
627 pName
->uType
= STRRET_CSTR
;
631 pFileName
= wcsrchr(pFileDetails
->szName
, L
'\\');
635 pName
->uType
= STRRET_CSTR
;
639 pName
->pOleStr
= StrDupW(pFileName
+ 1);
640 if (pName
->pOleStr
== NULL
)
641 return E_OUTOFMEMORY
;
643 pName
->uType
= STRRET_WSTR
;
647 HRESULT WINAPI
CRecycleBin::SetNameOf(HWND hwnd
, PCUITEMID_CHILD pidl
, LPCOLESTR pszName
,
648 SHGDNF uFlags
, PITEMID_CHILD
*ppidlOut
)
651 return E_FAIL
; /* not supported */
654 HRESULT WINAPI
CRecycleBin::GetDefaultSearchGUID(GUID
*pguid
)
660 HRESULT WINAPI
CRecycleBin::EnumSearches(IEnumExtraSearch
**ppEnum
)
667 HRESULT WINAPI
CRecycleBin::GetDefaultColumn(DWORD dwReserved
, ULONG
*pSort
, ULONG
*pDisplay
)
669 TRACE("(%p, %x, %p, %p)\n", this, (unsigned int)dwReserved
, pSort
, pDisplay
);
675 HRESULT WINAPI
CRecycleBin::GetDefaultColumnState(UINT iColumn
, SHCOLSTATEF
*pcsFlags
)
677 TRACE("(%p, %d, %p)\n", this, iColumn
, pcsFlags
);
678 if (iColumn
>= COLUMNS_COUNT
)
680 *pcsFlags
= RecycleBinColumns
[iColumn
].pcsFlags
;
684 HRESULT WINAPI
CRecycleBin::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
690 static HRESULT
FormatDateTime(LPWSTR buffer
, int size
, FILETIME
* ft
)
696 FileTimeToLocalFileTime(ft
, &lft
);
697 FileTimeToSystemTime(&lft
, &time
);
699 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &time
, NULL
, buffer
, size
);
700 if (ret
> 0 && ret
< size
)
702 /* Append space + time without seconds */
704 GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &time
, NULL
, &buffer
[ret
], size
- ret
);
707 return (ret
!= 0 ? E_FAIL
: S_OK
);
710 HRESULT WINAPI
CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, LPSHELLDETAILS pDetails
)
712 PIDLRecycleStruct
* pFileDetails
;
713 WCHAR buffer
[MAX_PATH
];
714 WCHAR szTypeName
[100];
718 TRACE("(%p, %p, %d, %p)\n", this, pidl
, iColumn
, pDetails
);
719 if (iColumn
>= COLUMNS_COUNT
)
721 pDetails
->fmt
= RecycleBinColumns
[iColumn
].fmt
;
722 pDetails
->cxChar
= RecycleBinColumns
[iColumn
].cxChars
;
725 pDetails
->str
.uType
= STRRET_WSTR
;
726 LoadStringW(shell32_hInstance
, RecycleBinColumns
[iColumn
].column_name_id
, buffer
, MAX_PATH
);
727 return SHStrDupW(buffer
, &pDetails
->str
.pOleStr
);
730 if (iColumn
== COLUMN_NAME
)
731 return GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &pDetails
->str
);
733 pFileDetails
= _ILGetRecycleStruct(pidl
);
737 FormatDateTime(buffer
, MAX_PATH
, &pFileDetails
->DeletionTime
);
740 pszBackslash
= wcsrchr(pFileDetails
->szName
, L
'\\');
741 Length
= (pszBackslash
- pFileDetails
->szName
);
742 memcpy((LPVOID
)buffer
, pFileDetails
->szName
, Length
* sizeof(WCHAR
));
743 buffer
[Length
] = L
'\0';
746 StrFormatKBSizeW(pFileDetails
->FileSize
.QuadPart
, buffer
, MAX_PATH
);
749 FormatDateTime(buffer
, MAX_PATH
, &pFileDetails
->LastModification
);
752 szTypeName
[0] = L
'\0';
753 wcscpy(buffer
, PathFindExtensionW(pFileDetails
->szName
));
754 if (!( HCR_MapTypeToValueW(buffer
, buffer
, sizeof(buffer
) / sizeof(WCHAR
), TRUE
) &&
755 HCR_MapTypeToValueW(buffer
, szTypeName
, sizeof(szTypeName
) / sizeof(WCHAR
), FALSE
)))
757 wcscpy (szTypeName
, PathFindExtensionW(pFileDetails
->szName
));
758 wcscat(szTypeName
, L
"-");
759 Length
= wcslen(szTypeName
);
760 if (LoadStringW(shell32_hInstance
, IDS_SHV_COLUMN1
, &szTypeName
[Length
], (sizeof(szTypeName
) / sizeof(WCHAR
)) - Length
))
761 szTypeName
[(sizeof(szTypeName
)/sizeof(WCHAR
))-1] = L
'\0';
763 pDetails
->str
.uType
= STRRET_WSTR
;
764 return SHStrDupW(szTypeName
, &pDetails
->str
.pOleStr
);
770 pDetails
->str
.uType
= STRRET_WSTR
;
771 return SHStrDupW(buffer
, &pDetails
->str
.pOleStr
);
774 HRESULT WINAPI
CRecycleBin::MapColumnToSCID(UINT iColumn
, SHCOLUMNID
*pscid
)
776 TRACE("(%p, %d, %p)\n", this, iColumn
, pscid
);
777 if (iColumn
>= COLUMNS_COUNT
)
779 pscid
->fmtid
= *RecycleBinColumns
[iColumn
].fmtId
;
780 pscid
->pid
= RecycleBinColumns
[iColumn
].pid
;
784 /*************************************************************************
785 * RecycleBin IContextMenu interface
788 HRESULT WINAPI
CRecycleBin::QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
794 TRACE("QueryContextMenu %p %p %u %u %u %u\n", this, hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
799 memset(&mii
, 0, sizeof(mii
));
800 mii
.cbSize
= sizeof(mii
);
801 mii
.fMask
= MIIM_TYPE
| MIIM_ID
| MIIM_STATE
;
802 mii
.fState
= MFS_ENABLED
;
804 LoadStringW(shell32_hInstance
, IDS_EMPTY_BITBUCKET
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
));
805 mii
.dwTypeData
= szBuffer
;
806 mii
.cch
= wcslen(mii
.dwTypeData
);
807 mii
.wID
= idCmdFirst
+ id
++;
808 mii
.fType
= MFT_STRING
;
811 if (!InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
814 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, id
);
817 HRESULT WINAPI
CRecycleBin::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
821 IShellView
* lpSV
= NULL
;
823 TRACE("%p %p verb %p\n", this, lpcmi
, lpcmi
->lpVerb
);
825 if (LOWORD(lpcmi
->lpVerb
) == iIdEmpty
)
829 hr
= SHEmptyRecycleBinW(lpcmi
->hwnd
, L
"C:\\", 0);
830 TRACE("result %x\n", hr
);
834 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
835 if (lpSB
&& SUCCEEDED(lpSB
->QueryActiveShellView(&lpSV
)))
841 HRESULT WINAPI
CRecycleBin::GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
)
843 FIXME("%p %lu %u %p %p %u\n", this, idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
848 /*************************************************************************
849 * RecycleBin IShellPropSheetExt interface
852 HRESULT WINAPI
CRecycleBin::AddPages(LPFNSVADDPROPSHEETPAGE pfnAddPage
, LPARAM lParam
)
854 FIXME("%p %p %lu\n", this, pfnAddPage
, lParam
);
859 HRESULT WINAPI
CRecycleBin::ReplacePage(EXPPS uPageID
, LPFNSVADDPROPSHEETPAGE pfnReplaceWith
, LPARAM lParam
)
861 FIXME("%p %lu %p %lu\n", this, uPageID
, pfnReplaceWith
, lParam
);
866 /*************************************************************************
867 * RecycleBin IShellExtInit interface
870 HRESULT WINAPI
CRecycleBin::Initialize(LPCITEMIDLIST pidlFolder
, IDataObject
*pdtobj
, HKEY hkeyProgID
)
872 TRACE("%p %p %p %p\n", this, pidlFolder
, pdtobj
, hkeyProgID
);
876 void toggleNukeOnDeleteOption(HWND hwndDlg
, BOOL bEnable
)
880 SendDlgItemMessage(hwndDlg
, 14001, BM_SETCHECK
, BST_UNCHECKED
, 0);
881 EnableWindow(GetDlgItem(hwndDlg
, 14002), FALSE
);
882 SendDlgItemMessage(hwndDlg
, 14003, BM_SETCHECK
, BST_CHECKED
, 0);
886 SendDlgItemMessage(hwndDlg
, 14001, BM_SETCHECK
, BST_CHECKED
, 0);
887 EnableWindow(GetDlgItem(hwndDlg
, 14002), TRUE
);
888 SendDlgItemMessage(hwndDlg
, 14003, BM_SETCHECK
, BST_UNCHECKED
, 0);
894 InitializeRecycleBinDlg(HWND hwndDlg
, WCHAR DefaultDrive
)
896 WCHAR CurDrive
= L
'A';
897 WCHAR szDrive
[] = L
"A:\\";
901 DWORD MaxComponent
, Flags
;
907 ULARGE_INTEGER TotalNumberOfFreeBytes
, TotalNumberOfBytes
, FreeBytesAvailable
;
912 PDRIVE_ITEM_CONTEXT pItem
= NULL
, pDefault
= NULL
, pFirst
= NULL
;
914 hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
916 if (!LoadStringW(shell32_hInstance
, IDS_RECYCLEBIN_LOCATION
, szVolume
, sizeof(szVolume
) / sizeof(WCHAR
)))
919 GetClientRect(hDlgCtrl
, &rect
);
921 memset(&lc
, 0, sizeof(LV_COLUMN
) );
922 lc
.mask
= LVCF_WIDTH
| LVCF_TEXT
| LVCF_SUBITEM
| LVCF_FMT
;
924 columnSize
= 140; //FIXME
926 lc
.fmt
= LVCFMT_FIXED_WIDTH
;
928 lc
.cchTextMax
= wcslen(szVolume
);
929 lc
.pszText
= szVolume
;
930 (void)SendMessageW(hDlgCtrl
, LVM_INSERTCOLUMNW
, 0, (LPARAM
)&lc
);
932 if (!LoadStringW(shell32_hInstance
, IDS_RECYCLEBIN_DISKSPACE
, szVolume
, sizeof(szVolume
) / sizeof(WCHAR
)))
936 lc
.cx
= rect
.right
- rect
.left
- columnSize
;
937 lc
.cchTextMax
= wcslen(szVolume
);
938 lc
.pszText
= szVolume
;
939 (void)SendMessageW(hDlgCtrl
, LVM_INSERTCOLUMNW
, 1, (LPARAM
)&lc
);
941 dwDrives
= GetLogicalDrives();
945 if ((dwDrives
& 0x1))
947 UINT Type
= GetDriveTypeW(szDrive
);
948 if (Type
== DRIVE_FIXED
) //FIXME
950 if (!GetVolumeInformationW(szDrive
, szName
, sizeof(szName
) / sizeof(WCHAR
), &dwSerial
, &MaxComponent
, &Flags
, NULL
, 0))
956 swprintf(szVolume
, L
"%s (%c)", szName
, szDrive
[0]);
957 memset(&li
, 0x0, sizeof(LVITEMW
));
958 li
.mask
= LVIF_TEXT
| LVIF_PARAM
;
960 li
.pszText
= szVolume
;
961 li
.iItem
= itemCount
;
962 SendMessageW(hDlgCtrl
, LVM_INSERTITEMW
, 0, (LPARAM
)&li
);
963 if (GetDiskFreeSpaceExW(szDrive
, &FreeBytesAvailable
, &TotalNumberOfBytes
, &TotalNumberOfFreeBytes
))
965 if (StrFormatByteSizeW(TotalNumberOfFreeBytes
.QuadPart
, szVolume
, sizeof(szVolume
) / sizeof(WCHAR
)))
968 pItem
= (DRIVE_ITEM_CONTEXT
*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(DRIVE_ITEM_CONTEXT
));
971 swprintf(szName
, L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\%04X-%04X", LOWORD(dwSerial
), HIWORD(dwSerial
));
972 dwSize
= sizeof(DWORD
);
973 RegGetValueW(HKEY_CURRENT_USER
, szName
, L
"MaxCapacity", RRF_RT_DWORD
, NULL
, &pItem
->dwMaxCapacity
, &dwSize
);
974 dwSize
= sizeof(DWORD
);
975 RegGetValueW(HKEY_CURRENT_USER
, szName
, L
"NukeOnDelete", RRF_RT_DWORD
, NULL
, &pItem
->dwNukeOnDelete
, &dwSize
);
976 pItem
->dwSerial
= dwSerial
;
977 li
.mask
= LVIF_PARAM
;
978 li
.lParam
= (LPARAM
)pItem
;
979 (void)SendMessageW(hDlgCtrl
, LVM_SETITEMW
, 0, (LPARAM
)&li
);
980 if (CurDrive
== DefaultDrive
)
982 defIndex
= itemCount
;
991 li
.pszText
= szVolume
;
992 li
.iItem
= itemCount
;
993 (void)SendMessageW(hDlgCtrl
, LVM_SETITEMW
, 0, (LPARAM
)&li
);
1000 szDrive
[0] = CurDrive
;
1001 dwDrives
= (dwDrives
>> 1);
1008 toggleNukeOnDeleteOption(hwndDlg
, pDefault
->dwNukeOnDelete
);
1009 SetDlgItemInt(hwndDlg
, 14002, pDefault
->dwMaxCapacity
, FALSE
);
1011 ZeroMemory(&li
, sizeof(li
));
1012 li
.mask
= LVIF_STATE
;
1013 li
.stateMask
= (UINT
) - 1;
1014 li
.state
= LVIS_FOCUSED
| LVIS_SELECTED
;
1015 li
.iItem
= defIndex
;
1016 (void)SendMessageW(hDlgCtrl
, LVM_SETITEMW
, 0, (LPARAM
)&li
);
1020 static BOOL
StoreDriveSettings(HWND hwndDlg
)
1023 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
1025 PDRIVE_ITEM_CONTEXT pItem
;
1031 if (RegCreateKeyExW(HKEY_CURRENT_USER
, L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume", 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, NULL
) != ERROR_SUCCESS
)
1034 iCount
= ListView_GetItemCount(hDlgCtrl
);
1036 ZeroMemory(&li
, sizeof(li
));
1037 li
.mask
= LVIF_PARAM
;
1039 for(iIndex
= 0; iIndex
< iCount
; iIndex
++)
1042 if (SendMessageW(hDlgCtrl
, LVM_GETITEMW
, 0, (LPARAM
)&li
))
1044 pItem
= (PDRIVE_ITEM_CONTEXT
)li
.lParam
;
1045 swprintf(szSerial
, L
"%04X-%04X", LOWORD(pItem
->dwSerial
), HIWORD(pItem
->dwSerial
));
1046 if (RegCreateKeyExW(hKey
, szSerial
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hSubKey
, NULL
) == ERROR_SUCCESS
)
1048 dwSize
= sizeof(DWORD
);
1049 RegSetValueExW(hSubKey
, L
"NukeOnDelete", 0, REG_DWORD
, (LPBYTE
)&pItem
->dwNukeOnDelete
, dwSize
);
1050 dwSize
= sizeof(DWORD
);
1051 RegSetValueExW(hSubKey
, L
"MaxCapacity", 0, REG_DWORD
, (LPBYTE
)&pItem
->dwMaxCapacity
, dwSize
);
1052 RegCloseKey(hSubKey
);
1061 static VOID
FreeDriveItemContext(HWND hwndDlg
)
1064 HWND hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
1067 iCount
= ListView_GetItemCount(hDlgCtrl
);
1069 ZeroMemory(&li
, sizeof(li
));
1070 li
.mask
= LVIF_PARAM
;
1072 for(iIndex
= 0; iIndex
< iCount
; iIndex
++)
1075 if (SendMessageW(hDlgCtrl
, LVM_GETITEMW
, 0, (LPARAM
)&li
))
1077 HeapFree(GetProcessHeap(), 0, (LPVOID
)li
.lParam
);
1083 GetDefaultItem(HWND hwndDlg
, LVITEMW
* li
)
1086 UINT iItemCount
, iIndex
;
1088 hDlgCtrl
= GetDlgItem(hwndDlg
, 14000);
1092 iItemCount
= ListView_GetItemCount(hDlgCtrl
);
1096 ZeroMemory(li
, sizeof(LVITEMW
));
1097 li
->mask
= LVIF_PARAM
| LVIF_STATE
;
1098 li
->stateMask
= (UINT
) - 1;
1099 for (iIndex
= 0; iIndex
< iItemCount
; iIndex
++)
1102 if (SendMessageW(hDlgCtrl
, LVM_GETITEMW
, 0, (LPARAM
)li
))
1104 if (li
->state
& LVIS_SELECTED
)
1112 static INT_PTR CALLBACK
1123 PDRIVE_ITEM_CONTEXT pItem
;
1126 PROPSHEETPAGE
* page
;
1132 page
= (PROPSHEETPAGE
*)lParam
;
1133 InitializeRecycleBinDlg(hwndDlg
, (WCHAR
)page
->lParam
);
1134 dwStyle
= (DWORD
) SendDlgItemMessage(hwndDlg
, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE
, 0, 0);
1135 dwStyle
= dwStyle
| LVS_EX_FULLROWSELECT
;
1136 SendDlgItemMessage(hwndDlg
, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE
, 0, dwStyle
);
1137 if (GetDlgCtrlID((HWND
)wParam
) != 14000)
1139 SetFocus(GetDlgItem(hwndDlg
, 14000));
1144 switch(LOWORD(wParam
))
1147 toggleNukeOnDeleteOption(hwndDlg
, FALSE
);
1148 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
1151 toggleNukeOnDeleteOption(hwndDlg
, TRUE
);
1152 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
1155 PropSheet_Changed(GetParent(hwndDlg
), hwndDlg
);
1160 lppsn
= (LPPSHNOTIFY
) lParam
;
1161 lppl
= (LPNMLISTVIEW
) lParam
;
1162 if (lppsn
->hdr
.code
== PSN_APPLY
)
1164 if (GetDefaultItem(hwndDlg
, &li
) > -1)
1166 pItem
= (PDRIVE_ITEM_CONTEXT
)li
.lParam
;
1169 uResult
= GetDlgItemInt(hwndDlg
, 14002, &bSuccess
, FALSE
);
1171 pItem
->dwMaxCapacity
= uResult
;
1172 if (SendDlgItemMessageW(hwndDlg
, 14003, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
1173 pItem
->dwNukeOnDelete
= TRUE
;
1175 pItem
->dwNukeOnDelete
= FALSE
;
1178 if (StoreDriveSettings(hwndDlg
))
1180 SetWindowLongPtr( hwndDlg
, DWL_MSGRESULT
, PSNRET_NOERROR
);
1184 else if (lppl
->hdr
.code
== LVN_ITEMCHANGING
)
1186 ZeroMemory(&li
, sizeof(li
));
1187 li
.mask
= LVIF_PARAM
;
1188 li
.iItem
= lppl
->iItem
;
1189 if (!SendMessageW(lppl
->hdr
.hwndFrom
, LVM_GETITEMW
, 0, (LPARAM
)&li
))
1192 pItem
= (PDRIVE_ITEM_CONTEXT
)li
.lParam
;
1196 if (!(lppl
->uOldState
& LVIS_FOCUSED
) && (lppl
->uNewState
& LVIS_FOCUSED
))
1198 /* new focused item */
1199 toggleNukeOnDeleteOption(lppl
->hdr
.hwndFrom
, pItem
->dwNukeOnDelete
);
1200 SetDlgItemInt(hwndDlg
, 14002, pItem
->dwMaxCapacity
, FALSE
);
1202 else if ((lppl
->uOldState
& LVIS_FOCUSED
) && !(lppl
->uNewState
& LVIS_FOCUSED
))
1205 uResult
= GetDlgItemInt(hwndDlg
, 14002, &bSuccess
, FALSE
);
1207 pItem
->dwMaxCapacity
= uResult
;
1208 if (SendDlgItemMessageW(hwndDlg
, 14003, BM_GETCHECK
, 0, 0) == BST_CHECKED
)
1209 pItem
->dwNukeOnDelete
= TRUE
;
1211 pItem
->dwNukeOnDelete
= FALSE
;
1218 FreeDriveItemContext(hwndDlg
);
1224 BOOL
SH_ShowRecycleBinProperties(WCHAR sDrive
)
1226 HPROPSHEETPAGE hpsp
[1];
1227 PROPSHEETHEADERW psh
;
1228 HPROPSHEETPAGE hprop
;
1233 ZeroMemory(&psh
, sizeof(PROPSHEETHEADERW
));
1234 psh
.dwSize
= sizeof(PROPSHEETHEADERW
);
1235 psh
.dwFlags
= PSP_DEFAULT
| PSH_PROPTITLE
;
1236 psh
.pszCaption
= MAKEINTRESOURCEW(IDS_RECYCLEBIN_FOLDER_NAME
);
1237 psh
.hwndParent
= NULL
;
1239 psh
.hInstance
= shell32_hInstance
;
1241 hprop
= SH_CreatePropertySheetPage(IDD_RECYCLE_BIN_PROPERTIES
, RecycleBinDlg
, (LPARAM
)sDrive
, NULL
);
1244 ERR("Failed to create property sheet\n");
1247 hpsp
[psh
.nPages
] = hprop
;
1251 ret
= PropertySheetW(&psh
);
1259 TRASH_CanTrashFile(LPCWSTR wszPath
)
1262 DWORD dwNukeOnDelete
, dwType
, VolSerialNumber
, MaxComponentLength
;
1263 DWORD FileSystemFlags
, dwSize
, dwDisposition
;
1266 WCHAR szKey
[150] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\";
1268 if (wszPath
[1] != L
':')
1274 if (GetDriveTypeW(wszPath
) != DRIVE_FIXED
)
1276 /* no bitbucket on removable media */
1280 if (!GetVolumeInformationW(wszPath
, NULL
, 0, &VolSerialNumber
, &MaxComponentLength
, &FileSystemFlags
, NULL
, 0))
1282 ERR("GetVolumeInformationW failed with %u\n", GetLastError());
1286 swprintf(szBuffer
, L
"%04X-%04X", LOWORD(VolSerialNumber
), HIWORD(VolSerialNumber
));
1287 wcscat(szKey
, szBuffer
);
1289 if (RegCreateKeyExW(HKEY_CURRENT_USER
, szKey
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, &dwDisposition
) != ERROR_SUCCESS
)
1291 ERR("RegCreateKeyExW failed\n");
1295 if (dwDisposition
& REG_CREATED_NEW_KEY
)
1297 /* per default move to bitbucket */
1299 RegSetValueExW(hKey
, L
"NukeOnDelete", 0, REG_DWORD
, (LPBYTE
)&dwNukeOnDelete
, sizeof(DWORD
));
1300 /* per default unlimited size */
1302 RegSetValueExW(hKey
, L
"MaxCapacity", 0, REG_DWORD
, (LPBYTE
)&dwSize
, sizeof(DWORD
));
1308 dwSize
= sizeof(dwNukeOnDelete
);
1309 ret
= RegQueryValueExW(hKey
, L
"NukeOnDelete", NULL
, &dwType
, (LPBYTE
)&dwNukeOnDelete
, &dwSize
);
1310 if (ret
!= ERROR_SUCCESS
)
1312 if (ret
== ERROR_FILE_NOT_FOUND
)
1314 /* restore key and enable bitbucket */
1316 RegSetValueExW(hKey
, L
"NukeOnDelete", 0, REG_DWORD
, (LPBYTE
)&dwNukeOnDelete
, sizeof(DWORD
));
1321 else if (dwNukeOnDelete
)
1323 /* do not delete to bitbucket */
1328 * check if bitbucket is full
1336 TRASH_TrashFile(LPCWSTR wszPath
)
1338 TRACE("(%s)\n", debugstr_w(wszPath
));
1339 return DeleteFileToRecycleBin(wszPath
);
1342 /*************************************************************************
1343 * SHUpdateCRecycleBinIcon [SHELL32.@]
1347 EXTERN_C HRESULT WINAPI
SHUpdateRecycleBinIcon(void)
1356 /****************************************************************************
1357 * IDropTarget implementation
1359 BOOL
CRecycleBin::QueryDrop(DWORD dwKeyState
, LPDWORD pdwEffect
)
1361 /* TODO on shift we should delete, we should update the cursor manager to show this. */
1363 DWORD dwEffect
= DROPEFFECT_COPY
;
1365 *pdwEffect
= DROPEFFECT_NONE
;
1367 if (fAcceptFmt
) { /* Does our interpretation of the keystate ... */
1368 *pdwEffect
= KeyStateToDropEffect (dwKeyState
);
1370 if (*pdwEffect
== DROPEFFECT_NONE
)
1371 *pdwEffect
= dwEffect
;
1373 /* ... matches the desired effect ? */
1374 if (dwEffect
& *pdwEffect
) {
1381 HRESULT WINAPI
CRecycleBin::DragEnter(IDataObject
*pDataObject
,
1382 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1384 TRACE("Recycle bin drag over (%p)\n", this);
1385 /* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */
1388 QueryDrop(dwKeyState
, pdwEffect
);
1392 HRESULT WINAPI
CRecycleBin::DragOver(DWORD dwKeyState
, POINTL pt
,
1395 TRACE("(%p)\n", this);
1398 return E_INVALIDARG
;
1400 QueryDrop(dwKeyState
, pdwEffect
);
1405 HRESULT WINAPI
CRecycleBin::DragLeave()
1407 TRACE("(%p)\n", this);
1414 HRESULT WINAPI
CRecycleBin::Drop(IDataObject
*pDataObject
,
1415 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1417 TRACE("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect
);
1419 /* TODO: pdwEffect should be read and make the drop object be permanently deleted in the move case (shift held) */
1422 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject
);
1423 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
1425 /* Handle cfShellIDList Drop objects here, otherwise send the approriate message to other software */
1426 if (SUCCEEDED(pDataObject
->QueryGetData(&fmt
))) {
1428 CoMarshalInterThreadInterfaceInStream(IID_IDataObject
, pDataObject
, &s
);
1429 SHCreateThread(DoDeleteThreadProc
, s
, NULL
, NULL
);
1434 * TODO call SetData on the data object with format CFSTR_TARGETCLSID
1435 * set to the Recycle Bin's class identifier CLSID_RecycleBin.
1441 DWORD WINAPI
DoDeleteThreadProc(LPVOID lpParameter
)
1444 CComPtr
<IDataObject
> pDataObject
;
1445 HRESULT hr
= CoGetInterfaceAndReleaseStream (static_cast<IStream
*>(lpParameter
), IID_PPV_ARG(IDataObject
, &pDataObject
));
1448 DoDeleteDataObject(pDataObject
);
1454 HRESULT WINAPI
DoDeleteDataObject(IDataObject
*pda
)
1456 TRACE("performing delete");
1460 FORMATETC formatetc
;
1461 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
1462 hr
= pda
->GetData(&formatetc
, &medium
);
1466 /* lock the handle */
1467 LPIDA lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
1470 ReleaseStgMedium(&medium
);
1474 /* convert the data into pidl */
1476 LPITEMIDLIST
*apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1479 ReleaseStgMedium(&medium
);
1483 CComPtr
<IShellFolder
> psfDesktop
;
1484 CComPtr
<IShellFolder
> psfFrom
= NULL
;
1486 /* Grab the desktop shell folder */
1487 hr
= SHGetDesktopFolder(&psfDesktop
);
1490 ERR("SHGetDesktopFolder failed\n");
1492 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1493 ReleaseStgMedium(&medium
);
1497 /* Find source folder, this is where the clipboard data was copied from */
1498 if (_ILIsDesktop(pidl
))
1500 psfFrom
= psfDesktop
;
1504 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfFrom
));
1507 ERR("no IShellFolder\n");
1509 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1510 ReleaseStgMedium(&medium
);
1516 hr
= psfFrom
->GetDisplayNameOf(apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1519 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1521 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1522 ReleaseStgMedium(&medium
);
1526 WCHAR wszPath
[MAX_PATH
];
1527 hr
= StrRetToBufW(&strTemp
, apidl
[0], wszPath
, _countof(wszPath
));
1530 ERR("StrRetToBufW failed with %x\n", hr
);
1532 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1533 ReleaseStgMedium(&medium
);
1537 /* Only keep the base path */
1538 LPWSTR pwszFilename
= PathFindFileNameW(wszPath
);
1539 *pwszFilename
= L
'\0';
1541 /* Build paths list */
1542 LPWSTR pwszPaths
= BuildPathsList(wszPath
, lpcida
->cidl
, (LPCITEMIDLIST
*) apidl
);
1546 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1547 ReleaseStgMedium(&medium
);
1552 SHFILEOPSTRUCTW FileOp
;
1553 ZeroMemory(&FileOp
, sizeof(FileOp
));
1554 FileOp
.wFunc
= FO_DELETE
;
1555 FileOp
.pFrom
= pwszPaths
;
1556 FileOp
.fFlags
= FOF_ALLOWUNDO
;
1558 if (SHFileOperationW(&FileOp
) != 0)
1560 ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths
));
1564 HeapFree(GetProcessHeap(), 0, pwszPaths
);
1566 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1567 ReleaseStgMedium(&medium
);
1572 /*************************************************************************
1573 * SHEmptyRecycleBinA (SHELL32.@)
1575 HRESULT WINAPI
SHEmptyRecycleBinA(HWND hwnd
, LPCSTR pszRootPath
, DWORD dwFlags
)
1577 LPWSTR szRootPathW
= NULL
;
1581 TRACE("%p, %s, 0x%08x\n", hwnd
, debugstr_a(pszRootPath
), dwFlags
);
1585 len
= MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, NULL
, 0);
1587 return HRESULT_FROM_WIN32(GetLastError());
1588 szRootPathW
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1590 return E_OUTOFMEMORY
;
1591 if (MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, szRootPathW
, len
) == 0)
1593 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1594 return HRESULT_FROM_WIN32(GetLastError());
1598 hr
= SHEmptyRecycleBinW(hwnd
, szRootPathW
, dwFlags
);
1599 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1604 HRESULT WINAPI
SHEmptyRecycleBinW(HWND hwnd
, LPCWSTR pszRootPath
, DWORD dwFlags
)
1606 WCHAR szPath
[MAX_PATH
] = {0}, szBuffer
[MAX_PATH
];
1607 DWORD dwSize
, dwType
, count
;
1609 IShellFolder
*pDesktop
, *pRecycleBin
;
1610 PIDLIST_ABSOLUTE pidlRecycleBin
;
1613 LPENUMIDLIST penumFiles
;
1616 TRACE("%p, %s, 0x%08x\n", hwnd
, debugstr_w(pszRootPath
), dwFlags
);
1618 if (!(dwFlags
& SHERB_NOCONFIRMATION
))
1620 hr
= SHGetDesktopFolder(&pDesktop
);
1623 hr
= SHGetFolderLocation(NULL
, CSIDL_BITBUCKET
, NULL
, 0, &pidlRecycleBin
);
1626 pDesktop
->Release();
1629 hr
= pDesktop
->BindToObject(pidlRecycleBin
, NULL
, IID_PPV_ARG(IShellFolder
, &pRecycleBin
));
1630 CoTaskMemFree(pidlRecycleBin
);
1631 pDesktop
->Release();
1634 hr
= pRecycleBin
->EnumObjects(hwnd
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &penumFiles
);
1637 pRecycleBin
->Release();
1644 while (penumFiles
->Next(1, &pidl
, NULL
) == S_OK
)
1647 pRecycleBin
->GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &StrRet
);
1648 StrRetToBuf(&StrRet
, pidl
, szBuffer
, _countof(szBuffer
));
1649 CoTaskMemFree(pidl
);
1651 penumFiles
->Release();
1653 pRecycleBin
->Release();
1658 /* no files, don't need confirmation */
1662 /* we have only one item inside the bin, so show a message box with its name */
1663 if (ShellMessageBoxW(shell32_hInstance
, hwnd
, MAKEINTRESOURCEW(IDS_DELETEITEM_TEXT
), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET
),
1664 MB_ICONEXCLAMATION
| MB_YESNO
| MB_DEFBUTTON2
, szBuffer
) == IDNO
)
1671 /* we have more than one item, so show a message box with the count of the items */
1672 StringCbPrintfW(szBuffer
, sizeof(szBuffer
), L
"%u", count
);
1673 if (ShellMessageBoxW(shell32_hInstance
, hwnd
, MAKEINTRESOURCEW(IDS_DELETEMULTIPLE_TEXT
), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET
),
1674 MB_ICONEXCLAMATION
| MB_YESNO
| MB_DEFBUTTON2
, szBuffer
) == IDNO
)
1682 if (dwFlags
& SHERB_NOPROGRESSUI
)
1684 ret
= EmptyRecycleBinW(pszRootPath
);
1689 * show a progress dialog
1691 ret
= EmptyRecycleBinW(pszRootPath
);
1695 return HRESULT_FROM_WIN32(GetLastError());
1697 if (!(dwFlags
& SHERB_NOSOUND
))
1699 dwSize
= sizeof(szPath
);
1700 ret
= RegGetValueW(HKEY_CURRENT_USER
,
1701 L
"AppEvents\\Schemes\\Apps\\Explorer\\EmptyRecycleBin\\.Current",
1707 if (ret
!= ERROR_SUCCESS
)
1710 if (dwType
!= REG_EXPAND_SZ
) /* type dismatch */
1713 szPath
[(sizeof(szPath
)/sizeof(WCHAR
))-1] = L
'\0';
1714 PlaySoundW(szPath
, NULL
, SND_FILENAME
);
1719 HRESULT WINAPI
SHQueryRecycleBinA(LPCSTR pszRootPath
, LPSHQUERYRBINFO pSHQueryRBInfo
)
1721 LPWSTR szRootPathW
= NULL
;
1725 TRACE("%s, %p\n", debugstr_a(pszRootPath
), pSHQueryRBInfo
);
1729 len
= MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, NULL
, 0);
1731 return HRESULT_FROM_WIN32(GetLastError());
1732 szRootPathW
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1734 return E_OUTOFMEMORY
;
1735 if (MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, szRootPathW
, len
) == 0)
1737 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1738 return HRESULT_FROM_WIN32(GetLastError());
1742 hr
= SHQueryRecycleBinW(szRootPathW
, pSHQueryRBInfo
);
1743 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1748 HRESULT WINAPI
SHQueryRecycleBinW(LPCWSTR pszRootPath
, LPSHQUERYRBINFO pSHQueryRBInfo
)
1750 FIXME("%s, %p - stub\n", debugstr_w(pszRootPath
), pSHQueryRBInfo
);
1752 if (!(pszRootPath
) || (pszRootPath
[0] == 0) ||
1753 !(pSHQueryRBInfo
) || (pSHQueryRBInfo
->cbSize
< sizeof(SHQUERYRBINFO
)))
1755 return E_INVALIDARG
;
1758 pSHQueryRBInfo
->i64Size
= 0;
1759 pSHQueryRBInfo
->i64NumItems
= 0;