[SHELL] IPersistFolder::Initialize takes a PCIDLIST_ABSOLUTE. CORE-16385
[reactos.git] / dll / win32 / shell32 / folders / CRecycleBin.cpp
index 96c581a..23e7e20 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2006 Mikolaj Zalewski
  * Copyright (C) 2009 Andrew Hill
+ * Copyright (C) 2018 Russell Johnson
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 
 #include <precomp.h>
 
+#include <mmsystem.h>
 #include <ntquery.h>
 
-#define MAX_PROPERTY_SHEET_PAGE 32
-
 WINE_DEFAULT_DEBUG_CHANNEL(CRecycleBin);
 
 typedef struct
@@ -39,12 +39,12 @@ typedef struct
 
 static const columninfo RecycleBinColumns[] =
 {
-    {IDS_SHV_COLUMN1,        &FMTID_Storage,   PID_STG_NAME,       SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  30},
+    {IDS_SHV_COLUMN_NAME,        &FMTID_Storage,   PID_STG_NAME,       SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  30},
     {IDS_SHV_COLUMN_DELFROM, &FMTID_Displaced, PID_DISPLACED_FROM, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  30},
     {IDS_SHV_COLUMN_DELDATE, &FMTID_Displaced, PID_DISPLACED_DATE, SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT,  20},
-    {IDS_SHV_COLUMN2,        &FMTID_Storage,   PID_STG_SIZE,       SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT,  LVCFMT_RIGHT, 20},
-    {IDS_SHV_COLUMN3,        &FMTID_Storage,   PID_STG_STORAGETYPE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  20},
-    {IDS_SHV_COLUMN4,        &FMTID_Storage,   PID_STG_WRITETIME,  SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT,  20},
+    {IDS_SHV_COLUMN_SIZE,        &FMTID_Storage,   PID_STG_SIZE,       SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT,  LVCFMT_RIGHT, 20},
+    {IDS_SHV_COLUMN_TYPE,        &FMTID_Storage,   PID_STG_STORAGETYPE, SHCOLSTATE_TYPE_INT | SHCOLSTATE_ONBYDEFAULT,  LVCFMT_LEFT,  20},
+    {IDS_SHV_COLUMN_MODIFIED,        &FMTID_Storage,   PID_STG_WRITETIME,  SHCOLSTATE_TYPE_DATE | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT,  20},
     /*    {"creation time",  &FMTID_Storage,   PID_STG_CREATETIME, SHCOLSTATE_TYPE_DATE,                        LVCFMT_LEFT,  20}, */
     /*    {"attribs",        &FMTID_Storage,   PID_STG_ATTRIBUTES, SHCOLSTATE_TYPE_STR,                         LVCFMT_LEFT,  20},       */
 };
@@ -62,6 +62,19 @@ static const columninfo RecycleBinColumns[] =
  * Recycle Bin folder
  */
 
+HRESULT CRecyclerExtractIcon_CreateInstance(LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
+{
+    CComPtr<IDefaultExtractIconInit> initIcon;
+    HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    /* FIXME: This is completely unimplemented */
+    initIcon->SetNormalIcon(swShell32Name, 0);
+
+    return initIcon->QueryInterface(riid, ppvOut);
+}
+
 class CRecycleBinEnum :
     public CEnumIDListBase
 {
@@ -110,13 +123,6 @@ typedef struct
     BOOL bFound;
 } SEARCH_CONTEXT, *PSEARCH_CONTEXT;
 
-typedef struct
-{
-    DWORD dwNukeOnDelete;
-    DWORD dwSerial;
-    DWORD dwMaxCapacity;
-} DRIVE_ITEM_CONTEXT, *PDRIVE_ITEM_CONTEXT;
-
 BOOL WINAPI CBSearchRecycleBin(IN PVOID Context, IN HANDLE hDeletedFile)
 {
     PSEARCH_CONTEXT pContext = (PSEARCH_CONTEXT)Context;
@@ -314,30 +320,30 @@ HRESULT WINAPI CRecycleBinItemContextMenu::QueryContextMenu(HMENU hMenu, UINT in
 
     TRACE("(%p)->(hmenu=%p indexmenu=%x cmdfirst=%x cmdlast=%x flags=%x )\n", this, hMenu, indexMenu, idCmdFirst, idCmdLast, uFlags);
 
-    if (LoadStringW(shell32_hInstance, IDS_RESTORE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+    if (LoadStringW(shell32_hInstance, IDS_RESTORE, szBuffer, _countof(szBuffer)))
     {
-        szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+        szBuffer[_countof(szBuffer)-1] = L'\0';
         _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_ENABLED);
         Count++;
     }
 
-    if (LoadStringW(shell32_hInstance, IDS_CUT, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+    if (LoadStringW(shell32_hInstance, IDS_CUT, szBuffer, _countof(szBuffer)))
     {
         _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
-        szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+        szBuffer[_countof(szBuffer)-1] = L'\0';
         _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
     }
 
-    if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+    if (LoadStringW(shell32_hInstance, IDS_DELETE, szBuffer, _countof(szBuffer)))
     {
-        szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+        szBuffer[_countof(szBuffer)-1] = L'\0';
         _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
         _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_STRING, szBuffer, MFS_ENABLED);
     }
 
-    if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, sizeof(szBuffer) / sizeof(WCHAR)))
+    if (LoadStringW(shell32_hInstance, IDS_PROPERTIES, szBuffer, _countof(szBuffer)))
     {
-        szBuffer[(sizeof(szBuffer)/sizeof(WCHAR))-1] = L'\0';
+        szBuffer[_countof(szBuffer)-1] = L'\0';
         _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count++, MFT_SEPARATOR, NULL, MFS_ENABLED);
         _InsertMenuItemW(hMenu, indexMenu++, TRUE, idCmdFirst + Count, MFT_STRING, szBuffer, MFS_DEFAULT);
     }
@@ -403,29 +409,13 @@ HRESULT WINAPI CRecycleBinItemContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wPara
     return E_NOTIMPL;
 }
 
-/**************************************************************************
-* registers clipboardformat once
-*/
-void CRecycleBin::SF_RegisterClipFmt()
-{
-    TRACE ("(%p)\n", this);
-
-    if (!cfShellIDList)
-        cfShellIDList = RegisterClipboardFormatW(CFSTR_SHELLIDLIST);
-}
-
 CRecycleBin::CRecycleBin()
 {
     pidl = NULL;
-    iIdEmpty = 0;
-    cfShellIDList = 0;
-    SF_RegisterClipFmt();
-    fAcceptFmt = FALSE;
 }
 
 CRecycleBin::~CRecycleBin()
 {
-    /*    InterlockedDecrement(&objCount);*/
     SHFree(pidl);
 }
 
@@ -442,7 +432,7 @@ HRESULT WINAPI CRecycleBin::GetClassID(CLSID *pClassID)
     return S_OK;
 }
 
