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
;
114 BOOL WINAPI
CBSearchRecycleBin(IN PVOID Context
, IN HANDLE hDeletedFile
)
116 PSEARCH_CONTEXT pContext
= (PSEARCH_CONTEXT
)Context
;
118 PDELETED_FILE_DETAILS_W pFileDetails
;
122 if (!GetDeletedFileDetailsW(hDeletedFile
,
126 GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
128 ERR("GetDeletedFileDetailsW failed\n");
132 pFileDetails
= (DELETED_FILE_DETAILS_W
*)SHAlloc(dwSize
);
139 if (!GetDeletedFileDetailsW(hDeletedFile
,
144 ERR("GetDeletedFileDetailsW failed\n");
145 SHFree(pFileDetails
);
149 ret
= memcmp(pFileDetails
, pContext
->pFileDetails
, dwSize
);
152 pContext
->hDeletedFile
= hDeletedFile
;
153 pContext
->bFound
= TRUE
;
156 CloseRecycleBinHandle(hDeletedFile
);
158 SHFree(pFileDetails
);
162 static PIDLRecycleStruct
* _ILGetRecycleStruct(LPCITEMIDLIST pidl
)
164 LPPIDLDATA pdata
= _ILGetDataPointer(pidl
);
166 if (pdata
&& pdata
->type
== 0x00)
167 return (PIDLRecycleStruct
*) & (pdata
->u
.crecycle
);
172 CRecycleBinEnum::CRecycleBinEnum()
176 CRecycleBinEnum::~CRecycleBinEnum()
180 HRESULT WINAPI
CRecycleBinEnum::Initialize(DWORD dwFlags
)
182 static LPCWSTR szDrive
= L
"C:\\";
184 if (dwFlags
& SHCONTF_NONFOLDERS
)
186 TRACE("Starting Enumeration\n");
188 if (!EnumerateRecycleBinW(szDrive
/* FIXME */ , CBEnumRecycleBin
, (PVOID
)this))
190 WARN("Error: EnumerateCRecycleBinW failed\n");
201 static LPITEMIDLIST
_ILCreateRecycleItem(PDELETED_FILE_DETAILS_W pFileDetails
)
205 PIDLRecycleStruct
* p
;
206 int size0
= (char*)&tmp
.u
.crecycle
.szName
- (char*)&tmp
.u
.crecycle
;
210 size
+= (wcslen(pFileDetails
->FileName
) + 1) * sizeof(WCHAR
);
212 pidl
= (LPITEMIDLIST
)SHAlloc(size
+ 4);
216 pidl
->mkid
.cb
= size
+ 2;
217 memcpy(pidl
->mkid
.abID
, &tmp
, 2 + size0
);
219 p
= &((PIDLDATA
*)pidl
->mkid
.abID
)->u
.crecycle
;
220 RtlCopyMemory(p
, pFileDetails
, sizeof(DELETED_FILE_DETAILS_W
));
221 wcscpy(p
->szName
, pFileDetails
->FileName
);
222 *(WORD
*)((char*)pidl
+ (size
+ 2)) = 0;
226 BOOL WINAPI
CRecycleBinEnum::CBEnumRecycleBin(IN PVOID Context
, IN HANDLE hDeletedFile
)
228 return static_cast<CRecycleBinEnum
*>(Context
)->CBEnumRecycleBin(hDeletedFile
);
231 BOOL WINAPI
CRecycleBinEnum::CBEnumRecycleBin(IN HANDLE hDeletedFile
)
233 PDELETED_FILE_DETAILS_W pFileDetails
;
235 LPITEMIDLIST pidl
= NULL
;
238 if (!GetDeletedFileDetailsW(hDeletedFile
,
242 GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
244 ERR("GetDeletedFileDetailsW failed\n");
248 pFileDetails
= (DELETED_FILE_DETAILS_W
*)SHAlloc(dwSize
);
255 if (!GetDeletedFileDetailsW(hDeletedFile
,
260 ERR("GetDeletedFileDetailsW failed\n");
261 SHFree(pFileDetails
);
265 pidl
= _ILCreateRecycleItem(pFileDetails
);
268 SHFree(pFileDetails
);
272 ret
= AddToEnumList(pidl
);
276 SHFree(pFileDetails
);
277 TRACE("Returning %d\n", ret
);
278 CloseRecycleBinHandle(hDeletedFile
);
282 /**************************************************************************
283 * IContextMenu2 Bitbucket Item Implementation
286 CRecycleBinItemContextMenu::CRecycleBinItemContextMenu()
291 CRecycleBinItemContextMenu::~CRecycleBinItemContextMenu()
296 HRESULT WINAPI
CRecycleBinItemContextMenu::Initialize(LPCITEMIDLIST pidl
)
298 apidl
= ILClone(pidl
);
300 return E_OUTOFMEMORY
;
304 HRESULT WINAPI
CRecycleBinItemContextMenu::QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
306 WCHAR szBuffer
[30] = {0};
309 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", this, hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
311 if (LoadStringW(shell32_hInstance
, IDS_RESTORE
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
313 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
314 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
, MFT_STRING
, szBuffer
, MFS_ENABLED
);
318 if (LoadStringW(shell32_hInstance
, IDS_CUT
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
320 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
321 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
322 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_STRING
, szBuffer
, MFS_ENABLED
);
325 if (LoadStringW(shell32_hInstance
, IDS_DELETE
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
)))
327 szBuffer
[(sizeof(szBuffer
)/sizeof(WCHAR
))-1] = L
'\0';
328 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
329 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, idCmdFirst
+ Count
++, MFT_STRING
, szBuffer
, MFS_ENABLED
);
332 if (LoadStringW(shell32_hInstance
, IDS_PROPERTIES
, 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_DEFAULT
);
339 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, Count
);
342 HRESULT WINAPI
CRecycleBinItemContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
344 SEARCH_CONTEXT Context
;
345 static LPCWSTR szDrive
= L
"C:\\";
347 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi
, lpcmi
->lpVerb
, lpcmi
->hwnd
);
349 if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(1) || lpcmi
->lpVerb
== MAKEINTRESOURCEA(5))
351 Context
.pFileDetails
= _ILGetRecycleStruct(apidl
);
352 Context
.bFound
= FALSE
;
354 EnumerateRecycleBinW(szDrive
, CBSearchRecycleBin
, (PVOID
)&Context
);
358 if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(1))
361 if (RestoreFile(Context
.hDeletedFile
))
368 DeleteFileHandleToRecycleBin(Context
.hDeletedFile
);
372 else if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(3))
374 FIXME("implement cut\n");
377 else if (lpcmi
->lpVerb
== MAKEINTRESOURCEA(7))
379 FIXME("implement properties\n");
386 HRESULT WINAPI
CRecycleBinItemContextMenu::GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
)
388 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
393 HRESULT WINAPI
CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
395 TRACE("CRecycleBin_IContextMenu2Item_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg
, wParam
, lParam
);
400 /**************************************************************************
401 * registers clipboardformat once
403 void CRecycleBin::SF_RegisterClipFmt()
405 TRACE ("(%p)\n", this);
408 cfShellIDList
= RegisterClipboardFormatW(CFSTR_SHELLIDLIST
);
411 CRecycleBin::CRecycleBin()
416 SF_RegisterClipFmt();
420 CRecycleBin::~CRecycleBin()
422 /* InterlockedDecrement(&objCount);*/
426 /*************************************************************************
427 * RecycleBin IPersistFolder2 interface
430 HRESULT WINAPI
CRecycleBin::GetClassID(CLSID
*pClassID
)
432 TRACE("(%p, %p)\n", this, pClassID
);
433 if (pClassID
== NULL
)
435 memcpy(pClassID
, &CLSID_RecycleBin
, sizeof(CLSID
));
439 HRESULT WINAPI
CRecycleBin::Initialize(LPCITEMIDLIST pidl
)
441 TRACE("(%p, %p)\n", this, pidl
);
443 SHFree((LPVOID
)this->pidl
);
444 this->pidl
= ILClone(pidl
);
445 if (this->pidl
== NULL
)
446 return E_OUTOFMEMORY
;
450 HRESULT WINAPI
CRecycleBin::GetCurFolder(LPITEMIDLIST
*ppidl
)
453 *ppidl
= ILClone(pidl
);
457 /*************************************************************************
458 * RecycleBin IShellFolder2 interface
461 HRESULT WINAPI
CRecycleBin::ParseDisplayName(HWND hwnd
, LPBC pbc
,
462 LPOLESTR pszDisplayName
, ULONG
*pchEaten
, PIDLIST_RELATIVE
*ppidl
,
463 ULONG
*pdwAttributes
)
470 PDELETED_FILE_DETAILS_W
471 UnpackDetailsFromPidl(LPCITEMIDLIST pidl
)
473 return (PDELETED_FILE_DETAILS_W
)&pidl
->mkid
.abID
;
476 HRESULT WINAPI
CRecycleBin::EnumObjects(HWND hwndOwner
, DWORD dwFlags
, LPENUMIDLIST
*ppEnumIDList
)
478 return ShellObjectCreatorInit
<CRecycleBinEnum
>(dwFlags
, IID_IEnumIDList
, ppEnumIDList
);
481 HRESULT WINAPI
CRecycleBin::BindToObject(PCUIDLIST_RELATIVE pidl
, LPBC pbc
, REFIID riid
, void **ppv
)
483 FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl
, pbc
, debugstr_guid(&riid
), ppv
);
487 HRESULT WINAPI
CRecycleBin::BindToStorage(PCUIDLIST_RELATIVE pidl
, LPBC pbc
, REFIID riid
, void **ppv
)
489 FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl
, pbc
, debugstr_guid(&riid
), ppv
);
493 HRESULT WINAPI
CRecycleBin::CompareIDs(LPARAM lParam
, PCUIDLIST_RELATIVE pidl1
, PCUIDLIST_RELATIVE pidl2
)
495 PIDLRecycleStruct
* pData1
= _ILGetRecycleStruct(pidl1
);
496 PIDLRecycleStruct
* pData2
= _ILGetRecycleStruct(pidl2
);
497 LPWSTR pName1
, pName2
;
499 if(!pData1
|| !pData2
|| LOWORD(lParam
) >= COLUMNS_COUNT
)
504 switch (LOWORD(lParam
))
507 pName1
= PathFindFileNameW(pData1
->szName
);
508 pName2
= PathFindFileNameW(pData2
->szName
);
509 result
= wcsicmp(pName1
, pName2
);
511 case 1: /* Orig. Location */
512 result
= wcsicmp(pData1
->szName
, pData2
->szName
);
514 case 2: /* Date Deleted */
515 result
= CompareFileTime(&pData1
->DeletionTime
, &pData2
->DeletionTime
);
518 diff
= pData1
->FileSize
.QuadPart
- pData2
->FileSize
.QuadPart
;
519 return MAKE_COMPARE_HRESULT(diff
);
521 pName1
= PathFindExtensionW(pData1
->szName
);
522 pName2
= PathFindExtensionW(pData2
->szName
);
523 result
= wcsicmp(pName1
, pName2
);
525 case 5: /* Modified */
526 result
= CompareFileTime(&pData1
->LastModification
, &pData2
->LastModification
);
529 return MAKE_COMPARE_HRESULT(result
);
532 HRESULT WINAPI
CRecycleBin::CreateViewObject(HWND hwndOwner
, REFIID riid
, void **ppv
)
534 CComPtr
<IShellView
> pShellView
;
535 HRESULT hr
= E_NOINTERFACE
;
537 TRACE("(%p, %p, %s, %p)\n", this, hwndOwner
, debugstr_guid(&riid
), ppv
);
544 if (IsEqualIID (riid
, IID_IDropTarget
))
546 hr
= this->QueryInterface (IID_IDropTarget
, ppv
);
548 else if (IsEqualIID (riid
, IID_IContextMenu
) || IsEqualIID (riid
, IID_IContextMenu2
))
550 hr
= this->QueryInterface(riid
, ppv
);
552 else if (IsEqualIID (riid
, IID_IShellView
))
554 hr
= CDefView_Constructor(this, riid
, ppv
);
558 TRACE ("-- (%p)->(interface=%p)\n", this, ppv
);
563 HRESULT WINAPI
CRecycleBin::GetAttributesOf(UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
566 TRACE("(%p, %d, {%p, ...}, {%x})\n", this, cidl
, apidl
? apidl
[0] : NULL
, (unsigned int)*rgfInOut
);
567 *rgfInOut
&= SFGAO_FOLDER
|SFGAO_DROPTARGET
|SFGAO_HASPROPSHEET
|SFGAO_CANLINK
;
571 HRESULT WINAPI
CRecycleBin::GetUIObjectOf(HWND hwndOwner
, UINT cidl
, PCUITEMID_CHILD_ARRAY apidl
,
572 REFIID riid
, UINT
*prgfInOut
, void **ppv
)
574 IUnknown
*pObj
= NULL
;
575 HRESULT hr
= E_INVALIDARG
;
577 TRACE ("(%p)->(%p,%u,apidl=%p, %p %p)\n", this,
578 hwndOwner
, cidl
, apidl
, prgfInOut
, ppv
);
585 if ((IsEqualIID (riid
, IID_IContextMenu
) || IsEqualIID(riid
, IID_IContextMenu2
)) && (cidl
>= 1))
587 hr
= ShellObjectCreatorInit
<CRecycleBinItemContextMenu
>(apidl
[0], riid
, &pObj
);
589 else if (IsEqualIID (riid
, IID_IDropTarget
) && (cidl
== 1))
591 IDropTarget
* pDt
= NULL
;
592 hr
= QueryInterface(IID_PPV_ARG(IDropTarget
, &pDt
));
595 else if(IsEqualIID(riid
, IID_IExtractIconA
) && (cidl
== 1))
597 // FIXME: This is not correct, it does not show the right icons
598 LPITEMIDLIST pidlItem
= ILCombine(pidl
, apidl
[0]);
599 pObj
= IExtractIconA_Constructor(pidlItem
);
603 else if (IsEqualIID(riid
, IID_IExtractIconW
) && (cidl
== 1))
605 // FIXME: This is not correct, it does not show the right icons
606 LPITEMIDLIST pidlItem
= ILCombine(pidl
, apidl
[0]);
607 pObj
= IExtractIconW_Constructor(pidlItem
);
614 if (SUCCEEDED(hr
) && !pObj
)
618 TRACE ("(%p)->hr=0x%08x\n", this, hr
);
622 HRESULT WINAPI
CRecycleBin::GetDisplayNameOf(PCUITEMID_CHILD pidl
, SHGDNF uFlags
, STRRET
*pName
)
624 PIDLRecycleStruct
*pFileDetails
;
627 TRACE("(%p, %p, %x, %p)\n", this, pidl
, (unsigned int)uFlags
, pName
);
630 if (_ILIsBitBucket (pidl
))
634 if (HCR_GetClassNameW(CLSID_RecycleBin
, pszPath
, MAX_PATH
))
636 pName
->uType
= STRRET_WSTR
;
637 pName
->pOleStr
= StrDupW(pszPath
);
642 pFileDetails
= _ILGetRecycleStruct(pidl
);
646 pName
->uType
= STRRET_CSTR
;
650 pFileName
= wcsrchr(pFileDetails
->szName
, L
'\\');
654 pName
->uType
= STRRET_CSTR
;
658 pName
->pOleStr
= StrDupW(pFileName
+ 1);
659 if (pName
->pOleStr
== NULL
)
660 return E_OUTOFMEMORY
;
662 pName
->uType
= STRRET_WSTR
;
666 HRESULT WINAPI
CRecycleBin::SetNameOf(HWND hwnd
, PCUITEMID_CHILD pidl
, LPCOLESTR pszName
,
667 SHGDNF uFlags
, PITEMID_CHILD
*ppidlOut
)
670 return E_FAIL
; /* not supported */
673 HRESULT WINAPI
CRecycleBin::GetDefaultSearchGUID(GUID
*pguid
)
679 HRESULT WINAPI
CRecycleBin::EnumSearches(IEnumExtraSearch
**ppEnum
)
686 HRESULT WINAPI
CRecycleBin::GetDefaultColumn(DWORD dwReserved
, ULONG
*pSort
, ULONG
*pDisplay
)
688 TRACE("(%p, %x, %p, %p)\n", this, (unsigned int)dwReserved
, pSort
, pDisplay
);
694 HRESULT WINAPI
CRecycleBin::GetDefaultColumnState(UINT iColumn
, SHCOLSTATEF
*pcsFlags
)
696 TRACE("(%p, %d, %p)\n", this, iColumn
, pcsFlags
);
697 if (iColumn
>= COLUMNS_COUNT
)
699 *pcsFlags
= RecycleBinColumns
[iColumn
].pcsFlags
;
703 HRESULT WINAPI
CRecycleBin::GetDetailsEx(PCUITEMID_CHILD pidl
, const SHCOLUMNID
*pscid
, VARIANT
*pv
)
709 static HRESULT
FormatDateTime(LPWSTR buffer
, int size
, FILETIME
* ft
)
715 FileTimeToLocalFileTime(ft
, &lft
);
716 FileTimeToSystemTime(&lft
, &time
);
718 ret
= GetDateFormatW(LOCALE_USER_DEFAULT
, DATE_SHORTDATE
, &time
, NULL
, buffer
, size
);
719 if (ret
> 0 && ret
< size
)
721 /* Append space + time without seconds */
723 GetTimeFormatW(LOCALE_USER_DEFAULT
, TIME_NOSECONDS
, &time
, NULL
, &buffer
[ret
], size
- ret
);
726 return (ret
!= 0 ? E_FAIL
: S_OK
);
729 HRESULT WINAPI
CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl
, UINT iColumn
, LPSHELLDETAILS pDetails
)
731 PIDLRecycleStruct
* pFileDetails
;
732 WCHAR buffer
[MAX_PATH
];
733 WCHAR szTypeName
[100];
737 TRACE("(%p, %p, %d, %p)\n", this, pidl
, iColumn
, pDetails
);
738 if (iColumn
>= COLUMNS_COUNT
)
740 pDetails
->fmt
= RecycleBinColumns
[iColumn
].fmt
;
741 pDetails
->cxChar
= RecycleBinColumns
[iColumn
].cxChars
;
743 return SHSetStrRet(&pDetails
->str
, RecycleBinColumns
[iColumn
].column_name_id
);
745 if (iColumn
== COLUMN_NAME
)
746 return GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &pDetails
->str
);
748 pFileDetails
= _ILGetRecycleStruct(pidl
);
752 FormatDateTime(buffer
, MAX_PATH
, &pFileDetails
->DeletionTime
);
755 pszBackslash
= wcsrchr(pFileDetails
->szName
, L
'\\');
756 Length
= (pszBackslash
- pFileDetails
->szName
);
757 memcpy((LPVOID
)buffer
, pFileDetails
->szName
, Length
* sizeof(WCHAR
));
758 buffer
[Length
] = L
'\0';
761 StrFormatKBSizeW(pFileDetails
->FileSize
.QuadPart
, buffer
, MAX_PATH
);
764 FormatDateTime(buffer
, MAX_PATH
, &pFileDetails
->LastModification
);
767 // FIXME: We should in fact use a UNICODE version of _ILGetFileType
768 szTypeName
[0] = L
'\0';
769 wcscpy(buffer
, PathFindExtensionW(pFileDetails
->szName
));
770 if (!( HCR_MapTypeToValueW(buffer
, buffer
, sizeof(buffer
) / sizeof(WCHAR
), TRUE
) &&
771 HCR_MapTypeToValueW(buffer
, szTypeName
, sizeof(szTypeName
) / sizeof(WCHAR
), FALSE
)))
773 wcscpy (szTypeName
, PathFindExtensionW(pFileDetails
->szName
));
774 wcscat(szTypeName
, L
"-");
775 Length
= wcslen(szTypeName
);
776 if (LoadStringW(shell32_hInstance
, IDS_SHV_COLUMN1
, &szTypeName
[Length
], (sizeof(szTypeName
) / sizeof(WCHAR
)) - Length
))
777 szTypeName
[(sizeof(szTypeName
)/sizeof(WCHAR
))-1] = L
'\0';
779 return SHSetStrRet(&pDetails
->str
, szTypeName
);
784 return SHSetStrRet(&pDetails
->str
, buffer
);
787 HRESULT WINAPI
CRecycleBin::MapColumnToSCID(UINT iColumn
, SHCOLUMNID
*pscid
)
789 TRACE("(%p, %d, %p)\n", this, iColumn
, pscid
);
790 if (iColumn
>= COLUMNS_COUNT
)
792 pscid
->fmtid
= *RecycleBinColumns
[iColumn
].fmtId
;
793 pscid
->pid
= RecycleBinColumns
[iColumn
].pid
;
797 BOOL
CRecycleBin::RecycleBinIsEmpty()
799 CComPtr
<IEnumIDList
> spEnumFiles
;
800 HRESULT hr
= EnumObjects(NULL
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
, &spEnumFiles
);
803 CComHeapPtr
<ITEMIDLIST
> spPidl
;
805 return spEnumFiles
->Next(1, &spPidl
, &itemcount
) != S_OK
;
808 /*************************************************************************
809 * RecycleBin IContextMenu interface
812 HRESULT WINAPI
CRecycleBin::QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
)
818 TRACE("QueryContextMenu %p %p %u %u %u %u\n", this, hMenu
, indexMenu
, idCmdFirst
, idCmdLast
, uFlags
);
823 memset(&mii
, 0, sizeof(mii
));
824 mii
.cbSize
= sizeof(mii
);
825 mii
.fMask
= MIIM_TYPE
| MIIM_ID
| MIIM_STATE
;
826 mii
.fState
= RecycleBinIsEmpty() ? MFS_DISABLED
: MFS_ENABLED
;
828 LoadStringW(shell32_hInstance
, IDS_EMPTY_BITBUCKET
, szBuffer
, sizeof(szBuffer
) / sizeof(WCHAR
));
829 mii
.dwTypeData
= szBuffer
;
830 mii
.cch
= wcslen(mii
.dwTypeData
);
831 mii
.wID
= idCmdFirst
+ id
++;
832 mii
.fType
= MFT_STRING
;
835 if (!InsertMenuItemW(hMenu
, indexMenu
, TRUE
, &mii
))
838 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, id
);
841 HRESULT WINAPI
CRecycleBin::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
)
845 IShellView
* lpSV
= NULL
;
847 TRACE("%p %p verb %p\n", this, lpcmi
, lpcmi
->lpVerb
);
849 if (LOWORD(lpcmi
->lpVerb
) == iIdEmpty
)
853 hr
= SHEmptyRecycleBinW(lpcmi
->hwnd
, L
"C:\\", 0);
854 TRACE("result %x\n", hr
);
858 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
859 if (lpSB
&& SUCCEEDED(lpSB
->QueryActiveShellView(&lpSV
)))
865 HRESULT WINAPI
CRecycleBin::GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
)
867 FIXME("%p %lu %u %p %p %u\n", this, idCommand
, uFlags
, lpReserved
, lpszName
, uMaxNameLen
);
872 /*************************************************************************
873 * RecycleBin IShellPropSheetExt interface
876 HRESULT WINAPI
CRecycleBin::AddPages(LPFNSVADDPROPSHEETPAGE pfnAddPage
, LPARAM lParam
)
878 FIXME("%p %p %lu\n", this, pfnAddPage
, lParam
);
883 HRESULT WINAPI
CRecycleBin::ReplacePage(EXPPS uPageID
, LPFNSVADDPROPSHEETPAGE pfnReplaceWith
, LPARAM lParam
)
885 FIXME("%p %lu %p %lu\n", this, uPageID
, pfnReplaceWith
, lParam
);
890 /*************************************************************************
891 * RecycleBin IShellExtInit interface
894 HRESULT WINAPI
CRecycleBin::Initialize(LPCITEMIDLIST pidlFolder
, IDataObject
*pdtobj
, HKEY hkeyProgID
)
896 TRACE("%p %p %p %p\n", this, pidlFolder
, pdtobj
, hkeyProgID
);
901 TRASH_CanTrashFile(LPCWSTR wszPath
)
904 DWORD dwNukeOnDelete
, dwType
, VolSerialNumber
, MaxComponentLength
;
905 DWORD FileSystemFlags
, dwSize
, dwDisposition
;
908 WCHAR szKey
[150] = L
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\";
910 if (wszPath
[1] != L
':')
916 if (GetDriveTypeW(wszPath
) != DRIVE_FIXED
)
918 /* no bitbucket on removable media */
922 if (!GetVolumeInformationW(wszPath
, NULL
, 0, &VolSerialNumber
, &MaxComponentLength
, &FileSystemFlags
, NULL
, 0))
924 ERR("GetVolumeInformationW failed with %u\n", GetLastError());
928 swprintf(szBuffer
, L
"%04X-%04X", LOWORD(VolSerialNumber
), HIWORD(VolSerialNumber
));
929 wcscat(szKey
, szBuffer
);
931 if (RegCreateKeyExW(HKEY_CURRENT_USER
, szKey
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hKey
, &dwDisposition
) != ERROR_SUCCESS
)
933 ERR("RegCreateKeyExW failed\n");
937 if (dwDisposition
& REG_CREATED_NEW_KEY
)
939 /* per default move to bitbucket */
941 RegSetValueExW(hKey
, L
"NukeOnDelete", 0, REG_DWORD
, (LPBYTE
)&dwNukeOnDelete
, sizeof(DWORD
));
942 /* per default unlimited size */
944 RegSetValueExW(hKey
, L
"MaxCapacity", 0, REG_DWORD
, (LPBYTE
)&dwSize
, sizeof(DWORD
));
950 dwSize
= sizeof(dwNukeOnDelete
);
951 ret
= RegQueryValueExW(hKey
, L
"NukeOnDelete", NULL
, &dwType
, (LPBYTE
)&dwNukeOnDelete
, &dwSize
);
952 if (ret
!= ERROR_SUCCESS
)
954 if (ret
== ERROR_FILE_NOT_FOUND
)
956 /* restore key and enable bitbucket */
958 RegSetValueExW(hKey
, L
"NukeOnDelete", 0, REG_DWORD
, (LPBYTE
)&dwNukeOnDelete
, sizeof(DWORD
));
963 else if (dwNukeOnDelete
)
965 /* do not delete to bitbucket */
970 * check if bitbucket is full
978 TRASH_TrashFile(LPCWSTR wszPath
)
980 TRACE("(%s)\n", debugstr_w(wszPath
));
981 return DeleteFileToRecycleBin(wszPath
);
984 /*************************************************************************
985 * SHUpdateCRecycleBinIcon [SHELL32.@]
989 EXTERN_C HRESULT WINAPI
SHUpdateRecycleBinIcon(void)
998 /****************************************************************************
999 * IDropTarget implementation
1001 BOOL
CRecycleBin::QueryDrop(DWORD dwKeyState
, LPDWORD pdwEffect
)
1003 /* TODO on shift we should delete, we should update the cursor manager to show this. */
1005 DWORD dwEffect
= DROPEFFECT_COPY
;
1007 *pdwEffect
= DROPEFFECT_NONE
;
1009 if (fAcceptFmt
) { /* Does our interpretation of the keystate ... */
1010 *pdwEffect
= KeyStateToDropEffect (dwKeyState
);
1012 if (*pdwEffect
== DROPEFFECT_NONE
)
1013 *pdwEffect
= dwEffect
;
1015 /* ... matches the desired effect ? */
1016 if (dwEffect
& *pdwEffect
) {
1023 HRESULT WINAPI
CRecycleBin::DragEnter(IDataObject
*pDataObject
,
1024 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1026 TRACE("Recycle bin drag over (%p)\n", this);
1027 /* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */
1030 QueryDrop(dwKeyState
, pdwEffect
);
1034 HRESULT WINAPI
CRecycleBin::DragOver(DWORD dwKeyState
, POINTL pt
,
1037 TRACE("(%p)\n", this);
1040 return E_INVALIDARG
;
1042 QueryDrop(dwKeyState
, pdwEffect
);
1047 HRESULT WINAPI
CRecycleBin::DragLeave()
1049 TRACE("(%p)\n", this);
1056 HRESULT WINAPI
CRecycleBin::Drop(IDataObject
*pDataObject
,
1057 DWORD dwKeyState
, POINTL pt
, DWORD
*pdwEffect
)
1059 TRACE("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect
);
1061 /* TODO: pdwEffect should be read and make the drop object be permanently deleted in the move case (shift held) */
1064 TRACE("(%p)->(DataObject=%p)\n", this, pDataObject
);
1065 InitFormatEtc (fmt
, cfShellIDList
, TYMED_HGLOBAL
);
1067 /* Handle cfShellIDList Drop objects here, otherwise send the approriate message to other software */
1068 if (SUCCEEDED(pDataObject
->QueryGetData(&fmt
)))
1072 if ((dwKeyState
& MK_SHIFT
) == MK_SHIFT
)
1073 fMask
|= CMIC_MASK_SHIFT_DOWN
;
1075 DoDeleteAsync(pDataObject
, fMask
);
1080 * TODO call SetData on the data object with format CFSTR_TARGETCLSID
1081 * set to the Recycle Bin's class identifier CLSID_RecycleBin.
1087 HRESULT WINAPI
DoDeleteDataObject(IDataObject
*pda
, DWORD fMask
)
1089 TRACE("performing delete");
1093 FORMATETC formatetc
;
1094 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
1095 hr
= pda
->GetData(&formatetc
, &medium
);
1099 /* lock the handle */
1100 LPIDA lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
1103 ReleaseStgMedium(&medium
);
1107 /* convert the data into pidl */
1109 LPITEMIDLIST
*apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1112 ReleaseStgMedium(&medium
);
1116 CComPtr
<IShellFolder
> psfDesktop
;
1117 CComPtr
<IShellFolder
> psfFrom
= NULL
;
1119 /* Grab the desktop shell folder */
1120 hr
= SHGetDesktopFolder(&psfDesktop
);
1123 ERR("SHGetDesktopFolder failed\n");
1125 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1126 ReleaseStgMedium(&medium
);
1130 /* Find source folder, this is where the clipboard data was copied from */
1131 if (_ILIsDesktop(pidl
))
1133 psfFrom
= psfDesktop
;
1137 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfFrom
));
1140 ERR("no IShellFolder\n");
1142 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1143 ReleaseStgMedium(&medium
);
1149 hr
= psfFrom
->GetDisplayNameOf(apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1152 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1154 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1155 ReleaseStgMedium(&medium
);
1159 WCHAR wszPath
[MAX_PATH
];
1160 hr
= StrRetToBufW(&strTemp
, apidl
[0], wszPath
, _countof(wszPath
));
1163 ERR("StrRetToBufW failed with %x\n", hr
);
1165 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1166 ReleaseStgMedium(&medium
);
1170 /* Only keep the base path */
1171 LPWSTR pwszFilename
= PathFindFileNameW(wszPath
);
1172 *pwszFilename
= L
'\0';
1174 /* Build paths list */
1175 LPWSTR pwszPaths
= BuildPathsList(wszPath
, lpcida
->cidl
, (LPCITEMIDLIST
*) apidl
);
1179 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1180 ReleaseStgMedium(&medium
);
1185 SHFILEOPSTRUCTW FileOp
;
1186 ZeroMemory(&FileOp
, sizeof(FileOp
));
1187 FileOp
.wFunc
= FO_DELETE
;
1188 FileOp
.pFrom
= pwszPaths
;
1189 if ((fMask
& CMIC_MASK_SHIFT_DOWN
) == 0)
1190 FileOp
.fFlags
= FOF_ALLOWUNDO
;
1192 if (SHFileOperationW(&FileOp
) != 0)
1194 ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths
));
1198 HeapFree(GetProcessHeap(), 0, pwszPaths
);
1200 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1201 ReleaseStgMedium(&medium
);
1206 struct DeleteThreadData
{
1211 DWORD WINAPI
DoDeleteThreadProc(LPVOID lpParameter
)
1213 DeleteThreadData
*data
= static_cast<DeleteThreadData
*>(lpParameter
);
1215 IDataObject
*pDataObject
;
1216 HRESULT hr
= CoGetInterfaceAndReleaseStream (data
->s
, IID_PPV_ARG(IDataObject
, &pDataObject
));
1219 DoDeleteDataObject(pDataObject
, data
->fMask
);
1221 pDataObject
->Release();
1223 HeapFree(GetProcessHeap(), 0, data
);
1227 void DoDeleteAsync(IDataObject
*pda
, DWORD fMask
)
1229 DeleteThreadData
*data
= static_cast<DeleteThreadData
*>(HeapAlloc(GetProcessHeap(), 0, sizeof(DeleteThreadData
)));
1230 data
->fMask
= fMask
;
1231 CoMarshalInterThreadInterfaceInStream(IID_IDataObject
, pda
, &data
->s
);
1232 SHCreateThread(DoDeleteThreadProc
, data
, NULL
, NULL
);
1235 /*************************************************************************
1236 * SHEmptyRecycleBinA (SHELL32.@)
1238 HRESULT WINAPI
SHEmptyRecycleBinA(HWND hwnd
, LPCSTR pszRootPath
, DWORD dwFlags
)
1240 LPWSTR szRootPathW
= NULL
;
1244 TRACE("%p, %s, 0x%08x\n", hwnd
, debugstr_a(pszRootPath
), dwFlags
);
1248 len
= MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, NULL
, 0);
1250 return HRESULT_FROM_WIN32(GetLastError());
1251 szRootPathW
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1253 return E_OUTOFMEMORY
;
1254 if (MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, szRootPathW
, len
) == 0)
1256 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1257 return HRESULT_FROM_WIN32(GetLastError());
1261 hr
= SHEmptyRecycleBinW(hwnd
, szRootPathW
, dwFlags
);
1262 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1267 HRESULT WINAPI
SHEmptyRecycleBinW(HWND hwnd
, LPCWSTR pszRootPath
, DWORD dwFlags
)
1269 WCHAR szPath
[MAX_PATH
] = {0}, szBuffer
[MAX_PATH
];
1270 DWORD dwSize
, dwType
, count
;
1272 IShellFolder
*pDesktop
, *pRecycleBin
;
1273 PIDLIST_ABSOLUTE pidlRecycleBin
;
1276 LPENUMIDLIST penumFiles
;
1279 TRACE("%p, %s, 0x%08x\n", hwnd
, debugstr_w(pszRootPath
), dwFlags
);
1281 if (!(dwFlags
& SHERB_NOCONFIRMATION
))
1283 hr
= SHGetDesktopFolder(&pDesktop
);
1286 hr
= SHGetFolderLocation(NULL
, CSIDL_BITBUCKET
, NULL
, 0, &pidlRecycleBin
);
1289 pDesktop
->Release();
1292 hr
= pDesktop
->BindToObject(pidlRecycleBin
, NULL
, IID_PPV_ARG(IShellFolder
, &pRecycleBin
));
1293 CoTaskMemFree(pidlRecycleBin
);
1294 pDesktop
->Release();
1297 hr
= pRecycleBin
->EnumObjects(hwnd
, SHCONTF_FOLDERS
| SHCONTF_NONFOLDERS
| SHCONTF_INCLUDEHIDDEN
, &penumFiles
);
1300 pRecycleBin
->Release();
1307 while (penumFiles
->Next(1, &pidl
, NULL
) == S_OK
)
1310 pRecycleBin
->GetDisplayNameOf(pidl
, SHGDN_NORMAL
, &StrRet
);
1311 StrRetToBuf(&StrRet
, pidl
, szBuffer
, _countof(szBuffer
));
1312 CoTaskMemFree(pidl
);
1314 penumFiles
->Release();
1316 pRecycleBin
->Release();
1321 /* no files, don't need confirmation */
1325 /* we have only one item inside the bin, so show a message box with its name */
1326 if (ShellMessageBoxW(shell32_hInstance
, hwnd
, MAKEINTRESOURCEW(IDS_DELETEITEM_TEXT
), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET
),
1327 MB_ICONEXCLAMATION
| MB_YESNO
| MB_DEFBUTTON2
, szBuffer
) == IDNO
)
1334 /* we have more than one item, so show a message box with the count of the items */
1335 StringCbPrintfW(szBuffer
, sizeof(szBuffer
), L
"%u", count
);
1336 if (ShellMessageBoxW(shell32_hInstance
, hwnd
, MAKEINTRESOURCEW(IDS_DELETEMULTIPLE_TEXT
), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET
),
1337 MB_ICONEXCLAMATION
| MB_YESNO
| MB_DEFBUTTON2
, szBuffer
) == IDNO
)
1345 if (dwFlags
& SHERB_NOPROGRESSUI
)
1347 ret
= EmptyRecycleBinW(pszRootPath
);
1352 * show a progress dialog
1354 ret
= EmptyRecycleBinW(pszRootPath
);
1358 return HRESULT_FROM_WIN32(GetLastError());
1360 if (!(dwFlags
& SHERB_NOSOUND
))
1362 dwSize
= sizeof(szPath
);
1363 ret
= RegGetValueW(HKEY_CURRENT_USER
,
1364 L
"AppEvents\\Schemes\\Apps\\Explorer\\EmptyRecycleBin\\.Current",
1370 if (ret
!= ERROR_SUCCESS
)
1373 if (dwType
!= REG_EXPAND_SZ
) /* type dismatch */
1376 szPath
[(sizeof(szPath
)/sizeof(WCHAR
))-1] = L
'\0';
1377 PlaySoundW(szPath
, NULL
, SND_FILENAME
);
1382 HRESULT WINAPI
SHQueryRecycleBinA(LPCSTR pszRootPath
, LPSHQUERYRBINFO pSHQueryRBInfo
)
1384 LPWSTR szRootPathW
= NULL
;
1388 TRACE("%s, %p\n", debugstr_a(pszRootPath
), pSHQueryRBInfo
);
1392 len
= MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, NULL
, 0);
1394 return HRESULT_FROM_WIN32(GetLastError());
1395 szRootPathW
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1397 return E_OUTOFMEMORY
;
1398 if (MultiByteToWideChar(CP_ACP
, 0, pszRootPath
, -1, szRootPathW
, len
) == 0)
1400 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1401 return HRESULT_FROM_WIN32(GetLastError());
1405 hr
= SHQueryRecycleBinW(szRootPathW
, pSHQueryRBInfo
);
1406 HeapFree(GetProcessHeap(), 0, szRootPathW
);
1411 HRESULT WINAPI
SHQueryRecycleBinW(LPCWSTR pszRootPath
, LPSHQUERYRBINFO pSHQueryRBInfo
)
1413 FIXME("%s, %p - stub\n", debugstr_w(pszRootPath
), pSHQueryRBInfo
);
1415 if (!(pszRootPath
) || (pszRootPath
[0] == 0) ||
1416 !(pSHQueryRBInfo
) || (pSHQueryRBInfo
->cbSize
< sizeof(SHQUERYRBINFO
)))
1418 return E_INVALIDARG
;
1421 pSHQueryRBInfo
->i64Size
= 0;
1422 pSHQueryRBInfo
->i64NumItems
= 0;