drivfldr.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 54k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "shellprv.h"
  2. #include "caggunk.h"
  3. #include "views.h"
  4. #include "drives.h"
  5. #include "netview.h"
  6. #include "propsht.h"
  7. #include "infotip.h"
  8. #include "sfviewp.h"
  9. #include "mtpt.h"
  10. #include "prop.h"
  11. extern "C"
  12. {
  13. #include "fstreex.h"
  14. #include "ovrlaymn.h"
  15. #include "idmk.h"
  16. }
  17. #include "shitemid.h"
  18. #include "shobjprv.h"
  19. #include "deskfldr.h"
  20. #include "datautil.h"
  21. #ifdef WINNT
  22. #include <ntddcdrm.h>
  23. #else
  24. #define Not_VxD
  25. #include <vwin32.h>     // DeviceIOCtl calls
  26. #endif
  27. // BUGBUG: At some point we should check an ini switch or something
  28. #define ShowDriveInfo(_iDrive)  (!IsRemovableDrive(_iDrive))
  29. #define CDRIVES_REGITEM_CONTROL 0
  30. #define IDLIST_DRIVES           ((LPCITEMIDLIST)&c_idlDrives)
  31. // These are the sort order for items in MyComputer
  32. #define CONTROLS_SORT_INDEX             30
  33. #define CDRIVES_REGITEM_CONTROL          0
  34. REQREGITEM g_asDrivesReqItems[] =
  35. {
  36.     { &CLSID_ControlPanel, IDS_CONTROLPANEL, c_szShell32Dll, CONTROLS_SORT_INDEX, -IDI_CPLFLD, SFGAO_FOLDER | SFGAO_HASSUBFOLDER, NULL},
  37. };
  38. REGITEMSINFO g_sDrivesRegInfo =
  39. {
  40.     REGSTR_PATH_EXPLORER TEXT("\MyComputer\NameSpace"),
  41.     NULL,
  42.     TEXT(':'),
  43.     SHID_COMPUTER_REGITEM,
  44.     -1,
  45.     SFGAO_CANLINK,
  46.     ARRAYSIZE(g_asDrivesReqItems),
  47.     g_asDrivesReqItems,
  48.     RIISA_ORIGINAL,
  49.     NULL,
  50.     0,
  51.     0,
  52. };
  53. class CDrivesViewCallback;
  54. class CDrivesFolder : public CAggregatedUnknown, IShellFolder2, IPersistFolder2, IShellIconOverlay
  55. {
  56. public:
  57.     // *** IUnknown ***
  58.     STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj)
  59.                 { return CAggregatedUnknown::QueryInterface(riid, ppvObj); };
  60.     STDMETHODIMP_(ULONG) AddRef(void) 
  61.                 { return CAggregatedUnknown::AddRef(); };
  62.     STDMETHODIMP_(ULONG) Release(void) 
  63.                 { return CAggregatedUnknown::Release(); };
  64.     // *** IShellFolder methods ***
  65.     STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
  66.                                   ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
  67.     STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumIDList);
  68.     STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvOut);
  69.     STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvObj);
  70.     STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  71.     STDMETHODIMP CreateViewObject (HWND hwndOwner, REFIID riid, void** ppvOut);
  72.     STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut);
  73.     STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST* apidl,
  74.                                REFIID riid, UINT* prgfInOut, void** ppvOut);
  75.     STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName);
  76.     STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags,
  77.                            LPITEMIDLIST* ppidlOut);
  78.     // *** IShellFolder2 methods ***
  79.     STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid);
  80.     STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH* ppenum);
  81.     STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay);
  82.     STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD* pbState);
  83.     STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv);
  84.     STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS* pDetails);
  85.     STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid);
  86.     // *** IPersist methods ***
  87.     STDMETHODIMP GetClassID(CLSID* pClassID);
  88.     // *** IPersistFolder methods ***
  89.     STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  90.     // *** IPersistFolder2 methods ***
  91.     STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl);
  92.     // *** IShellIconOverlay methods ***
  93.     STDMETHODIMP GetOverlayIndex(LPCITEMIDLIST pidl, int* pIndex);
  94.     STDMETHODIMP GetOverlayIconIndex(LPCITEMIDLIST pidl, int* pIconIndex);
  95. protected:
  96.     CDrivesFolder(IUnknown* punkOuter);
  97.     ~CDrivesFolder();
  98.     // used by the CAggregatedUnknown stuff
  99.     HRESULT v_InternalQueryInterface(REFIID riid, void** ppvObj);
  100.     BOOL v_HandleDelete(PLONG pcRef);
  101.     
  102.     STDMETHODIMP CompareItemIDs(LPCIDDRIVE pidd1, LPCIDDRIVE pidd2);
  103.     BOOL TypeIsRemoveable(LPCIDDRIVE pidd);
  104.     static BOOL _GetFreeSpace(LPCIDDRIVE pidd, ULONGLONG *pSize, ULONGLONG *pFree);
  105.     static BOOL _GetFreeSpaceString(LPCIDDRIVE pidd, LPTSTR szBuf, UINT cchBuf);
  106.     static HRESULT _OnChangeNotify(LPARAM lNotification, LPCITEMIDLIST *ppidl);
  107.     static void _FillIDDrive(DRIVE_IDLIST *piddl, int iDrive, BOOL bSimple);
  108.     static LPCIDDRIVE _IsValidID(LPCITEMIDLIST pidl);
  109.     static int _GetSHID(int iDrive);
  110.     static HRESULT _GetCCHMax(LPCITEMIDLIST pidlItem, UINT *pcchMax);
  111.     static HRESULT _GetDisplayNameStrRet(LPCIDDRIVE pidd, STRRET *pStrRet);
  112.     static HRESULT _GetDisplayName(LPCIDDRIVE pidd, LPTSTR pszName, UINT cchMax);
  113.     static HRESULT _CreateFSFolder(LPCITEMIDLIST pidlDrive, LPCIDDRIVE pidd, REFIID riid, void **ppv);
  114.     static void _GetTypeString(BYTE bFlags, LPTSTR pszName, UINT cbName);
  115.     static HRESULT _GetEditTextStrRet(LPCIDDRIVE pidd, STRRET *pstr);
  116.     static BOOL _IsReg(LPCIDDRIVE pidd) { return pidd->bFlags == SHID_COMPUTER_REGITEM; }
  117.     static HRESULT _GetIconOverlayInfo(LPCIDDRIVE pidd, int *pIndex, DWORD dwFlags);
  118.     static CDrivesFolder* _spThis;
  119.     
  120. private:
  121.     friend HRESULT CDrives_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv);
  122.     friend void CDrives_Terminate(void);
  123.     friend CDrivesViewCallback;
  124.     static HRESULT CALLBACK EnumCallBack(LPARAM lParam, void *pvData, UINT ecid, UINT index);
  125.     IUnknown* _punkReg;
  126. };  
  127. #define DRIVES_EVENTS 
  128.     SHCNE_DRIVEADD | 
  129.     SHCNE_DRIVEREMOVED | 
  130.     SHCNE_MEDIAINSERTED | 
  131.     SHCNE_MEDIAREMOVED | 
  132.     SHCNE_NETSHARE | 
  133.     SHCNE_NETUNSHARE | 
  134.     SHCNE_DELETE | 
  135.     SHCNE_RENAMEITEM | 
  136.     SHCNE_RENAMEFOLDER | 
  137.     SHCNE_UPDATEITEM
  138. HRESULT _GetSelectedObjectsFromSite(IUnknown *psite, LPCITEMIDLIST **pppidl, UINT *pcCount)
  139. {
  140.     if (pcCount)
  141.         *pcCount = 0;
  142.     if (pppidl)
  143.         *pppidl = NULL;
  144.     IShellFolderView *psfv;
  145.     HRESULT hres = IUnknown_QueryService(psite, SID_DefView, IID_IShellFolderView, (void **)&psfv); 
  146.     if (SUCCEEDED(hres))
  147.     {
  148.         hres = psfv->GetSelectedObjects(pppidl, pcCount);
  149.         psfv->Release();
  150.     }
  151.     return hres;
  152. }
  153. //
  154. //  Obtains the pidl for the selected item from the defview.  If no objects
  155. //  are selected or more than one object is selected, then returns NULL.
  156. //
  157. //  The returned pidl should NOT be freed.  It belongs to the view.
  158. //
  159. STDAPI_(LPCITEMIDLIST) GetSelectedObjectFromSite(IUnknown *psite)
  160. {
  161.     LPCITEMIDLIST pidl = NULL;
  162.     IShellBrowser *psb;
  163.     if (SUCCEEDED(IUnknown_QueryService(psite, SID_STopLevelBrowser, IID_IShellBrowser, (void **)&psb)))
  164.     {
  165.         UINT cSelected;
  166.         if (SUCCEEDED(_GetSelectedObjectsFromSite(psite, NULL, &cSelected)) && (cSelected == 1))
  167.         {
  168.             LPCITEMIDLIST *apidl;
  169.             if (SUCCEEDED(_GetSelectedObjectsFromSite(psite, &apidl, &cSelected)))
  170.             {
  171.                 pidl = apidl[0];
  172.                 LocalFree(apidl);
  173.             }
  174.         }
  175.         psb->Release();
  176.     }
  177.     return pidl;
  178. }
  179. HRESULT CDrivesFolder::_GetCCHMax(LPCITEMIDLIST pidlItem, UINT *pcchMax)
  180. {
  181.     LPCIDDRIVE pidd = _IsValidID(pidlItem);
  182.     if (pidd)
  183.     {
  184.         if (pidd->bFlags == SHID_COMPUTER_REGITEM)
  185.             *pcchMax = MAX_REGITEMCCH;
  186.         else
  187.         {
  188.             HRESULT hres = E_FAIL;
  189.             TCHAR szLabel[MAX_LABEL_NTFS + 1];
  190.             CMountPoint* pMtPt = CMountPoint::GetMountPoint(DRIVEID(pidd->cName));
  191.             if (pMtPt)
  192.                 hres = pMtPt->GetLabel(szLabel, ARRAYSIZE(szLabel));
  193.             if (SUCCEEDED(hres))
  194.             {
  195.                 if (pMtPt->IsNTFS())
  196.                     *pcchMax = MAX_LABEL_NTFS;
  197.                 else
  198.                     *pcchMax = MAX_LABEL_FAT;
  199.             }
  200.             if (pMtPt)
  201.                 pMtPt->Release();
  202.         }
  203.     }
  204.     return NOERROR;
  205. }
  206. class CDrivesViewCallback : public CBaseShellFolderViewCB
  207. {
  208. public:
  209.     CDrivesViewCallback(IShellFolder* psf)
  210.         : CBaseShellFolderViewCB(psf, (LPCITEMIDLIST)&c_idlDrives, DRIVES_EVENTS)
  211.     { 
  212.     }
  213.     STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  214. private:
  215.     HRESULT OnMergeMenu(DWORD pv, QCMINFO*lP)
  216.     {
  217.         CDefFolderMenu_MergeMenu(HINST_THISDLL, 0, POPUP_DRIVES_POPUPMERGE, lP);
  218.         return NOERROR;
  219.     }
  220.     HRESULT OnInvokeCommand(DWORD pv, UINT wP)
  221.     {
  222.         return CDrives_InvokeCommand(m_hwndMain, wP);
  223.     }
  224.     HRESULT OnGETHELPTEXT(DWORD pv, UINT id, UINT cch, LPTSTR psz)
  225.     {
  226. #ifdef UNICODE
  227.         return CDrives_GetHelpText(id, TRUE, (LPARAM)psz, cch);
  228. #else
  229.         return CDrives_GetHelpText(id, FALSE, (LPARAM)psz, cch);
  230. #endif
  231.     }
  232.     HRESULT OnInsertItem(DWORD pv, LPCITEMIDLIST wP)
  233.     {
  234.         LPIDDRIVE pidd = (LPIDDRIVE)wP;
  235.         if (pidd && pidd->bFlags != SHID_COMPUTER_REGITEM)
  236.         {
  237.             // clear the size info
  238.             pidd->qwSize = pidd->qwFree = 0;
  239.         }
  240.         return NOERROR;
  241.     }
  242.     HRESULT OnWindowCreated(DWORD pv, HWND wP)
  243.     {
  244.         InitializeStatus(_punkSite);
  245.         return S_OK;
  246.     }
  247.     HRESULT OnSize(DWORD pv, UINT cx, UINT cy)
  248.     {
  249.         ResizeStatus(_punkSite, cx);
  250.         return S_OK;
  251.     }
  252.     HRESULT OnGetPane(DWORD pv, LPARAM dwPaneID, DWORD *pdwPane)
  253.     {
  254.         if (PANE_ZONE == dwPaneID)
  255.             *pdwPane = 2;
  256.         return S_OK;
  257.     }
  258.     HRESULT OnUpdateStatusBar(DWORD pv, BOOL fIniting)
  259.     {
  260.         // Ask DefView to set the default text but not initialize
  261.         // since we did the initialization in our OnSize handler.
  262.         return SFVUSB_INITED;
  263.     }
  264.     HRESULT OnFSNotify(DWORD pv, LPCITEMIDLIST*wP, LPARAM lP)
  265.     {
  266.         return CDrivesFolder::_OnChangeNotify(lP, wP);
  267.     }
  268.     HRESULT OnBACKGROUNDENUM(DWORD pv)
  269.     {
  270.         return S_OK;
  271.     }
  272.     HRESULT OnDEFITEMCOUNT(DWORD pv, UINT*lP)
  273.     {
  274.         // if we time out enuming items make a guess at how many items there
  275.         // will be to make sure we get large icon mode and a reasonable window size
  276.         *lP = 20;
  277.         return S_OK;
  278.     }
  279.     HRESULT OnGetCCHMax(DWORD pv, LPCITEMIDLIST pidlItem, UINT *pcchMax)
  280.     {
  281.         return CDrivesFolder::_GetCCHMax(pidlItem, pcchMax);
  282.     }
  283.     HRESULT OnSupportsIdentity(DWORD pv)
  284.     {
  285.         return S_OK;
  286.     }
  287. };
  288. STDMETHODIMP CDrivesViewCallback::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  289. {
  290.     switch (uMsg)
  291.     {
  292.     HANDLE_MSG(0, SFVM_MERGEMENU, OnMergeMenu);
  293.     HANDLE_MSG(0, SFVM_INVOKECOMMAND, OnInvokeCommand);
  294.     HANDLE_MSG(0, SFVM_GETHELPTEXT, OnGETHELPTEXT);
  295.     HANDLE_MSG(0, SFVM_INSERTITEM, OnInsertItem);
  296.     HANDLE_MSG(0, SFVM_UPDATESTATUSBAR, OnUpdateStatusBar);
  297.     HANDLE_MSG(0, SFVM_FSNOTIFY, OnFSNotify);
  298.     HANDLE_MSG(0, SFVM_BACKGROUNDENUM, OnBACKGROUNDENUM);
  299.     HANDLE_MSG(0, SFVM_DEFITEMCOUNT, OnDEFITEMCOUNT);
  300.     HANDLE_MSG(0, SFVM_ADDPROPERTYPAGES, SFVCB_OnAddPropertyPages);
  301.     HANDLE_MSG(0, SFVM_WINDOWCREATED, OnWindowCreated);
  302.     HANDLE_MSG(0, SFVM_SIZE, OnSize);
  303.     HANDLE_MSG(0, SFVM_GETPANE, OnGetPane);
  304.     HANDLE_MSG(0, SFVM_GETCCHMAX, OnGetCCHMax);
  305.     HANDLE_MSG(0, SFVM_SUPPORTSIDENTITY, OnSupportsIdentity);
  306.     default:
  307.         return E_FAIL;
  308.     }
  309.     return NOERROR;
  310. }
  311. STDAPI_(IShellFolderViewCB*) CDrives_CreateSFVCB(IShellFolder* psf)
  312. {
  313.     return new CDrivesViewCallback(psf);
  314. }
  315. typedef struct
  316. {
  317.     DWORD       dwDrivesMask;
  318.     int         nLastFoundDrive;
  319.     DWORD       dwRestricted;
  320.     DWORD       dwSavedErrorMode;
  321.     DWORD       grfFlags;
  322. } EnumDrives;
  323. typedef enum
  324. {
  325.     DRIVES_ICOL_NAME = 0,
  326.     DRIVES_ICOL_TYPE,
  327.     DRIVES_ICOL_SIZE,
  328.     DRIVES_ICOL_FREE,
  329.     DRIVES_ICOL_COMMENT,
  330.     DRIVES_ICOL_HTMLINFOTIPFILE,
  331. } EnumDrivesCols;
  332. const COL_DATA c_drives_cols[] = {
  333.     { DRIVES_ICOL_NAME,         IDS_DRIVES_NAME, 20,    LVCFMT_LEFT,    &SCID_NAME},
  334.     { DRIVES_ICOL_TYPE,         IDS_DRIVES_TYPE, 25,    LVCFMT_LEFT,    &SCID_TYPE},
  335.     { DRIVES_ICOL_SIZE,         IDS_DRIVES_SIZE, 15,    LVCFMT_RIGHT,   &SCID_SIZE},
  336.     { DRIVES_ICOL_FREE,         IDS_DRIVES_FREE, 15,    LVCFMT_RIGHT,   &SCID_FREESPACE},
  337.     { DRIVES_ICOL_COMMENT,      IDS_COMMENT_COL, 20,    LVCFMT_LEFT,    &SCID_Comment},
  338.     { DRIVES_ICOL_HTMLINFOTIPFILE, IDS_COMMENT_COL, 20, LVCFMT_LEFT,    &SCID_HTMLINFOTIPFILE}
  339. };
  340. const TCHAR c_szVolumeNamePrefix[]  = TEXT("\\?\Volume{");
  341. CDrivesFolder* CDrivesFolder::_spThis = NULL;
  342. HRESULT CDrives_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
  343. {
  344.     HRESULT hres;
  345.     ASSERT(NULL != ppv);
  346.     
  347.     ENTERCRITICAL;
  348.     if (NULL != CDrivesFolder::_spThis)
  349.     {
  350.         hres = CDrivesFolder::_spThis->QueryInterface(riid, ppv);
  351.         LEAVECRITICAL;
  352.     }
  353.     else
  354.     {
  355.         LEAVECRITICAL;
  356.         CDrivesFolder* pDF = new CDrivesFolder(punkOuter);
  357.         if (NULL != pDF)
  358.         {
  359.             ASSERT(NULL == pDF->_punkReg);
  360.             if (!SHRestricted(REST_NOSETFOLDERS))
  361.             {
  362.                 if (SHRestricted(REST_NOCONTROLPANEL))
  363.                     g_asDrivesReqItems[CDRIVES_REGITEM_CONTROL].dwAttributes |= SFGAO_NONENUMERATED;
  364.                     
  365.                 CRegFolder_CreateInstance(&g_sDrivesRegInfo,
  366.                                           (IUnknown*) (IShellFolder2*) pDF,
  367.                                           IID_IUnknown,
  368.                                           (void **) &pDF->_punkReg);
  369.             }
  370.             if (SHInterlockedCompareExchange((void**) &CDrivesFolder::_spThis, pDF, NULL))
  371.             {
  372.                 // Someone else snuck in and initialized a CDrivesFolder first,
  373.                 // so release our object and then recurse so we should get the other instance
  374.                 pDF->Release();
  375.                 hres = CDrives_CreateInstance(punkOuter, riid, ppv);
  376.             }
  377.             else
  378.             {
  379.                 hres = pDF->QueryInterface(riid, ppv);
  380.                 // release the self-reference, but keep _spThis intact
  381.                 // (it will be reset to NULL in the destructor)
  382.                 pDF->Release();
  383.             }
  384.         }
  385.         else
  386.         {
  387.             hres = E_OUTOFMEMORY;
  388.             *ppv = NULL;
  389.         }
  390.     }
  391.     return hres;
  392. }
  393. // This should only be called during process detach
  394. void CDrives_Terminate(void)
  395. {
  396.     if (NULL != CDrivesFolder::_spThis)
  397.     {
  398.         delete CDrivesFolder::_spThis;
  399.     }
  400. }
  401. CDrivesFolder::CDrivesFolder(IUnknown* punkOuter) : 
  402.     CAggregatedUnknown      (punkOuter),
  403.     _punkReg                (NULL)
  404. {
  405.     DllAddRef();
  406. }
  407. CDrivesFolder::~CDrivesFolder()
  408. {
  409.     SHReleaseInnerInterface(SAFECAST(this, IShellFolder *), &_punkReg);
  410.     SHInterlockedCompareExchange((void**) &CDrivesFolder::_spThis, NULL, this);
  411.     DllRelease();
  412. }
  413. HRESULT CDrivesFolder::v_InternalQueryInterface(REFIID riid, void** ppv)
  414. {
  415.     static const QITAB qit[] = {
  416.         QITABENT(CDrivesFolder, IShellFolder2),                        // IID_IShellFolder2
  417.         QITABENTMULTI(CDrivesFolder, IShellFolder, IShellFolder2),     // IID_IShellFolder
  418.         QITABENT(CDrivesFolder, IPersistFolder2),                      // IID_IPersistFolder2
  419.         QITABENTMULTI(CDrivesFolder, IPersistFolder, IPersistFolder2), // IID_IPersistFolder
  420.         QITABENTMULTI(CDrivesFolder, IPersist, IPersistFolder2),       // IID_IPersist
  421.         QITABENTMULTI2(CDrivesFolder, IID_IPersistFreeThreadedObject, IPersist), // IID_IPersistFreeThreadedObject
  422.         QITABENT(CDrivesFolder, IShellIconOverlay),                    // IID_IShellIconOverlay
  423.         { 0 },
  424.     };
  425.     if (_punkReg && (IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IShellFolder2)))
  426.     {
  427.         return _punkReg->QueryInterface(riid, ppv);
  428.     }
  429.     else
  430.     {
  431.         HRESULT hr = QISearch(this, qit, riid, ppv);
  432.         if ((E_NOINTERFACE == hr) && (NULL != _punkReg))
  433.         {
  434.             return _punkReg->QueryInterface(riid, ppv);
  435.         }
  436.         else
  437.         {
  438.             return hr;
  439.         }
  440.     }
  441. }
  442. BOOL CDrivesFolder::v_HandleDelete(PLONG pcRef)
  443. {
  444.     ASSERT(NULL != pcRef);
  445.     ENTERCRITICAL;
  446.     //
  447.     //  The same bad thing can happen here as in
  448.     //  CNetRootFolder::v_HandleDelete.  See that function for gory details.
  449.     //
  450.     if (this == _spThis && 0 == *pcRef)
  451.     {
  452.         *pcRef = 1000; // protect against cached pointers bumping us up then down
  453.         delete this;
  454.     }
  455.     LEAVECRITICAL;
  456.     // return TRUE to indicate that we've implemented this function
  457.     // (regardless of whether or not this object was actually deleted)
  458.     return TRUE;
  459. }
  460. HRESULT CDrivesFolder::_GetDisplayName(LPCIDDRIVE pidd, LPTSTR pszName, UINT cchMax)
  461. {
  462.     HRESULT hres = E_FAIL;
  463.     CMountPoint* pMtPt = CMountPoint::GetMountPoint(DRIVEID(pidd->cName));
  464.     if (pMtPt)
  465.     {
  466.         hres = pMtPt->GetDisplayName(pszName, cchMax);
  467.         pMtPt->Release();
  468.     }
  469.     return hres;
  470. }
  471. HRESULT CDrivesFolder::_GetDisplayNameStrRet(LPCIDDRIVE pidd, STRRET *pStrRet)
  472. {
  473.     HRESULT hres = E_FAIL;
  474.     CMountPoint* pMtPt = CMountPoint::GetMountPoint(DRIVEID(pidd->cName));
  475.     if (pMtPt)
  476.     {
  477.         TCHAR szName[MAX_DISPLAYNAME];
  478.         hres = pMtPt->GetDisplayName(szName, ARRAYSIZE(szName));
  479.         if (SUCCEEDED(hres))
  480.             hres = StringToStrRet(szName, pStrRet);
  481.         pMtPt->Release();
  482.     }
  483.     return hres;
  484. }
  485. int CDrivesFolder::_GetSHID(int iDrive)
  486. {
  487.     int bType = SHID_COMPUTER_MISC;
  488.     CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive);
  489.     if (pMtPt)
  490.     {
  491.         bType = pMtPt->GetSHIDType(FALSE);
  492.         pMtPt->Release();
  493.     }
  494.     return bType;
  495. }
  496. // hash the display name to detect volume lable and other changes on the drive
  497. WORD DriveNameHash(LPCTSTR pszDriveName)
  498. {
  499.     BYTE bCheckPlus, bCheckXor;
  500.     bCheckXor = bCheckPlus = (BYTE)*pszDriveName;
  501.     for (pszDriveName = CharNext(pszDriveName); *pszDriveName; pszDriveName = CharNext(pszDriveName))
  502.     {
  503.         bCheckPlus += (BYTE)*pszDriveName;
  504.         bCheckXor = (bCheckXor << 1) ^ (BYTE)*pszDriveName;
  505.     }
  506.     return (WORD)bCheckPlus << 8 | (WORD)bCheckXor;
  507. }
  508. void CDrivesFolder::_FillIDDrive(DRIVE_IDLIST *piddl, int iDrive, BOOL bSimple)
  509. {
  510.     TCHAR szDriveName[MAX_PATH];
  511.     if (!CMountPoint::GetDriveIDList(iDrive, piddl))
  512.     {
  513.         memset(piddl, 0, sizeof(*piddl));
  514.         piddl->idd.bFlags = bSimple ? SHID_COMPUTER_MISC : (BYTE)_GetSHID(iDrive);
  515.         PathBuildRoot(szDriveName, iDrive);
  516.         SHTCharToAnsi(szDriveName, piddl->idd.cName, ARRAYSIZE(piddl->idd.cName));
  517.         if (!bSimple)
  518.         {
  519.             _GetDisplayName(&piddl->idd, szDriveName, ARRAYSIZE(szDriveName));
  520.             piddl->idd.wChecksum = DriveNameHash(szDriveName);
  521.         }
  522.         piddl->idd.cb = SIZEOF(IDDRIVE);
  523.         ASSERT(piddl->cbNext == 0);
  524.         if (!bSimple)
  525.             CMountPoint::SetDriveIDList(iDrive, piddl);
  526.     }
  527. }
  528. STDMETHODIMP CDrivesFolder::ParseDisplayName(HWND hwnd, LPBC pbc,
  529.                                              LPOLESTR pwzDisplayName, ULONG* pchEaten,
  530.                                              LPITEMIDLIST* ppidlOut, ULONG* pdwAttributes)
  531. {
  532.     HRESULT hres = E_INVALIDARG;
  533.     *ppidlOut = NULL;   // assume error
  534.     if (pwzDisplayName && pwzDisplayName[0] && 
  535.         pwzDisplayName[1] == TEXT(':') && pwzDisplayName[2] == TEXT('\'))
  536.     {
  537.         DRIVE_IDLIST idlDrive;
  538.         UINT iDrive;
  539.         if (InRange(*pwzDisplayName, 'a', 'z'))
  540.         {
  541.             iDrive = *pwzDisplayName - 'a';
  542.         }
  543.         else if (InRange(*pwzDisplayName, 'A', 'Z'))
  544.         {
  545.             iDrive = *pwzDisplayName - 'A';
  546.         }
  547.         else
  548.         {
  549.             TraceMsg(TF_WARNING, "CDrivesFolder::ParseDisplayName(), failing:%hs", pwzDisplayName);
  550.             return E_INVALIDARG;
  551.         }
  552.         _FillIDDrive(&idlDrive, iDrive, SHIsFileSysBindCtx(pbc, NULL) == S_OK);
  553.         // Check if there are any subdirs
  554.         if (pwzDisplayName[3])
  555.         {
  556.             IShellFolder *psfDrive;
  557.             hres = BindToObject((LPITEMIDLIST)&idlDrive, pbc, IID_IShellFolder, (void **) &psfDrive);
  558.             if (SUCCEEDED(hres))
  559.             {
  560.                 ULONG chEaten;
  561.                 LPITEMIDLIST pidlDir;
  562.                 hres = psfDrive->ParseDisplayName(  hwnd,
  563.                                                     pbc,
  564.                                                     pwzDisplayName + 3,
  565.                                                     &chEaten,
  566.                                                     &pidlDir,
  567.                                                     pdwAttributes);
  568.                 if (SUCCEEDED(hres))
  569.                 {
  570.                     hres = SHILCombine((LPCITEMIDLIST)&idlDrive, pidlDir, ppidlOut);
  571.                     SHFree(pidlDir);
  572.                 }
  573.                 psfDrive->Release();
  574.             }
  575.         }
  576.         else
  577.         {
  578.             hres = SHILClone((LPITEMIDLIST)&idlDrive, ppidlOut);
  579.             if (pdwAttributes && *pdwAttributes)
  580.                 GetAttributesOf(1, (LPCITEMIDLIST*) ppidlOut, pdwAttributes);
  581.         }
  582.     }
  583. #ifdef WINNT
  584.     else
  585.     {//check if dealing with mounteddrive
  586.      //something like: "\?Volume{9e2df3f5-c7f1-11d1-84d5-000000000000}" (without quotes)
  587.         if (0 == StrCmpNI(c_szVolumeNamePrefix, pwzDisplayName, ARRAYSIZE(c_szVolumeNamePrefix)))
  588.         {
  589.             TraceMsg(TF_WARNING, "CDrivesFolder::ParseDisplayName(), Volume GUID (%ls)", pwzDisplayName);
  590.             //fail anyway, not implemented yet
  591.         }
  592.     }
  593. #endif
  594.     if (FAILED(hres))
  595.         TraceMsg(TF_WARNING, "CDrivesFolder::ParseDisplayName(), hres:%x %ls", hres, pwzDisplayName);
  596.     return hres;
  597. }
  598. STDMETHODIMP CDrivesFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumUnknown)
  599. {
  600.     // We should always create enum objects with this helper call.
  601.     EnumDrives * pedrv = (EnumDrives *)LocalAlloc(LPTR, SIZEOF(EnumDrives));
  602.     if (pedrv)
  603.     {
  604.         pedrv->dwDrivesMask = GetLogicalDrives();
  605.         pedrv->nLastFoundDrive = -1;
  606.         pedrv->dwRestricted = SHRestricted(REST_NODRIVES);
  607.         pedrv->dwSavedErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  608.         pedrv->grfFlags = grfFlags;
  609.         return SHCreateEnumObjects(hwnd, pedrv, EnumCallBack, ppenumUnknown);
  610.     }
  611.     else
  612.     {
  613.         *ppenumUnknown = NULL;
  614.         return E_OUTOFMEMORY;
  615.     }
  616. }
  617. LPCIDDRIVE CDrivesFolder::_IsValidID(LPCITEMIDLIST pidl)
  618. {
  619.     if (pidl && (SIL_GetType(pidl) & SHID_GROUPMASK) == SHID_COMPUTER)
  620.         return (LPCIDDRIVE)pidl;
  621.     return NULL;
  622. }
  623. HRESULT CDrivesFolder::_CreateFSFolder(LPCITEMIDLIST pidlDrive, LPCIDDRIVE pidd, REFIID riid, void **ppv)
  624. {
  625.     PERSIST_FOLDER_TARGET_INFO pfti = {0};
  626.     
  627.     pfti.pidlTargetFolder = (LPITEMIDLIST)pidlDrive;
  628.     SHAnsiToUnicode(pidd->cName, pfti.szTargetParsingName, ARRAYSIZE(pfti.szTargetParsingName));
  629.     pfti.dwAttributes = FILE_ATTRIBUTE_DIRECTORY; // maybe add system?
  630.     pfti.csidl = -1;
  631.     return CFSFolder_CreateFolder(NULL, pidlDrive, &pfti, riid, ppv);
  632. }
  633. STDMETHODIMP CDrivesFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppv)
  634. {
  635.     HRESULT hres;
  636.     LPCIDDRIVE pidd;
  637.     *ppv = NULL;
  638.     pidd = _IsValidID(pidl);
  639.     if (pidd)
  640.     {
  641.         LPCITEMIDLIST pidlNext = _ILNext(pidl);
  642.         LPITEMIDLIST pidlDrive = ILCombineParentAndFirst(IDLIST_DRIVES, pidl, pidlNext);
  643.         if (pidlDrive)
  644.         {
  645.             //  we only try ask for the riid at the end of the pidl binding.
  646.             if (ILIsEmpty(pidlNext))
  647.             {
  648.                 hres = _CreateFSFolder(pidlDrive, pidd, riid, ppv);
  649.             }
  650.             else
  651.             {
  652.                 //  now we need to get the subfolder from which to grab our goodies
  653.                 IShellFolder *psfDrive;
  654.                 hres = _CreateFSFolder(pidlDrive, pidd, IID_IShellFolder, (void **)&psfDrive);
  655.                 if (SUCCEEDED(hres))
  656.                 {
  657.                     //  this means that there is more to bind to, we must pass it on...
  658.                     hres = psfDrive->BindToObject(pidlNext, pbc, riid, ppv);
  659.                     psfDrive->Release();
  660.                 }
  661.             }
  662.             ILFree(pidlDrive);
  663.         }
  664.         else
  665.             hres = E_OUTOFMEMORY;
  666.     }
  667.     else
  668.     {
  669.         hres = E_INVALIDARG;
  670.         TraceMsg(TF_WARNING, "CDrivesFolder::BindToObject(), bad PIDL %s", DumpPidl(pidl));
  671.     }
  672.     return hres;
  673. }
  674. STDMETHODIMP CDrivesFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppv)
  675. {
  676.     ASSERT(NULL != ppv);
  677.     *ppv = NULL;
  678.     return E_NOTIMPL;
  679. }
  680. STDAPI_(void) CDrivesFolder::_GetTypeString(BYTE bFlags, LPTSTR pszName, UINT cbName)
  681. {
  682.     CMountPoint::GetTypeString(bFlags, pszName, cbName);
  683. }
  684. BOOL CDrivesFolder::_GetFreeSpace(LPCIDDRIVE pidd, ULONGLONG *pSize, ULONGLONG *pFree)
  685. {
  686.     BOOL bRet = FALSE;
  687.     if (!_IsReg(pidd) && ShowDriveInfo(DRIVEID(pidd->cName)))
  688.     {
  689.         if (pidd->qwSize || pidd->qwFree)
  690.         {
  691.             *pSize = pidd->qwSize;      // cache hit
  692.             *pFree = pidd->qwFree;
  693.             bRet = TRUE;
  694.         }
  695.         else
  696.         {
  697.             int iDrive = DRIVEID(pidd->cName);
  698.             // Don't wake up sleeping net connections
  699.             if (!IsRemoteDrive(iDrive) || !IsDisconnectedNetDrive(iDrive))
  700.             {
  701.                 // Call our helper function Who understands
  702.                 // OSR2 and NT as well as old W95...
  703.                 ULARGE_INTEGER qwFreeUser, qwTotal, qwTotalFree;
  704.                 bRet = SHGetDiskFreeSpaceExA(pidd->cName, &qwFreeUser, &qwTotal, &qwTotalFree);
  705.                 if (bRet)
  706.                 {
  707.                     *pSize = qwTotal.QuadPart;
  708.                     *pFree = qwFreeUser.QuadPart;
  709.                 }
  710.             }
  711.         }
  712.     }
  713.     return bRet;
  714. }
  715. STDMETHODIMP CDrivesFolder::CompareIDs(LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  716. {
  717.     HRESULT hres;
  718.     LPCIDDRIVE pidd1 = _IsValidID(pidl1);
  719.     LPCIDDRIVE pidd2 = _IsValidID(pidl2);
  720.     if (!pidd1 || !pidd2)
  721.     {
  722.         TraceMsg(TF_WARNING, "CDrivesFolder::CompareIDs(), bad(s) pidl11:%s, pidl2:%s", DumpPidl(pidl1), DumpPidl(pidl2));
  723.         return E_INVALIDARG;
  724.     }
  725.     //
  726.     //  For any column other than DRIVES_ICOL_NAME, we force an
  727.     //  all-fields comparison to break ties.
  728.     //
  729.     if ((iCol & SHCIDS_COLUMNMASK) != DRIVES_ICOL_NAME) 
  730.         iCol |= SHCIDS_ALLFIELDS;
  731.     switch (iCol & SHCIDS_COLUMNMASK) {
  732.     default:                    // If asking for unknown column, just use name
  733.     case DRIVES_ICOL_NAME:
  734.         hres = ResultFromShort(StrCmpICA(pidd1->cName, pidd2->cName));
  735.         break;
  736.     case DRIVES_ICOL_TYPE:
  737.     {
  738.         TCHAR szName1[80], szName2[80];
  739.         _GetTypeString(pidd1->bFlags, szName1, ARRAYSIZE(szName1));
  740.         _GetTypeString(pidd2->bFlags, szName2, ARRAYSIZE(szName2));
  741.         hres = ResultFromShort(ustrcmpi(szName1, szName2));
  742.         break;
  743.     }
  744.     case DRIVES_ICOL_SIZE:
  745.     case DRIVES_ICOL_FREE:
  746.         {
  747.             ULONGLONG qwSize1, qwFree1;
  748.             ULONGLONG qwSize2, qwFree2;
  749.             BOOL fGotInfo1 = _GetFreeSpace(pidd1, &qwSize1, &qwFree1);
  750.             BOOL fGotInfo2 = _GetFreeSpace(pidd2, &qwSize2, &qwFree2);
  751.             if (fGotInfo1 && fGotInfo2) 
  752.             {
  753.                 ULONGLONG i1, i2;  // this is a "guess" at the disk size and free space
  754.                 if ((iCol & SHCIDS_COLUMNMASK) == DRIVES_ICOL_SIZE)
  755.                 {
  756.                     i1 = qwSize1;
  757.                     i2 = qwSize2;
  758.                 } 
  759.                 else 
  760.                 {
  761.                     i1 = qwFree1;
  762.                     i2 = qwFree2;
  763.                 }
  764.                 if (i1 == i2)
  765.                     hres = ResultFromShort(0);
  766.                 else if (i1 < i2)
  767.                     hres = ResultFromShort(-1);
  768.                 else
  769.                     hres = ResultFromShort(1);
  770.             } 
  771.             else if (!fGotInfo1 && !fGotInfo2) 
  772.             {
  773.                 hres = ResultFromShort(0);
  774.             } 
  775.             else 
  776.             {
  777.                 hres = ResultFromShort(fGotInfo1 - fGotInfo2);
  778.             }
  779.         }
  780.         break;
  781.     }
  782.     // if they were the same so far, and we forcing an all-fields
  783.     // comparison, then use the all-fields comparison to break ties.
  784.     //
  785.     if (hres == S_OK && (iCol & SHCIDS_ALLFIELDS)) 
  786.         hres = CompareItemIDs(pidd1, pidd2);
  787.     //
  788.     //  If the items are still the same, then ask ILCompareRelIDs
  789.     //  to walk recursively to the next ids.
  790.     //
  791.     if (hres == S_OK)
  792.         hres = ILCompareRelIDs((IShellFolder*) this, pidl1, pidl2);
  793.     return hres;
  794. }
  795. STDMETHODIMP CDrivesFolder::CreateViewObject(HWND hwnd, REFIID riid, void** ppv)
  796. {
  797.     // We should not get here unless we have initialized properly
  798.     if (IsEqualIID(riid, IID_IShellView))
  799.     {
  800.         SFV_CREATE sSFV;
  801.         HRESULT hres;
  802.         sSFV.cbSize   = sizeof(sSFV);
  803.         sSFV.psvOuter = NULL;
  804.         sSFV.psfvcb   = CDrives_CreateSFVCB((IShellFolder*) this);
  805.         QueryInterface(IID_IShellFolder, (void **)&sSFV.pshf);   // in case we are agregated
  806.         hres = SHCreateShellFolderView(&sSFV, (IShellView**)ppv);
  807.         if (sSFV.pshf)
  808.             sSFV.pshf->Release();
  809.         if (sSFV.psfvcb)
  810.             sSFV.psfvcb->Release();
  811.         return hres;
  812.     }
  813.     else if (IsEqualIID(riid, IID_IDropTarget))
  814.     {
  815.         return CIDLDropTarget_Create(hwnd, &c_CDrivesDropTargetVtbl,
  816.                         IDLIST_DRIVES, (IDropTarget **)ppv);
  817.     }
  818.     else if (IsEqualIID(riid, IID_IContextMenu))
  819.     {
  820.         return CDefFolderMenu_Create(IDLIST_DRIVES, hwnd, 0, NULL, 
  821.             (IShellFolder*) this, CDrives_DFMCallBackBG, NULL, NULL, (IContextMenu **)ppv);
  822.     }
  823.     *ppv = NULL;
  824.     return E_NOINTERFACE;
  825. }
  826. STDMETHODIMP CDrivesFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* prgfInOut)
  827. {
  828.     UINT rgfOut = SFGAO_HASSUBFOLDER | SFGAO_CANLINK | SFGAO_CANMONIKER
  829.                 | SFGAO_DROPTARGET | SFGAO_HASPROPSHEET | SFGAO_FOLDER
  830.                 | SFGAO_FILESYSTEM | SFGAO_FILESYSANCESTOR | SFGAO_FOLDER;
  831.     if (cidl == 0)
  832.     {
  833.         if (*prgfInOut & SFGAO_VALIDATE)
  834.             InvalidateDriveType(-1);    // nuke all the cached drive types on a real refresh (F5)
  835.         // We are getting the attributes for the "MyComputer" folder itself.
  836.         rgfOut = (*prgfInOut & g_asDesktopReqItems[CDESKTOP_REGITEM_DRIVES].dwAttributes);
  837.     }
  838.     else if (cidl == 1)
  839.     {
  840.         TCHAR szDrive[MAX_PATH];
  841.         LPIDDRIVE pidd = (LPIDDRIVE)apidl[0];
  842.         SHAnsiToTChar(pidd->cName, szDrive, ARRAYSIZE(szDrive));
  843.         // If caller wants compression status, we need to ask the filesystem
  844.         if (*prgfInOut & SFGAO_COMPRESSED)
  845.         {
  846.             int iDrive = DRIVEID(pidd->cName);
  847.             // Don't wake up sleeping net connections
  848.             if (!IsRemoteDrive(iDrive) || !IsDisconnectedNetDrive(iDrive))
  849.             {
  850.                 if (CMountPoint::IsCompressed(iDrive))
  851.                     rgfOut |= SFGAO_COMPRESSED;
  852.             }
  853.         }
  854.         if (*prgfInOut & SFGAO_SHARE)
  855.         {
  856.             if (IsShared(szDrive, FALSE))
  857.                 rgfOut |= SFGAO_SHARE;
  858.         }
  859.         if ((*prgfInOut & SFGAO_REMOVABLE) && TypeIsRemoveable(pidd))
  860.             rgfOut |= SFGAO_REMOVABLE;
  861.         // we need to also handle the SFGAO_READONLY bit.
  862.         if (*prgfInOut & SFGAO_READONLY)
  863.         {
  864.             DWORD dwErrMode = SetErrorMode(SEM_FAILCRITICALERRORS);
  865.             DWORD dwAttributes = GetFileAttributes(szDrive);
  866.     
  867.             SetErrorMode(dwErrMode);
  868.     
  869.             if (dwAttributes != -1 && dwAttributes & FILE_ATTRIBUTE_READONLY)
  870.                 rgfOut |= SFGAO_READONLY;
  871.         }
  872.         if ((*prgfInOut & SFGAO_CANRENAME) && 
  873.             (TypeIsRemoveable(pidd) || pidd->bFlags == SHID_COMPUTER_FIXED
  874.             || pidd->bFlags == SHID_COMPUTER_NETDRIVE))
  875.         {
  876.             rgfOut |= SFGAO_CANRENAME;
  877.         }
  878.     }
  879.     *prgfInOut = rgfOut;
  880.     return NOERROR;
  881. }
  882. HRESULT CDrivesFolder::_GetEditTextStrRet(LPCIDDRIVE pidd, STRRET *pstr)
  883. {
  884.     HRESULT hres = E_FAIL;
  885.     TCHAR szEdit[MAX_PATH];
  886.     CMountPoint* pMtPt = CMountPoint::GetMountPoint(DRIVEID(pidd->cName));
  887.     if (pMtPt)
  888.     {
  889.         hres = pMtPt->GetLabel(szEdit, ARRAYSIZE(szEdit));
  890.         pMtPt->Release();
  891.     }
  892.     if (SUCCEEDED(hres))
  893.         hres = StringToStrRet(szEdit, pstr);
  894.     return hres;
  895. }
  896. STDMETHODIMP CDrivesFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET* pStrRet)
  897. {
  898.     HRESULT hres;
  899.     LPCIDDRIVE pidd = _IsValidID(pidl);
  900.     if (pidd)
  901.     {
  902.         TCHAR szDrive[ARRAYSIZE(pidd->cName)];
  903.         LPCITEMIDLIST pidlNext = _ILNext(pidl); // Check if pidl contains more than one ID
  904.         SHAnsiToTChar(pidd->cName, szDrive, ARRAYSIZE(szDrive));
  905.         if (ILIsEmpty(pidlNext))
  906.         {
  907.             if (uFlags & SHGDN_FORPARSING)
  908.             {
  909.                 hres = StringToStrRet(szDrive, pStrRet);
  910.             }
  911.             else if (uFlags & SHGDN_FOREDITING)
  912.             {
  913.                 hres = _GetEditTextStrRet(pidd, pStrRet);
  914.             }
  915.             else
  916.                 hres = _GetDisplayNameStrRet(pidd, pStrRet);
  917.         }
  918.         else
  919.         {
  920.             LPITEMIDLIST pidlDrive = ILCombineParentAndFirst(IDLIST_DRIVES, pidl, pidlNext);
  921.             if (pidlDrive)
  922.             {
  923.                 //  now we need to get the subfolder from which to grab our goodies
  924.                 IShellFolder *psfDrive;
  925.                 hres = _CreateFSFolder(pidlDrive, pidd, IID_IShellFolder, (void **)&psfDrive);
  926.                 if (SUCCEEDED(hres))
  927.                 {
  928.                     hres = psfDrive->GetDisplayNameOf(pidlNext, uFlags, pStrRet);
  929.                     psfDrive->Release();
  930.                 }
  931.                 ILFree(pidlDrive);
  932.             }
  933.             else
  934.                 hres = E_OUTOFMEMORY;
  935.         }
  936.     }
  937.     else
  938.     {
  939.         hres = E_INVALIDARG;
  940.         TraceMsg(TF_WARNING, "CDrivesFolder::GetDisplayNameOf() bad PIDL %s", DumpPidl(pidl));
  941.     }
  942.     return hres;
  943. }
  944. STDMETHODIMP CDrivesFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, 
  945.                                       LPCWSTR pszName, DWORD dwReserved, LPITEMIDLIST* ppidlOut)
  946. {
  947.     HRESULT hr = E_INVALIDARG;
  948.     LPCIDDRIVE pidd = _IsValidID(pidl);
  949.     if (pidd)
  950.     {
  951.         TCHAR szName[MAX_LABEL_NTFS + 1];
  952.         if (ppidlOut)
  953.             *ppidlOut = NULL;
  954.         SHUnicodeToTChar(pszName, szName, ARRAYSIZE(szName));
  955.         // BUGBUG: We need to impl ::SetSite() and pass it to SetDriveLabel
  956.         //         to go modal if we display UI.
  957.         hr = SetDriveLabel(hwnd, NULL, DRIVEID(pidd->cName), szName);
  958.     }
  959.     return hr;
  960. }
  961. BOOL CDrivesFolder::_GetFreeSpaceString(LPCIDDRIVE pidd, LPTSTR szBuf, UINT cchBuf)
  962. {
  963.     ULONGLONG qwSize, qwFree;
  964.     BOOL bRet = _GetFreeSpace(pidd, &qwSize, &qwFree);
  965.     if (bRet)
  966.     {
  967.         TCHAR szFree[30], szTotal[30];
  968.         StrFormatByteSize64(qwSize, szTotal, ARRAYSIZE(szTotal));
  969.         StrFormatByteSize64(qwFree, szFree, ARRAYSIZE(szFree));
  970.         LPTSTR psz = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_DRIVESSTATUSTEMPLATE),
  971.                         szFree, szTotal);
  972.         if (psz)
  973.         {
  974.             StrCpyN(szBuf, psz, cchBuf);
  975.             LocalFree(psz);
  976.         }
  977.         else
  978.         {
  979.             bRet = FALSE;
  980.         }
  981.     }
  982.     return bRet;
  983. }
  984. HKEY _GetDriveKey(int iDrive)
  985. {
  986.     HKEY hkRet = NULL;
  987.     if (CMountPoint::IsAudioCD(iDrive))
  988.     {
  989.         RegOpenKey(HKEY_CLASSES_ROOT, TEXT("AudioCD"), &hkRet);
  990.     }
  991.     else if (CMountPoint::IsAutoRun(iDrive))
  992.     {
  993.         CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive);
  994.         if (pMtPt)
  995.         {
  996.             hkRet = pMtPt->GetRegKey();
  997.             pMtPt->Release();
  998.         }
  999.     }
  1000.     else if (CMountPoint::IsDVD(iDrive))
  1001.     {
  1002.         RegOpenKey(HKEY_CLASSES_ROOT, TEXT("DVD"), &hkRet);
  1003.     }
  1004.     else
  1005.     {
  1006.         CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive);
  1007.         if (pMtPt)
  1008.         {
  1009.             hkRet = pMtPt->GetRegKey();
  1010.             pMtPt->Release();
  1011.         }
  1012.     }
  1013.     return hkRet;
  1014. }
  1015. void CDrives_GetKeys(LPCIDDRIVE pidd, HKEY *keys)
  1016. {
  1017.     keys[0] = NULL;
  1018.     keys[1] = NULL;
  1019.     keys[2] = NULL;
  1020.     if (pidd)
  1021.         keys[0] = _GetDriveKey(DRIVEID(pidd->cName));
  1022.     RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Drive"), &keys[1]);
  1023.     RegOpenKey(HKEY_CLASSES_ROOT, c_szFolderClass, &keys[2]);
  1024. }
  1025. HRESULT CDrives_AssocCreate(LPCIDDRIVE pidd, REFIID riid, void **ppv)
  1026. {
  1027.     IQueryAssociations *pqa;
  1028.     HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_IQueryAssociations, (LPVOID*)&pqa);
  1029.     *ppv = NULL;
  1030.     
  1031.     if (SUCCEEDED(hr))
  1032.     {
  1033.         HKEY hkDrive = _GetDriveKey(DRIVEID(pidd->cName));
  1034.         if (hkDrive)
  1035.         {
  1036.             hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, NULL, hkDrive, NULL);
  1037.             RegCloseKey(hkDrive);
  1038.         }
  1039.         else
  1040.             hr = pqa->Init(ASSOCF_INIT_DEFAULTTOFOLDER, L"Drive", NULL, NULL);
  1041.         if (SUCCEEDED(hr))
  1042.             hr = pqa->QueryInterface(riid, ppv);
  1043.         pqa->Release();
  1044.     }
  1045.     return hr;
  1046. }
  1047. // BUGBUG (stephstm) - remove this
  1048. const ICONMAP c_aicmpDrive[] = {
  1049.     { SHID_COMPUTER_DRIVE525 , II_DRIVE525      },
  1050.     { SHID_COMPUTER_DRIVE35  , II_DRIVE35       },
  1051.     { SHID_COMPUTER_FIXED    , II_DRIVEFIXED    },
  1052.     { SHID_COMPUTER_REMOTE   , II_DRIVEFIXED    },
  1053.     { SHID_COMPUTER_CDROM    , II_DRIVECD       },
  1054.     { SHID_COMPUTER_NETDRIVE , II_DRIVENET      },
  1055.     { SHID_COMPUTER_REMOVABLE, II_DRIVEREMOVE   },
  1056.     { SHID_COMPUTER_RAMDISK  , II_DRIVERAM      },
  1057. };
  1058. const int c_nicmpDrives = ARRAYSIZE(c_aicmpDrive);
  1059. STDMETHODIMP CDrivesFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl,
  1060.                                           REFIID riid, UINT* prgfInOut, void** ppv)
  1061. {
  1062.     HRESULT hres;
  1063.     HKEY keys[3];
  1064.     IDDRIVE idDrive;
  1065.     LPCIDDRIVE pidd = (cidl && apidl) ? _IsValidID(apidl[0]) : NULL;
  1066.     *ppv = NULL;
  1067.     if (pidd == NULL)
  1068.         return E_INVALIDARG;
  1069.     if (pidd->bFlags == SHID_COMPUTER_MISC)
  1070.     {
  1071.         // deal with simple IDLISTs
  1072.         idDrive.cb = SIZEOF(idDrive);
  1073.         idDrive.cName[0] = pidd->cName[0];
  1074.         idDrive.cName[1] = TEXT(':');
  1075.         idDrive.cName[2] = 0;
  1076.         idDrive.bFlags = (BYTE) _GetSHID(DRIVEID(pidd->cName));
  1077.         pidd = &idDrive;
  1078.     }
  1079.     if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW) && pidd)
  1080.     {
  1081.         UINT iIndex = SILGetIconIndex((LPCITEMIDLIST)pidd, c_aicmpDrive, c_nicmpDrives);
  1082.         CDrives_GetKeys(pidd, keys);
  1083.         switch (pidd->bFlags & SHID_TYPEMASK) 
  1084.         {
  1085.         case SHID_COMPUTER_CDROM:
  1086.         {
  1087.             TCHAR szIconPath[MAX_PATH];
  1088.             LONG cbIconPath = ARRAYSIZE(szIconPath) * sizeof(TCHAR);
  1089.             if (CMountPoint::IsAudioCD(DRIVEID(pidd->cName)))
  1090.                 iIndex = II_CDAUDIO;
  1091.             // BUGBUG: (?) maybe we should check for the presence of a CD instead.  Here if the icon
  1092.             // is in shell32.dll for ex, then even if there is no CD in the drive we'll still have the
  1093.             // icon (stephstm)
  1094.             if (SHRegQueryValue(keys[0], c_szDefaultIcon, szIconPath, &cbIconPath) == ERROR_SUCCESS &&
  1095.                 szIconPath[0])
  1096.             {
  1097.                 int iIcon = PathParseIconLocation(szIconPath);
  1098.                 if (!PathFileExistsAndAttributes(szIconPath, NULL))
  1099.                 {
  1100.                     SHDeleteValue(keys[0], c_szDefaultIcon, NULL);
  1101.                 }
  1102.             }
  1103.             break;
  1104.         }
  1105.         case SHID_COMPUTER_NETDRIVE:
  1106.             if (IsUnavailableNetDrive(DRIVEID(pidd->cName)) ||
  1107.                 IsDisconnectedNetDrive(DRIVEID(pidd->cName)))
  1108.             {
  1109.                 iIndex = II_DRIVENETDISABLED;
  1110.             }
  1111.             
  1112.             break;
  1113.         // bFlags stays SHID_COMPUTER_MISC if the drive is bogus.
  1114.         case SHID_COMPUTER_MISC:
  1115.             iIndex = -IDI_DRIVEUNKNOWN;
  1116.             break;
  1117.         }
  1118.         hres = SHCreateDefExtIconKey(keys[0], NULL, iIndex, iIndex, GIL_PERCLASS, riid, ppv);
  1119.         SHRegCloseKeys(keys, ARRAYSIZE(keys));
  1120.     }
  1121.     else if (IsEqualIID(riid, IID_IContextMenu))
  1122.     {
  1123.         CDrives_GetKeys(pidd, keys);
  1124.         hres = CDefFolderMenu_Create2(IDLIST_DRIVES, hwnd, cidl, apidl, 
  1125.             (IShellFolder*) this, CDrives_DFMCallBack, ARRAYSIZE(keys), keys, (IContextMenu **)ppv);
  1126.         SHRegCloseKeys(keys, ARRAYSIZE(keys));
  1127.     }
  1128.     else if (IsEqualIID(riid, IID_IDataObject))
  1129.     {
  1130.         hres = FS_CreateFSIDArray(IDLIST_DRIVES, cidl, apidl, NULL, (IDataObject **)ppv);
  1131.     }
  1132.     else if (IsEqualIID(riid, IID_IDropTarget) && pidd)
  1133.     {
  1134.         IShellFolder *psfT;
  1135.         hres = BindToObject((LPCITEMIDLIST)pidd, NULL, IID_IShellFolder, (void **)&psfT);
  1136.         if (SUCCEEDED(hres))
  1137.         {
  1138.             hres = psfT->CreateViewObject(hwnd, IID_IDropTarget, ppv);
  1139.             psfT->Release();
  1140.         }
  1141.     }
  1142.     else if (IsEqualIID(riid, IID_IQueryInfo) && pidd)
  1143.     {
  1144.         TCHAR szStatus[80];
  1145.         if (_GetFreeSpaceString(pidd, szStatus, ARRAYSIZE(szStatus)))
  1146.             hres = CreateInfoTipFromText(szStatus, riid, ppv);
  1147.         else
  1148.             hres = E_NOINTERFACE;
  1149.     }
  1150.     else if (IsEqualIID(riid, IID_IQueryAssociations))
  1151.     {
  1152.         hres = CDrives_AssocCreate(pidd, riid, ppv);
  1153.     }
  1154.     else
  1155.     {
  1156.         hres = E_NOINTERFACE;
  1157.     }
  1158.     return hres;
  1159. }
  1160. STDMETHODIMP CDrivesFolder::GetDefaultSearchGUID(LPGUID pGuid)
  1161. {
  1162.     return FindFileOrFolders_GetDefaultSearchGUID((IShellFolder2*) this, pGuid);
  1163. }
  1164. STDMETHODIMP CDrivesFolder::EnumSearches(LPENUMEXTRASEARCH* ppenum)
  1165. {
  1166.     ASSERT(NULL != ppenum);
  1167.     *ppenum = NULL;
  1168.     return E_NOTIMPL;
  1169. }
  1170. STDMETHODIMP CDrivesFolder::GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay)
  1171. {
  1172.     return E_NOTIMPL;
  1173. }
  1174. STDMETHODIMP CDrivesFolder::GetDefaultColumnState(UINT iColumn, DWORD* pdwState)
  1175. {
  1176.     HRESULT hres;
  1177.     *pdwState = 0;
  1178.     if (iColumn < ARRAYSIZE(c_drives_cols))
  1179.     {
  1180.         if ((iColumn != DRIVES_ICOL_COMMENT) && (iColumn != DRIVES_ICOL_HTMLINFOTIPFILE))
  1181.         {
  1182.             *pdwState |= SHCOLSTATE_ONBYDEFAULT;    // The comment column is off by default
  1183.         }
  1184.         else
  1185.         {
  1186.             *pdwState |= SHCOLSTATE_SLOW; // It takes a long time to extract the comment from drives
  1187.             if (iColumn == DRIVES_ICOL_HTMLINFOTIPFILE)
  1188.             {
  1189.                 *pdwState |= SHCOLSTATE_HIDDEN;
  1190.             }
  1191.         }
  1192.         
  1193.         if (iColumn == DRIVES_ICOL_SIZE || iColumn == DRIVES_ICOL_FREE)
  1194.         {
  1195.             *pdwState |= SHCOLSTATE_TYPE_INT;
  1196.         }
  1197.         else
  1198.         {
  1199.             *pdwState |= SHCOLSTATE_TYPE_STR;
  1200.         }
  1201.         hres = S_OK;
  1202.     }
  1203.     else
  1204.     {
  1205.         hres = E_INVALIDARG;
  1206.     }
  1207.     return hres;
  1208. }
  1209. STDMETHODIMP CDrivesFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv)
  1210. {
  1211.     HRESULT hr = E_INVALIDARG;
  1212.     LPCIDDRIVE pidd = _IsValidID(pidl);
  1213.     if (pidd)
  1214.     {
  1215.         if (IsEqualSCID(*pscid, SCID_DESCRIPTIONID))
  1216.         {
  1217.             SHDESCRIPTIONID did;
  1218.             switch(pidd->bFlags)
  1219.             {
  1220.             case SHID_COMPUTER_FIXED:       did.dwDescriptionId = SHDID_COMPUTER_FIXED;       break;
  1221.             case SHID_COMPUTER_RAMDISK:     did.dwDescriptionId = SHDID_COMPUTER_RAMDISK;     break;
  1222.             case SHID_COMPUTER_CDROM:       did.dwDescriptionId = SHDID_COMPUTER_CDROM;       break;
  1223.             case SHID_COMPUTER_NETDRIVE:    did.dwDescriptionId = SHDID_COMPUTER_NETDRIVE;    break;
  1224.             case SHID_COMPUTER_DRIVE525:    did.dwDescriptionId = SHDID_COMPUTER_DRIVE525;    break;
  1225.             case SHID_COMPUTER_DRIVE35:     did.dwDescriptionId = SHDID_COMPUTER_DRIVE35;     break;
  1226.             case SHID_COMPUTER_REMOVABLE:   did.dwDescriptionId = SHDID_COMPUTER_REMOVABLE;   break;
  1227.             default:                        did.dwDescriptionId = SHDID_COMPUTER_OTHER;       break;
  1228.             }
  1229.             did.clsid = CLSID_NULL;
  1230.             hr = InitVariantFromBuffer(pv, (PVOID)&did, sizeof(did));
  1231.         }
  1232.         else
  1233.         {
  1234.             int iCol = FindSCID(c_drives_cols, ARRAYSIZE(c_drives_cols), pscid);
  1235.             if (iCol >= 0)
  1236.             {
  1237.                 switch (iCol)
  1238.                 {
  1239.                 case DRIVES_ICOL_SIZE:
  1240.                 case DRIVES_ICOL_FREE:
  1241.                     {
  1242.                         ULONGLONG ullSize, ullFree;
  1243.                         
  1244.                         hr = E_FAIL;
  1245.                         if (_GetFreeSpace(pidd, &ullSize, &ullFree))
  1246.                         {
  1247.                             pv->vt = VT_UI8;
  1248.                             pv->ullVal = iCol == DRIVES_ICOL_SIZE ? ullSize : ullFree;
  1249.                             hr = S_OK;
  1250.                         }
  1251.                     }
  1252.                     break;
  1253.                 default:
  1254.                     {
  1255.                         SHELLDETAILS sd;
  1256.                         hr = GetDetailsOf(pidl, iCol, &sd);
  1257.                         if (SUCCEEDED(hr))
  1258.                         {
  1259.                             hr = InitVariantFromStrRet(&sd.str, pidl, pv);
  1260.                         }
  1261.                     }
  1262.                 }
  1263.             }
  1264.         }
  1265.     }
  1266.     return hr;
  1267. }
  1268. STDMETHODIMP CDrivesFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, LPSHELLDETAILS lpDetails)
  1269. {
  1270.     TCHAR szTemp[INFOTIPSIZE];
  1271.     
  1272.     if (iColumn >= ARRAYSIZE(c_drives_cols))
  1273.         return E_NOTIMPL;
  1274.     
  1275.     lpDetails->str.uType = STRRET_CSTR;
  1276.     lpDetails->str.cStr[0] = 0;
  1277.     szTemp[0] = 0;
  1278.     
  1279.     if (!pidl)
  1280.     {
  1281.         lpDetails->fmt = c_drives_cols[iColumn].iFmt;
  1282.         lpDetails->cxChar = c_drives_cols[iColumn].cchCol;
  1283.         return ResToStrRet(c_drives_cols[iColumn].ids, &lpDetails->str);
  1284.     }
  1285.     LPCIDDRIVE pidd = _IsValidID(pidl);
  1286.     ASSERTMSG(pidd != NULL, "someone passed us a bad pidl");
  1287.     if (!pidd)
  1288.         return E_FAIL;  // protect faulting code below
  1289.     
  1290.     switch (iColumn)
  1291.     {
  1292.     case DRIVES_ICOL_NAME:
  1293.         _GetDisplayName(pidd, szTemp, ARRAYSIZE(szTemp));
  1294.         break;
  1295.         
  1296.     case DRIVES_ICOL_TYPE:
  1297.         _GetTypeString(pidd->bFlags, szTemp, ARRAYSIZE(szTemp));
  1298.         break;
  1299.         
  1300.     case DRIVES_ICOL_COMMENT:
  1301.         GetDriveComment(DRIVEID(pidd->cName), szTemp, ARRAYSIZE(szTemp));
  1302.         break;
  1303.     case DRIVES_ICOL_HTMLINFOTIPFILE:
  1304.         GetDriveHTMLInfoTipFile(DRIVEID(pidd->cName), szTemp, ARRAYSIZE(szTemp));
  1305.         break;
  1306.     case DRIVES_ICOL_SIZE:
  1307.     case DRIVES_ICOL_FREE:
  1308.         {
  1309.             ULONGLONG ullSize, ullFree;
  1310.             if (_GetFreeSpace(pidd, &ullSize, &ullFree))
  1311.             {
  1312.                 StrFormatByteSize64((iColumn == DRIVES_ICOL_SIZE) ? ullSize : ullFree, szTemp, ARRAYSIZE(szTemp));
  1313.             }
  1314.         }
  1315.         break;
  1316.     }
  1317.     return StringToStrRet(szTemp, &lpDetails->str);
  1318. }
  1319. HRESULT CDrivesFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid)
  1320. {
  1321.     return MapColumnToSCIDImpl(c_drives_cols, ARRAYSIZE(c_drives_cols), iColumn, pscid);
  1322. }
  1323. STDMETHODIMP CDrivesFolder::GetClassID(CLSID* pCLSID)
  1324. {
  1325.     *pCLSID = CLSID_MyComputer;
  1326.     return NOERROR;
  1327. }
  1328. STDMETHODIMP CDrivesFolder::Initialize(LPCITEMIDLIST pidl)
  1329. {
  1330.     // Only allow the Drives root on the desktop
  1331.     return !IsIDListInNameSpace(pidl, &CLSID_MyComputer) || !ILIsEmpty(_ILNext(pidl)) ? E_INVALIDARG : S_OK;
  1332. }
  1333. STDMETHODIMP CDrivesFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  1334. {
  1335.     return GetCurFolderImpl(IDLIST_DRIVES, ppidl);
  1336. }
  1337. STDMETHODIMP CDrivesFolder::_GetIconOverlayInfo(LPCIDDRIVE pidd, int *pIndex, DWORD dwFlags)
  1338. {
  1339.     HRESULT hres = E_FAIL;
  1340.     IShellIconOverlayManager *psiom;
  1341.     if (SUCCEEDED(hres = GetIconOverlayManager(&psiom)))
  1342.     {
  1343.         WCHAR wszDrive[10];
  1344.         SHAnsiToUnicode(pidd->cName, wszDrive, ARRAYSIZE(wszDrive));
  1345. #ifdef UNICODE
  1346.         if (IsShared(wszDrive, FALSE))
  1347. #else
  1348.         if (IsShared(pidd->cName, FALSE))
  1349. #endif
  1350.         {
  1351.             hres = psiom->GetReservedOverlayInfo(wszDrive, 0, pIndex, SIOM_OVERLAYINDEX, SIOM_RESERVED_SHARED);
  1352.         }
  1353.         else
  1354.         {
  1355.             hres = psiom->GetFileOverlayInfo(wszDrive, 0, pIndex, dwFlags);
  1356.         }            
  1357.         psiom->Release();
  1358.     }
  1359.     return hres;
  1360. }    
  1361. STDMETHODIMP CDrivesFolder::GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
  1362. {
  1363.     HRESULT hres = E_FAIL;
  1364.     LPCIDDRIVE pidd = _IsValidID(pidl);
  1365.     if (pidd)
  1366.     {
  1367.         if (!_IsReg(pidd))
  1368.         {
  1369.             hres = _GetIconOverlayInfo(pidd, pIndex, SIOM_OVERLAYINDEX);
  1370.         }            
  1371.     }
  1372.     return hres;
  1373. }
  1374. STDMETHODIMP CDrivesFolder::GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIndex)
  1375. {
  1376.     HRESULT hres = E_FAIL;
  1377.     LPCIDDRIVE pidd = _IsValidID(pidl);
  1378.     if (pidd)
  1379.     {
  1380.         if (!_IsReg(pidd))
  1381.         {
  1382.             hres = _GetIconOverlayInfo(pidd, pIndex, SIOM_ICONINDEX);
  1383.         }            
  1384.     }
  1385.     return hres;
  1386. }
  1387. // NOTE: we don't include SHID_COMPUTER_CDROM as this test really implies (this is a floppy thing)
  1388. BOOL CDrivesFolder::TypeIsRemoveable(LPCIDDRIVE pidd)
  1389. {
  1390.     switch (pidd->bFlags) {
  1391.     case SHID_COMPUTER_REMOVABLE:
  1392.     case SHID_COMPUTER_DRIVE525:
  1393.     case SHID_COMPUTER_DRIVE35:
  1394.         return TRUE;
  1395.     }
  1396.     return FALSE;
  1397. }
  1398. STDMETHODIMP CDrivesFolder::CompareItemIDs(LPCIDDRIVE pidd1, LPCIDDRIVE pidd2)
  1399. {
  1400.     // Compare the drive letter for sorting purpose.
  1401.     int iRes = StrCmpICA(pidd1->cName, pidd2->cName);   // don't need local goo
  1402.     // Then, compare the volume label (if any) for identity.
  1403.     if (iRes == 0
  1404.         && pidd1->bFlags != SHID_COMPUTER_MISC
  1405.         && pidd2->bFlags != SHID_COMPUTER_MISC)
  1406.     {
  1407.         iRes = pidd1->wChecksum - pidd2->wChecksum;
  1408.         if (iRes == 0)
  1409.             iRes = pidd1->bFlags - pidd2->bFlags;
  1410.     }
  1411.     return ResultFromShort(iRes);
  1412. }
  1413. #ifdef WINNT
  1414. #define DoesDriveWantToHideItself(iDrive) FALSE
  1415. #else
  1416. BOOL DoesDriveWantToHideItself(int iDrive)
  1417. {
  1418.     // Only supported on Win95 OPK2 or beyond
  1419.     static BOOL s_fCheckToHideDrives = (BOOL)42;   // Preload some value to say lets calculate...
  1420.     BOOL fWantToHide = FALSE;
  1421.     if (s_fCheckToHideDrives == (BOOL)42)
  1422.     {
  1423.         OSVERSIONINFO osvi;
  1424.         osvi.dwOSVersionInfoSize = sizeof(osvi);
  1425.         GetVersionEx(&osvi);
  1426.         // On Win95 OSR2 and higher (dwBuildNumber is the key!) try this IOCTL
  1427.         // to allow the drive to hide itself.
  1428.         s_fCheckToHideDrives = (LOWORD(osvi.dwBuildNumber) > 1000) ||
  1429.                                (osvi.dwMajorVersion > 4) ||
  1430.                                (osvi.dwMinorVersion > 0);
  1431.     }
  1432.     if (s_fCheckToHideDrives)
  1433.     {
  1434.         CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive);
  1435.         if (pMtPt)
  1436.         {
  1437.             fWantToHide = pMtPt->WantToHide();
  1438.             pMtPt->Release();
  1439.         }
  1440.     }
  1441.     return fWantToHide;
  1442. }
  1443. #endif
  1444. BOOL IsShareable(int iDrive)
  1445. {
  1446.     return !IsRemoteDrive(iDrive);
  1447. }
  1448. HRESULT CALLBACK CDrivesFolder::EnumCallBack(LPARAM lParam, void *pvData, UINT ecid, UINT index)
  1449. {
  1450.     HRESULT hres = NOERROR;
  1451.     EnumDrives * pedrv = (EnumDrives *)pvData;
  1452.     if (ecid == ECID_SETNEXTID)
  1453.     {
  1454.         hres = S_FALSE; // assume "no more element"
  1455.         for (int iDrive = pedrv->nLastFoundDrive + 1; iDrive < 26; iDrive++)
  1456.         {
  1457.             if (pedrv->dwRestricted & (1 << iDrive))
  1458.             {
  1459.                 TraceMsg(DM_TRACE, "s.cd_ecb: Drive %d restricted.", iDrive);
  1460.             }
  1461.             else if ((pedrv->dwDrivesMask & (1 << iDrive)) || IsUnavailableNetDrive(iDrive))
  1462.             {
  1463.                 //
  1464.                 if (DoesDriveWantToHideItself(iDrive))
  1465.                 {
  1466.                     TraceMsg(DM_TRACE, "s.cd_ecb: Drive %d Drivespace says should be hidden.", iDrive);
  1467.                 }
  1468.                 else if (!(SHCONTF_SHAREABLE & pedrv->grfFlags) || IsShareable(iDrive))
  1469.                 {
  1470.                     DRIVE_IDLIST *piddl = (DRIVE_IDLIST *)_ILCreate(SIZEOF(DRIVE_IDLIST));
  1471.                     if (piddl)
  1472.                     {
  1473.                         _FillIDDrive(piddl, iDrive, FALSE);
  1474.                         // If the drive is bogus, we get SHID_COMPUTER_MISC back
  1475.                         if (piddl->idd.bFlags != SHID_COMPUTER_MISC)
  1476.                         {
  1477.                             CMountPoint* pMtPt = CMountPoint::GetMountPoint(iDrive, FALSE);
  1478.                             if (pMtPt)
  1479.                             {
  1480.                                 pMtPt->ChangeNotifyRegisterAlias();
  1481.                                 pMtPt->Release();
  1482.                             }
  1483.                             CDefEnum_SetReturn(lParam, (LPITEMIDLIST)piddl);
  1484.                             pedrv->nLastFoundDrive = iDrive;
  1485.                             return NOERROR;
  1486.                         }
  1487.                         ILFree((LPITEMIDLIST)piddl);
  1488.                     }
  1489.                     else
  1490.                     {
  1491.                         return E_OUTOFMEMORY;
  1492.                     }
  1493.                 }
  1494.             }
  1495.         }
  1496.     }
  1497.     else if (ecid == ECID_RELEASE)
  1498.     {
  1499.         SetErrorMode(pedrv->dwSavedErrorMode);  // restore this
  1500.         LocalFree((HLOCAL)pedrv);
  1501.     }
  1502.     return hres;
  1503. }
  1504. HRESULT CDrivesFolder::_OnChangeNotify(LPARAM lNotification, LPCITEMIDLIST *ppidl)
  1505. {
  1506.     // Get to the last part of this id list...
  1507.     DWORD dwRestricted;
  1508.     LPCIDDRIVE pidd;
  1509.     if ((lNotification != SHCNE_DRIVEADD) || (ppidl == NULL) || (*ppidl == NULL))
  1510.         return NOERROR;
  1511.     dwRestricted = SHRestricted(REST_NODRIVES);
  1512.     if (dwRestricted == 0)
  1513.         return NOERROR;   // no drives restricted... (majority case)
  1514.     pidd = (LPCIDDRIVE)ILFindLastID(*ppidl);
  1515.     if (((1 << DRIVEID(pidd->cName)) & dwRestricted) || 
  1516.         DoesDriveWantToHideItself(DRIVEID(pidd->cName)))
  1517.     {
  1518.         TraceMsg(DM_TRACE, "Drive not added due to restrictions or Drivespace says it should be hidden");
  1519.         return S_FALSE;
  1520.     }
  1521.     return NOERROR;
  1522. }