[SHELL32] Implement support for IID_IDropTarget in CDesktopFolder::GetUIObjectOf...
[reactos.git] / reactos / dll / win32 / shell32 / folders / CDrivesFolder.cpp
index e20d2e1..00c8107 100644 (file)
@@ -39,6 +39,132 @@ CDrivesFolderEnum is only responsible for returning the physical items.
 *   IShellFolder implementation
 */
 
+HRESULT CALLBACK DrivesContextMenuCallback(IShellFolder *psf,
+                                           HWND         hwnd,
+                                           IDataObject  *pdtobj,
+                                           UINT         uMsg,
+                                           WPARAM       wParam,
+                                           LPARAM       lParam)
+{
+    if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
+        return S_OK;
+
+    PIDLIST_ABSOLUTE pidlFolder;
+    PUITEMID_CHILD *apidl;
+    UINT cidl;
+    HRESULT hr = SH_GetApidlFromDataObject(pdtobj, &pidlFolder, &apidl, &cidl);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    char szDrive[8] = {0};
+    if (!_ILGetDrive(apidl[0], szDrive, sizeof(szDrive)))
+    {
+        ERR("pidl is not a drive\n");
+        SHFree(pidlFolder);
+        _ILFreeaPidl(apidl, cidl);
+        return E_FAIL;
+    }
+
+    if (uMsg == DFM_MERGECONTEXTMENU)
+    {
+        QCMINFO *pqcminfo = (QCMINFO *)lParam;
+        DWORD dwFlags;
+
+        if (GetVolumeInformationA(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0))
+        {
+            /* Disable format if read only */
+            if (!(dwFlags & FILE_READ_ONLY_VOLUME) && GetDriveTypeA(szDrive) != DRIVE_REMOTE)
+            {
+                _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+                _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, pqcminfo->idCmdFirst++, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
+            }
+        }
+    }
+    else if (uMsg == DFM_INVOKECOMMAND)
+    {
+        if (wParam == DFM_CMD_PROPERTIES)
+        {
+            WCHAR wszBuf[4];
+            wcscpy(wszBuf, L"A:\\");
+            wszBuf[0] = (WCHAR)szDrive[0];
+            if (!SH_ShowDriveProperties(wszBuf, pidlFolder, apidl))
+                hr = E_FAIL;
+        }
+        else
+        {
+            SHFormatDrive(hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
+        }
+    }
+
+    SHFree(pidlFolder);
+    _ILFreeaPidl(apidl, cidl);
+
+    return hr;
+}
+
+HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
+                                          HWND hwnd,
+                                          UINT cidl,
+                                          PCUITEMID_CHILD_ARRAY apidl,
+                                          IShellFolder *psf,
+                                          IContextMenu **ppcm)
+{
+    HKEY hKeys[2];
+    UINT cKeys = 0;
+    AddClassKeyToArray(L"Drive", hKeys, &cKeys);
+    AddClassKeyToArray(L"Folder", hKeys, &cKeys);
+
+    return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm);
+}
+
+HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
+{
+    CComPtr<IDefaultExtractIconInit> initIcon;
+    HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
+    WCHAR wTemp[MAX_PATH];
+    int icon_idx = -1;
+
+    if (pszDrive)
+    {
+        switch(GetDriveTypeA(pszDrive))
+        {
+            case DRIVE_REMOVABLE:
+                icon_idx = IDI_SHELL_3_14_FLOPPY;
+                break;
+            case DRIVE_CDROM:
+                icon_idx = IDI_SHELL_CDROM;
+                break;
+            case DRIVE_REMOTE:
+                icon_idx = IDI_SHELL_NETDRIVE;
+                break;
+            case DRIVE_RAMDISK:
+                icon_idx = IDI_SHELL_RAMDISK;
+                break;
+            case DRIVE_NO_ROOT_DIR:
+                icon_idx = IDI_SHELL_CDROM;
+                break;
+        }
+    }
+
+    if (icon_idx != -1)
+    {
+        initIcon->SetNormalIcon(swShell32Name, -icon_idx);
+    }
+    else
+    {
+        if (HCR_GetIconW(L"Drive", wTemp, NULL, MAX_PATH, &icon_idx))
+            initIcon->SetNormalIcon(wTemp, icon_idx);
+        else
+            initIcon->SetNormalIcon(swShell32Name, -IDI_SHELL_DRIVE);
+    }
+
+    return initIcon->QueryInterface(riid, ppvOut);
+}
+
 class CDrivesFolderEnum :
     public CEnumIDListBase
 {
@@ -58,14 +184,23 @@ class CDrivesFolderEnum :
 */
 
 static const shvheader MyComputerSFHeader[] = {
-    {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 15},
-    {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+    {IDS_SHV_COLUMN1, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
+    {IDS_SHV_COLUMN3, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
     {IDS_SHV_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
     {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
 };
 
 #define MYCOMPUTERSHELLVIEWCOLUMNS 4
 
+static const DWORD dwComputerAttributes =
+    SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
+    SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
+static const DWORD dwControlPanelAttributes =
+    SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
+static const DWORD dwDriveAttributes =
+    SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
+    SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
+
 CDrivesFolderEnum::CDrivesFolderEnum()
 {
 }
@@ -155,7 +290,6 @@ BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
 CDrivesFolder::CDrivesFolder()
 {
     pidlRoot = NULL;
-    sName = NULL;
 }
 
 CDrivesFolder::~CDrivesFolder()
@@ -166,27 +300,16 @@ CDrivesFolder::~CDrivesFolder()
 
 HRESULT WINAPI CDrivesFolder::FinalConstruct()
 {
-    DWORD dwSize;
-    WCHAR szName[MAX_PATH];
-    WCHAR wszMyCompKey[256];
-    INT i;
-
     pidlRoot = _ILCreateMyComputer();    /* my qualified pidl */
     if (pidlRoot == NULL)
         return E_OUTOFMEMORY;
 
-    i = swprintf(wszMyCompKey, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\");
-    StringFromGUID2(CLSID_MyComputer, wszMyCompKey + i, sizeof(wszMyCompKey) / sizeof(wszMyCompKey[0]) - i);
-    dwSize = sizeof(szName);
-    if (RegGetValueW(HKEY_CURRENT_USER, wszMyCompKey,
-                     NULL, RRF_RT_REG_SZ, NULL, szName, &dwSize) == ERROR_SUCCESS)
-    {
-        sName = (LPWSTR)SHAlloc((wcslen(szName) + 1) * sizeof(WCHAR));
-        if (sName)
-            wcscpy(sName, szName);
-        TRACE("sName %s\n", debugstr_w(sName));
-    }
-    return S_OK;
+    HRESULT hr = CRegFolder_CreateInstance(&CLSID_MyComputer, 
+                                           pidlRoot, 
+                                           L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", 
+                                           IID_PPV_ARG(IShellFolder2, &m_regFolder));
+
+    return hr;
 }
 
 /**************************************************************************
@@ -197,9 +320,7 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
 {
     HRESULT hr = E_INVALIDARG;
     LPCWSTR szNext = NULL;
-    WCHAR szElement[MAX_PATH];
     LPITEMIDLIST pidlTemp = NULL;
-    CLSID clsid;
 
     TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
           hwndOwner, pbc, lpszDisplayName, debugstr_w (lpszDisplayName),
@@ -211,20 +332,18 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
 
     /* handle CLSID paths */
     if (lpszDisplayName[0] == ':' && lpszDisplayName[1] == ':')
+        return m_regFolder->ParseDisplayName(hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
+
+    if (PathGetDriveNumberW(lpszDisplayName) < 0)
+        return E_INVALIDARG;
+
+    pidlTemp = _ILCreateDrive(lpszDisplayName);
+    if (!pidlTemp)
+        return E_OUTOFMEMORY;
+
+    if (lpszDisplayName[2] == L'\\')
     {
-        szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
-        TRACE ("-- element: %s\n", debugstr_w (szElement));
-        CLSIDFromString (szElement + 2, &clsid);
-        pidlTemp = _ILCreateGuid (PT_GUID, clsid);
-    }
-    /* do we have an absolute path name ? */
-    else if (PathGetDriveNumberW (lpszDisplayName) >= 0 &&
-             lpszDisplayName[2] == (WCHAR) '\\')
-    {
-        szNext = GetNextElementW (lpszDisplayName, szElement, MAX_PATH);
-        /* make drive letter uppercase to enable PIDL comparison */
-        szElement[0] = toupper(szElement[0]);
-        pidlTemp = _ILCreateDrive (szElement);
+        szNext = &lpszDisplayName[3];
     }
 
     if (szNext && *szNext)
@@ -234,10 +353,16 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
     }
     else
     {
-        if (pdwAttributes && *pdwAttributes)
-            SHELL32_GetItemAttributes (this,
-                                       pidlTemp, pdwAttributes);
         hr = S_OK;
+        if (pdwAttributes && *pdwAttributes)
+        {
+            if (_ILIsDrive(pidlTemp))
+                *pdwAttributes &= dwDriveAttributes;
+            else if (_ILIsSpecialFolder(pidlTemp))
+                m_regFolder->GetAttributesOf(1, &pidlTemp, pdwAttributes);
+            else
+                ERR("Got an unkown pidl here!\n");
+        }
     }
 
     *ppidl = pidlTemp;
@@ -263,7 +388,34 @@ HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcRese
     TRACE("(%p)->(pidl=%p,%p,%s,%p)\n", this,
           pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
 
-    return SHELL32_BindToChild(pidlRoot, NULL, pidl, riid, ppvOut);
+    if (_ILIsSpecialFolder(pidl))
+        return m_regFolder->BindToObject(pidl, pbcReserved, riid, ppvOut);
+
+    LPITEMIDLIST pidlChild = ILCloneFirst (pidl);
+    if (!pidlChild)
+        return E_OUTOFMEMORY;
+
+    CComPtr<IShellFolder> psf;
+    HRESULT hr = SHELL32_CoCreateInitSF(pidlRoot, 
+                                        NULL, 
+                                        pidlChild, 
+                                        &CLSID_ShellFSFolder, 
+                                        -1, 
+                                        IID_PPV_ARG(IShellFolder, &psf));
+
+    ILFree(pidlChild);
+
+    if (FAILED(hr))
+        return hr;
+
+    if (_ILIsPidlSimple (pidl))
+    {
+        return psf->QueryInterface(riid, ppvOut);
+    }
+    else
+    {
+        return psf->BindToObject(ILGetNext (pidl), pbcReserved, riid, ppvOut);
+    }
 }
 
 /**************************************************************************
@@ -284,12 +436,69 @@ HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcRes
 
 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
 {
-    int nReturn;
+    HRESULT hres;
+
+    if (!pidl1 || !pidl2)
+    {
+        ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
+        return E_INVALIDARG;
+    }
+
+    if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
+        return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
+
+    if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || LOWORD(lParam) >= MYCOMPUTERSHELLVIEWCOLUMNS)
+        return E_INVALIDARG;
+
+    CHAR* pszDrive1 = _ILGetDataPointer(pidl1)->u.drive.szDriveName;
+    CHAR* pszDrive2 = _ILGetDataPointer(pidl2)->u.drive.szDriveName;
 
-    TRACE("(%p)->(0x%08lx,pidl1=%p,pidl2=%p)\n", this, lParam, pidl1, pidl2);
-    nReturn = SHELL32_CompareIDs (this, lParam, pidl1, pidl2);
-    TRACE("-- %i\n", nReturn);
-    return nReturn;
+    int result;
+    switch(LOWORD(lParam)) 
+    {
+        case 0:        /* name */
+        {
+            result = stricmp(pszDrive1, pszDrive2);
+            hres = MAKE_COMPARE_HRESULT(result);
+            break;
+        }
+        case 1:        /* Type */
+        {
+            /* We want to return immediately because SHELL32_CompareDetails also compares children. */
+            return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
+        }
+        case 2:       /* Size */
+        case 3:       /* Size Available */
+        {
+            ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
+
+            if (GetVolumeInformationA(pszDrive1, NULL, 0, NULL, NULL, NULL, NULL, 0))
+                GetDiskFreeSpaceExA(pszDrive1, &Drive1Available, &Drive1Total, NULL);
+            else
+                Drive1Available.QuadPart = Drive1Total.QuadPart = 0;
+
+            if (GetVolumeInformationA(pszDrive2, NULL, 0, NULL, NULL, NULL, NULL, 0))
+                GetDiskFreeSpaceExA(pszDrive2, &Drive2Available, &Drive2Total, NULL);
+            else
+                Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
+
+            LARGE_INTEGER Diff;
+            if (lParam == 2) /* Size */
+                Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
+            else /* Size available */
+                Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
+
+            hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
+            break;
+        }
+        default:
+            return E_INVALIDARG;
+    }
+
+    if (HRESULT_CODE(hres) == 0)
+        return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
+
+    return hres;
 }
 
 /**************************************************************************
@@ -320,11 +529,7 @@ HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVO
     }
     else if (IsEqualIID(riid, IID_IShellView))
     {
-        hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
-        if (pShellView)
-        {
-            hr = pShellView->QueryInterface(riid, ppvOut);
-        }
+        hr = CDefView_Constructor(this, riid, ppvOut);
     }
     TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
     return hr;
@@ -346,15 +551,6 @@ static BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
 */
 HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, DWORD * rgfInOut)
 {
-    static const DWORD dwComputerAttributes =
-        SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
-        SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER | SFGAO_CANLINK;
-    static const DWORD dwControlPanelAttributes =
-        SFGAO_HASSUBFOLDER | SFGAO_FOLDER | SFGAO_CANLINK;
-    static const DWORD dwDriveAttributes =
-        SFGAO_HASSUBFOLDER | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_FILESYSANCESTOR |
-        SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_CANRENAME | SFGAO_CANLINK;
-
     TRACE ("(%p)->(cidl=%d apidl=%p mask=%p (0x%08x))\n",
            this, cidl, apidl, rgfInOut, rgfInOut ? *rgfInOut : 0);
 
@@ -375,11 +571,10 @@ HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY a
                 *rgfInOut &= dwDriveAttributes;
             else if (_ILIsControlPanel(apidl[i]))
                 *rgfInOut &= dwControlPanelAttributes;
+            else if (_ILIsSpecialFolder(*apidl))
+                m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
             else
-            {
-                pdump(apidl[i]);
-                SHELL32_GetItemAttributes(this, apidl[i], rgfInOut);
-            }
+                ERR("Got unknown pidl type!\n");
         }
     }
 
@@ -406,8 +601,7 @@ HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
     UINT cidl, PCUITEMID_CHILD_ARRAY apidl,
     REFIID riid, UINT *prgfInOut, LPVOID *ppvOut)
 {
-    LPITEMIDLIST pidl;
-    IUnknown *pObj = NULL;
+    LPVOID pObj = NULL;
     HRESULT hr = E_INVALIDARG;
 
     TRACE("(%p)->(%p,%u,apidl=%p,%s,%p,%p)\n", this,
@@ -420,39 +614,31 @@ HRESULT WINAPI CDrivesFolder::GetUIObjectOf(HWND hwndOwner,
 
     if (IsEqualIID (riid, IID_IContextMenu) && (cidl >= 1))
     {
-        hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, (IShellFolder*)this, NULL, 0, NULL, (IContextMenu**)&pObj);
+        if (_ILIsDrive(apidl[0]))
+            hr = CDrivesContextMenu_CreateInstance(pidlRoot, hwndOwner, cidl, apidl, static_cast<IShellFolder*>(this), (IContextMenu**)&pObj);
+        else
+            hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
     }
     else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))
     {
         hr = IDataObject_Constructor (hwndOwner,
                                       pidlRoot, apidl, cidl, (IDataObject **)&pObj);
     }
-    else if (IsEqualIID (riid, IID_IExtractIconA) && (cidl == 1))
+    else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (cidl == 1))
     {
-        pidl = ILCombine (pidlRoot, apidl[0]);
-        pObj = IExtractIconA_Constructor (pidl);
-        SHFree (pidl);
-        hr = S_OK;
-    }
-    else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
-    {
-        pidl = ILCombine (pidlRoot, apidl[0]);
-        pObj = IExtractIconW_Constructor (pidl);
-        SHFree (pidl);
-        hr = S_OK;
-    }
-    else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
-    {
-        IDropTarget * pDt = NULL;
-        hr = this->QueryInterface(IID_PPV_ARG(IDropTarget, &pDt));
-        pObj = pDt;
+        if (_ILIsDrive(apidl[0]))
+            hr = CDrivesExtractIcon_CreateInstance(this, apidl[0], riid, &pObj);
+        else
+            hr = m_regFolder->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, &pObj);
     }
