[SHELL32] Fix for BuildPathsList, this solves some problems showing while copying...
[reactos.git] / reactos / dll / win32 / shell32 / folders / CRecycleBin.cpp
index ea9b007..480d3ce 100644 (file)
@@ -63,6 +63,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
 {
@@ -111,13 +124,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;
@@ -482,7 +488,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)
@@ -499,11 +505,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)
@@ -528,11 +564,7 @@ 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);
-        }
+        hr = CDefView_Constructor(this, riid, ppv);
     }
     else
         return hr;
@@ -552,7 +584,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,
@@ -573,21 +605,9 @@ HRESULT WINAPI CRecycleBin::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_C
         hr = QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
         pObj = pDt;
     }
-    else if(IsEqualIID(riid, IID_IExtractIconA) && (cidl == 1))
+    else if((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && (cidl == 1))
     {
-        // FIXME: This is not correct, it does not show the right icons
-        LPITEMIDLIST pidlItem = ILCombine(pidl, apidl[0]);
-        pObj = IExtractIconA_Constructor(pidlItem);
-        SHFree(pidlItem);
-        hr = S_OK;
-    }
-    else if (IsEqualIID(riid, IID_IExtractIconW) && (cidl == 1))
-    {
-        // FIXME: This is not correct, it does not show the right icons
-        LPITEMIDLIST pidlItem = ILCombine(pidl, apidl[0]);
-        pObj = IExtractIconW_Constructor(pidlItem);
-        SHFree(pidlItem);
-        hr = S_OK;
+        hr = CRecyclerExtractIcon_CreateInstance(apidl[0], riid, &pObj);
     }
     else
         hr = E_NOINTERFACE;
@@ -607,19 +627,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)
     {
@@ -667,8 +674,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;
 }
 
@@ -721,11 +730,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);
@@ -749,6 +754,7 @@ 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) &&
@@ -760,15 +766,12 @@ HRESULT WINAPI CRecycleBin::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, LPS
                 if (LoadStringW(shell32_hInstance, IDS_SHV_COLUMN1, &szTypeName[Length], (sizeof(szTypeName) / sizeof(WCHAR)) - Length))
                     szTypeName[(sizeof(szTypeName)/sizeof(WCHAR))-1] = L'\0';
             }
-            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)
@@ -781,6 +784,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
  */
@@ -799,7 +813,7 @@ HRESULT WINAPI CRecycleBin::QueryContextMenu(HMENU hMenu, UINT indexMenu, UINT i
     memset(&mii, 0, 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));
     mii.dwTypeData = szBuffer;
