[SHELL] IPersistFolder2::GetCurFolder takes a PIDLIST_ABSOLUTE*. CORE-16385
[reactos.git] / dll / win32 / shell32 / folders / CDrivesFolder.cpp
index c7b945c..0f8810c 100644 (file)
@@ -4,6 +4,7 @@
  *    Copyright 1997                Marcus Meissner
  *    Copyright 1998, 1999, 2002    Juergen Schmied
  *    Copyright 2009                Andrew Hill
+ *    Copyright 2017-2018           Katayama Hirofumi MZ
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -35,127 +36,404 @@ CDrivesFolderEnum is only responsible for returning the physical items.
 3. The parsing name returned for my computer is incorrect. It should be "My Computer"
 */
 
+static int iDriveIconIds[7] = { IDI_SHELL_DRIVE,       /* DRIVE_UNKNOWN */
+                                IDI_SHELL_CDROM,       /* DRIVE_NO_ROOT_DIR*/
+                                IDI_SHELL_3_14_FLOPPY, /* DRIVE_REMOVABLE*/
+                                IDI_SHELL_DRIVE,       /* DRIVE_FIXED*/
+                                IDI_SHELL_NETDRIVE,    /* DRIVE_REMOTE*/
+                                IDI_SHELL_CDROM,       /* DRIVE_CDROM*/
+                                IDI_SHELL_RAMDISK      /* DRIVE_RAMDISK*/
+                                };
+
+static int iDriveTypeIds[7] = { IDS_DRIVE_FIXED,       /* DRIVE_UNKNOWN */
+                                IDS_DRIVE_FIXED,       /* DRIVE_NO_ROOT_DIR*/
+                                IDS_DRIVE_FLOPPY,      /* DRIVE_REMOVABLE*/
+                                IDS_DRIVE_FIXED,       /* DRIVE_FIXED*/
+                                IDS_DRIVE_NETWORK,     /* DRIVE_REMOTE*/
+                                IDS_DRIVE_CDROM,       /* DRIVE_CDROM*/
+                                IDS_DRIVE_FIXED        /* DRIVE_RAMDISK*/
+                                };
+
 /***********************************************************************
 *   IShellFolder implementation
 */
 
-class CDrivesFolderEnum :
-    public CEnumIDListBase
+#define RETRY_COUNT 3
+#define RETRY_SLEEP 250
+static BOOL TryToLockOrUnlockDrive(HANDLE hDrive, BOOL bLock)
 {
-    public:
-        CDrivesFolderEnum();
-        ~CDrivesFolderEnum();
-        HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags);
-        BOOL CreateMyCompEnumList(DWORD dwFlags);
+    DWORD dwError, dwBytesReturned;
+    DWORD dwCode = (bLock ? FSCTL_LOCK_VOLUME : FSCTL_UNLOCK_VOLUME);
+    for (DWORD i = 0; i < RETRY_COUNT; ++i)
+    {
+        if (DeviceIoControl(hDrive, dwCode, NULL, 0, NULL, 0, &dwBytesReturned, NULL))
+            return TRUE;
 
-        BEGIN_COM_MAP(CDrivesFolderEnum)
-        COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
-        END_COM_MAP()
-};
+        dwError = GetLastError();
+        if (dwError == ERROR_INVALID_FUNCTION)
+            break; /* don't sleep if function is not implemented */
 
-/***********************************************************************
-*   IShellFolder [MyComputer] implementation
-*/
+        Sleep(RETRY_SLEEP);
+    }
+    SetLastError(dwError);
+    return FALSE;
+}
 