-HRESULT WINAPI CRecycleBin::Initialize(LPCITEMIDLIST pidl)
+HRESULT WINAPI CRecycleBin::Initialize(PCIDLIST_ABSOLUTE pidl)
 {
     TRACE("(%p, %p)\n", this, pidl);
 
@@ -453,7 +443,7 @@ HRESULT WINAPI CRecycleBin::Initialize(LPCITEMIDLIST pidl)
     return S_OK;
 }
 
-HRESULT WINAPI CRecycleBin::GetCurFolder(LPITEMIDLIST *ppidl)
+HRESULT WINAPI CRecycleBin::GetCurFolder(PIDLIST_ABSOLUTE *ppidl)
 {
     TRACE("\n");
     *ppidl = ILClone(pidl);
@@ -481,7 +471,7 @@ UnpackDetailsFromPidl(LPCITEMIDLIST pidl)
 
 HRESULT WINAPI CRecycleBin::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
 {
-    return ShellObjectCreatorInit<CRecycleBinEnum>(dwFlags, IID_IEnumIDList, ppEnumIDList);
+    return ShellObjectCreatorInit<CRecycleBinEnum>(dwFlags, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
 }
 
 HRESULT WINAPI CRecycleBin::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbc, REFIID riid, void **ppv)
@@ -498,11 +488,41 @@ HRESULT WINAPI CRecycleBin::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbc, REF
 
 HRESULT WINAPI CRecycleBin::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
 {
-    /* TODO */
-    TRACE("(%p, %p, %p, %p)\n", this, (void *)lParam, pidl1, pidl2);
-    if (pidl1->mkid.cb != pidl2->mkid.cb)
-        return MAKE_HRESULT(SEVERITY_SUCCESS, 0, pidl1->mkid.cb - pidl2->mkid.cb);
-    return MAKE_HRESULT(SEVERITY_SUCCESS, 0, (unsigned short)memcmp(pidl1->mkid.abID, pidl2->mkid.abID, pidl1->mkid.cb));
+    PIDLRecycleStruct* pData1 = _ILGetRecycleStruct(pidl1);
+    PIDLRecycleStruct* pData2 = _ILGetRecycleStruct(pidl2);
+    LPWSTR pName1, pName2;
+
+    if(!pData1 || !pData2 || LOWORD(lParam) >= COLUMNS_COUNT)
+        return E_INVALIDARG;
+
+    SHORT result;
+    LONGLONG diff;
+    switch (LOWORD(lParam))
+    {
+        case 0: /* Name */
+            pName1 = PathFindFileNameW(pData1->szName);
+            pName2 = PathFindFileNameW(pData2->szName);
+            result = wcsicmp(pName1, pName2);
+            break;
+        case 1: /* Orig. Location */
+            result = wcsicmp(pData1->szName, pData2->szName);
+            break;
+        case 2: /* Date Deleted */
+            result = CompareFileTime(&pData1->DeletionTime, &pData2->DeletionTime);
+            break;
+        case 3: /* Size */
+            diff = pData1->FileSize.QuadPart - pData2->FileSize.QuadPart;
+            return MAKE_COMPARE_HRESULT(diff);
+        case 4: /* Type */
+            pName1 = PathFindExtensionW(pData1->szName);
+            pName2 = PathFindExtensionW(pData2->szName);
+            result = wcsicmp(pName1, pName2);
+            break;
+        case 5: /* Modified */
+            result = CompareFileTime(&pData1->LastModification, &pData2->LastModification);
+            break;
+    }
+    return MAKE_COMPARE_HRESULT(result);
 }
 
 HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv)
@@ -519,7 +539,7 @@ HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void *
 
     if (IsEqualIID (riid, IID_IDropTarget))
     {
-        hr = this->QueryInterface (IID_IDropTarget, ppv);
+        hr = CRecyclerDropTarget_CreateInstance(riid, ppv);
     }
     else if (IsEqualIID (riid, IID_IContextMenu) || IsEqualIID (riid, IID_IContextMenu2))
     {
@@ -527,14 +547,12 @@ HRESULT WINAPI CRecycleBin::CreateViewObject(HWND hwndOwner, REFIID riid, void *
     }
     else if (IsEqualIID (riid, IID_IShellView))
     {
-        hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
-        if (pShellView)
-        {
-            hr = pShellView->QueryInterface(riid, ppv);
-        }
+        SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
+        hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppv);
     }
     else
         return hr;
+
     TRACE ("-- (%p)->(interface=%p)\n", this, ppv);
     return hr;
 