-    else if ((IsEqualIID(riid, IID_IShellLinkW) ||
-              IsEqualIID(riid, IID_IShellLinkA)) && (cidl == 1))
+    else if (IsEqualIID (riid, IID_IDropTarget) && (cidl == 1))
     {
-        pidl = ILCombine (pidlRoot, apidl[0]);
-        hr = IShellLink_ConstructFromFile(NULL, riid, pidl, (LPVOID*) &pObj);
-        SHFree (pidl);
+        CComPtr<IShellFolder> psfChild;
+        hr = this->BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfChild));
+        if (FAILED_UNEXPECTEDLY(hr))
+            return hr;
+
+        return psfChild->CreateViewObject(NULL, riid, ppvOut);
     }
     else
         hr = E_NOINTERFACE;
@@ -479,165 +665,71 @@ HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFla
     if (!strRet)
         return E_INVALIDARG;
 
+    if (!_ILIsPidlSimple (pidl))
+    {
+        return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
+    }
+    else if (_ILIsSpecialFolder(pidl))
+    {
+        return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
+    }
+    else if (!_ILIsDrive(pidl))
+    {
+        ERR("Wrong pidl type\n");
+        return E_INVALIDARG;
+    }
+
     pszPath = (LPWSTR)CoTaskMemAlloc((MAX_PATH + 1) * sizeof(WCHAR));
     if (!pszPath)
         return E_OUTOFMEMORY;
 
     pszPath[0] = 0;
 