-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_COLUMN6, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
-    {IDS_SHV_COLUMN7, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
-};
+// NOTE: See also https://support.microsoft.com/en-us/help/165721/how-to-ejecting-removable-media-in-windows-nt-windows-2000-windows-xp
+static BOOL DoEjectDrive(const WCHAR *physical, UINT nDriveType, INT *pnStringID)
+{
+    /* GENERIC_WRITE isn't needed for umount */
+    DWORD dwAccessMode = GENERIC_READ;
+    DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+
+    HANDLE hDrive = CreateFile(physical, dwAccessMode, dwShareMode, 0, OPEN_EXISTING, 0, NULL);
+    if (hDrive == INVALID_HANDLE_VALUE)
+        return FALSE;
+
+    BOOL bResult, bNeedUnlock = FALSE;
+    DWORD dwBytesReturned, dwError = NO_ERROR;
+    PREVENT_MEDIA_REMOVAL removal;
+    do
+    {
+        bResult = TryToLockOrUnlockDrive(hDrive, TRUE);
+        if (!bResult)
+        {
+            dwError = GetLastError();
+            *pnStringID = IDS_CANTLOCKVOLUME; /* Unable to lock volume */
+            break;
+        }
+        bResult = DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
+        if (!bResult)
+        {
+            dwError = GetLastError();
+            *pnStringID = IDS_CANTDISMOUNTVOLUME; /* Unable to dismount volume */
+            bNeedUnlock = TRUE;
+            break;
+        }
+        removal.PreventMediaRemoval = FALSE;
+        bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_MEDIA_REMOVAL, &removal, sizeof(removal), NULL,
+                                  0, &dwBytesReturned, NULL);
+        if (!bResult)
+        {
+            *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */
+            dwError = GetLastError();
+            bNeedUnlock = TRUE;
+            break;
+        }
+        bResult = DeviceIoControl(hDrive, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &dwBytesReturned, NULL);
+        if (!bResult)
+        {
+            *pnStringID = IDS_CANTEJECTMEDIA; /* Unable to eject media */
+            dwError = GetLastError();
+            bNeedUnlock = TRUE;
+            break;
+        }
+    } while (0);
 
-#define MYCOMPUTERSHELLVIEWCOLUMNS 4
+    if (bNeedUnlock)
+    {
+        TryToLockOrUnlockDrive(hDrive, FALSE);
+    }
+
+    CloseHandle(hDrive);
+
+    SetLastError(dwError);
+    return bResult;
+}
 
-CDrivesFolderEnum::CDrivesFolderEnum()
+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;
+    UINT nDriveType;
+    DWORD dwFlags;
+    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;
+    }
+    nDriveType = GetDriveTypeA(szDrive);
+    GetVolumeInformationA(szDrive, NULL, 0, NULL, NULL, &dwFlags, NULL, 0);
+
+// custom command IDs
+#define CMDID_FORMAT        1
+#define CMDID_EJECT         2
+#define CMDID_DISCONNECT    3
+
+    if (uMsg == DFM_MERGECONTEXTMENU)
+    {
+        QCMINFO *pqcminfo = (QCMINFO *)lParam;
+
+        UINT idCmdFirst = pqcminfo->idCmdFirst;
+        if (!(dwFlags & FILE_READ_ONLY_VOLUME) && nDriveType != DRIVE_REMOTE)
+        {
+            /* add separator and Format */
+            UINT idCmd = idCmdFirst + CMDID_FORMAT;
+            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_FORMATDRIVE), MFS_ENABLED);
+        }
+        if (nDriveType == DRIVE_REMOVABLE || nDriveType == DRIVE_CDROM)
+        {
+            /* add separator and Eject */
+            UINT idCmd = idCmdFirst + CMDID_EJECT;
+            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_EJECT), MFS_ENABLED);
+        }
+        if (nDriveType == DRIVE_REMOTE)
+        {
+            /* add separator and Disconnect */
+            UINT idCmd = idCmdFirst + CMDID_DISCONNECT;
+            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, 0, MFT_SEPARATOR, NULL, 0);
+            _InsertMenuItemW(pqcminfo->hmenu, pqcminfo->indexMenu++, TRUE, idCmd, MFT_STRING, MAKEINTRESOURCEW(IDS_DISCONNECT), MFS_ENABLED);
+        }
+
+        pqcminfo->idCmdFirst += 3;
+    }
+    else if (uMsg == DFM_INVOKECOMMAND)
+    {
+        WCHAR wszBuf[4] = L"A:\\";
+        wszBuf[0] = (WCHAR)szDrive[0];
+
+        INT nStringID = 0;
+        DWORD dwError = NO_ERROR;
+
+        if (wParam == DFM_CMD_PROPERTIES)
+        {
+            hr = SH_ShowDriveProperties(wszBuf, pidlFolder, apidl);
+            if (FAILED(hr))
+            {
+                dwError = ERROR_CAN_NOT_COMPLETE;
+                nStringID = IDS_CANTSHOWPROPERTIES;
+            }
+        }
+        else
+        {
+            if (wParam == CMDID_FORMAT)
+            {
+                /* do format */
+                DWORD dwRet = SHFormatDrive(hwnd, szDrive[0] - 'A', SHFMT_ID_DEFAULT, 0);
+                switch (dwRet)
+                {
+                case SHFMT_ERROR: case SHFMT_CANCEL: case SHFMT_NOFORMAT:
+                    hr = E_FAIL;
+                    break;
+                }
+            }
+            else if (wParam == CMDID_EJECT)
+            {
+                /* do eject */
+                WCHAR physical[10];
+                wsprintfW(physical, _T("\\\\.\\%c:"), szDrive[0]);
+
+                if (DoEjectDrive(physical, nDriveType, &nStringID))
+                {
+                    SHChangeNotify(SHCNE_MEDIAREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL);
+                }
+                else
+                {
+                    dwError = GetLastError();
+                }
+            }
+            else if (wParam == CMDID_DISCONNECT)
+            {
+                /* do disconnect */
+                wszBuf[2] = UNICODE_NULL;
+                dwError = WNetCancelConnection2W(wszBuf, 0, FALSE);
+                if (dwError == NO_ERROR)
+                {
+                    SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATHW | SHCNF_FLUSHNOWAIT, wszBuf, NULL);
+                }
+                else
+                {
+                    nStringID = IDS_CANTDISCONNECT;
+                }
+            }
+        }
+
+        if (nStringID != 0)
+        {
+            /* show error message */
+            WCHAR szFormat[128], szMessage[128];
+            LoadStringW(shell32_hInstance, nStringID, szFormat, _countof(szFormat));
+            wsprintfW(szMessage, szFormat, dwError);
+            MessageBoxW(hwnd, szMessage, NULL, MB_ICONERROR);
+        }
+    }
+
+    SHFree(pidlFolder);
+    _ILFreeaPidl(apidl, cidl);
+
+    return hr;
 }
 
