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

Windows Kernel

Development Platform:

Visual C++

  1. #include "shellprv.h"
  2. #include "sfviewp.h"
  3. #include "deskfldr.h"
  4. #include "fstreex.h"
  5. #include "datautil.h"
  6. #include "views.h"
  7. #include "ids.h"
  8. #include "caggunk.h"
  9. #include "enum.h"
  10. #include "shitemid.h"
  11. #include "fstreex.h"
  12. #include "drives.h"
  13. #include "deskfldr.h"
  14. #include "infotip.h"
  15. #include "unicppdeskhtm.h"
  16. class CDesktopFolderEnum;
  17. class CDesktopViewCallBack;
  18. class CDesktopFolder : IShellFolder2, IPersistFolder2, IShellIcon, IShellIconOverlay
  19. {
  20. public:
  21.     // IUnknown
  22.     STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj); // { return CAggregatedUnknown::QueryInterface(riid, ppvObj); };
  23.     STDMETHODIMP_(ULONG) AddRef(void)  { return 3; /* CAggregatedUnknown::AddRef(); */ };
  24.     STDMETHODIMP_(ULONG) Release(void) { return 2; /* CAggregatedUnknown::Release(); */ };
  25.     // IShellFolder methods
  26.     STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  27.                                   ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  28.     STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
  29.     STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut);
  30.     STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj);
  31.     STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  32.     STDMETHODIMP CreateViewObject (HWND hwndOwner, REFIID riid, void **ppvOut);
  33.     STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG *rgfInOut);
  34.     STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
  35.                                REFIID riid, UINT * prgfInOut, void **ppvOut);
  36.     STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  37.     STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  38.                            LPITEMIDLIST * ppidlOut);
  39.     // IShellFolder2 methods
  40.     STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid);
  41.     STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH *ppenum);
  42.     STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay);
  43.     STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState);
  44.     STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv);
  45.     STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails);
  46.     STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid);
  47.     // IPersist
  48.     STDMETHODIMP GetClassID(LPCLSID lpClassID);
  49.     // IPersistFolder
  50.     STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  51.     //IPersistFolder2
  52.     STDMETHODIMP GetCurFolder(LPITEMIDLIST *ppidl);
  53.     // IShellIcon methods
  54.     STDMETHOD(GetIconOf)(LPCITEMIDLIST pidl, UINT flags, int *piIndex);
  55.     // IShellIconOverlay methods
  56.     STDMETHOD(GetOverlayIndex)(LPCITEMIDLIST pidl, int * pIndex);
  57.     STDMETHOD(GetOverlayIconIndex)(LPCITEMIDLIST pidl, int * pIndex);
  58.   
  59.     CDesktopFolder(IUnknown *punkOuter);
  60.     HRESULT _Init();
  61.     HRESULT _Init2();
  62.     void _Destroy();
  63. private:
  64. //    HRESULT v_InternalQueryInterface(REFIID riid, void **ppv);
  65.     ~CDesktopFolder();
  66.     friend CDesktopFolderEnum;
  67.     friend CDesktopViewCallBack;
  68.     friend HRESULT CDesktop_HandleCommand(CDesktopFolder *pdf, HWND hwndOwner, WPARAM wparam, BOOL bExecute);
  69.     friend HRESULT CDesktop_DFMCallBackBG(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam);
  70.     IShellFolder2 *_GetItemFolder(LPCITEMIDLIST pidl);
  71.     HRESULT _GetItemUIObject(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl, REFIID riid, UINT *prgfInOut, void **ppvOut);
  72.     HRESULT _QueryInterfaceItem(LPCITEMIDLIST pidl, REFIID riid, void **ppv);
  73.     HRESULT _CreateEnum(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum);
  74.     HRESULT _ChildParseDisplayName(LPCITEMIDLIST pidlLeft, HWND hwnd, IBindCtx *pbc, 
  75.                 LPWSTR pwzDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes);
  76.     HRESULT _TrySpecialUrl(HWND hwnd, LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  77.                                        LPITEMIDLIST *ppidl, ULONG *pdwAttributes);
  78.     IShellFolder2 *_psfDesktop;      // "Desktop" shell folder (real files live here)
  79.     IShellFolder2 *_psfAltDesktop;   // "Common Desktop" shell folder
  80.     IUnknown *_punkReg;             // regitem inner folder (agregate)
  81.     IContextMenu *_pcmDesktopExt;
  82. };
  83. class CDesktopFolderEnum : public IEnumIDList
  84. {
  85. public:
  86.     // *** IUnknown methods ***
  87.     STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  88.     STDMETHOD_(ULONG,AddRef)();
  89.     STDMETHOD_(ULONG,Release)();
  90.     // *** IEnumIDList methods ***
  91.     STDMETHOD(Next)(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  92.     STDMETHOD(Skip)(ULONG celt);
  93.     STDMETHOD(Reset)();
  94.     STDMETHOD(Clone)(IEnumIDList **ppenum);
  95.     
  96.     CDesktopFolderEnum(CDesktopFolder *pdf, HWND hwnd, DWORD grfFlags);
  97. private:
  98.     ~CDesktopFolderEnum();
  99.     LONG _cRef;
  100.     BOOL _bUseAltEnum;
  101.     IEnumIDList *_penumFolder;
  102.     IEnumIDList *_penumAltFolder;
  103. };
  104. IShellFolderViewCB* Desktop_CreateSFVCB(CDesktopFolder* pdf);
  105. //
  106. // Global variables
  107. //
  108. SFEnumCacheData g_EnumCache = {0};
  109. #ifdef WINNT
  110. #define NETCPL  TEXT("NCPA.CPL")
  111. #else
  112. #define NETCPL TEXT("NETCPL.CPL")
  113. #endif
  114. //
  115. // this is now perinstance so we can poke at it at runtime :)
  116. //
  117. REQREGITEM g_asDesktopReqItems[] =
  118. {
  119.     { 
  120.         &CLSID_MyComputer,  IDS_DRIVEROOT,  
  121.         TEXT("explorer.exe"), 0, SORT_ORDER_DRIVES, 
  122.         SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR  | SFGAO_DROPTARGET | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANMONIKER,
  123.         TEXT("SYSDM.CPL")
  124.     },
  125.     { 
  126.         &CLSID_NetworkPlaces, IDS_NETWORKROOT, 
  127.         TEXT("shell32.dll"), -IDI_MYNETWORK, SORT_ORDER_NETWORK, 
  128.         SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR | SFGAO_DROPTARGET | SFGAO_FOLDER | SFGAO_CANRENAME | SFGAO_CANMONIKER, 
  129.         NETCPL,
  130.     },
  131.     { 
  132.         &CLSID_Internet, IDS_INETROOT, 
  133.         TEXT("mshtml.dll"),   0, SORT_ORDER_INETROOT, 
  134.         SFGAO_BROWSABLE  | SFGAO_HASPROPSHEET | SFGAO_CANRENAME  | SFGAO_FOLDER, 
  135.         TEXT("INETCPL.CPL")
  136.     },
  137. };
  138. const UNALIGNED ITEMIDLIST c_idlDesktop = { { 0, 0 } };
  139. #define DESKTOP_PIDL  ((LPITEMIDLIST)&c_idlDesktop)
  140. BOOL CDesktop_IsDesktop(HWND hwnd)
  141. {
  142.     TCHAR szClassName[50];
  143.     return GetClassName(hwnd, szClassName, ARRAYSIZE(szClassName)) && 
  144.         lstrcmpi(szClassName, TEXT(STR_DESKTOPCLASS)) == 0;
  145. }
  146. //
  147. // single global instance of this CDesktopFolder object
  148. //
  149. CDesktopFolder *g_pDesktopFolder = NULL;
  150. REGITEMSINFO g_riiDesktop =
  151. {
  152.     REGSTR_PATH_EXPLORER TEXT("\Desktop\NameSpace"),
  153.     NULL,
  154.     TEXT(':'),
  155.     SHID_ROOT_REGITEM,
  156.     1,
  157.     SFGAO_CANLINK,
  158.     ARRAYSIZE(g_asDesktopReqItems),
  159.     g_asDesktopReqItems,
  160.     RIISA_ORIGINAL,
  161.     NULL,
  162.     0,
  163.     0,
  164. };
  165. void Desktop_InitRequiredItems(void)
  166. {
  167.     //  "NoNetHood" restruction -> always hide the hood.
  168.     //  Otherwise, show the hood if either MPR says so or we have RNA.
  169.     if (!(GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS) || SHRestricted(REST_NONETHOOD))
  170.     {
  171.         // Don't enumerate the "Net Hood" thing.
  172.         g_asDesktopReqItems[CDESKTOP_REGITEM_NETWORK].dwAttributes |= SFGAO_NONENUMERATED;
  173.     }
  174.     else
  175.     {
  176.         // Do enumerate the "My Network" thing.
  177.         g_asDesktopReqItems[CDESKTOP_REGITEM_NETWORK].dwAttributes &= ~SFGAO_NONENUMERATED;
  178.     }
  179.     //
  180.     // "NoInternetIcon" restriction -> hide The Internet on the desktop
  181.     //
  182.     if (SHRestricted(REST_NOINTERNETICON))
  183.     {
  184.         g_asDesktopReqItems[CDESKTOP_REGITEM_INTERNET].dwAttributes &=  ~(SFGAO_BROWSABLE | SFGAO_FOLDER);
  185.         g_asDesktopReqItems[CDESKTOP_REGITEM_INTERNET].dwAttributes |= SFGAO_NONENUMERATED;
  186.     }
  187.     // BUGBUG:: Word Perfect 7 faults when it enumerates the Internet item
  188.     // in their background thread.  For now App hack specific to this app
  189.     // later may need to extend...  Note: This app does not install on
  190.     // NT so only do for W95...
  191.     // it repros with Word Perfect Suite 8, too, this time on both NT and 95
  192.     // so removing the #ifndef... -- reljai 11/20/97, bug#842 in ie5 db
  193.     if (SHGetAppCompatFlags(ACF_CORELINTERNETENUM) & ACF_CORELINTERNETENUM)
  194.     {
  195.         g_asDesktopReqItems[CDESKTOP_REGITEM_INTERNET].dwAttributes &=  ~(SFGAO_BROWSABLE | SFGAO_HASSUBFOLDER | SFGAO_FOLDER);
  196.         g_asDesktopReqItems[CDESKTOP_REGITEM_INTERNET].dwAttributes |= SFGAO_NONENUMERATED;
  197.     }
  198. }
  199. CDesktopFolder::CDesktopFolder(IUnknown *punkOuter)
  200. {
  201.     DllAddRef();
  202. }
  203. CDesktopFolder::~CDesktopFolder()
  204. {
  205.     DllRelease();
  206. }
  207. // first phase of init (does not need to be seralized)
  208. HRESULT CDesktopFolder::_Init()
  209. {
  210.     Desktop_InitRequiredItems();
  211.     return CRegFolder_CreateInstance(&g_riiDesktop, SAFECAST(this, IShellFolder2 *), IID_IUnknown, (void **)&_punkReg);
  212. }
  213. // second phase of init (needs to be seralized)
  214. HRESULT CDesktopFolder::_Init2()
  215. {
  216.     HRESULT hr;
  217.     hr = SHCacheTrackingFolder(DESKTOP_PIDL, CSIDL_DESKTOPDIRECTORY | CSIDL_FLAG_CREATE, &_psfDesktop);
  218.     if (FAILED(hr))
  219.     {
  220.         DebugMsg(DM_TRACE, TEXT("Failed to create desktop IShellFolder!"));
  221.         return hr;
  222.     }
  223.     if ( !SHRestricted(REST_NOCOMMONGROUPS))
  224.     {
  225.         hr = SHCacheTrackingFolder(DESKTOP_PIDL, CSIDL_COMMON_DESKTOPDIRECTORY, &_psfAltDesktop);
  226.     }
  227.     return hr;
  228. }
  229. // CLSID_ShellDesktop constructor
  230. STDAPI CDesktop_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  231. {
  232.     HRESULT hr;
  233.     if (g_pDesktopFolder)
  234.     {
  235.         hr = g_pDesktopFolder->QueryInterface(riid, ppv);
  236.     }
  237.     else
  238.     {
  239.         *ppv = NULL;
  240.         // WARNING: the order of init of the desktop folder state is very important.
  241.         // the creation of the sub folders, in particular _psfAltDesktop will
  242.         // recurse on this function. we protect ourself from that here. the creation
  243.         // of that also requires the above members to be inited.
  244.         CDesktopFolder *pdf = new CDesktopFolder(punkOuter);
  245.         if (pdf)
  246.         {
  247.             hr = pdf->_Init();
  248.             if (SUCCEEDED(hr))
  249.             {
  250.                 // NOTE: there is a race condition here where we have stored g_pDesktopFolder but
  251.                 // not initialized _psfDesktop & _psfAltDesktop. the main line code deals with
  252.                 // this by testing for NULL on these members.
  253.                 if (SHInterlockedCompareExchange((void **)&g_pDesktopFolder, pdf, 0))
  254.                 {
  255.                     // Someone else beat us to creating the object.
  256.                     // get rid of our copy, global already set (the race case)
  257.                     pdf->_Destroy();    
  258.                 }
  259.                 else
  260.                 {
  261.                     g_pDesktopFolder->_Init2();
  262.                 }
  263.                 hr = g_pDesktopFolder->QueryInterface(riid, ppv);
  264.             }
  265.             else
  266.                 pdf->_Destroy();
  267.         }
  268.         else
  269.             hr = E_OUTOFMEMORY;
  270.     }
  271.     return hr;
  272. }
  273. STDAPI SHGetDesktopFolder(IShellFolder **ppshf)
  274. {
  275.     return CDesktop_CreateInstance(NULL, IID_IShellFolder, (void **)ppshf);
  276. }
  277. IShellFolder2 *CDesktopFolder::_GetItemFolder(LPCITEMIDLIST pidl)
  278. {
  279.     if (_psfAltDesktop && FS_IsCommonItem(pidl))
  280.         return _psfAltDesktop;
  281.     return _psfDesktop;
  282. }
  283. HRESULT CDesktopFolder::_QueryInterfaceItem(LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  284. {
  285.     HRESULT hr;
  286.     IShellFolder2 *psf = _GetItemFolder(pidl);
  287.     if (psf)
  288.         hr = psf->QueryInterface(riid, ppv);
  289.     else
  290.     {
  291.         *ppv = NULL;
  292.         hr = E_NOINTERFACE;
  293.     }
  294.     return hr;
  295. }
  296. __inline BOOL _RegGetsFirstShot(REFIID riid)
  297. {
  298.     return (IsEqualIID(riid, IID_IShellFolder) ||
  299.             IsEqualIID(riid, IID_IShellFolder2) ||
  300.             IsEqualIID(riid, IID_IShellIconOverlay));
  301. }
  302. HRESULT CDesktopFolder::QueryInterface(REFIID riid, void **ppv)
  303. {
  304.     static const QITAB qit[] = {
  305.         QITABENT(CDesktopFolder, IShellFolder2),                        // IID_ISHELLFolder2
  306.         QITABENTMULTI(CDesktopFolder, IShellFolder, IShellFolder2),     // IID_IShellFolder
  307.         QITABENT(CDesktopFolder, IShellIcon),                           // IID_IShellIcon
  308.         QITABENT(CDesktopFolder, IPersistFolder2),                      // IID_IPersistFolder2
  309.         QITABENTMULTI(CDesktopFolder, IPersistFolder, IPersistFolder2), // IID_IPersistFolder
  310.         QITABENTMULTI(CDesktopFolder, IPersist, IPersistFolder2),       // IID_IPersist
  311.         QITABENT(CDesktopFolder, IShellIconOverlay),                    // IID_IShellIconOverlay
  312.         { 0 },
  313.     };
  314.     if (IsEqualIID(riid, CLSID_ShellDesktop))
  315.     {
  316.         *ppv = this;     // class pointer (unrefed!)
  317.         return S_OK;
  318.     }
  319.     else if (_punkReg && _RegGetsFirstShot(riid))
  320.     {
  321.         return _punkReg->QueryInterface(riid, ppv);
  322.     }
  323.     HRESULT hr = QISearch(this, qit, riid, ppv);
  324.     if ((E_NOINTERFACE == hr) && (NULL != _punkReg))
  325.     {
  326.         return _punkReg->QueryInterface(riid, ppv);
  327.     }
  328.     else
  329.     {
  330.         return hr;
  331.     }
  332. }
  333. // During shell32.dll process detach, we will call here to do the final
  334. // release of the IShellFolder ptrs which used to be left around for the
  335. // life of the process.  This quiets things such as OLE's debug allocator,
  336. // which detected the leak.
  337. void CDesktopFolder::_Destroy()
  338. {
  339.     ATOMICRELEASE(_psfDesktop);
  340.     ATOMICRELEASE(_psfAltDesktop);
  341.     ATOMICRELEASE(_pcmDesktopExt);
  342.     SHReleaseInnerInterface(SAFECAST(this, IShellFolder *), &_punkReg);
  343.     delete this;
  344. }
  345. LPITEMIDLIST CreateMyComputerIDList()
  346. {
  347.     return ILCreateFromPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}")); // CLSID_MyComputer
  348. }
  349. LPITEMIDLIST CreateWebFoldersIDList()
  350. {
  351.     return ILCreateFromPath(TEXT("::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{BDEADF00-C265-11D0-BCED-00A0C90AB50F}")); // CLSID_MyComputerCLSID_WebFolders
  352. }
  353. LPITEMIDLIST CreateMyNetPlacesIDList()
  354. {
  355.     return ILCreateFromPath(TEXT("::{208D2C60-3AEA-1069-A2D7-08002B30309D}")); // CLSID_NetworkPlaces
  356. }
  357. HRESULT CDesktopFolder::_ChildParseDisplayName(LPCITEMIDLIST pidlLeft, HWND hwnd, IBindCtx *pbc, 
  358.                 LPWSTR pwzDisplayName, ULONG *pchEaten, LPITEMIDLIST *ppidl, DWORD *pdwAttributes)
  359. {
  360.     IShellFolder *psfBind;
  361.     HRESULT hr = QueryInterface(IID_IShellFolder, (void **)&psfBind);
  362.     if (SUCCEEDED(hr))
  363.     {
  364.         IShellFolder *psfRight;
  365.         hr = psfBind->BindToObject(pidlLeft, pbc, IID_IShellFolder, (void **)&psfRight);
  366.         if (SUCCEEDED(hr))
  367.         {
  368.             LPITEMIDLIST pidlRight;
  369.             hr = psfRight->ParseDisplayName(hwnd, pbc, 
  370.                 pwzDisplayName, pchEaten, &pidlRight, pdwAttributes);
  371.             if (SUCCEEDED(hr))
  372.             {
  373.                 hr = SHILCombine(pidlLeft, pidlRight, ppidl);
  374.                 ILFree(pidlRight);
  375.             }
  376.             psfRight->Release();
  377.         }
  378.         psfBind->Release();
  379.     }
  380.     return hr;
  381. }
  382. STDAPI_(int) SHGetSpecialFolderID(LPCWSTR pszName);
  383. HRESULT CDesktopFolder::_TrySpecialUrl(HWND hwnd, LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  384.                                        LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  385. {
  386.     HRESULT hr = E_INVALIDARG;
  387.     PARSEDURLW pu = {0};
  388.     pu.cbSize = SIZEOF(pu);
  389.     if (SUCCEEDED(ParseURLW(pwzDisplayName, &pu)) && pu.nScheme == URL_SCHEME_SHELL)
  390.     {
  391.         int csidl = SHGetSpecialFolderID(pu.pszSuffix);
  392.         if (-1 != csidl)
  393.         {
  394.             hr = SHGetFolderLocation(hwnd, csidl | CSIDL_FLAG_CREATE, NULL, 0, ppidl);
  395.             if (SUCCEEDED(hr) && pdwAttributes && *pdwAttributes)
  396.             {
  397.                 hr = SHGetNameAndFlags(*ppidl, 0, NULL, 0, pdwAttributes);
  398.                 if (FAILED(hr))
  399.                 {
  400.                     ILFree(*ppidl);
  401.                     *ppidl = NULL;
  402.                 }
  403.             }
  404.         }
  405.     }
  406.     else if (pu.nScheme != URL_SCHEME_FTP && pu.nScheme != URL_SCHEME_FILE)
  407.     {
  408.         //  string is an URL, webfolders might know what to do with it, as long as its not a file or ftp url.
  409.         LPITEMIDLIST pidlWeb = CreateWebFoldersIDList();
  410.         if (pidlWeb)
  411.         {
  412.             hr = _ChildParseDisplayName(pidlWeb, hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  413.             ILFree(pidlWeb);
  414.         }
  415.     }
  416.     return hr;
  417. }
  418. //----------------------------------------------------------------------------
  419. STDMETHODIMP CDesktopFolder::ParseDisplayName(HWND hwnd, 
  420.                                        LPBC pbc, WCHAR *pwzDisplayName, ULONG *pchEaten,
  421.                                        LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  422. {
  423.     HRESULT hr = E_INVALIDARG;
  424.     *ppidl = NULL;      // assume error
  425.     if (pwzDisplayName && *pwzDisplayName)
  426.     {
  427.         LPITEMIDLIST pidlLeft = NULL;
  428.         USES_CONVERSION;
  429.         LPTSTR szDisplayName = W2T(pwzDisplayName);
  430.         ASSERT(hr == E_INVALIDARG);
  431.         if ((InRange(szDisplayName[0], TEXT('A'), TEXT('Z')) || 
  432.              InRange(szDisplayName[0], TEXT('a'), TEXT('z'))) && 
  433.             szDisplayName[1] == TEXT(':'))
  434.         {
  435.             // The string contains a path, let "My Computer" figire it out.
  436.             pidlLeft = CreateMyComputerIDList();
  437.             if (pchEaten)
  438.                 *pchEaten = 0;
  439.         }
  440.         else if (PathIsUNC(szDisplayName))
  441.         {
  442.             // The path is UNC, let "World" figure it out.
  443.             pidlLeft = CreateMyNetPlacesIDList();
  444.         }
  445.         else if (UrlIsW(pwzDisplayName, URLIS_URL) && !SHSkipJunctionBinding(pbc, NULL))
  446.         {
  447.             hr = _TrySpecialUrl(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  448.         }
  449.         if (!pidlLeft && FAILED(hr))
  450.         {
  451.             //  when we request that something be created, we need to
  452.             //  check both folders and make sure that it doesnt exist in 
  453.             //  either one.  and then try and create it in the user folder
  454.             BIND_OPTS bo = {SIZEOF(bo)};
  455.             BOOL fCreate = FALSE;
  456.             if (pbc && SUCCEEDED(pbc->GetBindOptions(&bo)) && 
  457.                 (bo.grfMode & STGM_CREATE))
  458.             {
  459.                 fCreate = TRUE;
  460.                 bo.grfMode &= ~STGM_CREATE;
  461.                 pbc->SetBindOptions(&bo);
  462.             }
  463.             //  give the users desktop first shot.
  464.             // This must be a desktop item, _psfDesktop may not be inited in
  465.             // the case where we are called from ILCreateFromPath()
  466.             if (_psfDesktop)
  467.                 hr = _psfDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  468.             //  if the normal desktop folder didnt pick it off, 
  469.             //  it could be in the allusers folder.  give psfAlt a chance.
  470.             if (FAILED(hr) && _psfAltDesktop)
  471.             {
  472.                 hr = _psfAltDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  473.                 //  mark this as a common item.  
  474.                 if (SUCCEEDED(hr))
  475.                     FS_MakeCommonItem(*ppidl);
  476.             }
  477.             //  neither of the folders can identify an existing item
  478.             //  so we should pass the create flag to the real desktop
  479.             if (FAILED(hr) && fCreate && _psfDesktop)
  480.             {
  481.                 bo.grfMode |= STGM_CREATE;
  482.                 pbc->SetBindOptions(&bo);
  483.                 hr = _psfDesktop->ParseDisplayName(hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  484.                 //  when this succeeds, we know we got a magical ghost pidl...
  485.             }
  486.         }
  487.         if (pidlLeft)
  488.         {
  489.             hr = _ChildParseDisplayName(pidlLeft, hwnd, pbc, pwzDisplayName, pchEaten, ppidl, pdwAttributes);
  490.             ILFree(pidlLeft);
  491.         }
  492.     } 
  493.     else if (pwzDisplayName)
  494.     {
  495.         // we used to return this pidl when passed an empty string
  496.         // some apps (such as Wright Design) depend on this behavior,
  497.         // so i'm reinstating it --ccooney
  498.         hr = SHILClone((LPCITEMIDLIST)&c_idlDrives, ppidl);
  499.     }
  500.     return hr;
  501. }
  502. STDAPI_(void) UltRoot_Term()
  503. {
  504.     SFEnumCache_Terminate(&g_EnumCache);
  505.     if (g_pDesktopFolder)
  506.     {
  507.         g_pDesktopFolder->_Destroy();
  508.         g_pDesktopFolder = NULL;
  509.     }
  510. }
  511. HRESULT CDesktopFolder::_CreateEnum(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum)
  512. {
  513.     HRESULT hr;
  514.     CDesktopFolderEnum *pesf = new CDesktopFolderEnum(this, hwnd, grfFlags);
  515.     if (pesf)
  516.     {
  517.         hr = pesf->QueryInterface(IID_IEnumIDList, (void **)ppenum);
  518.         pesf->Release();
  519.     }
  520.     else
  521.         hr = E_OUTOFMEMORY;
  522.     return hr;
  523. }
  524. STDMETHODIMP CDesktopFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenum)
  525. {
  526.     HRESULT hr;
  527.     // should we cache this enum for later?
  528.     if (IsMainShellProcess() && EnumCanCache(grfFlags))
  529.     {
  530.         IEnumIDList *penum;
  531.         hr = _CreateEnum(hwnd, ENUMGRFFLAGS, &penum);
  532.         if (SUCCEEDED(hr)) 
  533.         {
  534.             hr = SFEnumCache_Create(penum, grfFlags, &g_EnumCache, SAFECAST(this, IShellFolder *), ppenum);
  535.             penum->Release();
  536.         }
  537.     }
  538.     else
  539.         hr = _CreateEnum(hwnd, grfFlags, ppenum);
  540.     return hr;
  541. }
  542. STDMETHODIMP CDesktopFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
  543. {
  544.     IShellFolder2 *psf = _GetItemFolder(pidl);
  545.     if (psf)
  546.         return psf->BindToObject(pidl, pbc, riid, ppvOut);
  547.     return E_UNEXPECTED;
  548. }
  549. STDMETHODIMP CDesktopFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
  550. {
  551.     IShellFolder2 *psf = _GetItemFolder(pidl);
  552.     if (psf)
  553.         return psf->BindToStorage(pidl, pbc, riid, ppvOut);
  554.     return E_UNEXPECTED;
  555. }
  556. STDMETHODIMP CDesktopFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  557. {
  558.     if (pidl1 == NULL || pidl2 == NULL)
  559.         return E_INVALIDARG;
  560.     if (pidl1->mkid.cb == 0 && pidl2->mkid.cb == 0)
  561.         return ResultFromShort(0);      // 2 empty IDLists, they are the same
  562.     // If both objects aren't from the same directory, they won't match.
  563.     if (_psfAltDesktop) 
  564.     {
  565.         if (FS_IsCommonItem(pidl1)) 
  566.         {
  567.             if (FS_IsCommonItem(pidl2)) 
  568.                 return _psfAltDesktop->CompareIDs(lParam, pidl1, pidl2);
  569.             else 
  570.                 return ResultFromShort(-1);
  571.         } 
  572.         else 
  573.         {
  574.             if (FS_IsCommonItem(pidl2)) 
  575.                 return ResultFromShort(1);
  576.             else if (_psfDesktop)
  577.                 return _psfDesktop->CompareIDs(lParam, pidl1, pidl2);
  578.         }
  579.     } 
  580.     else 
  581.     {
  582.         if (_psfDesktop)
  583.             return _psfDesktop->CompareIDs(lParam, pidl1, pidl2);
  584.     }
  585.     // If we have no _psfDesktop, we get here...
  586.     return ResultFromShort(-1);
  587. }
  588. HRESULT _GetDesktopExtMenu(HWND hwndOwner, IContextMenu** ppcm)
  589. {
  590.     HRESULT hr;
  591.     IShellBrowser *psb = FileCabinet_GetIShellBrowser(hwndOwner);
  592.     if (psb) 
  593.     {
  594.         IServiceProvider* psp;
  595.         hr = psb->QueryInterface(IID_IServiceProvider, (void **)&psp);
  596.         if (SUCCEEDED(hr)) 
  597.         {
  598.             hr = psp->QueryService(SID_SDesktopExtMenu, IID_IContextMenu, (void **)ppcm);
  599.             AssertMsg(SUCCEEDED(0), TEXT("WebBar: QueryService failed %x"), hr);
  600.             psp->Release();
  601.         } 
  602.         else 
  603.         {
  604.             AssertMsg(0, TEXT("WebBar: _GetDesktopExtMenu QI(IIS_ISP) failed %x"), hr);
  605.         }
  606.         // No need to release psb
  607.     } 
  608.     else 
  609.     {
  610.         AssertMsg(0, TEXT("WebBar: _GetDesktopExtMenu GetIShellFolder(%x) failed"), hwndOwner);
  611.         hr = E_UNEXPECTED;
  612.     }
  613.     return hr;
  614. }
  615. //----------------------------------------------------------------------------
  616. HRESULT CDesktop_HandleCommand(CDesktopFolder *pdf, HWND hwndOwner, WPARAM wparam, BOOL bExecute)
  617. {
  618.     HRESULT hr = NOERROR;
  619.     switch (wparam) {
  620.     case FSIDM_SORTBYNAME:
  621.     case FSIDM_SORTBYTYPE:
  622.     case FSIDM_SORTBYSIZE:
  623.     case FSIDM_SORTBYDATE:
  624.         if (bExecute)
  625.         {
  626.             ShellFolderView_ReArrange(hwndOwner, wparam - FSIDM_SORT_FIRST);
  627.         }
  628.         break;
  629.     case DFM_CMD_PROPERTIES:
  630.     case FSIDM_PROPERTIESBG:
  631.         if (bExecute)
  632.         {
  633.             // run the default applet in desk.cpl
  634.             SHRunControlPanel( TEXT("desk.cpl"), hwndOwner );
  635.         }
  636.         break;
  637.     case DFM_CMD_MOVE:
  638.     case DFM_CMD_COPY:
  639.         hr = E_FAIL;
  640.         break;
  641.     default:
  642.         //
  643.         // Dispatch Desktop Extended menus (for WebBar)
  644.         //
  645.         if (wparam >= FSIDM_DESKTOPEX_FIRST && wparam <= FSIDM_DESKTOPEX_LAST) 
  646.         {
  647.             if (pdf->_pcmDesktopExt) 
  648.             {
  649.                 CMINVOKECOMMANDINFO cinfo = {
  650.                         SIZEOF(cinfo), 0, hwndOwner,
  651.                         (LPCSTR)wparam-FSIDM_DESKTOPEX_FIRST, NULL, NULL, SW_SHOWNORMAL, 0, NULL };
  652.                 pdf->_pcmDesktopExt->InvokeCommand(&cinfo);
  653.                 pdf->_pcmDesktopExt->Release();
  654.                 pdf->_pcmDesktopExt = NULL;
  655.             }
  656.         }
  657.         // This is common menu items, use the default code.
  658.         hr = S_FALSE;
  659.         break;
  660.     }
  661.     return hr;
  662. }
  663. //
  664. //----------------------------------------------------------------------------
  665. // Helper function for CDesktop_DFMCallBackBG, adds an item for each desktop
  666. // component to the Add Desktop Items popup menu
  667. //
  668. // Returns:
  669. //  TRUE if at least one item was added to the menu
  670. //  FALSE otherwise
  671. //
  672. #define MAX_COMPONENT_WIDTH 40
  673. BOOL CDesktop_AddDesktopComponentsToMenu(HMENU hmenu)
  674. {
  675.     BOOL fRetVal = FALSE;
  676.     IActiveDesktop * piad;
  677.     if (SUCCEEDED(SHCoCreateInstance(NULL, &CLSID_ActiveDesktop, NULL, IID_IActiveDesktop, (void **)&piad)))
  678.     {
  679.         COMPONENTSOPT co;
  680.         co.dwSize = sizeof(co);
  681.         piad->GetDesktopItemOptions(&co, 0);
  682.         if (co.fActiveDesktop && co.fEnableComponents)
  683.         {
  684.             int cComp, i;
  685.             piad->GetDesktopItemCount(&cComp, 0);
  686.             for (i = 0; i < cComp; i++)
  687.             {
  688.                 COMPONENT comp;
  689.                 comp.dwSize = SIZEOF(comp);
  690.     
  691.                 if (SUCCEEDED(piad->GetDesktopItem(i, &comp, 0)))
  692.                 {
  693.                     MENUITEMINFO mii;
  694.                     WCHAR * pwszName;
  695.                     WCHAR wszName[MAX_COMPONENT_WIDTH];
  696.                     // Insert a menu item for this component
  697.                     mii.cbSize = sizeof(MENUITEMINFO);
  698.                     mii.fMask = MIIM_TYPE | MIIM_ID | MIIM_STATE;
  699.                     mii.fType = MFT_STRING;
  700.                     if (comp.wszFriendlyName[0])
  701.                         pwszName = comp.wszFriendlyName;
  702.                     else
  703.                         pwszName = comp.wszSource;
  704.                     // Truncate if necessary so the menu doesn't get too wide...
  705.                     if (!PathIsFileSpecW(pwszName))
  706.                     {
  707.                         pwszName = PathFindFileNameW(pwszName);
  708.                     }
  709.                     PathCompactPathExW(wszName, pwszName, ARRAYSIZE(wszName), 0);
  710. #ifdef UNICODE
  711.                     mii.cch = lstrlen(wszName);
  712.                     mii.dwTypeData = wszName;
  713. #else
  714.                     {
  715.                         CHAR szName[MAX_COMPONENT_WIDTH];
  716.                         WideCharToMultiByte( CP_ACP, 0, wszName, -1, (LPSTR)szName, ARRAYSIZE(szName), NULL, NULL);
  717.                         mii.cch = lstrlen(szName);
  718.                         mii.dwTypeData = szName;
  719.                     }
  720. #endif
  721.                     mii.wID = i + SFVIDM_DESKTOPHTML_ADDSEPARATOR + 1;
  722.                     mii.fState = comp.fChecked ? MFS_CHECKED : MFS_ENABLED;
  723.                     InsertMenuItem(hmenu, -1, TRUE, &mii);
  724.                     fRetVal = TRUE;
  725.                 }           
  726.             }
  727.         }
  728.         piad->Release();
  729.     } 
  730.     return fRetVal;
  731. }
  732. STDAPI_(HMENU) CDesktop_GetActiveDesktopMenu()
  733. {
  734.     HMENU hmenuAD;
  735.     // Load the menu and make the appropriate modifications
  736.     if (hmenuAD = SHLoadMenuPopup(HINST_THISDLL, POPUP_SFV_BACKGROUND_AD))
  737.     {
  738.         // Get the present settings regarding HTML on desktop
  739.         SHELLSTATE ss;
  740.         SHGetSetSettings(&ss, SSF_DESKTOPHTML | SSF_HIDEICONS, FALSE);
  741.         if (!ss.fDesktopHTML)
  742.         {
  743.             DeleteMenu(hmenuAD, SFVIDM_DESKTOPHTML_ICONS, MF_BYCOMMAND);
  744.             DeleteMenu(hmenuAD, SFVIDM_DESKTOPHTML_LOCK, MF_BYCOMMAND);
  745.             DeleteMenu(hmenuAD, SFVIDM_DESKTOPHTML_SYNCHRONIZE, MF_BYCOMMAND);
  746.             DeleteMenu(hmenuAD, SFVIDM_DESKTOPHTML_ADDSEPARATOR, MF_BYCOMMAND);
  747.         }
  748.         else
  749.         {
  750.             CheckMenuItem(hmenuAD, SFVIDM_DESKTOPHTML_WEBCONTENT, MF_BYCOMMAND | MF_CHECKED);
  751.             if(SHRestricted(REST_FORCEACTIVEDESKTOPON))
  752.                 EnableMenuItem(hmenuAD, SFVIDM_DESKTOPHTML_WEBCONTENT, MF_BYCOMMAND | MF_GRAYED);
  753.             if (!ss.fHideIcons)
  754.                 CheckMenuItem(hmenuAD, SFVIDM_DESKTOPHTML_ICONS, MF_BYCOMMAND | MF_CHECKED);
  755.             if (GetDesktopFlags() & COMPONENTS_LOCKED)
  756.                 CheckMenuItem(hmenuAD, SFVIDM_DESKTOPHTML_LOCK, MF_BYCOMMAND | MF_CHECKED);
  757.             if (SHRestricted(REST_NOADDDESKCOMP) || SHRestricted(REST_NODESKCOMP))
  758.                 EnableMenuItem(hmenuAD, SFVIDM_DESKTOPHTML_NEWITEM, MF_BYCOMMAND | MF_GRAYED);
  759.             // Add a menu item to the "Add Desktop Item" popup for each Desktop Component installed
  760.             if (SHRestricted(REST_NOCLOSEDESKCOMP) || SHRestricted(REST_NODESKCOMP) || !CDesktop_AddDesktopComponentsToMenu(hmenuAD))
  761.                 DeleteMenu(hmenuAD, SFVIDM_DESKTOPHTML_ADDSEPARATOR, MF_BYCOMMAND);
  762.         }
  763.     }
  764.     return hmenuAD;
  765. }
  766. // static const QCMINFO_IDMAP 
  767. static const struct {
  768.     UINT max;
  769.     struct {
  770.         UINT id;
  771.         UINT fFlags;
  772.     } list[2];
  773. } idMap = {
  774.     2, {
  775.         {FSIDM_FOLDER_SEP, QCMINFO_PLACE_BEFORE},
  776.         {FSIDM_VIEW_SEP, QCMINFO_PLACE_AFTER},
  777.     },
  778. };
  779. // background context menu callback
  780. //
  781. // Returns:
  782. //      NOERROR, if successfully processed.
  783. //      S_FALSE, if default code should be used.
  784. HRESULT CDesktop_DFMCallBackBG(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam)
  785. {
  786.     HRESULT hr = NOERROR;
  787.     CDesktopFolder *pdf;
  788.     psf->QueryInterface(CLSID_ShellDesktop, (void **)&pdf);
  789.     ASSERT(pdf);
  790.     switch(uMsg)
  791.     {
  792.     case DFM_MERGECONTEXTMENU:
  793.         if (!(wParam & CMF_VERBSONLY))
  794.         {
  795.             HRESULT hresT;
  796.             UINT idCmdFirst;
  797.             LPQCMINFO pqcm;
  798.             BOOL bDesktop = FALSE;
  799.             // If desktop is in ExtendedView, then the hwnd we get for
  800.             // the context menu is a child of the Desktop.
  801.             while (hwnd)
  802.             {
  803.                 bDesktop = CDesktop_IsDesktop(hwnd);
  804.                 if (bDesktop)
  805.                     break;
  806.                 hwnd = GetParent(hwnd);
  807.             }
  808.             pqcm = (LPQCMINFO)lParam;
  809.             // This needs to be saved before MergeMenu
  810.             idCmdFirst = pqcm->idCmdFirst;
  811.             pqcm->pIdMap = (QCMINFO_IDMAP *)&idMap;
  812.             // HACK: Note the Desktop and FSView menus are the same
  813.             CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_FSVIEW_BACKGROUND,
  814.                 POPUP_FSVIEW_POPUPMERGE, pqcm);
  815.             if (bDesktop)
  816.             {
  817.                 TCHAR szMenu[60];
  818.                 // HACK: We only want LargeIcons on the real desktop
  819.                 // so we remove the View menu
  820.                 DeleteMenu(pqcm->hmenu, SFVIDM_MENU_VIEW, MF_BYCOMMAND);
  821.                 // No Choose Columns either
  822.                 DeleteMenu(pqcm->hmenu, SFVIDM_VIEW_COLSETTINGS, MF_BYCOMMAND);
  823.                 // Only put on ActiveDesktop menu item if it isn't restricted.
  824.                 if ((SHRestricted(REST_FORCEACTIVEDESKTOPON) || (!SHRestricted(REST_NOACTIVEDESKTOP) && !SHRestricted(REST_CLASSICSHELL)))
  825.                     && !SHRestricted(REST_NOACTIVEDESKTOPCHANGES))
  826.                 {
  827.                     HMENU hmenuAD;
  828.                     MENUITEMINFO mii;
  829.                     if (hmenuAD = CDesktop_GetActiveDesktopMenu())
  830.                     {
  831.                         // Insert Active Desktop submenu at the top
  832.                         mii.cbSize = sizeof(MENUITEMINFO);
  833.                         mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
  834.                         mii.fType = MFT_STRING;
  835.                         mii.hSubMenu = hmenuAD;
  836.                         mii.cch = LoadString(HINST_THISDLL, IDS_ACTIVEDESKTOP, szMenu, ARRAYSIZE(szMenu));
  837.                         mii.dwTypeData = szMenu;
  838.                         InsertMenuItem(pqcm->hmenu, 0, TRUE, &mii);
  839.                     }
  840.                 }
  841.                 // Give a chance to add menuitem(s) to the extended menu object.
  842.                 //
  843.                 ASSERT(pqcm->idCmdFirst < idCmdFirst+FSIDM_DESKTOPEX_FIRST);
  844.                 ASSERT(pqcm->idCmdLast >= idCmdFirst+FSIDM_DESKTOPEX_LAST);
  845.                 if (!pdf->_pcmDesktopExt)
  846.                     hresT = _GetDesktopExtMenu(hwnd, &pdf->_pcmDesktopExt);
  847.                 if (pdf->_pcmDesktopExt)
  848.                 {
  849.                     hresT = pdf->_pcmDesktopExt->QueryContextMenu(
  850.                                 pqcm->hmenu, 0,
  851.                                 idCmdFirst+FSIDM_DESKTOPEX_FIRST,
  852.                                 idCmdFirst+FSIDM_DESKTOPEX_LAST,
  853.                                 0);
  854.                     if (SUCCEEDED(hresT))
  855.                     {
  856.                         pqcm->idCmdFirst = idCmdFirst + FSIDM_DESKTOPEX_FIRST + HRESULT_CODE(hresT);
  857.                     }
  858.                     else
  859.                     {
  860.                         DebugMsg(DM_ERROR, TEXT("WebBar: QueryContextMenu failed %x"), hresT);
  861.                     }
  862.                 }
  863.             }
  864.             else
  865.             {
  866.                 // HACK: We want no Properties for DesktopInExplorer
  867.                 DeleteMenu(pqcm->hmenu, FSIDM_PROPERTIESBG+idCmdFirst, MF_BYCOMMAND);
  868.             }
  869.         }
  870.         break;
  871.     case DFM_GETHELPTEXT:
  872.         LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));;
  873.         break;
  874.     case DFM_GETHELPTEXTW:
  875.         LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));;
  876.         break;
  877.     case DFM_INVOKECOMMAND:
  878.     case DFM_VALIDATECMD:
  879.         hr = CDesktop_HandleCommand(pdf, hwnd, wParam, uMsg == DFM_INVOKECOMMAND);
  880.         break;
  881.     default:
  882.         hr = E_NOTIMPL;
  883.         break;
  884.     }
  885.     return hr;
  886. }
  887. STDMETHODIMP CDesktopFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppvOut)
  888. {
  889.     HRESULT hr;
  890.     if (IsEqualIID(riid, IID_IShellView))
  891.     {
  892.         SFV_CREATE sSFV;
  893.         sSFV.cbSize   = sizeof(sSFV);
  894.         sSFV.psvOuter = NULL;
  895.         sSFV.psfvcb   = Desktop_CreateSFVCB(this);
  896.         QueryInterface(IID_IShellFolder, (void **)&sSFV.pshf);   // in case we are agregated
  897.         hr = SHCreateShellFolderView(&sSFV, (IShellView**)ppvOut);
  898.         if (sSFV.pshf)
  899.             sSFV.pshf->Release();
  900.         if (sSFV.psfvcb)
  901.             sSFV.psfvcb->Release();
  902.     }
  903.     else if (IsEqualIID(riid, IID_IDropTarget) && _psfDesktop)
  904.     {
  905.         hr = _psfDesktop->CreateViewObject(hwnd, riid, ppvOut);
  906.     }
  907.     else if (IsEqualIID(riid, IID_IContextMenu))
  908.     {
  909.         IShellFolder *psfTemp;
  910.         hr = QueryInterface(IID_IShellFolder, (void **)&psfTemp);
  911.         if (SUCCEEDED(hr))
  912.         {
  913.             HKEY hkNoFiles = NULL;
  914.             RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Directory\Background"), &hkNoFiles);
  915.             hr = CDefFolderMenu_Create2(&c_idlDesktop, hwnd, 0, NULL,
  916.                     psfTemp, CDesktop_DFMCallBackBG,
  917.                     1, &hkNoFiles, (IContextMenu **)ppvOut);
  918.             psfTemp->Release();
  919.             RegCloseKey(hkNoFiles);
  920.         }
  921.     }
  922.     else
  923.     {
  924.         *ppvOut = NULL;
  925.         hr = E_NOINTERFACE;
  926.     }
  927.     return hr;
  928. }
  929. STDMETHODIMP CDesktopFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfOut)
  930. {
  931.     if (IsSelf(cidl, apidl))
  932.     {
  933.         // the desktop's attributes
  934.         *rgfOut &= SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_CANRENAME | SFGAO_CANMONIKER |
  935.             SFGAO_HASSUBFOLDER | SFGAO_HASPROPSHEET | SFGAO_FILESYSANCESTOR;
  936.         return NOERROR;
  937.     }
  938.     IShellFolder2 *psf = _GetItemFolder(apidl[0]);
  939.     if (psf)
  940.         return psf->GetAttributesOf(cidl, apidl, rgfOut);
  941.     return E_UNEXPECTED;
  942. }
  943. HRESULT CDesktopFolder::_GetItemUIObject(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  944.                                          REFIID riid, UINT *prgfInOut, void **ppvOut)
  945. {
  946.     IShellFolder2 *psf = _GetItemFolder(apidl[0]);
  947.     if (psf)
  948.         return psf->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppvOut);
  949.     return E_UNEXPECTED;
  950. }
  951. STDMETHODIMP CDesktopFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  952.                                     REFIID riid, UINT *prgfInOut, void **ppvOut)
  953. {
  954.     HRESULT hr = E_NOINTERFACE;
  955.     
  956.     *ppvOut = NULL;
  957.     if (IsSelf(cidl, apidl))
  958.     {
  959.         // for the desktop itself
  960.         if (IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) 
  961.         {
  962.             hr = SHCreateDefExtIcon(NULL, II_DESKTOP, II_DESKTOP, GIL_PERCLASS, riid, ppvOut);
  963.         }
  964.         else if (IsEqualIID(riid, IID_IQueryInfo))
  965.         {
  966.             hr = CreateInfoTipFromText(MAKEINTRESOURCE(IDS_DESKTOP), riid, ppvOut); //The InfoTip COM object
  967.         }
  968.     }
  969.     else
  970.     {
  971.         if (IsEqualIID(riid, IID_IContextMenu))
  972.         {
  973.             hr = _GetItemUIObject(hwnd, cidl, apidl, riid, prgfInOut, ppvOut);
  974.         }
  975.         else if (IsEqualIID(riid, IID_IDataObject) && cidl)
  976.         {
  977.             if (cidl == 1)
  978.             {
  979.                 hr = _GetItemUIObject(hwnd, cidl, apidl, riid, prgfInOut, ppvOut);
  980.             }
  981.             else
  982.             {
  983.                 LPITEMIDLIST *ppidl, pidlAlt;
  984.                 SHGetIDListFromUnk((IUnknown*)_psfAltDesktop, &pidlAlt);
  985.             
  986.                 ppidl = (LPITEMIDLIST *)LocalAlloc(LPTR, sizeof(LPITEMIDLIST) * cidl);
  987.                 if (ppidl)
  988.                 {
  989.                     for (UINT i = 0; i < cidl; i++) 
  990.                     {
  991.                         if (pidlAlt && FS_IsCommonItem(apidl[i])) 
  992.                             ppidl[i] = ILCombine(pidlAlt, apidl[i]);
  993.                         else 
  994.                             ppidl[i] = ILClone(apidl[i]);
  995.                     }
  996.             
  997.                     hr = CFSFolder_CreateDataObject(&c_idlDesktop, cidl, (LPCITEMIDLIST *)ppidl, (IDataObject **)ppvOut);
  998.             
  999.                     for (i = 0; i < cidl; i++)
  1000.                         ILFree(ppidl[i]);
  1001.             
  1002.                     LocalFree(ppidl);
  1003.                 }
  1004.                 else
  1005.                     hr = E_OUTOFMEMORY;
  1006.                 if (pidlAlt)
  1007.                     ILFree(pidlAlt);
  1008.             }
  1009.         }
  1010.         else
  1011.         {
  1012.             hr = _GetItemUIObject(hwnd, cidl, apidl, riid, prgfInOut, ppvOut);
  1013.         }
  1014.     }
  1015.     return hr;
  1016. }
  1017. STDMETHODIMP CDesktopFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, STRRET *pStrRet)
  1018. {
  1019.     HRESULT hr;
  1020.     if (IsSelf(1, &pidl))
  1021.     {
  1022.         if ((dwFlags & (SHGDN_FORPARSING | SHGDN_INFOLDER | SHGDN_FORADDRESSBAR)) == SHGDN_FORPARSING)
  1023.         {
  1024.             // note some ISV apps puke if we return a full name here but the
  1025.             // rest of the shell depends on this...
  1026.             TCHAR szPath[MAX_PATH];
  1027.             SHGetFolderPath(NULL, CSIDL_DESKTOPDIRECTORY, NULL, 0, szPath);
  1028.             hr = StringToStrRet(szPath, pStrRet);
  1029.         }
  1030.         else
  1031.             hr = ResToStrRet(IDS_DESKTOP, pStrRet);   // display name, "Desktop"
  1032.     }
  1033.     else
  1034.     {
  1035.         IShellFolder2 *psf = _GetItemFolder(pidl);
  1036.         if (psf)
  1037.             hr = psf->GetDisplayNameOf(pidl, dwFlags, pStrRet);
  1038.         else
  1039.             hr = E_UNEXPECTED;
  1040.     }
  1041.     return hr;
  1042. }
  1043. STDMETHODIMP CDesktopFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, 
  1044.                                        LPCOLESTR pszName, DWORD dwRes, LPITEMIDLIST *ppidlOut)
  1045. {
  1046.     IShellFolder2 *psf = _GetItemFolder(pidl);
  1047.     if (psf)
  1048.         return psf->SetNameOf(hwnd, pidl, pszName, dwRes, ppidlOut);
  1049.     return E_UNEXPECTED;
  1050. }
  1051. STDMETHODIMP CDesktopFolder::GetDefaultSearchGUID(GUID *pGuid)
  1052. {
  1053.     return E_NOTIMPL;
  1054. }   
  1055. STDMETHODIMP CDesktopFolder::EnumSearches(LPENUMEXTRASEARCH *ppenum)
  1056. {
  1057.     *ppenum = NULL;
  1058.     return E_NOTIMPL;
  1059. }
  1060. STDMETHODIMP CDesktopFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  1061. {
  1062.     if (_psfDesktop)
  1063.         return _psfDesktop->GetDefaultColumn(dwRes, pSort, pDisplay);
  1064.     return E_UNEXPECTED;
  1065. }
  1066. STDMETHODIMP CDesktopFolder::GetDefaultColumnState(UINT iColumn, DWORD *pdwState)
  1067. {
  1068.     if (_psfDesktop)
  1069.         return _psfDesktop->GetDefaultColumnState(iColumn, pdwState);
  1070.     return E_UNEXPECTED;
  1071. }
  1072. STDMETHODIMP CDesktopFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  1073. {
  1074.     IShellFolder2 *psf = _GetItemFolder(pidl);
  1075.     if (psf)
  1076.         return psf->GetDetailsEx(pidl, pscid, pv);
  1077.     return E_UNEXPECTED;
  1078. }
  1079. STDMETHODIMP CDesktopFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  1080. {
  1081.     IShellFolder2 *psf = _GetItemFolder(pidl);
  1082.     if (psf)
  1083.         return psf->GetDetailsOf(pidl, iColumn, pDetails);
  1084.     return E_UNEXPECTED;
  1085. }
  1086. STDMETHODIMP CDesktopFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID *pscid)
  1087. {
  1088.     if (_psfDesktop)
  1089.         return _psfDesktop->MapColumnToSCID(iColumn, pscid);
  1090.     return E_UNEXPECTED;
  1091. }
  1092. STDMETHODIMP CDesktopFolder::GetClassID(CLSID *pCLSID)
  1093. {
  1094.     *pCLSID = CLSID_ShellDesktop;
  1095.     return NOERROR;
  1096. }
  1097. STDMETHODIMP CDesktopFolder::Initialize(LPCITEMIDLIST pidl)
  1098. {
  1099.     return ILIsEmpty(pidl) ? S_OK : E_INVALIDARG;
  1100. }
  1101. STDMETHODIMP CDesktopFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  1102. {
  1103.     return GetCurFolderImpl(&c_idlDesktop, ppidl);
  1104. }
  1105. STDMETHODIMP CDesktopFolder::GetIconOf(LPCITEMIDLIST pidl, UINT flags, int *piIndex)
  1106. {
  1107.     IShellIcon *psi;
  1108.     HRESULT hr = _QueryInterfaceItem(pidl, IID_IShellIcon, (void **)&psi);
  1109.     if (SUCCEEDED(hr))
  1110.     {
  1111.         hr = psi->GetIconOf(pidl, flags, piIndex);
  1112.         psi->Release();
  1113.     }
  1114.     return hr;
  1115. }
  1116. STDMETHODIMP CDesktopFolder::GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
  1117. {
  1118.     IShellIconOverlay *psio;
  1119.     HRESULT hr = _QueryInterfaceItem(pidl, IID_IShellIconOverlay, (void **)&psio);
  1120.     if (SUCCEEDED(hr))
  1121.     {
  1122.         hr = psio->GetOverlayIndex(pidl, pIndex);
  1123.         psio->Release();
  1124.     }
  1125.     return hr;
  1126. }
  1127. STDMETHODIMP CDesktopFolder::GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIconIndex)
  1128. {
  1129.     IShellIconOverlay *psio;
  1130.     HRESULT hr = _QueryInterfaceItem(pidl, IID_IShellIconOverlay, (void **)&psio);
  1131.     if (SUCCEEDED(hr))
  1132.     {
  1133.         hr = psio->GetOverlayIconIndex(pidl, pIconIndex);
  1134.         psio->Release();
  1135.     }
  1136.     return hr;
  1137. }
  1138. //
  1139. // we only care about events that actually change the enumeration
  1140. // so updateimage and the like we don't care about
  1141. //
  1142. STDAPI_(void) Desktop_InvalidateEnumCache(LPCITEMIDLIST pidl, LONG lEvent)
  1143. {
  1144.     if (pidl) 
  1145.     {
  1146.         if (ILIsEmpty(pidl)) 
  1147.         {
  1148.             if (lEvent & SHCNE_DISKEVENTS) 
  1149.             {
  1150.                 // change on the desktop itself
  1151.                 // invalidate all
  1152.                 SFEnumCache_Invalidate(&g_EnumCache, ENUMGRFFLAGS);
  1153.             }
  1154.         } 
  1155.         else if (ILIsEmpty(_ILNext(pidl))) 
  1156.         {
  1157.             // if it's the direct child of the desktop...
  1158.             if (lEvent & (SHCNE_RENAMEITEM | SHCNE_CREATE | SHCNE_DELETE))
  1159.                 SFEnumCache_Invalidate(&g_EnumCache, SHCONTF_INCLUDEHIDDEN | SHCONTF_NONFOLDERS);
  1160.             else if (lEvent & (SHCNE_RENAMEFOLDER | SHCNE_MKDIR | SHCNE_RMDIR))
  1161.                 SFEnumCache_Invalidate(&g_EnumCache, SHCONTF_INCLUDEHIDDEN | SHCONTF_FOLDERS);
  1162.             else if (lEvent & SHCNE_UPDATEITEM)
  1163.                 SFEnumCache_Invalidate(&g_EnumCache, SHCONTF_INCLUDEHIDDEN | SHCONTF_FOLDERS | SHCONTF_NONFOLDERS);
  1164.         }
  1165.     }
  1166. }
  1167. // Sets *ppidl to the proper pidl to notify and
  1168. // returns TRUE iff pidl is a desktop/commondesktop item.
  1169. // In the commondesktop case, it munges the pidl and stores the newly allocated pidl in ppidlTemp
  1170. BOOL CDesktop_FSEventHelper(LPITEMIDLIST pidfDesktop, LPITEMIDLIST pidfCommonDesktop, LPCITEMIDLIST pidl, LPITEMIDLIST * ppidl, LPITEMIDLIST * ppidlTemp)
  1171. {
  1172.     BOOL fResend;
  1173.     if (NULL != (*ppidl = ILFindChild(pidfDesktop, pidl))) 
  1174.     {
  1175.         fResend = TRUE;
  1176.     } 
  1177.     else if (NULL != (*ppidl = ILFindChild(pidfCommonDesktop, pidl))) 
  1178.     {
  1179.         fResend = TRUE;
  1180.         if (!ILIsEmpty(*ppidl)) 
  1181.         {
  1182.             *ppidlTemp = ILClone(*ppidl);
  1183.             if (*ppidlTemp) 
  1184.             {
  1185.                 FS_MakeCommonItem(*ppidlTemp);
  1186.                 *ppidl = *ppidlTemp;
  1187.             }
  1188.         }
  1189.     } 
  1190.     else
  1191.     {
  1192.         fResend = FALSE;
  1193.         *ppidl = (LPITEMIDLIST)pidl;
  1194.     }
  1195.     return fResend;
  1196. }
  1197. class CDesktopViewCallBack : public CBaseShellFolderViewCB
  1198. {
  1199. public:
  1200.     CDesktopViewCallBack(CDesktopFolder* pdf);
  1201.     STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  1202. private:
  1203.     CDesktopFolder* _pdf;
  1204.     HRESULT OnMERGEMENU(DWORD pv, QCMINFO*lP)
  1205.     {
  1206.         CDefFolderMenu_MergeMenu(HINST_THISDLL, 0, POPUP_FSVIEW_POPUPMERGE, lP);
  1207.         return S_OK;
  1208.     }
  1209.     HRESULT OnINVOKECOMMAND(DWORD pv, UINT wP)
  1210.     {
  1211.         return CDesktop_DFMCallBackBG(m_pshf, m_hwndMain, NULL, DFM_INVOKECOMMAND, wP, 0);
  1212.     }
  1213.     HRESULT OnSupportsIdentity(DWORD pv)
  1214.     {
  1215.         return S_OK;
  1216.     }
  1217.     HRESULT OnGETHELPTEXT(DWORD pv, UINT wPl, UINT wPh, LPTSTR lP)
  1218.     {
  1219. #ifdef UNICODE
  1220.         return CDesktop_DFMCallBackBG(m_pshf, m_hwndMain, NULL, DFM_GETHELPTEXTW, MAKEWPARAM(wPl, wPh), (LPARAM)lP);
  1221. #else
  1222.         return CDesktop_DFMCallBackBG(m_pshf, m_hwndMain, NULL, DFM_GETHELPTEXT, MAKEWPARAM(wPl, wPh), (LPARAM)lP);
  1223. #endif
  1224.     }
  1225.     HRESULT OnGETCCHMAX(DWORD pv, LPCITEMIDLIST pidlItem, UINT *lP)
  1226.     {
  1227.         if (SIL_GetType(pidlItem) == SHID_ROOT_REGITEM) // evil, we should not have to know this
  1228.         {
  1229.             *lP = MAX_REGITEMCCH;
  1230.             return NOERROR;
  1231.         }
  1232.         else
  1233.         {
  1234.             IShellFolder2 *psf = _pdf->_GetItemFolder(pidlItem);
  1235.             if (psf)
  1236.             {
  1237.                 CFSFolder *pfsf = FS_GetFSFolderFromShellFolder(psf);
  1238.                 return CFSFolder_GetCCHMax(pfsf, FS_IsValidID(pidlItem), lP);
  1239.             }
  1240.         }
  1241.         return E_FAIL;
  1242.     }
  1243.     HRESULT OnGetViews(DWORD pv, SHELLVIEWID *pvid, IEnumSFVViews **ppObj);
  1244.     HRESULT OnGetWorkingDir(DWORD pv, UINT wP, LPTSTR pszDir)
  1245.     {
  1246.         return SHGetSpecialFolderPath(NULL, pszDir, CSIDL_DESKTOPDIRECTORY, TRUE) ? S_OK : E_FAIL;
  1247.     }
  1248. };
  1249. #define DESKTOP_EVENTS 
  1250.     SHCNE_DISKEVENTS | 
  1251.     SHCNE_ASSOCCHANGED | 
  1252.     SHCNE_NETSHARE | 
  1253.     SHCNE_NETUNSHARE
  1254. CDesktopViewCallBack::CDesktopViewCallBack(CDesktopFolder* pdf) : 
  1255.     CBaseShellFolderViewCB(SAFECAST(pdf, IShellFolder *), (LPCITEMIDLIST)&c_idlDesktop, DESKTOP_EVENTS),
  1256.     _pdf(pdf)
  1257. }
  1258. IShellFolderViewCB* Desktop_CreateSFVCB(CDesktopFolder* pdf)
  1259. {
  1260.     return new CDesktopViewCallBack(pdf);
  1261. }
  1262. HRESULT CDesktopViewCallBack::OnGetViews(DWORD pv, SHELLVIEWID *pvid, IEnumSFVViews **ppObj)
  1263. {
  1264.     *ppObj = NULL;
  1265.     CViewsList cViews;
  1266.     // Add base class stuff
  1267.     cViews.AddReg(HKEY_CLASSES_ROOT, TEXT("folder"));
  1268.     // Add 2nd base class stuff
  1269.     cViews.AddReg(HKEY_CLASSES_ROOT, TEXT("directory"));
  1270.     IBrowserService2* pbs;
  1271.     if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SShellDesktop, IID_IUnknown, (void**)&pbs)))
  1272.     {   // It's the actual desktop
  1273.         pbs->Release();
  1274.         // Add this class stuff
  1275.         cViews.AddCLSID(&CLSID_ShellDesktop);
  1276.     }
  1277.     else    // Don't add the desktop.ini stuff for the actual desktop. Add it only if we are in folder view
  1278.     {
  1279.         TCHAR szHere[MAX_PATH];
  1280.         if (SHGetPathFromIDList(m_pidl, szHere))
  1281.         {
  1282.             TCHAR szIniFile[MAX_PATH];
  1283.             PathCombine(szIniFile, szHere, c_szDesktopIni);
  1284.             cViews.AddIni(szIniFile, szHere);
  1285.         }
  1286.     }
  1287.     cViews.GetDef(pvid);
  1288.     return CreateEnumCViewList(&cViews, ppObj);
  1289.     // Note the automatic destructor will free any views still left
  1290. }
  1291. STDMETHODIMP CDesktopViewCallBack::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1292. {
  1293.     switch (uMsg)
  1294.     {
  1295.     HANDLE_MSG(0, SFVM_MERGEMENU, OnMERGEMENU);
  1296.     HANDLE_MSG(0, SFVM_INVOKECOMMAND, OnINVOKECOMMAND);
  1297.     HANDLE_MSG(0, SFVM_SUPPORTSIDENTITY, OnSupportsIdentity);
  1298.     HANDLE_MSG(0, SFVM_GETHELPTEXT, OnGETHELPTEXT);
  1299.     HANDLE_MSG(0, SFVM_GETCCHMAX, OnGETCCHMAX);
  1300.     HANDLE_MSG(0, SFVM_GETVIEWS, OnGetViews);
  1301.     HANDLE_MSG(0, SFVM_GETWORKINGDIR, OnGetWorkingDir);
  1302.     default:
  1303.         return E_FAIL;
  1304.     }
  1305.     return NOERROR;
  1306. }
  1307. CDesktopFolderEnum::CDesktopFolderEnum(CDesktopFolder *pdf, HWND hwnd, DWORD grfFlags) : 
  1308.     _cRef(1), _bUseAltEnum(FALSE)
  1309. {
  1310.     if (pdf->_psfDesktop)
  1311.         pdf->_psfDesktop->EnumObjects(hwnd, grfFlags, &_penumFolder);
  1312.     if (pdf->_psfAltDesktop) 
  1313.         pdf->_psfAltDesktop->EnumObjects(hwnd, grfFlags, &_penumAltFolder);
  1314. }
  1315. CDesktopFolderEnum::~CDesktopFolderEnum()
  1316. {
  1317.     if (_penumFolder)
  1318.         _penumFolder->Release();
  1319.     if (_penumAltFolder)
  1320.         _penumAltFolder->Release();
  1321. }
  1322. STDMETHODIMP CDesktopFolderEnum::QueryInterface(REFIID riid, void **ppv)
  1323. {
  1324.     static const QITAB qit[] = {
  1325.         QITABENT(CDesktopFolderEnum, IEnumIDList),                        // IID_IEnumIDList
  1326.         { 0 },
  1327.     };
  1328.     return QISearch(this, qit, riid, ppv);
  1329. }
  1330. STDMETHODIMP_(ULONG) CDesktopFolderEnum::AddRef()
  1331. {
  1332.     return InterlockedIncrement(&_cRef);
  1333. }
  1334. STDMETHODIMP_(ULONG) CDesktopFolderEnum::Release()
  1335. {
  1336.     if (InterlockedDecrement(&_cRef))
  1337.         return _cRef;
  1338.     delete this;
  1339.     return 0;
  1340. }
  1341. STDMETHODIMP CDesktopFolderEnum::Next(ULONG celt, LPITEMIDLIST *ppidl, ULONG *pceltFetched)
  1342. {
  1343.     HRESULT hr;
  1344.     if (_bUseAltEnum)
  1345.     {
  1346.        if (_penumAltFolder) 
  1347.        {
  1348.            hr = _penumAltFolder->Next(celt, ppidl, pceltFetched);
  1349.            if (S_OK == hr)
  1350.            {
  1351.                ULONG i, iCount = pceltFetched ? *pceltFetched : 1;
  1352.                for (i = 0; i < iCount; i++)
  1353.                    FS_MakeCommonItem(ppidl[i]);
  1354.            }
  1355.        }
  1356.        else
  1357.            hr = S_FALSE;
  1358.     } 
  1359.     else if (_penumFolder)
  1360.     {
  1361.        hr = _penumFolder->Next(celt, ppidl, pceltFetched);
  1362.        if (S_OK != hr) 
  1363.        {
  1364.            _bUseAltEnum = TRUE;
  1365.            hr = Next(celt, ppidl, pceltFetched);  // recurse
  1366.        }
  1367.     }
  1368.     else
  1369.     {
  1370.         hr = S_FALSE;
  1371.     }
  1372.     if (hr == S_FALSE)
  1373.     {
  1374.         *ppidl = NULL;
  1375.         if (pceltFetched)
  1376.             *pceltFetched = 0;
  1377.     }
  1378.     return hr;
  1379. }
  1380. STDMETHODIMP CDesktopFolderEnum::Skip(ULONG celt) 
  1381. {
  1382.     return E_NOTIMPL;
  1383. }
  1384. STDMETHODIMP CDesktopFolderEnum::Reset() 
  1385. {
  1386.     if (_penumFolder)
  1387.         _penumFolder->Reset();
  1388.     if (_penumAltFolder)
  1389.         _penumAltFolder->Reset();
  1390.     _bUseAltEnum = FALSE;
  1391.     return S_OK;
  1392. }
  1393. STDMETHODIMP CDesktopFolderEnum::Clone(IEnumIDList **ppenum) 
  1394. {
  1395.     *ppenum = NULL;
  1396.     return E_NOTIMPL;
  1397. }