-    if (!pidl->mkid.cb)
+    _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);    /* append my own path */
+    /* long view "lw_name (C:)" */
+    if (!(dwFlags & SHGDN_FORPARSING))
     {
-        /* parsing name like ::{...} */
-        pszPath[0] = ':';
-        pszPath[1] = ':';
-        SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
-    }
-    else if (_ILIsPidlSimple(pidl))
-    {
-        /* take names of special folders only if its only this folder */
-        if (_ILIsSpecialFolder(pidl))
+        WCHAR wszDrive[18] = {0};
+        DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
+        static const WCHAR wszOpenBracket[] = {' ', '(', 0};
+        static const WCHAR wszCloseBracket[] = {')', 0};
+
+        lstrcpynW(wszDrive, pszPath, 4);
+        pszPath[0] = L'\0';
+        GetVolumeInformationW(wszDrive, pszPath,
+                                MAX_PATH - 7,
+                                &dwVolumeSerialNumber,
+                                &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
+        pszPath[MAX_PATH-1] = L'\0';
+        if (!wcslen(pszPath))
         {
-            GUID const *clsid;
-
-            clsid = _ILGetGUIDPointer (pidl);
-            if (clsid)
+            UINT DriveType, ResourceId;
+            DriveType = GetDriveTypeW(wszDrive);
+            switch(DriveType)
             {
-                if (GET_SHGDN_FOR (dwFlags) == SHGDN_FORPARSING)
-                {
-                    static const WCHAR clsidW[] = L"CLSID\\";
-                    static const WCHAR shellfolderW[] = L"\\shellfolder";
-                    static const WCHAR wantsForParsingW[] = L"WantsForParsing";
-                    BOOL bWantsForParsing = FALSE;
-                    WCHAR szRegPath[100];
-                    LONG r;
-
-                    /*
-                     * We can only get a filesystem path from a shellfolder
-                     * if the value WantsFORPARSING exists in
-                     *      CLSID\\{...}\\shellfolder
-                     * exception: the MyComputer folder has this keys not
-                     *            but like any filesystem backed
-                     *            folder it needs these behaviour
-                     *
-                     * Get the "WantsFORPARSING" flag from the registry
-                     */
-
-                    wcscpy(szRegPath, clsidW);
-                    SHELL32_GUIDToStringW(*clsid, &szRegPath[6]);
-                    wcscat(szRegPath, shellfolderW);
-                    r = SHGetValueW(HKEY_CLASSES_ROOT, szRegPath,
-                                    wantsForParsingW, NULL, NULL, NULL);
-                    if (r == ERROR_SUCCESS)
-                        bWantsForParsing = TRUE;
-
-                    if ((GET_SHGDN_RELATION (dwFlags) == SHGDN_NORMAL) &&
-                            bWantsForParsing)
-                    {
-                        /*
-                         * We need the filesystem path to the destination folder
-                         * Only the folder itself can know it
-                         */
-                        hr = SHELL32_GetDisplayNameOfChild (this, pidl,
-                                                            dwFlags, pszPath, MAX_PATH);
-                    }
-                    else
-                    {
-                        LPWSTR p = pszPath;
-
-                        /* parsing name like ::{...} */
-                        p[0] = ':';
-                        p[1] = ':';
-                        p += 2;
-                        p += SHELL32_GUIDToStringW(CLSID_MyComputer, p);
-
-                        /* \:: */
-                        p[0] = '\\';
-                        p[1] = ':';
-                        p[2] = ':';
-                        p += 3;
-                        SHELL32_GUIDToStringW(*clsid, p);
-                    }
-                }
-                else
-                {
-                    /* user friendly name */
-
-                    if (_ILIsMyComputer(pidl) && sName)
-                        wcscpy(pszPath, sName);
-                    else
-                        HCR_GetClassNameW (*clsid, pszPath, MAX_PATH);
-
-                    TRACE("pszPath %s\n", debugstr_w(pszPath));
-                }
+                case DRIVE_FIXED:
+                    ResourceId = IDS_DRIVE_FIXED;
+                    break;
+                case DRIVE_REMOTE:
+                    ResourceId = IDS_DRIVE_NETWORK;
+                    break;
+                case DRIVE_CDROM:
+                    ResourceId = IDS_DRIVE_CDROM;
+                    break;
+                default:
+                    ResourceId = 0;
             }
-            else
+            if (ResourceId)
             {
-                /* append my own path */
-                _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
+                dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
+                if (dwFileSystemFlags > MAX_PATH - 7)
+                    pszPath[MAX_PATH-7] = L'\0';
             }
         }
-        else if (_ILIsDrive(pidl))
-        {
-
-            _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);    /* append my own path */
-            /* long view "lw_name (C:)" */
-            if (!(dwFlags & SHGDN_FORPARSING))
-            {
-                WCHAR wszDrive[18] = {0};
-                DWORD dwVolumeSerialNumber, dwMaximumComponentLength, dwFileSystemFlags;
-                static const WCHAR wszOpenBracket[] = {' ', '(', 0};
-                static const WCHAR wszCloseBracket[] = {')', 0};
-
-                lstrcpynW(wszDrive, pszPath, 4);
-                pszPath[0] = L'\0';
-                GetVolumeInformationW(wszDrive, pszPath,
-                                      MAX_PATH - 7,
-                                      &dwVolumeSerialNumber,
-                                      &dwMaximumComponentLength, &dwFileSystemFlags, NULL, 0);
-                pszPath[MAX_PATH-1] = L'\0';
-                if (!wcslen(pszPath))
-                {
-                    UINT DriveType, ResourceId;
-                    DriveType = GetDriveTypeW(wszDrive);
-                    switch(DriveType)
-                    {
-                        case DRIVE_FIXED:
-                            ResourceId = IDS_DRIVE_FIXED;
-                            break;
-                        case DRIVE_REMOTE:
-                            ResourceId = IDS_DRIVE_NETWORK;
-                            break;
-                        case DRIVE_CDROM:
-                            ResourceId = IDS_DRIVE_CDROM;
-                            break;
-                        default:
-                            ResourceId = 0;
-                    }
-                    if (ResourceId)
-                    {
-                        dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
-                        if (dwFileSystemFlags > MAX_PATH - 7)
-                            pszPath[MAX_PATH-7] = L'\0';
-                    }
-                }
-                wcscat (pszPath, wszOpenBracket);
-                wszDrive[2] = L'\0';
-                wcscat (pszPath, wszDrive);
-                wcscat (pszPath, wszCloseBracket);
-            }
-        }
-        else
-        {
-            /* Neither a shell namespace extension nor a drive letter. */
-            ERR("Wrong pidl type\n");
-            CoTaskMemFree(pszPath);
-            return E_INVALIDARG;
-        }
-    }
-    else
-    {
-        /* Complex pidl. Let the child folder do the work */
-        hr = SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, pszPath, MAX_PATH);
+        wcscat (pszPath, wszOpenBracket);
+        wszDrive[2] = L'\0';
+        wcscat (pszPath, wszDrive);
+        wcscat (pszPath, wszCloseBracket);
     }
 
     if (SUCCEEDED(hr))