@@ -551,7 +569,7 @@ HRESULT WINAPI CRecycleBin::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY api
 HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
         REFIID riid, UINT *prgfInOut, void **ppv)
 {
-    IUnknown *pObj = NULL;
+    LPVOID pObj = NULL;
     HRESULT hr = E_INVALIDARG;
 
     TRACE ("(%p)->(%p,%u,apidl=%p, %p %p)\n", this,
@@ -566,11 +584,9 @@ HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_C
     {
         hr = ShellObjectCreatorInit<CRecycleBinItemContextMenu>(apidl[0], riid, &pObj);
     }
-    else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
+    else if((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1))
     {
-        IDropTarget * pDt = NULL;
-        hr = QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
-        pObj = pDt;
+        hr = CRecyclerExtractIcon_CreateInstance(apidl[0], riid, &pObj);
     }
     else
         hr = E_NOINTERFACE;
@@ -590,19 +606,6 @@ HRESULT WINAPI CRecycleBin::GetDisplayNameOf(PCUITEMID_CHILD pidl, SHGDNF uFlags
 
     TRACE("(%p, %p, %x, %p)\n", this, pidl, (unsigned int)uFlags, pName);
 
-
-    if (_ILIsBitBucket (pidl))
-    {
-        WCHAR pszPath[100];
-
-        if (HCR_GetClassNameW(CLSID_RecycleBin, pszPath, MAX_PATH))
-        {
-            pName->uType = STRRET_WSTR;
-            pName->pOleStr = StrDupW(pszPath);
-            return S_OK;
-        }
-    }
-
     pFileDetails = _ILGetRecycleStruct(pidl);
     if (!pFileDetails)
     {
@@ -650,8 +653,10 @@ HRESULT WINAPI CRecycleBin::EnumSearches(IEnumExtraSearch **ppEnum)
 HRESULT WINAPI CRecycleBin::GetDefaultColumn(DWORD dwReserved, ULONG *pSort, ULONG *pDisplay)
 {
     TRACE("(%p, %x, %p, %p)\n", this, (unsigned int)dwReserved, pSort, pDisplay);
-    *pSort = 0;
-    *pDisplay = 0;
+    if (pSort)
+        *pSort = 0;
+    if (pDisplay)
+        *pDisplay = 0;
     return S_OK;
 }
 
@@ -704,11 +709,7 @@ HRESULT WINAPI CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, LPS
     pDetails->fmt = RecycleBinColumns[iColumn].fmt;
     pDetails->cxChar = RecycleBinColumns[iColumn].cxChars;
     if (pidl == NULL)
-    {
-        pDetails->str.uType = STRRET_WSTR;
-        LoadStringW(shell32_hInstance, RecycleBinColumns[iColumn].column_name_id, buffer, MAX_PATH);
-        return SHStrDupW(buffer, &pDetails->str.pOleStr);
-    }
+        return SHSetStrRet(&pDetails->str, RecycleBinColumns[iColumn].column_name_id);
 
     if (iColumn == COLUMN_NAME)
         return GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
@@ -732,26 +733,26 @@ HRESULT WINAPI CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, LPS
             FormatDateTime(buffer, MAX_PATH, &pFileDetails->LastModification);
             break;
         case COLUMN_TYPE:
+            // FIXME: We should in fact use a UNICODE version of _ILGetFileType
             szTypeName[0] = L'\0';
             wcscpy(buffer, PathFindExtensionW(pFileDetails->szName));
-            if (!( HCR_MapTypeToValueW(buffer, buffer, sizeof(buffer) / sizeof(WCHAR), TRUE) &&
-                    HCR_MapTypeToValueW(buffer, szTypeName, sizeof(szTypeName) / sizeof(WCHAR), FALSE )))
+            if (!( HCR_MapTypeToValueW(buffer, buffer, _countof(buffer), TRUE) &&
+                    HCR_MapTypeToValueW(buffer, szTypeName, _countof(szTypeName), FALSE )))
             {
-                wcscpy (szTypeName, PathFindExtensionW(pFileDetails->szName));
-                wcscat(szTypeName, L"-");
-                Length = wcslen(szTypeName);
-                if (LoadStringW(shell32_hInstance, IDS_SHV_COLUMN1, &szTypeName[Length], (sizeof(szTypeName) / sizeof(WCHAR)) - Length))
-                    szTypeName[(sizeof(szTypeName)/sizeof(WCHAR))-1] = L'\0';
+                /* load localized file string */
+                szTypeName[0] = '\0';
+                if(LoadStringW(shell32_hInstance, IDS_ANY_FILE, szTypeName, _countof(szTypeName)))
+                {
+                    szTypeName[63] = '\0';
+                    StringCchPrintfW(buffer, _countof(buffer), szTypeName, PathFindExtensionW(pFileDetails->szName));
+                }
             }
-            pDetails->str.uType = STRRET_WSTR;
-            return SHStrDupW(szTypeName, &pDetails->str.pOleStr);
-            break;
+            return SHSetStrRet(&pDetails->str, szTypeName);
         default:
             return E_FAIL;
     }
 
-    pDetails->str.uType = STRRET_WSTR;
-    return SHStrDupW(buffer, &pDetails->str.pOleStr);
+    return SHSetStrRet(&pDetails->str, buffer);
 }
 
 HRESULT WINAPI CRecycleBin::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
@@ -764,6 +765,17 @@ HRESULT WINAPI CRecycleBin::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
     return S_OK;
 }
 
+BOOL CRecycleBin::RecycleBinIsEmpty()
+{
+    CComPtr<IEnumIDList> spEnumFiles;
+    HRESULT hr = EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, &spEnumFiles);
+    if (FAILED(hr))
+        return TRUE;
+    CComHeapPtr<ITEMIDLIST> spPidl;
+    ULONG itemcount;
+    return spEnumFiles->Next(1, &spPidl, &itemcount) != S_OK;
+    }
+
 /*************************************************************************
  * RecycleBin IContextMenu interface
  */
@@ -779,12 +791,12 @@ HRESULT WINAPI CRecycleBin::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT i
     if (!hMenu)
         return E_INVALIDARG;
 
-    memset(&mii, 0, sizeof(mii));
+    ZeroMemory(&mii, sizeof(mii));
     mii.cbSize = sizeof(mii);
     mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
-    mii.fState = MFS_ENABLED;
+    mii.fState = RecycleBinIsEmpty() ? MFS_DISABLED : MFS_ENABLED;
     szBuffer[0] = L'\0';
-    LoadStringW(shell32_hInstance, IDS_EMPTY_BITBUCKET, szBuffer, sizeof(szBuffer) / sizeof(WCHAR));
+    LoadStringW(shell32_hInstance, IDS_EMPTY_BITBUCKET, szBuffer, _countof(szBuffer));
     mii.dwTypeData = szBuffer;
     mii.cch = wcslen(mii.dwTypeData);
     mii.wID = idCmdFirst + id++;
@@ -856,388 +868,11 @@ HRESULT WINAPI CRecycleBin::Initialize(LPCITEMIDLIST pidlFolder, IDataObject *pd
     return S_OK;
 }
 
