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 #include <precomp.h> 23 24 #include <mmsystem.h> 25 #include <ntquery.h> 26 27 #define MAX_PROPERTY_SHEET_PAGE 32 28 29 WINE_DEFAULT_DEBUG_CHANNEL(CRecycleBin); 30 31 typedef struct 32 { 33 int column_name_id; 34 const GUID *fmtId; 35 DWORD pid; 36 int pcsFlags; 37 int fmt; 38 int cxChars; 39 } columninfo; 40 41 static const columninfo RecycleBinColumns[] = 42 { 43 {IDS_SHV_COLUMN_NAME, &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_COLUMN_SIZE, &FMTID_Storage, PID_STG_SIZE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 20}, 47 {IDS_SHV_COLUMN_TYPE, &FMTID_Storage, PID_STG_STORAGETYPE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 20}, 48 {IDS_SHV_COLUMN_MODIFIED, &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}, */ 51 }; 52 53 #define COLUMN_NAME 0 54 #define COLUMN_DELFROM 1 55 #define COLUMN_DATEDEL 2 56 #define COLUMN_SIZE 3 57 #define COLUMN_TYPE 4 58 #define COLUMN_MTIME 5 59 60 #define COLUMNS_COUNT 6 61 62 /* 63 * Recycle Bin folder 64 */ 65 66 HRESULT CRecyclerExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut) 67 { 68 CComPtr<IDefaultExtractIconInit> initIcon; 69 HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon)); 70 if (FAILED_UNEXPECTEDLY(hr)) 71 return hr; 72 73 /* FIXME: This is completely unimplemented */ 74 initIcon->SetNormalIcon(swShell32Name, 0); 75 76 return initIcon->QueryInterface(riid, ppvOut); 77 } 78 79 class CRecycleBinEnum : 80 public CEnumIDListBase 81 { 82 private: 83 public: 84 CRecycleBinEnum(); 85 ~CRecycleBinEnum(); 86 HRESULT WINAPI Initialize(DWORD dwFlags); 87 static BOOL WINAPI CBEnumRecycleBin(IN PVOID Context, IN HANDLE hDeletedFile); 88 BOOL WINAPI CBEnumRecycleBin(IN HANDLE hDeletedFile); 89 90 BEGIN_COM_MAP(CRecycleBinEnum) 91 COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList) 92 END_COM_MAP() 93 }; 94 95 class CRecycleBinItemContextMenu : 96 public CComObjectRootEx<CComMultiThreadModelNoCS>, 97 public IContextMenu2 98 { 99 private: 100 LPITEMIDLIST apidl; 101 public: 102 CRecycleBinItemContextMenu(); 103 ~CRecycleBinItemContextMenu(); 104 HRESULT WINAPI Initialize(LPCITEMIDLIST pidl); 105 106 // IContextMenu 107 virtual HRESULT WINAPI QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags); 108 virtual HRESULT WINAPI InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi); 109 virtual HRESULT WINAPI GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen); 110 111 // IContextMenu2 112 virtual HRESULT WINAPI HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam); 113 114 BEGIN_COM_MAP(CRecycleBinItemContextMenu) 115 COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu) 116 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2) 117 END_COM_MAP() 118 }; 119 120 typedef struct 121 { 122 PIDLRecycleStruct *pFileDetails; 123 HANDLE hDeletedFile; 124 BOOL bFound; 125 } SEARCH_CONTEXT, *PSEARCH_CONTEXT; 126 127 BOOL WINAPI CBSearchRecycleBin(IN PVOID Context, IN HANDLE hDeletedFile) 128 { 129 PSEARCH_CONTEXT pContext = (PSEARCH_CONTEXT)Context; 130 131 PDELETED_FILE_DETAILS_W pFileDetails; 132 DWORD dwSize; 133 BOOL ret; 134 135 if (!GetDeletedFileDetailsW(hDeletedFile, 136 0, 137 NULL, 138 &dwSize) && 139 GetLastError() != ERROR_INSUFFICIENT_BUFFER) 140 { 141 ERR("GetDeletedFileDetailsW failed\n"); 142 return FALSE; 143 } 144 145 pFileDetails = (DELETED_FILE_DETAILS_W *)SHAlloc(dwSize); 146 if (!pFileDetails) 147 { 148 ERR("No memory\n"); 149 return FALSE; 150 } 151 152 if (!GetDeletedFileDetailsW(hDeletedFile, 153 dwSize, 154 pFileDetails, 155 NULL)) 156 { 157 ERR("GetDeletedFileDetailsW failed\n"); 158 SHFree(pFileDetails); 159 return FALSE; 160 } 161 162 ret = memcmp(pFileDetails, pContext->pFileDetails, dwSize); 163 if (!ret) 164 { 165 pContext->hDeletedFile = hDeletedFile; 166 pContext->bFound = TRUE; 167 } 168 else 169 CloseRecycleBinHandle(hDeletedFile); 170 171 SHFree(pFileDetails); 172 return ret; 173 } 174 175 static PIDLRecycleStruct * _ILGetRecycleStruct(LPCITEMIDLIST pidl) 176 { 177 LPPIDLDATA pdata = _ILGetDataPointer(pidl); 178 179 if (pdata && pdata->type == 0x00) 180 return (PIDLRecycleStruct*) & (pdata->u.crecycle); 181 182 return NULL; 183 } 184 185 CRecycleBinEnum::CRecycleBinEnum() 186 { 187 } 188 189 CRecycleBinEnum::~CRecycleBinEnum() 190 { 191 } 192 193 HRESULT WINAPI CRecycleBinEnum::Initialize(DWORD dwFlags) 194 { 195 static LPCWSTR szDrive = L"C:\\"; 196 197 if (dwFlags & SHCONTF_NONFOLDERS) 198 { 199 TRACE("Starting Enumeration\n"); 200 201 if (!EnumerateRecycleBinW(szDrive /* FIXME */ , CBEnumRecycleBin, (PVOID)this)) 202 { 203 WARN("Error: EnumerateCRecycleBinW failed\n"); 204 return E_FAIL; 205 } 206 } 207 else 208 { 209 // do nothing 210 } 211 return S_OK; 212 } 213 214 static LPITEMIDLIST _ILCreateRecycleItem(PDELETED_FILE_DETAILS_W pFileDetails) 215 { 216 PIDLDATA tmp; 217 LPITEMIDLIST pidl; 218 PIDLRecycleStruct * p; 219 int size0 = (char*)&tmp.u.crecycle.szName - (char*)&tmp.u.crecycle; 220 int size = size0; 221 222 tmp.type = 0x00; 223 size += (wcslen(pFileDetails->FileName) + 1) * sizeof(WCHAR); 224 225 pidl = (LPITEMIDLIST)SHAlloc(size + 4); 226 if (!pidl) 227 return pidl; 228 229 pidl->mkid.cb = size + 2; 230 memcpy(pidl->mkid.abID, &tmp, 2 + size0); 231 232 p = &((PIDLDATA*)pidl->mkid.abID)->u.crecycle; 233 RtlCopyMemory(p, pFileDetails, sizeof(DELETED_FILE_DETAILS_W)); 234 wcscpy(p->szName, pFileDetails->FileName); 235 *(WORD*)((char*)pidl + (size + 2)) = 0; 236 return pidl; 237 } 238 239 BOOL WINAPI CRecycleBinEnum::CBEnumRecycleBin(IN PVOID Context, IN HANDLE hDeletedFile) 240 { 241 return static_cast<CRecycleBinEnum *>(Context)->CBEnumRecycleBin(hDeletedFile); 242 } 243 244 BOOL WINAPI CRecycleBinEnum::CBEnumRecycleBin(IN HANDLE hDeletedFile) 245 { 246 PDELETED_FILE_DETAILS_W pFileDetails; 247 DWORD dwSize; 248 LPITEMIDLIST pidl = NULL; 249 BOOL ret; 250 251 if (!GetDeletedFileDetailsW(hDeletedFile, 252 0, 253 NULL, 254 &dwSize) && 255 GetLastError() != ERROR_INSUFFICIENT_BUFFER) 256 { 257 ERR("GetDeletedFileDetailsW failed\n"); 258 return FALSE; 259 } 260 261 pFileDetails = (DELETED_FILE_DETAILS_W *)SHAlloc(dwSize); 262 if (!pFileDetails) 263 { 264 ERR("No memory\n"); 265 return FALSE; 266 } 267 268 if (!GetDeletedFileDetailsW(hDeletedFile, 269 dwSize, 270 pFileDetails, 271 NULL)) 272 { 273 ERR("GetDeletedFileDetailsW failed\n"); 274 SHFree(pFileDetails); 275 return FALSE; 276 } 277 278 pidl = _ILCreateRecycleItem(pFileDetails); 279 if (!pidl) 280 { 281 SHFree(pFileDetails); 282 return FALSE; 283 } 284 285 ret = AddToEnumList(pidl); 286 287 if (!ret) 288 SHFree(pidl); 289 SHFree(pFileDetails); 290 TRACE("Returning %d\n", ret); 291 CloseRecycleBinHandle(hDeletedFile); 292 return ret; 293 } 294 295 /************************************************************************** 296 * IContextMenu2 Bitbucket Item Implementation 297 */ 298 299 CRecycleBinItemContextMenu::CRecycleBinItemContextMenu() 300 { 301 apidl = NULL; 302 } 303 304 CRecycleBinItemContextMenu::~CRecycleBinItemContextMenu() 305 { 306 ILFree(apidl); 307 } 308 309 HRESULT WINAPI CRecycleBinItemContextMenu::Initialize(LPCITEMIDLIST pidl) 310 { 311 apidl = ILClone(pidl); 312 if (apidl == NULL) 313 return E_OUTOFMEMORY; 314 return S_OK; 315 } 316 317 HRESULT WINAPI CRecycleBinItemContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) 318 { 319 WCHAR szBuffer[30] = {0}; 320 ULONG Count = 1; 321 322 TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags); 323 324 if (LoadStringW(shell32_hInstance, IDS_RESTORE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) 325 { 326 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; 327 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED); 328 Count++; 329 } 330 331 if (LoadStringW(shell32_hInstance, IDS_CUT, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) 332 { 333 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); 334 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; 335 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED); 336 } 337 338 if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) 339 { 340 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; 341 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); 342 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED); 343 } 344 345 if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer) / sizeof(WCHAR))) 346 { 347 szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0'; 348 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED); 349 _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT); 350 } 351 352 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, Count); 353 } 354 355 HRESULT WINAPI CRecycleBinItemContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) 356 { 357 SEARCH_CONTEXT Context; 358 static LPCWSTR szDrive = L"C:\\"; 359 360 TRACE("(%p)->(invcom=%p verb=%p wnd=%p)\n", this, lpcmi, lpcmi->lpVerb, lpcmi->hwnd); 361 362 if (lpcmi->lpVerb == MAKEINTRESOURCEA(1) || lpcmi->lpVerb == MAKEINTRESOURCEA(5)) 363 { 364 Context.pFileDetails = _ILGetRecycleStruct(apidl); 365 Context.bFound = FALSE; 366 367 EnumerateRecycleBinW(szDrive, CBSearchRecycleBin, (PVOID)&Context); 368 if (!Context.bFound) 369 return E_FAIL; 370 371 if (lpcmi->lpVerb == MAKEINTRESOURCEA(1)) 372 { 373 /* restore file */ 374 if (RestoreFile(Context.hDeletedFile)) 375 return S_OK; 376 else 377 return E_FAIL; 378 } 379 else 380 { 381 DeleteFileHandleToRecycleBin(Context.hDeletedFile); 382 return E_NOTIMPL; 383 } 384 } 385 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(3)) 386 { 387 FIXME("implement cut\n"); 388 return E_NOTIMPL; 389 } 390 else if (lpcmi->lpVerb == MAKEINTRESOURCEA(7)) 391 { 392 FIXME("implement properties\n"); 393 return E_NOTIMPL; 394 } 395 396 return S_OK; 397 } 398 399 HRESULT WINAPI CRecycleBinItemContextMenu::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) 400 { 401 TRACE("(%p)->(idcom=%lx flags=%x %p name=%p len=%x)\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); 402 403 return E_FAIL; 404 } 405 406 HRESULT WINAPI CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam) 407 { 408 TRACE("CRecycleBin_IContextMenu2Item_HandleMenuMsg (%p)->(msg=%x wp=%lx lp=%lx)\n", this, uMsg, wParam, lParam); 409 410 return E_NOTIMPL; 411 } 412 413 CRecycleBin::CRecycleBin() 414 { 415 pidl = NULL; 416 } 417 418 CRecycleBin::~CRecycleBin() 419 { 420 SHFree(pidl); 421 } 422 423 /************************************************************************* 424 * RecycleBin IPersistFolder2 interface 425 */ 426 427 HRESULT WINAPI CRecycleBin::GetClassID(CLSID *pClassID) 428 { 429 TRACE("(%p, %p)\n", this, pClassID); 430 if (pClassID == NULL) 431 return E_INVALIDARG; 432 memcpy(pClassID, &CLSID_RecycleBin, sizeof(CLSID)); 433 return S_OK; 434 } 435 436 HRESULT WINAPI CRecycleBin::Initialize(LPCITEMIDLIST pidl) 437 { 438 TRACE("(%p, %p)\n", this, pidl); 439 440 SHFree((LPVOID)this->pidl); 441 this->pidl = ILClone(pidl); 442 if (this->pidl == NULL) 443 return E_OUTOFMEMORY; 444 return S_OK; 445 } 446 447 HRESULT WINAPI CRecycleBin::GetCurFolder(LPITEMIDLIST *ppidl) 448 { 449 TRACE("\n"); 450 *ppidl = ILClone(pidl); 451 return S_OK; 452 } 453 454 /************************************************************************* 455 * RecycleBin IShellFolder2 interface 456 */ 457 458 HRESULT WINAPI CRecycleBin::ParseDisplayName(HWND hwnd, LPBC pbc, 459 LPOLESTR pszDisplayName, ULONG *pchEaten, PIDLIST_RELATIVE *ppidl, 460 ULONG *pdwAttributes) 461 { 462 FIXME("stub\n"); 463 return E_NOTIMPL; 464 } 465 466 467 PDELETED_FILE_DETAILS_W 468 UnpackDetailsFromPidl(LPCITEMIDLIST pidl) 469 { 470 return (PDELETED_FILE_DETAILS_W)&pidl->mkid.abID; 471 } 472 473 HRESULT WINAPI CRecycleBin::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList) 474 { 475 return ShellObjectCreatorInit<CRecycleBinEnum>(dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList)); 476 } 477 478 HRESULT WINAPI CRecycleBin::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbc, REFIID riid, void **ppv) 479 { 480 FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl, pbc, debugstr_guid(&riid), ppv); 481 return E_NOTIMPL; 482 } 483 484 HRESULT WINAPI CRecycleBin::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbc, REFIID riid, void **ppv) 485 { 486 FIXME("(%p, %p, %p, %s, %p) - stub\n", this, pidl, pbc, debugstr_guid(&riid), ppv); 487 return E_NOTIMPL; 488 } 489 490 HRESULT WINAPI CRecycleBin::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2) 491 { 492 PIDLRecycleStruct* pData1 = _ILGetRecycleStruct(pidl1); 493 PIDLRecycleStruct* pData2 = _ILGetRecycleStruct(pidl2); 494 LPWSTR pName1, pName2; 495 496 if(!pData1 || !pData2 || LOWORD(lParam) >= COLUMNS_COUNT) 497 return E_INVALIDARG; 498 499 SHORT result; 500 LONGLONG diff; 501 switch (LOWORD(lParam)) 502 { 503 case 0: /* Name */ 504 pName1 = PathFindFileNameW(pData1->szName); 505 pName2 = PathFindFileNameW(pData2->szName); 506 result = wcsicmp(pName1, pName2); 507 break; 508 case 1: /* Orig. Location */ 509 result = wcsicmp(pData1->szName, pData2->szName); 510 break; 511 case 2: /* Date Deleted */ 512 result = CompareFileTime(&pData1->DeletionTime, &pData2->DeletionTime); 513 break; 514 case 3: /* Size */ 515 diff = pData1->FileSize.QuadPart - pData2->FileSize.QuadPart; 516 return MAKE_COMPARE_HRESULT(diff); 517 case 4: /* Type */ 518 pName1 = PathFindExtensionW(pData1->szName); 519 pName2 = PathFindExtensionW(pData2->szName); 520 result = wcsicmp(pName1, pName2); 521 break; 522 case 5: /* Modified */ 523 result = CompareFileTime(&pData1->LastModification, &pData2->LastModification); 524 break; 525 } 526 return MAKE_COMPARE_HRESULT(result); 527 } 528 529 HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv) 530 { 531 CComPtr<IShellView> pShellView; 532 HRESULT hr = E_NOINTERFACE; 533 534 TRACE("(%p, %p, %s, %p)\n", this, hwndOwner, debugstr_guid(&riid), ppv); 535 536 if (!ppv) 537 return hr; 538 539 *ppv = NULL; 540 541 if (IsEqualIID (riid, IID_IDropTarget)) 542 { 543 hr = CRecyclerDropTarget_CreateInstance(riid, ppv); 544 } 545 else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2)) 546 { 547 hr = this->QueryInterface(riid, ppv); 548 } 549 else if (IsEqualIID (riid, IID_IShellView)) 550 { 551 SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this}; 552 hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppv); 553 } 554 else 555 return hr; 556 557 TRACE ("-- (%p)->(interface=%p)\n", this, ppv); 558 return hr; 559 560 } 561 562 HRESULT WINAPI CRecycleBin::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 563 SFGAOF *rgfInOut) 564 { 565 TRACE("(%p, %d, {%p, ...}, {%x})\n", this, cidl, apidl ? apidl[0] : NULL, (unsigned int)*rgfInOut); 566 *rgfInOut &= SFGAO_FOLDER|SFGAO_DROPTARGET|SFGAO_HASPROPSHEET|SFGAO_CANLINK; 567 return S_OK; 568 } 569 570 HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl, 571 REFIID riid, UINT *prgfInOut, void **ppv) 572 { 573 LPVOID pObj = NULL; 574 HRESULT hr = E_INVALIDARG; 575 576 TRACE ("(%p)->(%p,%u,apidl=%p, %p %p)\n", this, 577 hwndOwner, cidl, apidl, prgfInOut, ppv); 578 579 if (!ppv) 580 return hr; 581 582 *ppv = NULL; 583 584 if ((IsEqualIID (riid, IID_IContextMenu) || IsEqualIID(riid, IID_IContextMenu2)) && (cidl >= 1)) 585 { 586 hr = ShellObjectCreatorInit<CRecycleBinItemContextMenu>(apidl[0], riid, &pObj); 587 } 588 else if((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1)) 589 { 590 hr = CRecyclerExtractIcon_CreateInstance(apidl[0], riid, &pObj); 591 } 592 else 593 hr = E_NOINTERFACE; 594 595 if (SUCCEEDED(hr) && !pObj) 596 hr = E_OUTOFMEMORY; 597 598 *ppv = pObj; 599 TRACE ("(%p)->hr=0x%08x\n", this, hr); 600 return hr; 601 } 602 603 HRESULT WINAPI CRecycleBin::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags, STRRET *pName) 604 { 605 PIDLRecycleStruct *pFileDetails; 606 LPWSTR pFileName; 607 608 TRACE("(%p, %p, %x, %p)\n", this, pidl, (unsigned int)uFlags, pName); 609 610 pFileDetails = _ILGetRecycleStruct(pidl); 611 if (!pFileDetails) 612 { 613 pName->cStr[0] = 0; 614 pName->uType = STRRET_CSTR; 615 return E_INVALIDARG; 616 } 617 618 pFileName = wcsrchr(pFileDetails->szName, L'\\'); 619 if (!pFileName) 620 { 621 pName->cStr[0] = 0; 622 pName->uType = STRRET_CSTR; 623 return E_UNEXPECTED; 624 } 625 626 pName->pOleStr = StrDupW(pFileName + 1); 627 if (pName->pOleStr == NULL) 628 return E_OUTOFMEMORY; 629 630 pName->uType = STRRET_WSTR; 631 return S_OK; 632 } 633 634 HRESULT WINAPI CRecycleBin::SetNameOf(HWND hwnd, PCUITEMID_CHILD pidl, LPCOLESTR pszName, 635 SHGDNF uFlags, PITEMID_CHILD *ppidlOut) 636 { 637 TRACE("\n"); 638 return E_FAIL; /* not supported */ 639 } 640 641 HRESULT WINAPI CRecycleBin::GetDefaultSearchGUID(GUID *pguid) 642 { 643 FIXME("stub\n"); 644 return E_NOTIMPL; 645 } 646 647 HRESULT WINAPI CRecycleBin::EnumSearches(IEnumExtraSearch **ppEnum) 648 { 649 FIXME("stub\n"); 650 *ppEnum = NULL; 651 return E_NOTIMPL; 652 } 653 654 HRESULT WINAPI CRecycleBin::GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay) 655 { 656 TRACE("(%p, %x, %p, %p)\n", this, (unsigned int)dwReserved, pSort, pDisplay); 657 if (pSort) 658 *pSort = 0; 659 if (pDisplay) 660 *pDisplay = 0; 661 return S_OK; 662 } 663 664 HRESULT WINAPI CRecycleBin::GetDefaultColumnState(UINT iColumn, SHCOLSTATEF *pcsFlags) 665 { 666 TRACE("(%p, %d, %p)\n", this, iColumn, pcsFlags); 667 if (iColumn >= COLUMNS_COUNT) 668 return E_INVALIDARG; 669 *pcsFlags = RecycleBinColumns[iColumn].pcsFlags; 670 return S_OK; 671 } 672 673 HRESULT WINAPI CRecycleBin::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNID *pscid, VARIANT *pv) 674 { 675 FIXME("stub\n"); 676 return E_NOTIMPL; 677 } 678 679 static HRESULT FormatDateTime(LPWSTR buffer, int size, FILETIME * ft) 680 { 681 FILETIME lft; 682 SYSTEMTIME time; 683 int ret; 684 685 FileTimeToLocalFileTime(ft, &lft); 686 FileTimeToSystemTime(&lft, &time); 687 688 ret = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &time, NULL, buffer, size); 689 if (ret > 0 && ret < size) 690 { 691 /* Append space + time without seconds */ 692 buffer[ret-1] = ' '; 693 GetTimeFormatW(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &time, NULL, &buffer[ret], size - ret); 694 } 695 696 return (ret != 0 ? E_FAIL : S_OK); 697 } 698 699 HRESULT WINAPI CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, LPSHELLDETAILS pDetails) 700 { 701 PIDLRecycleStruct * pFileDetails; 702 WCHAR buffer[MAX_PATH]; 703 WCHAR szTypeName[100]; 704 LPWSTR pszBackslash; 705 UINT Length; 706 707 TRACE("(%p, %p, %d, %p)\n", this, pidl, iColumn, pDetails); 708 if (iColumn >= COLUMNS_COUNT) 709 return E_FAIL; 710 pDetails->fmt = RecycleBinColumns[iColumn].fmt; 711 pDetails->cxChar = RecycleBinColumns[iColumn].cxChars; 712 if (pidl == NULL) 713 return SHSetStrRet(&pDetails->str, RecycleBinColumns[iColumn].column_name_id); 714 715 if (iColumn == COLUMN_NAME) 716 return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str); 717 718 pFileDetails = _ILGetRecycleStruct(pidl); 719 switch (iColumn) 720 { 721 case COLUMN_DATEDEL: 722 FormatDateTime(buffer, MAX_PATH, &pFileDetails->DeletionTime); 723 break; 724 case COLUMN_DELFROM: 725 pszBackslash = wcsrchr(pFileDetails->szName, L'\\'); 726 Length = (pszBackslash - pFileDetails->szName); 727 memcpy((LPVOID)buffer, pFileDetails->szName, Length * sizeof(WCHAR)); 728 buffer[Length] = L'\0'; 729 break; 730 case COLUMN_SIZE: 731 StrFormatKBSizeW(pFileDetails->FileSize.QuadPart, buffer, MAX_PATH); 732 break; 733 case COLUMN_MTIME: 734 FormatDateTime(buffer, MAX_PATH, &pFileDetails->LastModification); 735 break; 736 case COLUMN_TYPE: 737 // FIXME: We should in fact use a UNICODE version of _ILGetFileType 738 szTypeName[0] = L'\0'; 739 wcscpy(buffer, PathFindExtensionW(pFileDetails->szName)); 740 if (!( HCR_MapTypeToValueW(buffer, buffer, _countof(buffer), TRUE) && 741 HCR_MapTypeToValueW(buffer, szTypeName, _countof(szTypeName), FALSE ))) 742 { 743 /* load localized file string */ 744 szTypeName[0] = '\0'; 745 if(LoadStringW(shell32_hInstance, IDS_ANY_FILE, szTypeName, _countof(szTypeName))) 746 { 747 szTypeName[63] = '\0'; 748 StringCchPrintfW(buffer, _countof(buffer), szTypeName, PathFindExtensionW(pFileDetails->szName)); 749 } 750 } 751 return SHSetStrRet(&pDetails->str, szTypeName); 752 default: 753 return E_FAIL; 754 } 755 756 return SHSetStrRet(&pDetails->str, buffer); 757 } 758 759 HRESULT WINAPI CRecycleBin::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid) 760 { 761 TRACE("(%p, %d, %p)\n", this, iColumn, pscid); 762 if (iColumn >= COLUMNS_COUNT) 763 return E_INVALIDARG; 764 pscid->fmtid = *RecycleBinColumns[iColumn].fmtId; 765 pscid->pid = RecycleBinColumns[iColumn].pid; 766 return S_OK; 767 } 768 769 BOOL CRecycleBin::RecycleBinIsEmpty() 770 { 771 CComPtr<IEnumIDList> spEnumFiles; 772 HRESULT hr = EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &spEnumFiles); 773 if (FAILED(hr)) 774 return TRUE; 775 CComHeapPtr<ITEMIDLIST> spPidl; 776 ULONG itemcount; 777 return spEnumFiles->Next(1, &spPidl, &itemcount) != S_OK; 778 } 779 780 /************************************************************************* 781 * RecycleBin IContextMenu interface 782 */ 783 784 HRESULT WINAPI CRecycleBin::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) 785 { 786 WCHAR szBuffer[100]; 787 MENUITEMINFOW mii; 788 int id = 1; 789 790 TRACE("QueryContextMenu %p %p %u %u %u %u\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags ); 791 792 if (!hMenu) 793 return E_INVALIDARG; 794 795 memset(&mii, 0, sizeof(mii)); 796 mii.cbSize = sizeof(mii); 797 mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE; 798 mii.fState = RecycleBinIsEmpty() ? MFS_DISABLED : MFS_ENABLED; 799 szBuffer[0] = L'\0'; 800 LoadStringW(shell32_hInstance, IDS_EMPTY_BITBUCKET, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)); 801 mii.dwTypeData = szBuffer; 802 mii.cch = wcslen(mii.dwTypeData); 803 mii.wID = idCmdFirst + id++; 804 mii.fType = MFT_STRING; 805 iIdEmpty = 1; 806 807 if (!InsertMenuItemW(hMenu, indexMenu, TRUE, &mii)) 808 return E_FAIL; 809 810 return MAKE_HRESULT(SEVERITY_SUCCESS, 0, id); 811 } 812 813 HRESULT WINAPI CRecycleBin::InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi) 814 { 815 HRESULT hr; 816 LPSHELLBROWSER lpSB; 817 IShellView * lpSV = NULL; 818 819 TRACE("%p %p verb %p\n", this, lpcmi, lpcmi->lpVerb); 820 821 if (LOWORD(lpcmi->lpVerb) == iIdEmpty) 822 { 823 // FIXME 824 // path & flags 825 hr = SHEmptyRecycleBinW(lpcmi->hwnd, L"C:\\", 0); 826 TRACE("result %x\n", hr); 827 if (hr != S_OK) 828 return hr; 829 830 lpSB = (LPSHELLBROWSER)SendMessageA(lpcmi->hwnd, CWM_GETISHELLBROWSER, 0, 0); 831 if (lpSB && SUCCEEDED(lpSB->QueryActiveShellView(&lpSV))) 832 lpSV->Refresh(); 833 } 834 return S_OK; 835 } 836 837 HRESULT WINAPI CRecycleBin::GetCommandString(UINT_PTR idCommand, UINT uFlags, UINT *lpReserved, LPSTR lpszName, UINT uMaxNameLen) 838 { 839 FIXME("%p %lu %u %p %p %u\n", this, idCommand, uFlags, lpReserved, lpszName, uMaxNameLen); 840 841 return E_NOTIMPL; 842 } 843 844 /************************************************************************* 845 * RecycleBin IShellPropSheetExt interface 846 */ 847 848 HRESULT WINAPI CRecycleBin::AddPages(LPFNSVADDPROPSHEETPAGE pfnAddPage, LPARAM lParam) 849 { 850 FIXME("%p %p %lu\n", this, pfnAddPage, lParam); 851 852 return E_NOTIMPL; 853 } 854 855 HRESULT WINAPI CRecycleBin::ReplacePage(EXPPS uPageID, LPFNSVADDPROPSHEETPAGE pfnReplaceWith, LPARAM lParam) 856 { 857 FIXME("%p %lu %p %lu\n", this, uPageID, pfnReplaceWith, lParam); 858 859 return E_NOTIMPL; 860 } 861 862 /************************************************************************* 863 * RecycleBin IShellExtInit interface 864 */ 865 866 HRESULT WINAPI CRecycleBin::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pdtobj, HKEY hkeyProgID) 867 { 868 TRACE("%p %p %p %p\n", this, pidlFolder, pdtobj, hkeyProgID ); 869 return S_OK; 870 } 871 872 BOOL 873 TRASH_CanTrashFile(LPCWSTR wszPath) 874 { 875 LONG ret; 876 DWORD dwNukeOnDelete, dwType, VolSerialNumber, MaxComponentLength; 877 DWORD FileSystemFlags, dwSize, dwDisposition; 878 HKEY hKey; 879 WCHAR szBuffer[10]; 880 WCHAR szKey[150] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\"; 881 882 if (wszPath[1] != L':') 883 { 884 /* path is UNC */ 885 return FALSE; 886 } 887 888 // Only keep the base path. 889 WCHAR wszRootPathName[MAX_PATH]; 890 strcpyW(wszRootPathName, wszPath); 891 PathRemoveFileSpecW(wszRootPathName); 892 PathAddBackslashW(wszRootPathName); 893 894 if (GetDriveTypeW(wszRootPathName) != DRIVE_FIXED) 895 { 896 /* no bitbucket on removable media */ 897 return FALSE; 898 } 899 900 if (!GetVolumeInformationW(wszRootPathName, NULL, 0, &VolSerialNumber, &MaxComponentLength, &FileSystemFlags, NULL, 0)) 901 { 902 ERR("GetVolumeInformationW failed with %u\n", GetLastError()); 903 return FALSE; 904 } 905 906 swprintf(szBuffer, L"%04X-%04X", LOWORD(VolSerialNumber), HIWORD(VolSerialNumber)); 907 wcscat(szKey, szBuffer); 908 909 if (RegCreateKeyExW(HKEY_CURRENT_USER, szKey, 0, NULL, 0, KEY_WRITE, NULL, &hKey, &dwDisposition) != ERROR_SUCCESS) 910 { 911 ERR("RegCreateKeyExW failed\n"); 912 return FALSE; 913 } 914 915 if (dwDisposition & REG_CREATED_NEW_KEY) 916 { 917 /* per default move to bitbucket */ 918 dwNukeOnDelete = 0; 919 RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD)); 920 /* per default unlimited size */ 921 dwSize = -1; 922 RegSetValueExW(hKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&dwSize, sizeof(DWORD)); 923 RegCloseKey(hKey); 924 return TRUE; 925 } 926 else 927 { 928 dwSize = sizeof(dwNukeOnDelete); 929 ret = RegQueryValueExW(hKey, L"NukeOnDelete", NULL, &dwType, (LPBYTE)&dwNukeOnDelete, &dwSize); 930 if (ret != ERROR_SUCCESS) 931 { 932 if (ret == ERROR_FILE_NOT_FOUND) 933 { 934 /* restore key and enable bitbucket */ 935 dwNukeOnDelete = 0; 936 RegSetValueExW(hKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&dwNukeOnDelete, sizeof(DWORD)); 937 } 938 RegCloseKey(hKey); 939 return TRUE; 940 } 941 else if (dwNukeOnDelete) 942 { 943 /* do not delete to bitbucket */ 944 RegCloseKey(hKey); 945 return FALSE; 946 } 947 /* FIXME 948 * check if bitbucket is full 949 */ 950 RegCloseKey(hKey); 951 return TRUE; 952 } 953 } 954 955 BOOL 956 TRASH_TrashFile(LPCWSTR wszPath) 957 { 958 TRACE("(%s)\n", debugstr_w(wszPath)); 959 return DeleteFileToRecycleBin(wszPath); 960 } 961 962 /************************************************************************* 963 * SHUpdateCRecycleBinIcon [SHELL32.@] 964 * 965 * Undocumented 966 */ 967 EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void) 968 { 969 FIXME("stub\n"); 970 971 return S_OK; 972 } 973 974 /************************************************************************* 975 * SHEmptyRecycleBinA (SHELL32.@) 976 */ 977 HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags) 978 { 979 LPWSTR szRootPathW = NULL; 980 int len; 981 HRESULT hr; 982 983 TRACE("%p, %s, 0x%08x\n", hwnd, debugstr_a(pszRootPath), dwFlags); 984 985 if (pszRootPath) 986 { 987 len = MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, NULL, 0); 988 if (len == 0) 989 return HRESULT_FROM_WIN32(GetLastError()); 990 szRootPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 991 if (!szRootPathW) 992 return E_OUTOFMEMORY; 993 if (MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, szRootPathW, len) == 0) 994 { 995 HeapFree(GetProcessHeap(), 0, szRootPathW); 996 return HRESULT_FROM_WIN32(GetLastError()); 997 } 998 } 999 1000 hr = SHEmptyRecycleBinW(hwnd, szRootPathW, dwFlags); 1001 HeapFree(GetProcessHeap(), 0, szRootPathW); 1002 1003 return hr; 1004 } 1005 1006 HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags) 1007 { 1008 WCHAR szPath[MAX_PATH] = {0}, szBuffer[MAX_PATH]; 1009 DWORD dwSize, dwType, count; 1010 LONG ret; 1011 IShellFolder *pDesktop, *pRecycleBin; 1012 PIDLIST_ABSOLUTE pidlRecycleBin; 1013 PITEMID_CHILD pidl; 1014 HRESULT hr = S_OK; 1015 LPENUMIDLIST penumFiles; 1016 STRRET StrRet; 1017 1018 TRACE("%p, %s, 0x%08x\n", hwnd, debugstr_w(pszRootPath), dwFlags); 1019 1020 if (!(dwFlags & SHERB_NOCONFIRMATION)) 1021 { 1022 hr = SHGetDesktopFolder(&pDesktop); 1023 if (FAILED(hr)) 1024 return hr; 1025 hr = SHGetFolderLocation(NULL, CSIDL_BITBUCKET, NULL, 0, &pidlRecycleBin); 1026 if (FAILED(hr)) 1027 { 1028 pDesktop->Release(); 1029 return hr; 1030 } 1031 hr = pDesktop->BindToObject(pidlRecycleBin, NULL, IID_PPV_ARG(IShellFolder, &pRecycleBin)); 1032 CoTaskMemFree(pidlRecycleBin); 1033 pDesktop->Release(); 1034 if (FAILED(hr)) 1035 return hr; 1036 hr = pRecycleBin->EnumObjects(hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penumFiles); 1037 if (FAILED(hr)) 1038 { 1039 pRecycleBin->Release(); 1040 return hr; 1041 } 1042 1043 count = 0; 1044 if (hr != S_FALSE) 1045 { 1046 while (penumFiles->Next(1, &pidl, NULL) == S_OK) 1047 { 1048 count++; 1049 pRecycleBin->GetDisplayNameOf(pidl, SHGDN_NORMAL, &StrRet); 1050 StrRetToBuf(&StrRet, pidl, szBuffer, _countof(szBuffer)); 1051 CoTaskMemFree(pidl); 1052 } 1053 penumFiles->Release(); 1054 } 1055 pRecycleBin->Release(); 1056 1057 switch (count) 1058 { 1059 case 0: 1060 /* no files, don't need confirmation */ 1061 break; 1062 1063 case 1: 1064 /* we have only one item inside the bin, so show a message box with its name */ 1065 if (ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_DELETEITEM_TEXT), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET), 1066 MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, szBuffer) == IDNO) 1067 { 1068 return S_OK; 1069 } 1070 break; 1071 1072 default: 1073 /* we have more than one item, so show a message box with the count of the items */ 1074 StringCbPrintfW(szBuffer, sizeof(szBuffer), L"%u", count); 1075 if (ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_DELETEMULTIPLE_TEXT), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET), 1076 MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, szBuffer) == IDNO) 1077 { 1078 return S_OK; 1079 } 1080 break; 1081 } 1082 } 1083 1084 if (dwFlags & SHERB_NOPROGRESSUI) 1085 { 1086 ret = EmptyRecycleBinW(pszRootPath); 1087 } 1088 else 1089 { 1090 /* FIXME 1091 * show a progress dialog 1092 */ 1093 ret = EmptyRecycleBinW(pszRootPath); 1094 } 1095 1096 if (!ret) 1097 return HRESULT_FROM_WIN32(GetLastError()); 1098 1099 if (!(dwFlags & SHERB_NOSOUND)) 1100 { 1101 dwSize = sizeof(szPath); 1102 ret = RegGetValueW(HKEY_CURRENT_USER, 1103 L"AppEvents\\Schemes\\Apps\\Explorer\\EmptyRecycleBin\\.Current", 1104 NULL, 1105 RRF_RT_REG_SZ, 1106 &dwType, 1107 (PVOID)szPath, 1108 &dwSize); 1109 if (ret != ERROR_SUCCESS) 1110 return S_OK; 1111 1112 if (dwType != REG_EXPAND_SZ) /* type dismatch */ 1113 return S_OK; 1114 1115 szPath[(sizeof(szPath)/sizeof(WCHAR))-1] = L'\0'; 1116 PlaySoundW(szPath, NULL, SND_FILENAME); 1117 } 1118 return S_OK; 1119 } 1120 1121 HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo) 1122 { 1123 LPWSTR szRootPathW = NULL; 1124 int len; 1125 HRESULT hr; 1126 1127 TRACE("%s, %p\n", debugstr_a(pszRootPath), pSHQueryRBInfo); 1128 1129 if (pszRootPath) 1130 { 1131 len = MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, NULL, 0); 1132 if (len == 0) 1133 return HRESULT_FROM_WIN32(GetLastError()); 1134 szRootPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1135 if (!szRootPathW) 1136 return E_OUTOFMEMORY; 1137 if (MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, szRootPathW, len) == 0) 1138 { 1139 HeapFree(GetProcessHeap(), 0, szRootPathW); 1140 return HRESULT_FROM_WIN32(GetLastError()); 1141 } 1142 } 1143 1144 hr = SHQueryRecycleBinW(szRootPathW, pSHQueryRBInfo); 1145 HeapFree(GetProcessHeap(), 0, szRootPathW); 1146 1147 return hr; 1148 } 1149 1150 HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo) 1151 { 1152 FIXME("%s, %p - stub\n", debugstr_w(pszRootPath), pSHQueryRBInfo); 1153 1154 if (!(pszRootPath) || (pszRootPath[0] == 0) || 1155 !(pSHQueryRBInfo) || (pSHQueryRBInfo->cbSize < sizeof(SHQUERYRBINFO))) 1156 { 1157 return E_INVALIDARG; 1158 } 1159 1160 pSHQueryRBInfo->i64Size = 0; 1161 pSHQueryRBInfo->i64NumItems = 0; 1162 1163 return S_OK; 1164 } 1165