@@ -667,14 +759,8 @@ HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFla
 HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
                                         LPCOLESTR lpName, DWORD dwFlags, PITEMID_CHILD *pPidlOut)
 {
-    LPWSTR sName;
-    HKEY hKey;
-    UINT length;
     WCHAR szName[30];
 
-    TRACE("(%p)->(%p,pidl=%p,%s,%u,%p)\n", this,
-          hwndOwner, pidl, debugstr_w (lpName), dwFlags, pPidlOut);
-
     if (_ILIsDrive(pidl))
     {
         if (_ILSimpleGetTextW(pidl, szName, _countof(szName)))
@@ -684,35 +770,7 @@ HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
         return S_OK;
     }
 
-
-    if (pPidlOut != NULL)
-        *pPidlOut = _ILCreateMyComputer();
-
-    length = (wcslen(lpName) + 1) * sizeof(WCHAR);
-    sName = (LPWSTR)SHAlloc(length);
-
-    if (!sName)
-        return E_OUTOFMEMORY;
-
-    if (RegOpenKeyExW(HKEY_CURRENT_USER,
-                      L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}",
-                      0,
-                      KEY_WRITE,
-                      &hKey) != ERROR_SUCCESS)
-    {
-        WARN("Error: failed to open registry key\n");
-    }
-    else
-    {
-        RegSetValueExW(hKey, NULL, 0, REG_SZ, (const LPBYTE)lpName, length);
-        RegCloseKey(hKey);
-    }
-
-    wcscpy(sName, lpName);
-    SHFree(this->sName);
-    this->sName = sName;
-    TRACE("result %s\n", debugstr_w(sName));
-    return S_OK;
+    return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
 }
 
 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