-void toggleNukeOnDeleteOption(HWND hwndDlg, BOOL bEnable)
-{
-    if (bEnable)
-    {
-        SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_UNCHECKED, 0);
-        EnableWindow(GetDlgItem(hwndDlg, 14002), FALSE);
-        SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_CHECKED, 0);
-    }
-    else
-    {
-        SendDlgItemMessage(hwndDlg, 14001, BM_SETCHECK, BST_CHECKED, 0);
-        EnableWindow(GetDlgItem(hwndDlg, 14002), TRUE);
-        SendDlgItemMessage(hwndDlg, 14003, BM_SETCHECK, BST_UNCHECKED, 0);
-    }
-}
-
-
-static VOID
-InitializeRecycleBinDlg(HWND hwndDlg, WCHAR DefaultDrive)
-{
-    WCHAR CurDrive = L'A';
-    WCHAR szDrive[] = L"A:\\";
-    DWORD dwDrives;
-    WCHAR szName[100];
-    WCHAR szVolume[100];
-    DWORD MaxComponent, Flags;
-    DWORD dwSerial;
-    LVCOLUMNW lc;
-    HWND hDlgCtrl;
-    LVITEMW li;
-    INT itemCount;
-    ULARGE_INTEGER TotalNumberOfFreeBytes, TotalNumberOfBytes, FreeBytesAvailable;
-    RECT rect;
-    int columnSize;
-    int defIndex = 0;
-    DWORD dwSize;
-    PDRIVE_ITEM_CONTEXT pItem = NULL, pDefault = NULL, pFirst = NULL;
-
-    hDlgCtrl = GetDlgItem(hwndDlg, 14000);
-
-    if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_LOCATION, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
-        szVolume[0] = 0;
-
-    GetClientRect(hDlgCtrl, &rect);
-
-    memset(&lc, 0, sizeof(LV_COLUMN) );
-    lc.mask = LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_FMT;
-
-    columnSize = 140; //FIXME
-    lc.iSubItem   = 0;
-    lc.fmt = LVCFMT_FIXED_WIDTH;
-    lc.cx         = columnSize;
-    lc.cchTextMax = wcslen(szVolume);
-    lc.pszText    = szVolume;
-    (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 0, (LPARAM)&lc);
-
-    if (!LoadStringW(shell32_hInstance, IDS_RECYCLEBIN_DISKSPACE, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
-        szVolume[0] = 0;
-
-    lc.iSubItem   = 1;
-    lc.cx         = rect.right - rect.left - columnSize;
-    lc.cchTextMax = wcslen(szVolume);
-    lc.pszText    = szVolume;
-    (void)SendMessageW(hDlgCtrl, LVM_INSERTCOLUMNW, 1, (LPARAM)&lc);
-
-    dwDrives = GetLogicalDrives();
-    itemCount = 0;
-    do
-    {
-        if ((dwDrives & 0x1))
-        {
-            UINT Type = GetDriveTypeW(szDrive);
-            if (Type == DRIVE_FIXED) //FIXME
-            {
-                if (!GetVolumeInformationW(szDrive, szName, sizeof(szName) / sizeof(WCHAR), &dwSerial, &MaxComponent, &Flags, NULL, 0))
-                {
-                    szName[0] = 0;
-                    dwSerial = -1;
-                }
-
-                swprintf(szVolume, L"%s (%c)", szName, szDrive[0]);
-                memset(&li, 0x0, sizeof(LVITEMW));
-                li.mask = LVIF_TEXT | LVIF_PARAM;
-                li.iSubItem = 0;
-                li.pszText = szVolume;
-                li.iItem = itemCount;
-                SendMessageW(hDlgCtrl, LVM_INSERTITEMW, 0, (LPARAM)&li);
-                if (GetDiskFreeSpaceExW(szDrive, &FreeBytesAvailable , &TotalNumberOfBytes, &TotalNumberOfFreeBytes))
-                {
-                    if (StrFormatByteSizeW(TotalNumberOfFreeBytes.QuadPart, szVolume, sizeof(szVolume) / sizeof(WCHAR)))
-                    {
-
-                        pItem = (DRIVE_ITEM_CONTEXT *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DRIVE_ITEM_CONTEXT));
-                        if (pItem)
-                        {
-                            swprintf(szName, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\%04X-%04X", LOWORD(dwSerial), HIWORD(dwSerial));
-                            dwSize = sizeof(DWORD);
-                            RegGetValueW(HKEY_CURRENT_USER, szName, L"MaxCapacity", RRF_RT_DWORD, NULL, &pItem->dwMaxCapacity, &dwSize);
-                            dwSize = sizeof(DWORD);
-                            RegGetValueW(HKEY_CURRENT_USER, szName, L"NukeOnDelete", RRF_RT_DWORD, NULL, &pItem->dwNukeOnDelete, &dwSize);
-                            pItem->dwSerial = dwSerial;
-                            li.mask = LVIF_PARAM;
-                            li.lParam = (LPARAM)pItem;
-                            (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
-                            if (CurDrive == DefaultDrive)
-                            {
-                                defIndex = itemCount;
-                                pDefault = pItem;
-                            }
-                        }
-                        if (!pFirst)
-                            pFirst = pItem;
-
-                        li.mask = LVIF_TEXT;
-                        li.iSubItem = 1;
-                        li.pszText = szVolume;
-                        li.iItem = itemCount;
-                        (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
-                    }
-                }
-                itemCount++;
-            }
-        }
-        CurDrive++;
-        szDrive[0] = CurDrive;
-        dwDrives = (dwDrives >> 1);
-    } while(dwDrives);
-
-    if (!pDefault)
-        pDefault = pFirst;
-    if (pDefault)
-    {
-        toggleNukeOnDeleteOption(hwndDlg, pDefault->dwNukeOnDelete);
-        SetDlgItemInt(hwndDlg, 14002, pDefault->dwMaxCapacity, FALSE);
-    }
-    ZeroMemory(&li, sizeof(li));
-    li.mask = LVIF_STATE;
-    li.stateMask = (UINT) - 1;
-    li.state = LVIS_FOCUSED | LVIS_SELECTED;
-    li.iItem = defIndex;
-    (void)SendMessageW(hDlgCtrl, LVM_SETITEMW, 0, (LPARAM)&li);
-
-}
-
-static BOOL StoreDriveSettings(HWND hwndDlg)
-{
-    int iCount, iIndex;
-    HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
-    LVITEMW li;
-    PDRIVE_ITEM_CONTEXT pItem;
-    HKEY hKey, hSubKey;
-    WCHAR szSerial[20];
-    DWORD dwSize;
-
-
-    if (RegCreateKeyExW(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume", 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL) != ERROR_SUCCESS)
-        return FALSE;
-
-    iCount = ListView_GetItemCount(hDlgCtrl);
-
-    ZeroMemory(&li, sizeof(li));
-    li.mask = LVIF_PARAM;
-
-    for(iIndex = 0; iIndex < iCount; iIndex++)
-    {
-        li.iItem = iIndex;
-        if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
-        {
-            pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
-            swprintf(szSerial, L"%04X-%04X", LOWORD(pItem->dwSerial), HIWORD(pItem->dwSerial));
-            if (RegCreateKeyExW(hKey, szSerial, 0, NULL, 0, KEY_WRITE, NULL, &hSubKey, NULL) == ERROR_SUCCESS)
-            {
-                dwSize = sizeof(DWORD);
-                RegSetValueExW(hSubKey, L"NukeOnDelete", 0, REG_DWORD, (LPBYTE)&pItem->dwNukeOnDelete, dwSize);
-                dwSize = sizeof(DWORD);
-                RegSetValueExW(hSubKey, L"MaxCapacity", 0, REG_DWORD, (LPBYTE)&pItem->dwMaxCapacity, dwSize);
-                RegCloseKey(hSubKey);
-            }
-        }
-    }
-    RegCloseKey(hKey);
-    return TRUE;
-
-}
-
-static VOID FreeDriveItemContext(HWND hwndDlg)
-{
-    int iCount, iIndex;
-    HWND hDlgCtrl = GetDlgItem(hwndDlg, 14000);
-    LVITEMW li;
-
-    iCount = ListView_GetItemCount(hDlgCtrl);
-
-    ZeroMemory(&li, sizeof(li));
-    li.mask = LVIF_PARAM;
-
-    for(iIndex = 0; iIndex < iCount; iIndex++)
-    {
-        li.iItem = iIndex;
-        if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)&li))
-        {
-            HeapFree(GetProcessHeap(), 0, (LPVOID)li.lParam);
-        }
-    }
-}
-
-static INT
-GetDefaultItem(HWND hwndDlg, LVITEMW * li)
-{
-    HWND hDlgCtrl;
-    UINT iItemCount, iIndex;
-
-    hDlgCtrl = GetDlgItem(hwndDlg, 14000);
-    if (!hDlgCtrl)
-        return -1;
-
-    iItemCount = ListView_GetItemCount(hDlgCtrl);
-    if (!iItemCount)
-        return -1;
-
-    ZeroMemory(li, sizeof(LVITEMW));
-    li->mask = LVIF_PARAM | LVIF_STATE;
-    li->stateMask = (UINT) - 1;
-    for (iIndex = 0; iIndex < iItemCount; iIndex++)
-    {
-        li->iItem = iIndex;
-        if (SendMessageW(hDlgCtrl, LVM_GETITEMW, 0, (LPARAM)li))
-        {
-            if (li->state & LVIS_SELECTED)
-                return iIndex;
-        }
-    }
-    return -1;
-
-}
-
-static INT_PTR CALLBACK
-RecycleBinDlg(
-    HWND hwndDlg,
-    UINT uMsg,
-    WPARAM wParam,
-    LPARAM lParam
-)
-{
-    LPPSHNOTIFY lppsn;
-    LPNMLISTVIEW lppl;
-    LVITEMW li;
-    PDRIVE_ITEM_CONTEXT pItem;
-    BOOL bSuccess;
-    UINT uResult;
-    PROPSHEETPAGE * page;
-    DWORD dwStyle;
-
-    switch(uMsg)
-    {
-        case WM_INITDIALOG:
-            page = (PROPSHEETPAGE*)lParam;
-            InitializeRecycleBinDlg(hwndDlg, (WCHAR)page->lParam);
-            dwStyle = (DWORD) SendDlgItemMessage(hwndDlg, 14000, LVM_GETEXTENDEDLISTVIEWSTYLE, 0, 0);
-            dwStyle = dwStyle | LVS_EX_FULLROWSELECT;
-            SendDlgItemMessage(hwndDlg, 14000, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, dwStyle);
-            if (GetDlgCtrlID((HWND)wParam) != 14000)
-            {
-                SetFocus(GetDlgItem(hwndDlg, 14000));
-                return FALSE;
-            }
-            return TRUE;
-        case WM_COMMAND:
-            switch(LOWORD(wParam))
-            {
-                case 14001:
-                    toggleNukeOnDeleteOption(hwndDlg, FALSE);
-                    PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
-                    break;
-                case 14003:
-                    toggleNukeOnDeleteOption(hwndDlg, TRUE);
-                    PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
-                    break;
-                case 14004:
-                    PropSheet_Changed(GetParent(hwndDlg), hwndDlg);
-                    break;
-            }
-            break;
-        case WM_NOTIFY:
-            lppsn = (LPPSHNOTIFY) lParam;
-            lppl = (LPNMLISTVIEW) lParam;
-            if (lppsn->hdr.code == PSN_APPLY)
-            {
-                if (GetDefaultItem(hwndDlg, &li) > -1)
-                {
-                    pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
-                    if (pItem)
-                    {
-                        uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
-                        if (bSuccess)
-                            pItem->dwMaxCapacity = uResult;
-                        if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
-                            pItem->dwNukeOnDelete = TRUE;
-                        else
-                            pItem->dwNukeOnDelete = FALSE;
-                    }
-                }
-                if (StoreDriveSettings(hwndDlg))
-                {
-                    SetWindowLongPtr( hwndDlg, DWL_MSGRESULT, PSNRET_NOERROR );
-                    return TRUE;
-                }
-            }
-            else if (lppl->hdr.code == LVN_ITEMCHANGING)
-            {
-                ZeroMemory(&li, sizeof(li));
-                li.mask = LVIF_PARAM;
-                li.iItem = lppl->iItem;
-                if (!SendMessageW(lppl->hdr.hwndFrom, LVM_GETITEMW, 0, (LPARAM)&li))
-                    return TRUE;
-
-                pItem = (PDRIVE_ITEM_CONTEXT)li.lParam;
-                if (!pItem)
-                    return TRUE;
-
-                if (!(lppl->uOldState & LVIS_FOCUSED) && (lppl->uNewState & LVIS_FOCUSED))
-                {
-                    /* new focused item */
-                    toggleNukeOnDeleteOption(lppl->hdr.hwndFrom, pItem->dwNukeOnDelete);
-                    SetDlgItemInt(hwndDlg, 14002, pItem->dwMaxCapacity, FALSE);
-                }
-                else if ((lppl->uOldState & LVIS_FOCUSED) && !(lppl->uNewState & LVIS_FOCUSED))
-                {
-                    /* kill focus */
-                    uResult = GetDlgItemInt(hwndDlg, 14002, &bSuccess, FALSE);
-                    if (bSuccess)
-                        pItem->dwMaxCapacity = uResult;
-                    if (SendDlgItemMessageW(hwndDlg, 14003, BM_GETCHECK, 0, 0) == BST_CHECKED)
-                        pItem->dwNukeOnDelete = TRUE;
-                    else
-                        pItem->dwNukeOnDelete = FALSE;
-                }
-                return TRUE;
-
-            }
-            break;
-        case WM_DESTROY:
-            FreeDriveItemContext(hwndDlg);
-            break;
-    }
-    return FALSE;
-}
-
-BOOL SH_ShowRecycleBinProperties(WCHAR sDrive)
-{
-    HPROPSHEETPAGE hpsp[1];
-    PROPSHEETHEADERW psh;
-    HPROPSHEETPAGE hprop;
-
-    BOOL ret;
-
-
-    ZeroMemory(&psh, sizeof(PROPSHEETHEADERW));
-    psh.dwSize = sizeof(PROPSHEETHEADERW);
-    psh.dwFlags = PSP_DEFAULT | PSH_PROPTITLE;
-    psh.pszCaption = MAKEINTRESOURCEW(IDS_RECYCLEBIN_FOLDER_NAME);
-    psh.hwndParent = NULL;
-    psh.phpage = hpsp;
-    psh.hInstance = shell32_hInstance;
-
-    hprop = SH_CreatePropertySheetPage(IDD_RECYCLE_BIN_PROPERTIES, RecycleBinDlg, (LPARAM)sDrive, NULL);
-    if (!hprop)
-    {
-        ERR("Failed to create property sheet\n");
-        return FALSE;
-    }
-    hpsp[psh.nPages] = hprop;
-    psh.nPages++;
-
-
-    ret = PropertySheetW(&psh);
-    if (ret < 0)
-        return FALSE;
-    else
-        return TRUE;
-}
-
+/**
+ * Tests whether a file can be trashed
+ * @param wszPath Path to the file to be trash
+ * @returns TRUE if the file can be trashed, FALSE otherwise
+ */
 BOOL
 TRASH_CanTrashFile(LPCWSTR wszPath)
 {
@@ -1246,7 +881,7 @@ TRASH_CanTrashFile(LPCWSTR wszPath)
     DWORD FileSystemFlags, dwSize, dwDisposition;
     HKEY hKey;
     WCHAR szBuffer[10];
-    WCHAR szKey[150] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Bitbucket\\Volume\\";
+    WCHAR szKey[150] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\BitBucket\\Volume\\";
 
     if (wszPath[1] != L':')
     {
@@ -1254,15 +889,21 @@ TRASH_CanTrashFile(LPCWSTR wszPath)
         return FALSE;
     }
 
-    if (GetDriveTypeW(wszPath) != DRIVE_FIXED)
+    // Copy and retrieve the root path from get given string
+    WCHAR wszRootPathName[MAX_PATH];
+    StringCbCopy(wszRootPathName, sizeof(wszRootPathName), wszPath);
+    PathStripToRootW(wszRootPathName);
+
+    // Test to see if the drive is fixed (non removable)
+    if (GetDriveTypeW(wszRootPathName) != DRIVE_FIXED)
     {
         /* no bitbucket on removable media */
         return FALSE;
     }
 
-    if (!GetVolumeInformationW(wszPath, NULL, 0, &VolSerialNumber, &MaxComponentLength, &FileSystemFlags, NULL, 0))
+    if (!GetVolumeInformationW(wszRootPathName, NULL, 0, &VolSerialNumber, &MaxComponentLength, &FileSystemFlags, NULL, 0))
     {
-        ERR("GetVolumeInformationW failed with %u\n", GetLastError());
+        ERR("GetVolumeInformationW failed with %u wszRootPathName=%s\n", GetLastError(), debugstr_w(wszRootPathName));
         return FALSE;
     }
 
@@ -1331,223 +972,197 @@ EXTERN_C HRESULT WINAPI SHUpdateRecycleBinIcon(void)
 {
     FIXME("stub\n");
 
-
-
     return S_OK;
 }
 
-/****************************************************************************
- * IDropTarget implementation
+/*************************************************************************
+ *              SHEmptyRecycleBinA (SHELL32.@)
  */
-BOOL CRecycleBin::QueryDrop(DWORD dwKeyState, LPDWORD pdwEffect)
+HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
 {
-    /* TODO on shift we should delete, we should update the cursor manager to show this. */
-
-    DWORD dwEffect = DROPEFFECT_COPY;
-
-    *pdwEffect = DROPEFFECT_NONE;
-
-    if (fAcceptFmt) { /* Does our interpretation of the keystate ... */
-        *pdwEffect = KeyStateToDropEffect (dwKeyState);
+    LPWSTR szRootPathW = NULL;
+    int len;
+    HRESULT hr;
 
-        if (*pdwEffect == DROPEFFECT_NONE)
-            *pdwEffect = dwEffect;
+    TRACE("%p, %s, 0x%08x\n", hwnd, debugstr_a(pszRootPath), dwFlags);
 
-        /* ... matches the desired effect ? */
-        if (dwEffect & *pdwEffect) {
-            return TRUE;
+    if (pszRootPath)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, NULL, 0);
+        if (len == 0)
+            return HRESULT_FROM_WIN32(GetLastError());
+        szRootPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!szRootPathW)
+            return E_OUTOFMEMORY;
+        if (MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, szRootPathW, len) == 0)
+        {
+            HeapFree(GetProcessHeap(), 0, szRootPathW);
+            return HRESULT_FROM_WIN32(GetLastError());
         }
     }
-    return FALSE;
-}
 
-HRESULT WINAPI CRecycleBin::DragEnter(IDataObject *pDataObject,
-                                    DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
-{
-    TRACE("Recycle bin drag over (%p)\n", this);
-    /* The recycle bin accepts pretty much everything, and sets a CSIDL flag. */
-    fAcceptFmt = TRUE;
+    hr = SHEmptyRecycleBinW(hwnd, szRootPathW, dwFlags);
+    HeapFree(GetProcessHeap(), 0, szRootPathW);
 
-    QueryDrop(dwKeyState, pdwEffect);
-    return S_OK;
+    return hr;
 }
 
-HRESULT WINAPI CRecycleBin::DragOver(DWORD dwKeyState, POINTL pt,
-                                   DWORD *pdwEffect)
+HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
 {
-    TRACE("(%p)\n", this);
-
-    if (!pdwEffect)
-        return E_INVALIDARG;
+    WCHAR szPath[MAX_PATH] = {0}, szBuffer[MAX_PATH];
+    DWORD dwSize, dwType, count;
+    LONG ret;
+    IShellFolder *pDesktop, *pRecycleBin;
+    PIDLIST_ABSOLUTE pidlRecycleBin;
+    PITEMID_CHILD pidl;
+    HRESULT hr = S_OK;
+    LPENUMIDLIST penumFiles;
+    STRRET StrRet;
 
-    QueryDrop(dwKeyState, pdwEffect);
+    TRACE("%p, %s, 0x%08x\n", hwnd, debugstr_w(pszRootPath), dwFlags);
 
-    return S_OK;
-}
+    if (!(dwFlags & SHERB_NOCONFIRMATION))
+    {
+        hr = SHGetDesktopFolder(&pDesktop);
+        if (FAILED(hr))
+            return hr;
+        hr = SHGetFolderLocation(NULL, CSIDL_BITBUCKET, NULL, 0, &pidlRecycleBin);
+        if (FAILED(hr))
+        {
+            pDesktop->Release();
+            return hr;
+        }
+        hr = pDesktop->BindToObject(pidlRecycleBin, NULL, IID_PPV_ARG(IShellFolder, &pRecycleBin));
+        CoTaskMemFree(pidlRecycleBin);
+        pDesktop->Release();
+        if (FAILED(hr))
+            return hr;
+        hr = pRecycleBin->EnumObjects(hwnd, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &penumFiles);
+        if (FAILED(hr))
+        {
+            pRecycleBin->Release();
+            return hr;
+        }
 
-HRESULT WINAPI CRecycleBin::DragLeave()
-{
-    TRACE("(%p)\n", this);
+        count = 0;
+        if (hr != S_FALSE)
+        {
+            while (penumFiles->Next(1, &pidl, NULL) == S_OK)
+            {
+                count++;
+                pRecycleBin->GetDisplayNameOf(pidl, SHGDN_NORMAL, &StrRet);
+                StrRetToBuf(&StrRet, pidl, szBuffer, _countof(szBuffer));
+                CoTaskMemFree(pidl);
+            }
+            penumFiles->Release();
+        }
+        pRecycleBin->Release();
 
-    fAcceptFmt = FALSE;
+        switch (count)
+        {
+            case 0:
+                /* no files, don't need confirmation */
+                break;
+
+            case 1:
+                /* we have only one item inside the bin, so show a message box with its name */
+                if (ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_DELETEITEM_TEXT), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET),
+                                   MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, szBuffer) == IDNO)
+                {
+                    return S_OK;
+                }
+                break;
 
-    return S_OK;
-}
+            default:
+                /* we have more than one item, so show a message box with the count of the items */
+                StringCbPrintfW(szBuffer, sizeof(szBuffer), L"%u", count);
+                if (ShellMessageBoxW(shell32_hInstance, hwnd, MAKEINTRESOURCEW(IDS_DELETEMULTIPLE_TEXT), MAKEINTRESOURCEW(IDS_EMPTY_BITBUCKET),
+                                   MB_ICONEXCLAMATION | MB_YESNO | MB_DEFBUTTON2, szBuffer) == IDNO)
+                {
+                    return S_OK;
+                }
+                break;
+        }
+    }
 
