[SHELL] IPersistFolder2::GetCurFolder takes a PIDLIST_ABSOLUTE*. CORE-16385
[reactos.git] / dll / win32 / shell32 / folders / CDrivesFolder.cpp
index 1d38d18..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,136 +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_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},
-};
+// 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);
+    }
 
-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;
+    CloseHandle(hDrive);
 
-CDrivesFolderEnum::CDrivesFolderEnum()
+    SetLastError(dwError);
+    return bResult;
+}
+
+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)))
+    {
+        initIcon->SetNormalIcon(wTemp, icon_idx);
+    }
+    else
     {
-        WCHAR wszDriveName[] = {'A', ':', '\\', '\0'};
-        DWORD dwDrivemap = GetLogicalDrives();
-        HKEY hKey;
-        UINT i;
+        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()
@@ -175,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;
 }
 
 /**************************************************************************
@@ -206,7 +465,6 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
 {
     HRESULT hr = E_INVALIDARG;
     LPCWSTR szNext = NULL;
-    WCHAR szElement[MAX_PATH];
     LPITEMIDLIST pidlTemp = NULL;
 
     TRACE("(%p)->(HWND=%p,%p,%p=%s,%p,pidl=%p,%p)\n", this,
@@ -219,17 +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'\\')
     {
-        return SH_ParseGuidDisplayName(this, hwndOwner, pbc, lpszDisplayName, pchEaten, ppidl, pdwAttributes);
-    }
-    /* 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)
@@ -245,7 +504,7 @@ HRESULT WINAPI CDrivesFolder::ParseDisplayName(HWND hwndOwner, LPBC pbc, LPOLEST
             if (_ILIsDrive(pidlTemp))
                 *pdwAttributes &= dwDriveAttributes;
             else if (_ILIsSpecialFolder(pidlTemp))
-                SHELL32_GetGuidItemAttributes(this, pidlTemp, pdwAttributes);
+                m_regFolder->GetAttributesOf(1, &pidlTemp, pdwAttributes);
             else
                 ERR("Got an unkown pidl here!\n");
         }
@@ -263,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));
 }
 
 /**************************************************************************
@@ -275,9 +537,27 @@ HRESULT WINAPI CDrivesFolder::BindToObject(PCUIDLIST_RELATIVE pidl, LPBC pbcRese
           pidl, pbcReserved, shdebugstr_guid(&riid), ppvOut);
 
     if (_ILIsSpecialFolder(pidl))
-        return SHELL32_BindToGuidItem(pidlRoot, pidl, pbcReserved, riid, ppvOut);
+        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 SHELL32_BindToFS(pidlRoot, NULL, pidl, riid, ppvOut);
+    return S_OK;
 }
 
 /**************************************************************************
@@ -298,6 +578,8 @@ HRESULT WINAPI CDrivesFolder::BindToStorage(PCUIDLIST_RELATIVE pidl, LPBC pbcRes
 
 HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1, PCUIDLIST_RELATIVE pidl2)
 {
+    HRESULT hres;
+
     if (!pidl1 || !pidl2)
     {
         ERR("Got null pidl pointer (%Ix %p %p)!\n", lParam, pidl1, pidl2);
@@ -305,7 +587,7 @@ HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1
     }
 
     if (_ILIsSpecialFolder(pidl1) || _ILIsSpecialFolder(pidl2))
-        return SHELL32_CompareGuidItems(this, lParam, pidl1, pidl2);
+        return m_regFolder->CompareIDs(lParam, pidl1, pidl2);
 
     if (!_ILIsDrive(pidl1) || !_ILIsDrive(pidl2) || LOWORD(lParam) >= MYCOMPUTERSHELLVIEWCOLUMNS)
         return E_INVALIDARG;
@@ -319,14 +601,19 @@ HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1
         case 0:        /* name */
         {
             result = stricmp(pszDrive1, pszDrive2);
-            return MAKE_COMPARE_HRESULT(result);
+            hres = MAKE_COMPARE_HRESULT(result);
+            break;
         }
-        case 1:        /* Type */
+        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 2:       /* Size */
-        case 3:       /* Size Available */
+        case 3:       /* Size */
+        case 4:       /* Size Available */
         {
             ULARGE_INTEGER Drive1Available, Drive1Total, Drive2Available, Drive2Total;
 
@@ -341,15 +628,22 @@ HRESULT WINAPI CDrivesFolder::CompareIDs(LPARAM lParam, PCUIDLIST_RELATIVE pidl1
                 Drive2Available.QuadPart = Drive2Total.QuadPart = 0;
 
             LARGE_INTEGER Diff;
-            if (lParam == 2) /* Size */
+            if (lParam == 3) /* Size */
                 Diff.QuadPart = Drive1Total.QuadPart - Drive2Total.QuadPart;
             else /* Size available */
                 Diff.QuadPart = Drive1Available.QuadPart - Drive2Available.QuadPart;
 
-            return MAKE_COMPARE_HRESULT(Diff.QuadPart);
+            hres = MAKE_COMPARE_HRESULT(Diff.QuadPart);
+            break;
         }
+        default:
+            return E_INVALIDARG;
     }