@@ -754,7 +812,6 @@ HRESULT WINAPI CDrivesFolder::GetDetailsEx(PCUITEMID_CHILD pidl, const SHCOLUMNI
     return E_NOTIMPL;
 }
 
-/* FIXME: drive size >4GB is rolling over */
 HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, SHELLDETAILS *psd)
 {
     HRESULT hr;
@@ -768,10 +825,11 @@ HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, S
     {
         psd->fmt = MyComputerSFHeader[iColumn].fmt;
         psd->cxChar = MyComputerSFHeader[iColumn].cxChar;
-        psd->str.uType = STRRET_CSTR;
-        LoadStringA(shell32_hInstance, MyComputerSFHeader[iColumn].colnameid,
-                    psd->str.cStr, MAX_PATH);
-        return S_OK;
+        return SHSetStrRet(&psd->str, MyComputerSFHeader[iColumn].colnameid);
+    }
+    else if (_ILIsSpecialFolder(pidl))
+    {
+        return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
     }
     else
     {
@@ -783,26 +841,25 @@ HRESULT WINAPI CDrivesFolder::GetDetailsOf(PCUITEMID_CHILD pidl, UINT iColumn, S
         switch (iColumn)
         {
             case 0:        /* name */
-                hr = GetDisplayNameOf(pidl,
-                                      SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
+                hr = GetDisplayNameOf(pidl, SHGDN_NORMAL | SHGDN_INFOLDER, &psd->str);
                 break;
             case 1:        /* type */
                 _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
                 break;
             case 2:        /* total size */
-                if (_ILIsDrive(pidl))
+                _ILSimpleGetText (pidl, szPath, MAX_PATH);
+                if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
                 {
-                    _ILSimpleGetText (pidl, szPath, MAX_PATH);
-                    GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
-                    StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
+                    GetDiskFreeSpaceExA(szPath, NULL, &ulBytes, NULL);
+                    StrFormatByteSize64A(ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
                 }
                 break;
             case 3:        /* free size */
-                if (_ILIsDrive(pidl))
+                _ILSimpleGetText (pidl, szPath, MAX_PATH);
+                if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
                 {
-                    _ILSimpleGetText (pidl, szPath, MAX_PATH);
-                    GetDiskFreeSpaceExA (szPath, &ulBytes, NULL, NULL);
-                    StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
+                    GetDiskFreeSpaceExA(szPath, &ulBytes, NULL, NULL);
+                    StrFormatByteSize64A(ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
                 }
                 break;
         }
@@ -839,12 +896,6 @@ HRESULT WINAPI CDrivesFolder::GetClassID(CLSID *lpClassId)
  */
 HRESULT WINAPI CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
 {
-    TRACE ("(%p)->(%p)\n", this, pidl);
-
-    if (pidlRoot)
-        SHFree((LPVOID)pidlRoot);
-
-    pidlRoot = ILClone(pidl);
     return S_OK;
 }
 
@@ -856,7 +907,7 @@ HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
     TRACE("(%p)->(%p)\n", this, pidl);
 
     if (!pidl)
-        return E_POINTER;
+        return E_INVALIDARG; /* xp doesn't have this check and crashes on NULL */
 
     *pidl = ILClone(pidlRoot);
     return S_OK;