-HRESULT WINAPI CRecycleBin::Drop(IDataObject *pDataObject,
-                               DWORD dwKeyState, POINTL pt, DWORD *pdwEffect)
-{
-    TRACE("(%p) object dropped on recycle bin, effect %u\n", this, *pdwEffect);
-    
-    /* TODO: pdwEffect should be read and make the drop object be permanently deleted in the move case (shift held) */
-
-    FORMATETC fmt;
-    TRACE("(%p)->(DataObject=%p)\n", this, pDataObject);
-    InitFormatEtc (fmt, cfShellIDList, TYMED_HGLOBAL);
-
-    /* Handle cfShellIDList Drop objects here, otherwise send the approriate message to other software */
-    if (SUCCEEDED(pDataObject->QueryGetData(&fmt))) {
-        IStream *s;
-        CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pDataObject, &s);
-        SHCreateThread(DoDeleteThreadProc, s, NULL, NULL);
+    if (dwFlags & SHERB_NOPROGRESSUI)
+    {
+        ret = EmptyRecycleBinW(pszRootPath);
     }
     else
     {
-        /* 
-         * TODO call SetData on the data object with format CFSTR_TARGETCLSID
-         * set to the Recycle Bin's class identifier CLSID_RecycleBin.
-         */
+       /* FIXME
+        * show a progress dialog
+        */
+        ret = EmptyRecycleBinW(pszRootPath);
     }
-    return S_OK;
-}
 