-CDrivesFolderEnum::~CDrivesFolderEnum()
+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 WINAPI CDrivesFolderEnum::Initialize(HWND hwndOwner, DWORD dwFlags)
+static HRESULT
+getIconLocationForDrive(IShellFolder *psf, PCITEMID_CHILD pidl, UINT uFlags,
+                        LPWSTR szIconFile, UINT cchMax, int *piIndex, UINT *pwFlags)
 {
-    if (CreateMyCompEnumList(dwFlags) == FALSE)
+    WCHAR wszPath[MAX_PATH];
+    WCHAR wszAutoRunInfPath[MAX_PATH];
+    WCHAR wszValue[MAX_PATH], wszTemp[MAX_PATH];
+    static const WCHAR wszAutoRunInf[] = { 'a','u','t','o','r','u','n','.','i','n','f',0 };
+    static const WCHAR wszAutoRun[] = { 'a','u','t','o','r','u','n',0 };
+
+    // get path
+    if (!ILGetDisplayNameExW(psf, pidl, wszPath, 0))
+        return E_FAIL;
+    if (!PathIsDirectoryW(wszPath))
         return E_FAIL;
 
-    return S_OK;
-}
+    // build the full path of autorun.inf
+    StringCchCopyW(wszAutoRunInfPath, _countof(wszAutoRunInfPath), wszPath);
+    PathAppendW(wszAutoRunInfPath, wszAutoRunInf);
 
-/**************************************************************************
- *  CDrivesFolderEnum::CreateMyCompEnumList()
- */
+    // autorun.inf --> wszValue
+    if (GetPrivateProfileStringW(wszAutoRun, L"icon", NULL, wszValue, _countof(wszValue),
+                                 wszAutoRunInfPath) && wszValue[0] != 0)
+    {
+        // wszValue --> wszTemp
+        ExpandEnvironmentStringsW(wszValue, wszTemp, _countof(wszTemp));
+
+        // parse the icon location
+        *piIndex = PathParseIconLocationW(wszTemp);
+
+        // wszPath + wszTemp --> wszPath
+        if (PathIsRelativeW(wszTemp))
+            PathAppendW(wszPath, wszTemp);
+        else
+            StringCchCopyW(wszPath, _countof(wszPath), wszTemp);
+
+        // wszPath --> szIconFile
+        GetFullPathNameW(wszPath, cchMax, szIconFile, NULL);
+
+        return S_OK;
+    }
+
+    return E_FAIL;
+}
 