@@ -873,388 +887,6 @@ 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;
-}
-
 BOOL
 TRASH_CanTrashFile(LPCWSTR wszPath)
 {
@@ -1415,7 +1047,7 @@ 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;
@@ -1423,14 +1055,18 @@ HRESULT WINAPI CRecycleBin::Drop(IDataObject *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 (SUCCEEDED(pDataObject->QueryGetData(&fmt)))
+    {
+        DWORD fMask = 0;
+
+        if ((dwKeyState & MK_SHIFT) == MK_SHIFT)
+            fMask |= CMIC_MASK_SHIFT_DOWN;
+
+        DoDeleteAsync(pDataObject, fMask);
     }
     else
     {
-        /* 
+        /*
          * TODO call SetData on the data object with format CFSTR_TARGETCLSID
          * set to the Recycle Bin's class identifier CLSID_RecycleBin.
          */
@@ -1438,20 +1074,7 @@ HRESULT WINAPI CRecycleBin::Drop(IDataObject *pDataObject,
     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))
-    {
-        DoDeleteDataObject(pDataObject);
-    }
-    CoUninitialize();
-    return 0;
-}
-
-HRESULT WINAPI DoDeleteDataObject(IDataObject *pda) 
+HRESULT WINAPI DoDeleteDataObject(IDataObject *pda, DWORD fMask)
 {
     TRACE("performing delete");
     HRESULT hr;
@@ -1499,7 +1122,7 @@ HRESULT WINAPI DoDeleteDataObject(IDataObject *pda)
     {
         psfFrom = psfDesktop;
     }
-    else 
+    else
     {
         hr = psfDesktop->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, &psfFrom));
         if (FAILED(hr))
@@ -1539,7 +1162,7 @@ HRESULT WINAPI DoDeleteDataObject(IDataObject *pda)
     *pwszFilename = L'\0';
 
     /* Build paths list */
-    LPWSTR pwszPaths = BuildPathsList(wszPath, lpcida->cidl, (LPCITEMIDLIST*) apidl);
+    LPWSTR pwszPaths = BuildPathsList(wszPath, lpcida->cidl, (LPCITEMIDLIST*) apidl, FALSE);
     if (!pwszPaths)
     {
         SHFree(pidl);
@@ -1553,7 +1176,8 @@ HRESULT WINAPI DoDeleteDataObject(IDataObject *pda)
     ZeroMemory(&FileOp, sizeof(FileOp));
     FileOp.wFunc = FO_DELETE;
     FileOp.pFrom = pwszPaths;
-    FileOp.fFlags = FOF_ALLOWUNDO;
+    if ((fMask & CMIC_MASK_SHIFT_DOWN) == 0)
+        FileOp.fFlags = FOF_ALLOWUNDO;
 
     if (SHFileOperationW(&FileOp) != 0)
     {
@@ -1569,6 +1193,35 @@ HRESULT WINAPI DoDeleteDataObject(IDataObject *pda)
     return hr;
 }
 
+struct DeleteThreadData {
+    IStream *s;
+    DWORD fMask;
+};
+
+DWORD WINAPI DoDeleteThreadProc(LPVOID lpParameter)
+{
+    DeleteThreadData *data = static_cast<DeleteThreadData*>(lpParameter);
+    CoInitialize(NULL);
+    IDataObject *pDataObject;
+    HRESULT hr = CoGetInterfaceAndReleaseStream (data->s, IID_PPV_ARG(IDataObject, &pDataObject));
+    if (SUCCEEDED(hr))
+    {
+        DoDeleteDataObject(pDataObject, data->fMask);
+    }
+    pDataObject->Release();
+    CoUninitialize();
+    HeapFree(GetProcessHeap(), 0, data);
+    return 0;
+}
+
+void DoDeleteAsync(IDataObject *pda, DWORD fMask)
+{
+    DeleteThreadData *data = static_cast<DeleteThreadData*>(HeapAlloc(GetProcessHeap(), 0, sizeof(DeleteThreadData)));
+    data->fMask = fMask;
+    CoMarshalInterThreadInterfaceInStream(IID_IDataObject, pda, &data->s);
+    SHCreateThread(DoDeleteThreadProc, data, NULL, NULL);
+}
+
 /*************************************************************************
  *              SHEmptyRecycleBinA (SHELL32.@)
  */
@@ -1603,19 +1256,80 @@ HRESULT WINAPI SHEmptyRecycleBinA(HWND hwnd, LPCSTR pszRootPath, DWORD dwFlags)
 
 HRESULT WINAPI SHEmptyRecycleBinW(HWND hwnd, LPCWSTR pszRootPath, DWORD dwFlags)
 {
-    WCHAR szPath[MAX_PATH] = {0};
-    DWORD dwSize, dwType;
+    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;
 
     TRACE("%p, %s, 0x%08x\n", hwnd, debugstr_w(pszRootPath), dwFlags);
 
     if (!(dwFlags & SHERB_NOCONFIRMATION))
     {
-        /* FIXME
-         * enumerate available files
-         * show confirmation dialog
-         */
-        FIXME("show confirmation dialog\n");
+        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;
+        }
+
+        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();
+
+        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;
+
+            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;
+        }
     }
 
     if (dwFlags & SHERB_NOPROGRESSUI)