-DWORD WINAPI DoDeleteThreadProc(LPVOID lpParameter) 
-{
-    CoInitialize(NULL);
-    CComPtr<IDataObject> pDataObject;
-    HRESULT hr = CoGetInterfaceAndReleaseStream (static_cast<IStream*>(lpParameter), IID_PPV_ARG(IDataObject, &pDataObject));
-    if (SUCCEEDED(hr))
+    if (!ret)
+        return HRESULT_FROM_WIN32(GetLastError());
+
+    if (!(dwFlags & SHERB_NOSOUND))
     {
-        DoDeleteDataObject(pDataObject);
+        dwSize = sizeof(szPath);
+        ret = RegGetValueW(HKEY_CURRENT_USER,
+                           L"AppEvents\\Schemes\\Apps\\Explorer\\EmptyRecycleBin\\.Current",
+                           NULL,
+                           RRF_RT_REG_SZ,
+                           &dwType,
+                           (PVOID)szPath,
+                           &dwSize);
+        if (ret != ERROR_SUCCESS)
+            return S_OK;
+
+        if (dwType != REG_EXPAND_SZ) /* type dismatch */
+            return S_OK;
+
+        szPath[_countof(szPath)-1] = L'\0';
+        PlaySoundW(szPath, NULL, SND_FILENAME);
     }
-    CoUninitialize();
-    return 0;
+    return S_OK;
 }
 