-BOOL CDrivesFolderEnum::CreateMyCompEnumList(DWORD dwFlags)
+HRESULT CDrivesExtractIcon_CreateInstance(IShellFolder * psf, LPCITEMIDLIST pidl, REFIID riid, LPVOID * ppvOut)
 {
-    BOOL bRet = TRUE;
-    static const WCHAR MyComputer_NameSpaceW[] = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MyComputer\\Namespace";
+    CComPtr<IDefaultExtractIconInit> initIcon;
+    HRESULT hr = SHCreateDefaultExtractIcon(IID_PPV_ARG(IDefaultExtractIconInit, &initIcon));
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
 
-    TRACE("(%p)->(flags=0x%08x)\n", this, dwFlags);
+    CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
+    UINT DriveType = GetDriveTypeA(pszDrive);
+    if (DriveType > DRIVE_RAMDISK)
+        DriveType = DRIVE_FIXED;
 
-    /* enumerate the folders */
-    if (dwFlags & SHCONTF_FOLDERS)
+    WCHAR wTemp[MAX_PATH];
+    int icon_idx;
+    UINT flags = 0;
+    if ((DriveType == DRIVE_FIXED || DriveType == DRIVE_UNKNOWN) &&
+        (HCR_GetIconW(L"Drive", wTemp, NULL, MAX_PATH, &icon_idx)))
+    {
+        initIcon->SetNormalIcon(wTemp, icon_idx);
+    }
+    else if (SUCCEEDED(getIconLocationForDrive(psf, pidl, 0, wTemp, _countof(wTemp),
+                                               &icon_idx, &flags)))
     {
-        WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
-        DWORD dwDrivemap = GetLogicalDrives();
-        HKEY hKey;
-        UINT i;
+        initIcon->SetNormalIcon(wTemp, icon_idx);
+    }
+    else
+    {
+        icon_idx = iDriveIconIds[DriveType];
+        initIcon->SetNormalIcon(swShell32Name, -icon_idx);
+    }
 
-        while (bRet && wszDriveName[0] <= 'Z')
-        {
-            if(dwDrivemap & 0x00000001L)
-                bRet = AddToEnumList(_ILCreateDrive(wszDriveName));
-            wszDriveName[0]++;
-            dwDrivemap = dwDrivemap >> 1;
-        }
+    return initIcon->QueryInterface(riid, ppvOut);
+}
 