-    return E_INVALIDARG;
+
+    if (HRESULT_CODE(hres) == 0)
+        return SHELL32_CompareChildren(this, lParam, pidl1, pidl2);
+
+    return hres;
 }
 
 /**************************************************************************
@@ -375,12 +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 = CDefView_Constructor(this, riid, ppvOut);
+            SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this};
+            hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
     }
     TRACE ("-- (%p)->(interface=%p)\n", this, ppvOut);
     return hr;
@@ -423,7 +731,7 @@ HRESULT WINAPI CDrivesFolder::GetAttributesOf(UINT cidl, PCUITEMID_CHILD_ARRAY a
             else if (_ILIsControlPanel(apidl[i]))
                 *rgfInOut &= dwControlPanelAttributes;
             else if (_ILIsSpecialFolder(*apidl))
-                SHELL32_GetGuidItemAttributes(this, apidl[i], rgfInOut);
+                m_regFolder->GetAttributesOf(1, &apidl[i], rgfInOut);
             else
                 ERR("Got unknown pidl type!\n");
         }
@@ -452,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,
@@ -466,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))
-    {
-        pidl = ILCombine (pidlRoot, apidl[0]);
-        pObj = IExtractIconW_Constructor (pidl);
-        SHFree (pidl);
-        hr = S_OK;
-    }
-    else if (IsEqualIID (riid, IID_IDropTarget) && (cidl >= 1))
+    else if ((IsEqualIID (riid, IID_IExtractIconA) || IsEqualIID (riid, IID_IExtractIconW)) && (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;
@@ -529,11 +828,11 @@ HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFla
     {
         return SHELL32_GetDisplayNameOfChild(this, pidl, dwFlags, strRet);
     }
-    else if (!_ILIsDesktop(pidl) && _ILIsSpecialFolder(pidl))
+    else if (_ILIsSpecialFolder(pidl))
     {
-        return SHELL32_GetDisplayNameOfGUIDItem(this, L"::{20D04FE0-3AEA-1069-A2D8-08002B30309D}", pidl, dwFlags, strRet);
+        return m_regFolder->GetDisplayNameOf(pidl, dwFlags, strRet);
     }
-    else if (pidl->mkid.cb && !_ILIsDrive(pidl))
+    else if (!_ILIsDrive(pidl))
     {
         ERR("Wrong pidl type\n");
         return E_INVALIDARG;
@@ -545,61 +844,51 @@ HRESULT WINAPI CDrivesFolder::GetDisplayNameOf(PCUITEMID_CHILD pidl, DWORD dwFla
 
     pszPath[0] = 0;
 
-    if (!pidl->mkid.cb)
-    {
-        /* parsing name like ::{...} */
-        pszPath[0] = ':';
-        pszPath[1] = ':';
-        SHELL32_GUIDToStringW(CLSID_MyComputer, &pszPath[2]);
-    }
-    else
+    _ILSimpleGetTextW(pidl, pszPath, MAX_PATH);    /* append my own path */
+    /* long view "lw_name (C:)" */
+    if (!(dwFlags & SHGDN_FORPARSING))
     {
-        _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))
         {
-            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)
             {
-                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';
-                }
+                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);
         }
+        wcscat (pszPath, wszOpenBracket);
+        wszDrive[2] = L'\0';
+        wcscat (pszPath, wszDrive);
+        wcscat (pszPath, wszCloseBracket);
     }
 
     if (SUCCEEDED(hr))
@@ -640,7 +929,7 @@ HRESULT WINAPI CDrivesFolder::SetNameOf(HWND hwndOwner, PCUITEMID_CHILD pidl,
         return S_OK;
     }
 
-    return SHELL32_SetNameOfGuidItem(pidl, lpName, dwFlags, pPidlOut);
+    return m_regFolder->SetNameOf(hwndOwner, pidl, lpName, dwFlags, pPidlOut);
 }
 
 HRESULT WINAPI CDrivesFolder::GetDefaultSearchGUID(GUID * pguid)
@@ -682,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;
@@ -696,48 +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 (_ILIsSpecialFolder(pidl))
+    else if (!_ILIsDrive(pidl))
     {
-        return SHELL32_GetDetailsOfGuidItem(this, pidl, iColumn, psd);
+        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);
                 break;
-            case 1:        /* type */
-                _ILGetFileType(pidl, psd->str.cStr, MAX_PATH);
+            case 1:                /* FIXME: comments */
+                hr = SHSetStrRet(&psd->str, "");
                 break;
-            case 2:        /* total size */
-                _ILSimpleGetText (pidl, szPath, MAX_PATH);
-                if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
-                {
-                    GetDiskFreeSpaceExA(szPath, NULL, &ulBytes, NULL);
-                    StrFormatByteSize64A(ulBytes.QuadPart, psd->str.cStr, MAX_PATH);
-                }
+            case 2:        /* type */
+                hr = SHSetStrRet(&psd->str, iDriveTypeIds[DriveType]);
                 break;
-            case 3:        /* free size */
-                _ILSimpleGetText (pidl, szPath, MAX_PATH);
-                if (GetVolumeInformationA(szPath, NULL, 0, NULL, NULL, NULL, NULL, 0))
+            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))
                 {
-                    GetDiskFreeSpaceExA(szPath, &ulBytes, NULL, NULL);
-                    StrFormatByteSize64A(ulBytes.QuadPart, 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;
@@ -770,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);
+}