-HRESULT WINAPI DoDeleteDataObject(IDataObject *pda) 
+HRESULT WINAPI SHQueryRecycleBinA(LPCSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
 {
-    TRACE("performing delete");
+    LPWSTR szRootPathW = NULL;
+    int len;
     HRESULT hr;
 
-    STGMEDIUM medium;
-    FORMATETC formatetc;
-    InitFormatEtc(formatetc, RegisterClipboardFormatW(CFSTR_SHELLIDLIST), TYMED_HGLOBAL);
-    hr = pda->GetData(&formatetc, &medium);
-    if (FAILED(hr))
-        return hr;
+    TRACE("%s, %p\n", debugstr_a(pszRootPath), pSHQueryRBInfo);
 
-    /* lock the handle */
-    LPIDA lpcida = (LPIDA)GlobalLock(medium.hGlobal);
-    if (!lpcida)
-    {
-        ReleaseStgMedium(&medium);
-        return E_FAIL;
-    }
-
-    /* convert the data into pidl */
-    LPITEMIDLIST pidl;
-    LPITEMIDLIST *apidl = _ILCopyCidaToaPidl(&pidl, lpcida);
-    if (!apidl)
-    {
-        ReleaseStgMedium(&medium);
-        return E_FAIL;
-    }
-
-    CComPtr<IShellFolder> psfDesktop;
-    CComPtr<IShellFolder> psfFrom = NULL;
-
-    /* Grab the desktop shell folder */
-    hr = SHGetDesktopFolder(&psfDesktop);
-    if (FAILED(hr))
+    if (pszRootPath)
     {
-        ERR("SHGetDesktopFolder failed\n");
-        SHFree(pidl);
-        _ILFreeaPidl(apidl, lpcida->cidl);
-        ReleaseStgMedium(&medium);
-        return E_FAIL;
-    }
-
-    /* Find source folder, this is where the clipboard data was copied from */
-    if (_ILIsDesktop(pidl))
-    {
-        psfFrom = psfDesktop;
-    }
-    else 
-    {
-        hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
-        if (FAILED(hr))
+        len = MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, NULL, 0);
+        if (len == 0)
+            return HRESULT_FROM_WIN32(GetLastError());
+        szRootPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!szRootPathW)
+            return E_OUTOFMEMORY;
+        if (MultiByteToWideChar(CP_ACP, 0, pszRootPath, -1, szRootPathW, len) == 0)
         {
-            ERR("no IShellFolder\n");
-            SHFree(pidl);
-            _ILFreeaPidl(apidl, lpcida->cidl);
-            ReleaseStgMedium(&medium);
-            return E_FAIL;
+            HeapFree(GetProcessHeap(), 0, szRootPathW);
+            return HRESULT_FROM_WIN32(GetLastError());
         }
     }
 