-        TRACE("-- (%p)-> enumerate (mycomputer shell extensions)\n", this);
-        for (i = 0; i < 2; i++)
+class CDrivesFolderEnum :
+    public CEnumIDListBase
+{
+    public:
+        HRESULT WINAPI Initialize(HWND hwndOwner, DWORD dwFlags, IEnumIDList* pRegEnumerator)
         {
-            if (bRet && ERROR_SUCCESS == RegOpenKeyExW(i == 0 ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER,
-                    MyComputer_NameSpaceW, 0, KEY_READ, &hKey))
+            /* enumerate the folders */
+            if (dwFlags & SHCONTF_FOLDERS)
             {
-                WCHAR wszBuf[50];
-                DWORD dwSize, j = 0;
-                LONG ErrorCode;
-                LPITEMIDLIST pidl;
+                WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
+                DWORD dwDrivemap = GetLogicalDrives();
 
-                while (bRet)
+                while (wszDriveName[0] <= 'Z')
                 {
-                    dwSize = sizeof(wszBuf) / sizeof(wszBuf[0]);
-                    ErrorCode = RegEnumKeyExW(hKey, j, wszBuf, &dwSize, 0, NULL, NULL, NULL);
-                    if (ERROR_SUCCESS == ErrorCode)
-                    {
-                        if (wszBuf[0] != L'{')
-                        {
-                            dwSize = sizeof(wszBuf);
-                            RegGetValueW(hKey, wszBuf, NULL, RRF_RT_REG_SZ, NULL, wszBuf, &dwSize);
-                        }
-
-                        /* FIXME: shell extensions - the type should be PT_SHELLEXT (tested) */
-                        pidl = _ILCreateGuidFromStrW(wszBuf);
-                        if (pidl != NULL)
-                            bRet = AddToEnumList(pidl);
-                        else
-                            ERR("Invalid MyComputer namespace extesion: %s\n", wszBuf);
-                        j++;
-                    }
-                    else if (ERROR_NO_MORE_ITEMS == ErrorCode)
-                        break;
-                    else
-                        bRet = FALSE;
+                    if(dwDrivemap & 0x00000001L)
+                        AddToEnumList(_ILCreateDrive(wszDriveName));
+                    wszDriveName[0]++;
+                    dwDrivemap = dwDrivemap >> 1;
                 }
-                RegCloseKey(hKey);
             }
+
+            /* Enumerate the items of the reg folder */
+            AppendItemsFromEnumerator(pRegEnumerator);
+
+            return S_OK;
         }
-    }
-    return bRet;
-}
+
+        BEGIN_COM_MAP(CDrivesFolderEnum)
+        COM_INTERFACE_ENTRY_IID(IID_IEnumIDList, IEnumIDList)
+        END_COM_MAP()
+};
+
+/***********************************************************************
+*   IShellFolder [MyComputer] implementation
+*/
+
+static const shvheader MyComputerSFHeader[] = {
+    {IDS_SHV_COLUMN_NAME, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 15},
+    {IDS_SHV_COLUMN_COMMENTS, SHCOLSTATE_TYPE_STR, LVCFMT_LEFT, 10},
+    {IDS_SHV_COLUMN_TYPE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_LEFT, 10},
+    {IDS_SHV_COLUMN_DISK_CAPACITY, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+    {IDS_SHV_COLUMN_DISK_AVAILABLE, SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT, LVCFMT_RIGHT, 10},
+};
+
+#define MYCOMPUTERSHELLVIEWCOLUMNS 5
+
+static const DWORD dwComputerAttributes =
+    SFGAO_CANRENAME | SFGAO_CANDELETE | SFGAO_HASPROPSHEET | SFGAO_DROPTARGET |
+    SFGAO_FILESYSANCESTOR | SFGAO_FOLDER | SFGAO_HASSUBFOLDER;
+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;
 
 CDrivesFolder::CDrivesFolder()
 {
     pidlRoot = NULL;
-    sName = NULL;
 }
 
 CDrivesFolder::~CDrivesFolder()
@@ -166,27 +444,17 @@ 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}", 
+                                           L"MyComputer",
+                                           IID_PPV_ARG(IShellFolder2, &m_regFolder));
+
+    return hr;
 }
 
 /**************************************************************************
@@ -197,9 +465,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 +477,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 +498,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;
@@ -252,7 +522,10 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
 */
 HRESULT WINAPI CDrivesFolder::EnumObjects(HWND hwndOwner, DWORD dwFlags, LPENUMIDLIST *ppEnumIDList)
 {
-    return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, IID_IEnumIDList, ppEnumIDList);
+    CComPtr<IEnumIDList> pRegEnumerator;
+    m_regFolder->EnumObjects(hwndOwner, dwFlags, &pRegEnumerator);
+
+    return ShellObjectCreatorInit<CDrivesFolderEnum>(hwndOwner, dwFlags, pRegEnumerator, IID_PPV_ARG(IEnumIDList, ppEnumIDList));
 }
 
 /**************************************************************************
@@ -263,7 +536,28 @@ 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);
+
+    CHAR* pchDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
+    
+    PERSIST_FOLDER_TARGET_INFO pfti = {0};
+    pfti.dwAttributes = -1;
+    pfti.csidl = -1;
+    pfti.szTargetParsingName[0] = *pchDrive;
+    pfti.szTargetParsingName[1] = L':';
+    pfti.szTargetParsingName[2] = L'\\';
+
+    HRESULT hr = SHELL32_BindToSF(pidlRoot,
+                                  &pfti,
+                                  pidl,
+                                  &CLSID_ShellFSFolder,
+                                  riid,
+                                  ppvOut);
+    if (FAILED_UNEXPECTEDLY(hr))
+        return hr;
+
+    return S_OK;
 }
 
 /**************************************************************************
@@ -284,12 +578,72 @@ 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;
+
+    int result;
+    switch(LOWORD(lParam)) 
+    {
+        case 0:        /* name */
+        {
+            result = stricmp(pszDrive1, pszDrive2);
+            hres = MAKE_COMPARE_HRESULT(result);
+            break;
+        }
+        case 1:        /* comments */
+            hres = MAKE_COMPARE_HRESULT(0);
+            break;
+        case 2:        /* Type */
+        {
+            /* We want to return immediately because SHELL32_CompareDetails also compares children. */
+            return SHELL32_CompareDetails(this, lParam, pidl1, pidl2);
+        }
+        case 3:       /* Size */
+        case 4:       /* Size Available */
+        {
+            ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
 
-    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;
+            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 == 3) /* 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;
 }
 
 /**************************************************************************
@@ -315,16 +669,26 @@ HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVO
     }
     else if (IsEqualIID(riid, IID_IContextMenu))
     {
-        WARN("IContextMenu not implemented\n");
-        hr = E_NOTIMPL;
+        HKEY hKeys[16];
+        UINT cKeys = 0;
+        AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
+
+        DEFCONTEXTMENU dcm;
+        dcm.hwnd = hwndOwner;
+        dcm.pcmcb = this;
+        dcm.pidlFolder = pidlRoot;
+        dcm.psf = this;
+        dcm.cidl = 0;
+        dcm.apidl = NULL;
+        dcm.cKeys = cKeys;
+        dcm.aKeys = hKeys;
+        dcm.punkAssociationInfo = NULL;
+        hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
     }
     else if (IsEqualIID(riid, IID_IShellView))
     {
-        hr = IShellView_Constructor ((IShellFolder *)this, &pShellView);
-        if (pShellView)
-        {
-            hr = pShellView->QueryInterface(riid, ppvOut);
-        }
+            SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
+            hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
     }
     TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
     return hr;
@@ -332,12 +696,12 @@ HRESULT WINAPI CDrivesFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVO
 
 static BOOL _ILIsControlPanel(LPCITEMIDLIST pidl)
 {
-    IID *iid = _ILGetGUIDPointer(pidl);
+    GUID *guid = _ILGetGUIDPointer(pidl);
 
     TRACE("(%p)\n", pidl);
 
-    if (iid)
-        return IsEqualIID(iid, CLSID_ControlPanel);
+    if (guid)
+        return IsEqualIID(*guid, CLSID_ControlPanel);
     return FALSE;
 }
 
@@ -346,15 +710,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 +730,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 +760,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 +773,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))
-    {
-        pidl = ILCombine (pidlRoot, apidl[0]);
-        pObj = IExtractIconA_Constructor (pidl);
-        SHFree (pidl);
-        hr = S_OK;
-    }
-    else if (IsEqualIID (riid, IID_IExtractIconW) && (cidl == 1))
+    else if ((IsEqualIID (riid, IID_IExtractIconA) || 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 +824,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)
-    {
-        /* parsing name like ::{...} */
-        pszPath[0] = ':';
-        pszPath[1] = ':';
-        SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
-    }
-    else if (_ILIsPidlSimple(pidl))
+    _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);    /* append my own path */
+    /* long view "lw_name (C:)" */
+    if (!(dwFlags & SHGDN_FORPARSING))
     {
-        /* 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
-            {
-                /* append my own path */
-                _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);
-            }
-        }
-        else if (_ILIsDrive(pidl))
-        {
-
-            _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);    /* append my own path */
-            /* long view "lw_name (C:)" */
-            if (!(dwFlags & SHGDN_FORPARSING))
+            if (ResourceId)
             {
-                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);
+                dwFileSystemFlags = LoadStringW(shell32_hInstance, ResourceId, pszPath, MAX_PATH);
+                if (dwFileSystemFlags > MAX_PATH - 7)
+                    pszPath[MAX_PATH-7] = L'\0';
             }
         }
