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

Windows Kernel

Development Platform:

Visual C++

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1991-1996
  4. //
  5. // File:      recdocs.cpp
  6. //
  7. // History -  created from recent.c in explorer  - ZekeL - 5-MAR-98
  8. //              combining functionality in to one place
  9. //              now that the desktop lives here.
  10. //---------------------------------------------------------------------------
  11. #include "shellprv.h"
  12. #include "shobjprv.h"
  13. #include "recdocs.h"
  14. #include "fstreex.h"
  15. #include "shcombox.h"
  16. #include "ids.h"
  17. #include <urlhist.h>
  18. #include <runtask.h>
  19. #define DM_RECENTDOCS 0x80000000
  20. #define GETRECNAME(p) ((LPCTSTR)(p))
  21. #define GETRECPIDL(p) ((LPCITEMIDLIST) (((LPBYTE) (p)) + CbFromCch(lstrlen(GETRECNAME(p)) +1)))
  22. #define REGSTR_KEY_RECENTDOCS TEXT("RecentDocs")
  23. #define MAX_RECMRU_BUF      (CbFromCch(3 * MAX_PATH))   // Max MRUBuf size
  24. STDAPI RecentDocs_Install(BOOL bInstall)
  25. {
  26.     TCHAR szPath[MAX_PATH];
  27.     // get the path to the favorites folder. Create it if it is missing and we
  28.     // are installing, otherwise don't bother.
  29.     if (SHGetSpecialFolderPath(NULL, szPath, CSIDL_RECENT, bInstall))
  30.     {
  31.         if (bInstall)
  32.         {
  33.             SHFOLDERCUSTOMSETTINGS fcs = {sizeof(fcs), FCSM_INFOTIP | FCSM_ICONFILE, 0};
  34.             TCHAR szInfoTip[128];
  35.             TCHAR szIconFile[MAX_PATH];
  36.     
  37.             //Get the infotip for the recent files Folder
  38.             LoadString(HINST_THISDLL, IDS_RECENT, szInfoTip, ARRAYSIZE(szInfoTip) );
  39.             fcs.pszInfoTip = szInfoTip;
  40.             // Get the IconFile and IconIndex for the Recent Files Folder
  41.             GetSystemDirectory(szIconFile, ARRAYSIZE(szIconFile));
  42.             PathAppend(szIconFile, TEXT("shdocvw.dll"));
  43.             fcs.pszIconFile = szIconFile;
  44.             fcs.iIconIndex = -20785;    // IDI_HISTFOLDER
  45.             SHGetSetFolderCustomSettings(&fcs, szPath, FCS_WRITE);
  46.         }
  47.     }
  48.     return NOERROR; 
  49. }
  50. class CTaskAddDoc : public CRunnableTask
  51. {
  52. public:
  53.     CTaskAddDoc();
  54.     HRESULT Init(HANDLE hMem, DWORD dwProcId);
  55.     // *** pure virtuals ***
  56.     virtual STDMETHODIMP RunInitRT(void);
  57. private:
  58.     virtual ~CTaskAddDoc();
  59.     void _AddToRecentDocs(LPCITEMIDLIST pidlItem, LPCTSTR pszPath);
  60.     void _TryDeleteMRUItem(HANDLE hmru, DWORD cMax, LPCTSTR pszFileName, LPCITEMIDLIST pidlItem, HANDLE hmruOther, BOOL fOverwrite);
  61.     LPBYTE _CreateMRUItem(LPCITEMIDLIST pidlItem, LPCTSTR pszItem, DWORD *pcbItem, UINT uFlags);
  62.     BOOL _AddDocToRecentAndExtRecent(LPCITEMIDLIST pidlItem, LPCTSTR pszFileName, LPCTSTR pszExt);
  63.     void _TryUpdateNetHood(LPCITEMIDLIST pidlFolder, LPCTSTR pszFolder);
  64.     void _UpdateNetHood(LPCITEMIDLIST pidlFolder, LPCTSTR pszShare);
  65.     //  private members
  66.     HANDLE _hMem;
  67.     DWORD  _dwProcId;
  68.     HANDLE _hmruRecent;
  69.     DWORD _cMaxRecent;
  70.     LPITEMIDLIST _pidlTarget;
  71. };
  72. BOOL ShouldAddToRecentDocs(LPCITEMIDLIST pidl)
  73. {
  74.     HKEY hk;
  75.     BOOL fRet = TRUE;  //  default to true
  76.     SHGetClassKey(pidl, &hk, NULL);
  77.     if (hk)
  78.     {
  79.         fRet = !(GetFileTypeAttributes(hk) & FTA_NoRecentDocs);
  80.         SHCloseClassKey(hk);
  81.     }
  82.     return fRet;
  83. }
  84. int cdecl RecentDocsCompareName(const void * p1, const void *p2, size_t cb)
  85. {
  86.     return lstrcmpi(GETRECNAME(p2), (LPCTSTR)p1);
  87. }
  88. int cdecl RecentDocsComparePidl(const void * p1, const void *p2, size_t cb)
  89. {
  90.     //  p2 is the one that is in the MRU and p1 is the one that we are passing in...
  91.     return !ILIsEqual(GETRECPIDL(p2), (LPCITEMIDLIST)p1);
  92. }
  93. CTaskAddDoc::~CTaskAddDoc(void)
  94. {
  95.     TraceMsg(DM_RECENTDOCS, "[%X] CTaskAddDoc destroyed", this);
  96. }
  97. CTaskAddDoc::CTaskAddDoc(void) : CRunnableTask(RTF_DEFAULT)
  98. {
  99.     TraceMsg(DM_RECENTDOCS, "[%X] CTaskAddDoc created", this);
  100. }
  101. HRESULT CTaskAddDoc::Init( HANDLE hMem, DWORD dwProcId)
  102. {
  103.     if (hMem)
  104.     {
  105.         _hMem = hMem;
  106.         _dwProcId = dwProcId;
  107.         return S_OK;
  108.     }
  109.     return E_FAIL;
  110. }
  111. typedef struct _ARD {
  112.     DWORD   dwOffsetPath;
  113.     DWORD   dwOffsetPidl;
  114. } XMITARD, *PXMITARD;
  115. HRESULT CTaskAddDoc::RunInitRT(void)
  116. {
  117.     TraceMsg(DM_RECENTDOCS, "[%X] CTaskAddDoc::RunInitRT() running", this);
  118.     PXMITARD px = (PXMITARD)SHLockShared(_hMem, _dwProcId);
  119.     if (px)
  120.     {
  121.         LPITEMIDLIST pidl = px->dwOffsetPidl ? (LPITEMIDLIST)((LPBYTE)px+px->dwOffsetPidl) : NULL;
  122.         LPTSTR pszPath = px->dwOffsetPath ? (LPTSTR)((LPBYTE)px+px->dwOffsetPath) : NULL;
  123.         ASSERT(pszPath);
  124.         
  125.         _AddToRecentDocs(pidl, pszPath);
  126.         SHUnlockShared(px);
  127.         SHFreeShared(_hMem, _dwProcId);
  128.     }
  129.     
  130.     return S_OK;
  131. }
  132. BOOL GetExtensionClassDescription(LPCTSTR lpszFile)
  133. {
  134.     LPTSTR lpszExt = PathFindExtension(lpszFile);
  135.     if (*lpszExt) 
  136.     {
  137.         TCHAR szClass[128];
  138.         TCHAR szDescription[MAX_PATH];
  139.         long cchClass = SIZEOF(szClass);
  140.         if (SHRegQueryValue(HKEY_CLASSES_ROOT, lpszExt, szClass, &cchClass) != ERROR_SUCCESS) 
  141.         {
  142.             // if this fails, use the extension cause it might be a pseudoclass
  143.             lstrcpyn(szClass, lpszExt, ARRAYSIZE(szClass));
  144.         }
  145.         return GetClassDescription(HKEY_CLASSES_ROOT, szClass, szDescription, ARRAYSIZE(szDescription),
  146.                                    GCD_MUSTHAVEOPENCMD | GCD_ALLOWPSUDEOCLASSES);
  147.     }
  148.     return FALSE;
  149. }
  150. STDAPI_(void) FlushRunDlgMRU(void);
  151. //
  152. //  _CleanRecentDocs()
  153. //  cleans out the recent docs folder and the associate registry keys.
  154. //
  155. void _CleanRecentDocs(void)
  156. {
  157.     LPITEMIDLIST pidlTargetLocal = SHCloneSpecialIDList(NULL, CSIDL_RECENT, TRUE);
  158.     if (pidlTargetLocal)
  159.     {
  160.         HKEY hkey;
  161.         TCHAR szDir[MAX_PATH];
  162.         // first, delete all the files
  163.         SHFILEOPSTRUCT sFileOp =
  164.         {
  165.             NULL,
  166.             FO_DELETE,
  167.             szDir,
  168.             NULL,
  169.             FOF_NOCONFIRMATION | FOF_SILENT,
  170.         };
  171.         
  172.         SHGetPathFromIDList(pidlTargetLocal, szDir);
  173.         PathAppend(szDir, c_szStarDotStar);
  174.         szDir[lstrlen(szDir) +1] = 0;     // double null terminate
  175.         SHFileOperation(&sFileOp);
  176.         ILFree(pidlTargetLocal);
  177.         pidlTargetLocal = SHCloneSpecialIDList(NULL, CSIDL_NETHOOD, TRUE);
  178.         if (pidlTargetLocal)
  179.         {
  180.             //  now we take care of cleaning out the nethood
  181.             //  we have to more careful, cuz we let other people
  182.             //  add their own stuff in here.
  183.             
  184.             HANDLE hmru = CreateSharedRecentMRUList(TEXT("NetHood"), NULL, SRMLF_COMPPIDL);
  185.             if (hmru)
  186.             {
  187.                 IShellFolder* psf;
  188.                 if (SUCCEEDED(SHBindToObject(NULL, IID_IShellFolder, pidlTargetLocal, (void **)&psf)))
  189.                 {
  190.                     BOOL fUpdate = FALSE;
  191.                     int iItem = 0;
  192.                     LPITEMIDLIST pidlItem;
  193.                     ASSERT(psf);
  194.                     while (-1 != EnumSharedRecentMRUList(hmru, iItem++, NULL, &pidlItem))
  195.                     {
  196.                         ASSERT(pidlItem);
  197.                         STRRET str;
  198.                         if (SUCCEEDED(psf->GetDisplayNameOf(pidlItem, SHGDN_FORPARSING, &str))
  199.                         && SUCCEEDED(StrRetToBuf(&str, pidlItem, szDir, ARRAYSIZE(szDir))))
  200.                         {
  201.                             szDir[lstrlen(szDir) +1] = 0;     // double null terminate
  202.                             SHFileOperation(&sFileOp);
  203.                         }
  204.                         ILFree(pidlItem);
  205.                     }
  206.                     if (fUpdate)
  207.                         SHChangeNotify(SHCNE_UPDATEDIR, 0, (void *)pidlTargetLocal, NULL);
  208.                     psf->Release();
  209.                 }
  210.                 FreeMRUList(hmru);
  211.             }
  212.             ILFree(pidlTargetLocal);
  213.         }
  214.         // now delete the registry stuff
  215.         hkey = SHGetExplorerHkey(HKEY_CURRENT_USER, TRUE);
  216.         if (hkey)
  217.         {
  218.             SHDeleteKey(hkey, REGSTR_KEY_RECENTDOCS);
  219.             RegCloseKey(hkey);
  220.         }
  221.         //  reinit the the folder.
  222.         RecentDocs_Install(TRUE);
  223.         SHChangeNotifyHandleEvents();
  224.     }
  225.     
  226.     FlushRunDlgMRU();
  227.     return;
  228. }
  229. //
  230. //  WARNING - _TryDeleteMRUItem() returns an allocated string that must be freed
  231. //
  232. void CTaskAddDoc::_TryDeleteMRUItem(HANDLE hmru, DWORD cMax, LPCTSTR pszFileName, LPCITEMIDLIST pidlItem, HANDLE hmruOther, BOOL fOverwrite)
  233. {
  234.     BYTE buf[MAX_RECMRU_BUF] = {0};
  235.     DWORD cbItem = CbFromCch(lstrlen(pszFileName) + 1);
  236.     int iItem = fOverwrite ? FindMRUData(hmru, pszFileName, cbItem, NULL) : -1;
  237.     //
  238.     //  if iItem is not -1 then it is already existing item that we will replace.
  239.     //  if it is -1 then we need to point iItem to the last in the list.
  240.     if (iItem == -1)
  241.     {
  242.         //  torch the last one if we have the max number of items in the list.
  243.         //  default to success, cuz if we dont find it we dont need to delete it
  244.         iItem = cMax - 1;
  245.     }
  246.     //  if we cannot get it in order to delete it, 
  247.     //  then we will not overwrite the item.
  248.     if (EnumMRUList(hmru, iItem, buf, SIZEOF(buf)) != -1)
  249.     {
  250.         //  convert the buf into the last segment of the pidl
  251.         LPITEMIDLIST pidlFullLink = ILCombine(_pidlTarget, GETRECPIDL(buf));
  252.         if (pidlFullLink)
  253.         {
  254.             // This is semi-gross, but some link types like calling cards are the
  255.             // actual data.  If we delete and recreate they lose their info for the
  256.             // run.  We will detect this by knowing that their pidl will be the
  257.             // same as the one we are deleting...
  258.             if (!ILIsEqual(pidlFullLink, pidlItem))
  259.             {
  260.                 TCHAR sz[MAX_PATH];
  261.                 // now remove out link to it
  262.                 SHGetPathFromIDList(pidlFullLink, sz);
  263.                 Win32DeleteFile(sz);
  264.                 TraceMsg(DM_RECENTDOCS, "[%X] CTaskAddDoc::_TryDeleteMRUItem() deleting '%s'", this, sz);   
  265.                 if (hmruOther) 
  266.                 {
  267.                     //  deleted a shortcut, 
  268.                     //  need to try and remove it from the hmruOther...
  269.                     iItem = FindMRUData(hmruOther, GETRECNAME(buf), CbFromCch(lstrlen(GETRECNAME(buf)) +1), NULL);
  270.                     if (iItem != -1)
  271.                         DelMRUString(hmruOther, iItem);
  272.                 }
  273.             }
  274.             ILFree(pidlFullLink);
  275.         }
  276.     }
  277. }
  278. // in:
  279. // pidlItem - full IDList for the item being added
  280. // pszItem  - name (file spec) of the item (used in the display to the user)
  281. // uFlags   - SHCL_ flags
  282. LPBYTE CTaskAddDoc::_CreateMRUItem(LPCITEMIDLIST pidlItem, LPCTSTR pszItem, 
  283.                                    DWORD *pcbOut, UINT uFlags)
  284. {
  285.     TCHAR sz[MAX_PATH];
  286.     LPBYTE pitem = NULL;
  287.     // create the new one
  288.     if (SHGetPathFromIDList(_pidlTarget, sz)) 
  289.     {
  290.         LPITEMIDLIST pidlFullLink;
  291.         if (SUCCEEDED(CreateLinkToPidl(pidlItem, sz, &pidlFullLink, uFlags)) && 
  292.             pidlFullLink)
  293.         {
  294.             LPCITEMIDLIST pidlLinkLast = ILFindLastID(pidlFullLink);
  295.             int cbLinkLast = ILGetSize(pidlLinkLast);
  296.             DWORD cbItem = CbFromCch(lstrlen(pszItem) + 1);
  297.             pitem = (LPBYTE) LocalAlloc(LPTR, cbItem + cbLinkLast);
  298.             if (pitem)
  299.             {
  300.                 memcpy( pitem, pszItem, cbItem );
  301.                 memcpy( pitem + cbItem, pidlLinkLast, cbLinkLast);
  302.                 *pcbOut = cbItem + cbLinkLast;
  303.             }
  304.             ILFree(pidlFullLink);
  305.         }
  306.     }
  307.     
  308.     return pitem;
  309. }
  310. int EnumSharedRecentMRUList(HANDLE hmru, int iItem, LPTSTR *ppszName, LPITEMIDLIST *ppidl)
  311. {
  312.     BYTE buf[MAX_RECMRU_BUF] = {0};
  313.     int iRet;
  314.     //  if both out params are NULL or iItem < 0 then this is a query for the size
  315.     //  of the MRU list...
  316.     if (ppszName)
  317.         *ppszName = NULL;
  318.     if (ppidl)
  319.         *ppidl = NULL;
  320.         
  321.     if (iItem < 0 || (!ppszName && !ppidl))
  322.         iRet = EnumMRUList(hmru, -1, NULL, 0);
  323.     else if (-1 != (iRet = EnumMRUList(hmru, iItem, buf, SIZEOF(buf))))
  324.     {
  325.         if (ppszName)
  326.         {
  327.             *ppszName = StrDup(GETRECNAME(buf));
  328.             if (!*ppszName)
  329.                 iRet = -1;
  330.         }
  331.         else if (ppidl)
  332.         {
  333.             *ppidl = ILClone(GETRECPIDL(buf));
  334.             if (!*ppidl)
  335.                 iRet = -1;
  336.         }
  337.     }
  338.     return iRet;
  339. }
  340. #define MAXRECENT_DEFAULTDOC      10
  341. #define MAXRECENT_MAJORDOC        20
  342. HANDLE CreateSharedRecentMRUList(LPCTSTR pszClass, DWORD *pcMax, DWORD dwFlags)
  343. {
  344.     if (SHRestricted(REST_NORECENTDOCSHISTORY))
  345.         return NULL;
  346.     DWORD cMax;
  347.     MRUCMPDATAPROC procCompare = RecentDocsCompareName;
  348.     TCHAR szKey[MAX_PATH];
  349.     LPCTSTR pszKey = REGSTR_PATH_EXPLORER TEXT("\") REGSTR_KEY_RECENTDOCS;
  350.     if (pszClass)
  351.     {
  352.         //  want to use the pszExt as a sub key
  353.         lstrcpy(szKey, pszKey);
  354.         StrCatBuff(szKey, TEXT("\"), SIZECHARS(szKey));
  355.         StrCatBuff(szKey, pszClass, SIZECHARS(szKey));
  356.         pszKey = szKey;
  357.         //  we need to find out how many
  358.         DWORD dwType = REG_DWORD, dwMajor = 0, cbSize = SIZEOF(cbSize);
  359.         SHGetValue(HKEY_CLASSES_ROOT, pszClass, TEXT("MajorDoc"), &dwType, (LPVOID)&dwMajor, &cbSize);
  360.         cMax = dwMajor ? MAXRECENT_MAJORDOC : MAXRECENT_DEFAULTDOC;
  361.     }
  362.     else
  363.     {
  364.         //  this the root MRU
  365.         cMax = SHRestricted(REST_MaxRecentDocs);
  366.         //  default max docs...
  367.         if (cMax < 1)
  368.             cMax = MAXRECENTDOCS * MAXRECENT_DEFAULTDOC;
  369.     }
  370.     if (dwFlags & SRMLF_COMPPIDL)
  371.         procCompare = RecentDocsComparePidl;
  372.         
  373.     MRUDATAINFO mi =  {
  374.         SIZEOF(MRUDATAINFO),
  375.         cMax,
  376.         MRU_BINARY | MRU_CACHEWRITE,
  377.         HKEY_CURRENT_USER,
  378.         pszKey,
  379.         procCompare
  380.         };
  381.     if (pcMax)
  382.         *pcMax = cMax;
  383.         
  384.     return CreateMRUList((MRUINFO *)&mi);
  385. }
  386. BOOL CTaskAddDoc::_AddDocToRecentAndExtRecent(LPCITEMIDLIST pidlItem, LPCTSTR pszFileName, 
  387.                                               LPCTSTR pszExt)
  388. {
  389.     DWORD cbItem = CbFromCch(lstrlen(pszFileName) + 1);
  390.     DWORD cMax;
  391.     HANDLE hmru = CreateSharedRecentMRUList(pszExt, &cMax, SRMLF_COMPNAME);
  392.     _TryDeleteMRUItem(_hmruRecent, _cMaxRecent, pszFileName, pidlItem, hmru, TRUE);
  393.     LPBYTE pitem = _CreateMRUItem(pidlItem, pszFileName, &cbItem, 0);
  394.     if (pitem)
  395.     {
  396.         AddMRUData(_hmruRecent, pitem, cbItem);
  397.         if (hmru)
  398.         {
  399.             //  we dont want to delete the file if it already existed, because
  400.             //  the TryDelete on the RecentMRU would have already done that
  401.             //  we only want to delete if we have some overflow from the ExtMRU
  402.             _TryDeleteMRUItem(hmru, cMax, pszFileName, pidlItem, _hmruRecent, FALSE);
  403.             //  can reuse the already created item to this mru
  404.             AddMRUData(hmru, pitem, cbItem);
  405.             FreeMRUList(hmru);
  406.         }
  407.                 
  408.         LocalFree(pitem);
  409.     }
  410.     //  its been freed but not nulled out...
  411.     return (pitem != NULL);
  412. }
  413. // 
  414. //  WARNING:  UpdateNetHood() changes _pidlTarget to the NetHood then frees it!
  415. //
  416. void CTaskAddDoc::_UpdateNetHood(LPCITEMIDLIST pidlFolder, LPCTSTR pszShare)
  417. {
  418.     if (SHRestricted(REST_NORECENTDOCSNETHOOD))
  419.         return;
  420.     //  need to add this boy to the Network Places
  421.     LPITEMIDLIST pidl = ILCreateFromPath(pszShare);
  422.     if (pidl)
  423.     {
  424.         //
  425.         //  BUGBUG - must verify parentage here - ZekeL - 27-MAY-99
  426.         //  http servers exist in both the webfolders namespace 
  427.         //  and the Internet namespace.  thus we must make sure
  428.         //  that what ever parent the folder had, the share has
  429.         //  the same one.
  430.         //
  431.         if (ILIsParent(pidl, pidlFolder, FALSE))
  432.         {
  433.             ASSERT(_pidlTarget);
  434.             ILFree(_pidlTarget);
  435.             
  436.             _pidlTarget = SHCloneSpecialIDList(NULL, CSIDL_NETHOOD, TRUE);
  437.             if (_pidlTarget)
  438.             {
  439.                 DWORD cMax;
  440.                 HANDLE hmru = CreateSharedRecentMRUList(TEXT("NetHood"), &cMax, SRMLF_COMPNAME);
  441.                 if (hmru)
  442.                 {
  443.                     _TryDeleteMRUItem(hmru, cMax, pszShare, pidl, NULL, TRUE);
  444.                     DWORD cbItem = CbFromCch(lstrlen(pszShare) + 1);
  445.                     LPBYTE pitem = _CreateMRUItem(pidl, pszShare, &cbItem, SHCL_MAKEFOLDERSHORTCUT);
  446.                     if (pitem)
  447.                     {
  448.                         AddMRUData(hmru, pitem, cbItem);
  449.                         LocalFree(pitem);
  450.                     }
  451.                     FreeMRUList(hmru);
  452.                 }
  453.                 ILFree(_pidlTarget);
  454.                 _pidlTarget = NULL;
  455.             }
  456.         }
  457.         
  458.         ILFree(pidl);
  459.     }
  460. }
  461. BOOL PathIsOneOf(const UINT rgFolders[], LPCTSTR pszFolder);
  462.             
  463. BOOL _IsPlacesFolder(LPCTSTR pszFolder)
  464. {
  465.     static const UINT places[] = {
  466.         CSIDL_PERSONAL,
  467.         CSIDL_DESKTOPDIRECTORY,
  468.         CSIDL_COMMON_DESKTOPDIRECTORY,
  469.         CSIDL_NETHOOD,
  470.         CSIDL_FAVORITES,
  471.         (UINT)-1 // terminator
  472.     };
  473.     return PathIsOneOf(places, pszFolder);
  474. }
  475. void _AddToUrlHistory(LPCTSTR pszPath)
  476. {
  477.     ASSERT(pszPath);
  478.     WCHAR szUrl[MAX_URL_STRING];
  479.     DWORD cchUrl = SIZECHARS(szUrl);
  480.     SHTCharToUnicode(pszPath, szUrl, cchUrl);
  481.     //  the URL parsing APIs tolerate same in/out buffer
  482.     if (SUCCEEDED(UrlCreateFromPathW(szUrl, szUrl, &cchUrl, 0)))
  483.     {
  484.         IUrlHistoryStg *puhs;
  485.         if (SUCCEEDED(CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER, 
  486.                 IID_IUrlHistoryStg, (void **)&puhs)))
  487.         {
  488.             ASSERT(puhs);
  489.             puhs->AddUrl(szUrl, NULL, 0);
  490.             puhs->Release();
  491.         }
  492.     }
  493. }
  494. void CTaskAddDoc::_TryUpdateNetHood(LPCITEMIDLIST pidlFolder, LPCTSTR pszFolder)
  495. {
  496.     TCHAR sz[MAX_URL_STRING];
  497.     DWORD cch = SIZECHARS(sz);
  498.     BOOL fUpdate = FALSE;
  499.     // changing szFolder, and changing _pidlTarget here...
  500.     //  if this is an URL or a UNC share add it to the nethood
  501.     if (UrlIs(pszFolder, URLIS_URL) 
  502.     && !UrlIs(pszFolder, URLIS_OPAQUE)
  503.     && SUCCEEDED(UrlCombine(pszFolder, TEXT("/"), sz, &cch, 0)))
  504.         fUpdate = TRUE;
  505.     else if (PathIsUNC(pszFolder) 
  506.     && StrCpyN(sz, pszFolder, cch)
  507.     && PathStripToRoot(sz))
  508.         fUpdate = TRUE;
  509.     if (fUpdate)
  510.         _UpdateNetHood(pidlFolder, sz);
  511. }
  512. //-----------------------------------------------------------------
  513. //
  514. // Add the named file to the Recently opened MRU list, that is used
  515. // by the shell to display the recent menu of the tray.
  516. // this registry will hold two pidls:  the target pointing to followed by
  517. // the pidl of the link created pointing it.  In both cases,
  518. // only the last item id is stored. (we may want to change this... but
  519. // then again, we may not)
  520. void CTaskAddDoc::_AddToRecentDocs(LPCITEMIDLIST pidlItem, LPCTSTR pszItem)
  521. {
  522.     TCHAR szUnescaped[MAX_PATH];
  523.     LPTSTR pszFileName;
  524.     //  if these are NULL the caller meant to call _CleanRecentDocs()
  525.     ASSERT(pszItem && *pszItem);
  526.     TraceMsg(DM_RECENTDOCS, "[%X] CTaskAddDoc::_AddToRecentDocs() called for '%s'", this, pszItem);   
  527.     // allow only classes with default commands
  528.     //
  529.     //  dont add if:
  530.     //     it is RESTRICTED
  531.     //     it is in the temporary directory
  532.     //     it actually has a file name
  533.     //     it can be shell exec'd with "open" verb
  534.     //
  535.     if ( (SHRestricted(REST_NORECENTDOCSHISTORY))     ||
  536.          (PathIsTemporary(pszItem))                   ||
  537.          (!(pszFileName = PathFindFileName(pszItem))) ||
  538.          (!*pszFileName)                              ||
  539.          (!GetExtensionClassDescription(pszFileName))   
  540.        )  
  541.         return;
  542.     //  pretty up the URL file names.
  543.     if (UrlIs(pszItem, URLIS_URL))
  544.     {
  545.         StrCpyN(szUnescaped, pszFileName, SIZECHARS(szUnescaped));
  546.         UrlUnescapeInPlace(szUnescaped, 0);
  547.         pszFileName = szUnescaped;
  548.     }
  549.     
  550.     //  otherwise we try our best.
  551.     ASSERT(!_pidlTarget);
  552.     _pidlTarget = SHCloneSpecialIDList(NULL, CSIDL_RECENT, TRUE);
  553.     if (_pidlTarget) 
  554.     {
  555.         _hmruRecent = CreateSharedRecentMRUList(NULL, &_cMaxRecent, SRMLF_COMPNAME);
  556.         if (_hmruRecent)
  557.         {
  558.             if (_AddDocToRecentAndExtRecent(pidlItem, pszFileName, PathFindExtension(pszFileName)))
  559.             {
  560.                 _AddToUrlHistory(pszItem);
  561.                 //  get the folder and do it to the folder
  562.                 LPITEMIDLIST pidlFolder = ILClone(pidlItem);
  563.                 
  564.                 if (pidlFolder)
  565.                 {
  566.                     ILRemoveLastID(pidlFolder);
  567.                     //  if it is a folder we already have quick
  568.                     //  access to from the shell, dont put it in here
  569.                     TCHAR szFolder[MAX_URL_STRING];
  570.                     if (SUCCEEDED(SHGetNameAndFlags(pidlFolder, SHGDN_FORPARSING, szFolder, SIZECHARS(szFolder), NULL))
  571.                     && !_IsPlacesFolder(szFolder))
  572.                     {
  573.                         //  get the friendly name for the folder
  574.                         TCHAR szTitle[MAX_PATH];
  575.                         if (FAILED(SHGetNameAndFlags(pidlFolder, SHGDN_NORMAL, szTitle, SIZECHARS(szTitle), NULL)))
  576.                             StrCpyN(szTitle, PathFindFileName(szFolder), ARRAYSIZE(szTitle));
  577.                             
  578.                         _AddDocToRecentAndExtRecent(pidlFolder, szTitle, TEXT("Folder"));
  579.                         _TryUpdateNetHood(pidlFolder, szFolder);
  580.                     }
  581.                     
  582.                     ILFree(pidlFolder);
  583.                 }
  584.                 SHChangeNotifyHandleEvents();
  585.             }
  586.             
  587.             FreeMRUList(_hmruRecent);
  588.             _hmruRecent = NULL;
  589.         }
  590.         //cleanup
  591.         if (_pidlTarget)
  592.         {
  593.             ILFree(_pidlTarget);
  594.             _pidlTarget = NULL;
  595.         }
  596.     }
  597. }
  598. STDAPI_(void) OpenWithListSoftRegisterProcess(DWORD dwFlags, LPCTSTR pszExt);
  599. void AddToRecentDocs(LPCITEMIDLIST pidl, LPCTSTR pszItem)
  600. {
  601.     HWND hwnd;
  602.     DWORD cbSizePidl, cbSizePath;
  603.     ASSERT(pidl && pszItem);
  604.     if (!ShouldAddToRecentDocs(pidl))
  605.         return;
  606.     OpenWithListSoftRegisterProcess(0, PathFindExtension(pszItem));   
  607.     
  608.     cbSizePidl = ILGetSize(pidl);
  609.     cbSizePath = CbFromCch(lstrlen(pszItem) + 1);
  610.     hwnd = GetShellWindow();
  611.     if (hwnd)
  612.     {
  613.         PXMITARD px;
  614.         DWORD dwProcId, dwOffset;
  615.         HANDLE hARD;
  616.         GetWindowThreadProcessId(hwnd, &dwProcId);
  617.         hARD = SHAllocShared(NULL, SIZEOF(XMITARD)+cbSizePath+cbSizePidl, dwProcId);
  618.         if (!hARD)
  619.             return;         // Well, we are going to miss one, sorry.
  620.         px = (PXMITARD)SHLockShared(hARD,dwProcId);
  621.         if (!px)
  622.         {
  623.             SHFreeShared(hARD,dwProcId);
  624.             return;         // Well, we are going to miss one, sorry.
  625.         }
  626.         px->dwOffsetPidl = 0;
  627.         px->dwOffsetPath = 0;
  628.         dwOffset = SIZEOF(XMITARD);
  629.         if (pszItem)
  630.         {
  631.             px->dwOffsetPath = dwOffset;
  632.             memcpy((LPBYTE)px + dwOffset, pszItem, cbSizePath);
  633.             dwOffset += cbSizePath;
  634.         }
  635.         if (pidl)
  636.         {
  637.             px->dwOffsetPidl = dwOffset;
  638.             memcpy((LPBYTE)px + dwOffset, pidl, cbSizePidl);
  639.         }
  640.         SHUnlockShared(px);
  641.         PostMessage(hwnd, CWM_ADDTORECENT, (WPARAM)hARD, (LPARAM)dwProcId);
  642.     }
  643. }
  644. //
  645. // put things in the shells recent docs list for the start menu
  646. //
  647. // in:
  648. //      uFlags  SHARD_ (shell add recent docs) flags
  649. //      pv      LPCSTR or LPCITEMIDLIST (path or pidl indicated by uFlags)
  650. //              may be NULL, meaning clear the recent list
  651. //
  652. STDAPI_(void) SHAddToRecentDocs(UINT uFlags, LPCVOID pv)
  653. {
  654.     TCHAR szTemp[MAX_URL_STRING]; // for double null
  655.     TraceMsg(DM_RECENTDOCS, "SHAddToRecentDocs() called with %d, [%X]", uFlags, pv);
  656.     
  657.     if (pv == NULL)     // we should nuke all recent docs.
  658.     {
  659.         //  we do this synchronously
  660.         _CleanRecentDocs();
  661.         return;
  662.     }
  663.     if (SHRestricted(REST_NORECENTDOCSHISTORY))
  664.         // Don't bother tracking recent documents if restriction is set
  665.         // for privacy.
  666.         return;
  667.     
  668.     if (uFlags == SHARD_PIDL)
  669.     {
  670.         // pv is a LPCITEMIDLIST (pidl)
  671.         if (SUCCEEDED(SHGetNameAndFlags((LPCITEMIDLIST)pv, SHGDN_FORPARSING, szTemp, SIZECHARS(szTemp), NULL)))
  672.         {
  673.             AddToRecentDocs((LPCITEMIDLIST)pv, szTemp);
  674.         }
  675.     }
  676.     else if (uFlags == SHARD_PATH)
  677.     {
  678.         // pv is a LPTCSTR (path)
  679.         LPITEMIDLIST pidl = ILCreateFromPath((LPCTSTR)pv);
  680.         if (!pidl)
  681.             pidl = SHSimpleIDListFromPath((LPCTSTR)pv);
  682.         if (pidl)
  683.         {
  684.             AddToRecentDocs(pidl, (LPCTSTR)pv);
  685.             ILFree(pidl);
  686.         }
  687.     }
  688. #ifdef UNICODE
  689.     else if (uFlags == SHARD_PATHA)
  690.     {
  691.         SHAnsiToUnicode((LPCSTR)pv, szTemp, ARRAYSIZE(szTemp));
  692.         SHAddToRecentDocs(SHARD_PATH, szTemp);
  693.     }
  694. #else
  695.     else if (uFlags == SHARD_PATHW)
  696.     {
  697.         SHUnicodeToAnsi((LPCWSTR)pv, szTemp, ARRAYSIZE(szTemp));
  698.         SHAddToRecentDocs(SHARD_PATH, szTemp);
  699.     }
  700. #endif
  701. }
  702. WINSHELLAPI void ReceiveAddToRecentDocs(HANDLE hARD, DWORD dwProcId)
  703. {
  704.     //  NOTIMPL
  705.     ASSERT(FALSE);
  706. }
  707. STDAPI CTaskAddDoc_Create(HANDLE hMem, DWORD dwProcId, IRunnableTask **pptask)
  708. {
  709.     HRESULT hres;
  710.     CTaskAddDoc *ptad = new CTaskAddDoc();
  711.     if (ptad)
  712.     {
  713.         hres = ptad->Init(hMem, dwProcId);
  714.         if (SUCCEEDED(hres))
  715.             hres = ptad->QueryInterface(IID_IRunnableTask, (void **)pptask);
  716.         ptad->Release();
  717.     }
  718.     else
  719.         hres = E_OUTOFMEMORY;
  720.     return hres;
  721. }
  722. STDAPI RecentDocs_GetDisplayName(LPCITEMIDLIST pidl, LPTSTR pszName, DWORD cchName)
  723. {
  724.     HRESULT hr = E_FAIL;
  725.     HANDLE hmru = CreateSharedRecentMRUList(NULL, NULL, SRMLF_COMPPIDL);
  726.     if (hmru)
  727.     {
  728.         int iItem = FindMRUData(hmru, pidl, ILGetSize(pidl), NULL);
  729.         if (-1 != iItem)
  730.         {
  731.             BYTE buf[MAX_RECMRU_BUF];
  732.             if (-1 != EnumMRUList(hmru, iItem, buf, SIZEOF(buf)))
  733.             {
  734.                 StrCpyN(pszName, GETRECNAME(buf), cchName);
  735.                 hr = S_OK;
  736.             }
  737.         }
  738.         FreeMRUList(hmru);
  739.      }
  740.      return hr;
  741.  }