-    STRRET strTemp;
-    hr = psfFrom->GetDisplayNameOf(apidl[0], SHGDN_FORPARSING, &strTemp);
-    if (FAILED(hr))
-    {
-        ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr);
-        SHFree(pidl);
-        _ILFreeaPidl(apidl, lpcida->cidl);
-        ReleaseStgMedium(&medium);
-        return hr;
-    }
+    hr = SHQueryRecycleBinW(szRootPathW, pSHQueryRBInfo);
+    HeapFree(GetProcessHeap(), 0, szRootPathW);
 
-    WCHAR wszPath[MAX_PATH];
-    hr = StrRetToBufW(&strTemp, apidl[0], wszPath, _countof(wszPath));
-    if (FAILED(hr))
-    {
-        ERR("StrRetToBufW failed with %x\n", hr);
-        SHFree(pidl);
-        _ILFreeaPidl(apidl, lpcida->cidl);
-        ReleaseStgMedium(&medium);
-        return hr;
-    }
-
-    /* Only keep the base path */
-    LPWSTR pwszFilename = PathFindFileNameW(wszPath);
-    *pwszFilename = L'\0';
-
-    /* Build paths list */
-    LPWSTR pwszPaths = BuildPathsList(wszPath, lpcida->cidl, (LPCITEMIDLIST*) apidl);
-    if (!pwszPaths)
-    {
-        SHFree(pidl);
-        _ILFreeaPidl(apidl, lpcida->cidl);
-        ReleaseStgMedium(&medium);
-        return E_FAIL;
-    }
+    return hr;
+}
 
-    /* Delete them */
-    SHFILEOPSTRUCTW FileOp;
-    ZeroMemory(&FileOp, sizeof(FileOp));
-    FileOp.wFunc = FO_DELETE;
-    FileOp.pFrom = pwszPaths;
-    FileOp.fFlags = FOF_ALLOWUNDO;
+HRESULT WINAPI SHQueryRecycleBinW(LPCWSTR pszRootPath, LPSHQUERYRBINFO pSHQueryRBInfo)
+{
+    FIXME("%s, %p - stub\n", debugstr_w(pszRootPath), pSHQueryRBInfo);
 
-    if (SHFileOperationW(&FileOp) != 0)
+    if (!(pszRootPath) || (pszRootPath[0] == 0) ||
+        !(pSHQueryRBInfo) || (pSHQueryRBInfo->cbSize < sizeof(SHQUERYRBINFO)))
     {
-        ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths));
-        hr = E_FAIL;
+        return E_INVALIDARG;
     }
 
-    HeapFree(GetProcessHeap(), 0, pwszPaths);
-    SHFree(pidl);
-    _ILFreeaPidl(apidl, lpcida->cidl);
-    ReleaseStgMedium(&medium);
+    pSHQueryRBInfo->i64Size = 0;
+    pSHQueryRBInfo->i64NumItems = 0;
 
-    return hr;
-}
\ No newline at end of file
+    return S_OK;
+}