-        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 +918,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 +929,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 +971,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,45 +984,46 @@ 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 (!_ILIsDrive(pidl))
+    {
+        return m_regFolder->GetDetailsOf(pidl, iColumn, psd);
     }
     else
     {
-        char szPath[MAX_PATH];
-        ULARGE_INTEGER ulBytes;
+        ULARGE_INTEGER ulTotalBytes, ulFreeBytes;
+        CHAR* pszDrive = _ILGetDataPointer(pidl)->u.drive.szDriveName;
+        UINT DriveType = GetDriveTypeA(pszDrive);
+        if (DriveType > DRIVE_RAMDISK)
+            DriveType = DRIVE_FIXED;
 
-        psd->str.cStr[0] = 0x00;
-        psd->str.uType = STRRET_CSTR;
         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);
+            case 1:                /* FIXME: comments */
+                hr = SHSetStrRet(&psd->str, "");
                 break;
-            case 2:        /* total size */
-                if (_ILIsDrive(pidl))
-                {
-                    _ILSimpleGetText (pidl, szPath, MAX_PATH);
-                    GetDiskFreeSpaceExA (szPath, NULL, &ulBytes, NULL);
-                    StrFormatByteSizeA (ulBytes.LowPart, psd->str.cStr, MAX_PATH);
-                }
+            case 2:        /* type */
+                hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]);
                 break;
-            case 3:        /* free size */
-                if (_ILIsDrive(pidl))
+            case 3:        /* total size */
+            case 4:        /* free size */
+                psd->str.cStr[0] = 0x00;
+                psd->str.uType = STRRET_CSTR;
+                if (GetVolumeInformationA(pszDrive, 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(pszDrive, &ulFreeBytes, &ulTotalBytes, NULL);
+                    if (iColumn == 3)
+                        StrFormatByteSize64A(ulTotalBytes.QuadPart, psd->str.cStr, MAX_PATH);
+                    else
+                        StrFormatByteSize64A(ulFreeBytes.QuadPart, psd->str.cStr, MAX_PATH);
                 }
+                hr = S_OK;
                 break;
         }
-        hr = S_OK;
     }
 
     return hr;
@@ -839,25 +1056,59 @@ 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;
 }
 
 /**************************************************************************
  *    CDrivesFolder::GetCurFolder
  */
-HRESULT WINAPI CDrivesFolder::GetCurFolder(LPITEMIDLIST *pidl)
+HRESULT WINAPI CDrivesFolder::GetCurFolder(PIDLIST_ABSOLUTE *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;
 }
+
+/************************************************************************/
+/* IContextMenuCB interface */
+
+HRESULT WINAPI CDrivesFolder::CallBack(IShellFolder *psf, HWND hwndOwner, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+    if (uMsg != DFM_MERGECONTEXTMENU && uMsg != DFM_INVOKECOMMAND)
+        return S_OK;
+
+    /* no data object means no selection */
+    if (!pdtobj)
+    {
+        if (uMsg == DFM_INVOKECOMMAND && wParam == 1)   // #1
+        {
+            // "System" properties
+            ShellExecuteW(hwndOwner,
+                          NULL,
+                          L"rundll32.exe",
+                          L"shell32.dll,Control_RunDLL sysdm.cpl",
+                          NULL,
+                          SW_SHOWNORMAL);
+        }
+        else if (uMsg == DFM_MERGECONTEXTMENU)
+        {
+            QCMINFO *pqcminfo = (QCMINFO *)lParam;
+            HMENU hpopup = CreatePopupMenu();
+            _InsertMenuItemW(hpopup, 0, TRUE, 0, MFT_SEPARATOR, NULL, MFS_ENABLED); // #0
+            _InsertMenuItemW(hpopup, 1, TRUE, 1, MFT_STRING, MAKEINTRESOURCEW(IDS_PROPERTIES), MFS_ENABLED); // #1
+            Shell_MergeMenus(pqcminfo->hmenu, hpopup, pqcminfo->indexMenu++, pqcminfo->idCmdFirst, pqcminfo->idCmdLast, MM_ADDSEPARATOR);
+            DestroyMenu(hpopup);
+        }
+
+        return S_OK;
+    }
+
+    if (uMsg != DFM_INVOKECOMMAND || wParam != DFM_CMD_PROPERTIES)
+        return S_OK;
+
+    return Shell_DefaultContextMenuCallBack(this, pdtobj);
+}