filetbl.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 31k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. // routines for managing the icon cache tables, and file type tables.
  2. // Jan 95, ToddLa
  3. //
  4. //  icon cache
  5. //
  6. //      the icon cache is two ImageLists (g_himlIcons and g_himlIconsSmall)
  7. //      and a table mapping a name/icon number/flags to a ImageList
  8. //      index, the global hash table (pht==NULL) is used to hold
  9. //      the names.
  10. //
  11. //          AddToIconTable      - associate a name/number/flags with a image index
  12. //          SHLookupIconIndex   - return a image index, given name/number/flags
  13. //          RemoveFromIconTable - remove all entries with the given name
  14. //          FlushIconCache      - remove all entries.
  15. //          GetFreeImageIndex   - return a free ImageList index.
  16. //
  17. //      the worst part about the whole icon cache design is that people
  18. //      can add or lookup a image index (given a name/number/flags) but
  19. //      they never have to release it.  we never know if a ImageList index
  20. //      is currently in use or not.  this should be the first thing
  21. //      fixed about the shell.  currently we use a MRU type scheme when
  22. //      we need to remove a entry from the icon cache, it is far from
  23. //      perfect.
  24. //
  25. //  file type cache
  26. //
  27. //      the file type cache is a hash table with two DWORDs of extra data.
  28. //      DWORD #0 holds flags, DWORD #1 holds a pointer to the name of
  29. //      the class.
  30. //
  31. //          LookupFileClass     - given a file class (ie ".doc" or "Directory")
  32. //                                maps it to a DWORD of flags, return 0 if not found.
  33. //
  34. //          AddFileClass        - adds a class (and flags) to cache
  35. //
  36. //          LookupFileClassName - given a file class, returns it name.
  37. //          AddFileClassName    - sets the name of a class.
  38. //          FlushFileClass      - removes all items in cache.
  39. //
  40. #include "shellprv.h"
  41. #pragma  hdrstop
  42. #include "fstreex.h"
  43. #include <ntverp.h>
  44. #include "ovrlaymn.h"
  45. extern int g_ccIcon;
  46. TIMEVAR(LookupFileClass);
  47. TIMEVAR(AddFileClass);
  48. TIMEVAR(LookupFileClassName);
  49. TIMEVAR(AddFileClassName);
  50. TIMEVAR(LookupIcon);
  51. TIMEVAR(RemoveIcon);
  52. TIMEVAR(AddIcon);
  53. TIMEVAR(IconFlush);
  54. TCHAR const c_szIconCacheFile[] = TEXT("ShellIconCache");
  55. #pragma data_seg(DATASEG_SHARED)
  56. DWORD IconTimeBase     = ICONTIME_ZERO;
  57. DWORD IconTimeFlush    = ICONTIME_ZERO;
  58. DWORD FreeImageCount   = 0;
  59. DWORD FreeEntryCount   = 0;
  60. HDSA g_hdsaIcons = NULL;
  61. BOOL g_DirtyIcons = FALSE;
  62. UINT g_iLastSysIcon = 0;
  63. #pragma data_seg()
  64. LOCATION_ENTRY *_LookupIcon(LPCTSTR szName, int iIconIndex, UINT uFlags)
  65. {
  66.     LOCATION_ENTRY *p=NULL;
  67.     int i,n;
  68.     ASSERTCRITICAL
  69.     ASSERT(szName == PathFindFileName(szName));
  70.     szName = FindHashItem(NULL, szName);
  71.     if (szName && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
  72.     {
  73.         for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
  74.         {
  75.             if ((p->szName == szName) &&
  76.                 ((UINT)(p->uFlags&GIL_COMPARE) == (uFlags&GIL_COMPARE)) &&
  77.                 (p->iIconIndex == iIconIndex))
  78.             {
  79.                 p->Access = GetIconTime();
  80.                 goto exit;
  81.             }
  82.         }
  83.         p = NULL;       // not found
  84.     }
  85. exit:
  86.     return p;
  87. }
  88. int LookupIconIndex(LPCTSTR pszName, int iIconIndex, UINT uFlags)
  89. {
  90.     PLOCATION_ENTRY p;
  91.     int iIndex=-1;
  92.     ASSERT(IS_VALID_STRING_PTR(pszName, -1));
  93.     ASSERT(pszName == PathFindFileName(pszName));
  94.     ENTERCRITICAL;
  95.     TIMESTART(LookupIcon);
  96.     if (NULL != (p = _LookupIcon(pszName, iIconIndex, uFlags)))
  97.         iIndex = p->iIndex;
  98.     TIMESTOP(LookupIcon);
  99.     LEAVECRITICAL;
  100.     return iIndex;
  101. }
  102. STDAPI_(int) SHLookupIconIndex(LPCTSTR pszName, int iIconIndex, UINT uFlags)
  103. {
  104.     return LookupIconIndex(pszName, iIconIndex, uFlags);
  105. }
  106. #ifdef UNICODE
  107. STDAPI_(int) SHLookupIconIndexA(LPCSTR pszName, int iIconIndex, UINT uFlags)
  108. {
  109.     WCHAR wsz[MAX_PATH];
  110.     SHAnsiToUnicode(pszName, wsz, ARRAYSIZE(wsz));
  111.     return SHLookupIconIndex(wsz, iIconIndex, uFlags);
  112. }    
  113. #else
  114. STDAPI_(int) SHLookupIconIndexW(LPCWSTR pszName, int iIconIndex, UINT uFlags)
  115. {
  116.     char sz[MAX_PATH];
  117.     
  118.     SHUnicodeToAnsi(pszName, sz, ARRAYSIZE(sz));
  119.     return SHLookupIconIndex(sz, iIconIndex, uFlags);
  120. }    
  121. #endif
  122. //
  123. //  GetFreeImageIndex()
  124. //
  125. //      returns a free image index, or -1 if none
  126. //
  127. int GetFreeImageIndex(void)
  128. {
  129.     PLOCATION_ENTRY p=NULL;
  130.     int i,n;
  131.     int iIndex=-1;
  132.     ASSERTCRITICAL
  133.     if (FreeImageCount && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
  134.     {
  135.         for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
  136.         {
  137.             if (p->szName == NULL && p->iIndex != 0)
  138.             {
  139.                 iIndex = p->iIndex;     // get free index
  140.                 p->iIndex=0;            // claim it.
  141.                 p->Access=ICONTIME_ZERO;// mark unused entry.
  142.                 FreeImageCount--;
  143.                 FreeEntryCount++;
  144.                 break;
  145.             }
  146.         }
  147.     }
  148.     return iIndex;
  149. }
  150. //
  151. //  GetImageIndexUsage()
  152. //
  153. int GetImageIndexUsage(int iIndex)
  154. {
  155.     PLOCATION_ENTRY p=NULL;
  156.     int i,n,usage=0;
  157.     ASSERT(g_hdsaIcons);
  158.     ASSERTCRITICAL
  159.     if (g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
  160.     {
  161.         for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
  162.         {
  163.             if (p->iIndex == iIndex)
  164.             {
  165.                 usage++;
  166.             }
  167.         }
  168.     }
  169.     return usage;
  170. }
  171. void _FreeEntry(LOCATION_ENTRY *p)
  172. {
  173.     ASSERTCRITICAL
  174.     g_DirtyIcons = TRUE;        // we need to save now.
  175.     ASSERT(p->szName);
  176.     DeleteHashItem(NULL, p->szName);
  177.     p->szName = 0;
  178.     if (GetImageIndexUsage(p->iIndex) > 1)
  179.     {
  180.         FreeEntryCount++;
  181.         p->iIndex = 0;              // unused entry
  182.         p->Access=ICONTIME_ZERO;
  183.     }
  184.     else
  185.     {
  186.         FreeImageCount++;
  187.         p->Access=ICONTIME_ZERO;
  188.     }
  189. }
  190. //
  191. //  GetFreeEntry()
  192. //
  193. LOCATION_ENTRY *GetFreeEntry(void)
  194. {
  195.     PLOCATION_ENTRY p;
  196.     int i,n;
  197.     ASSERTCRITICAL
  198.     if (FreeEntryCount && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
  199.     {
  200.         for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
  201.         {
  202.             if (p->szName == NULL && p->iIndex == 0)
  203.             {
  204.                 FreeEntryCount--;
  205.                 return p;
  206.             }
  207.         }
  208.     }
  209.     return NULL;
  210. }
  211. //
  212. //  AddToIconTable  - add a item the the cache
  213. //
  214. //      lpszIconFile    - filename to add
  215. //      iIconIndex      - icon index in file.
  216. //      uFlags          - flags
  217. //                          GIL_SIMULATEDOC - this is a simulated doc icon
  218. //                          GIL_NOTFILENAME - file is not a path/index that
  219. //                                            ExtractIcon can deal with
  220. //      iIndex          - image index to use.
  221. //
  222. //  returns:
  223. //      image index for new entry.
  224. //
  225. //  notes:
  226. //      if the item already exists it is replaced.
  227. //
  228. void AddToIconTable(LPCTSTR szName, int iIconIndex, UINT uFlags, int iIndex)
  229. {
  230.     LOCATION_ENTRY LocationEntry;
  231.     LOCATION_ENTRY *p;
  232.     szName = PathFindFileName(szName);
  233.     ENTERCRITICAL;
  234.     TIMESTART(AddIcon);
  235.     if (g_hdsaIcons == NULL)
  236.     {
  237.         g_hdsaIcons = DSA_Create(SIZEOF(LOCATION_ENTRY), 8);
  238.         FreeEntryCount = 0;
  239.         FreeImageCount = 0;
  240.         IconTimeBase   = 0;
  241.         IconTimeFlush  = 0;
  242.         if (g_hdsaIcons == NULL)
  243.             goto exit;
  244.     }
  245.     g_DirtyIcons = TRUE;        // we need to save now.
  246.     if (NULL != (p = _LookupIcon(szName, iIconIndex, uFlags)))
  247.     {
  248.         if (p->iIndex == iIndex)
  249.         {
  250.             TraceMsg(TF_IMAGE, "IconCache: adding %s;%d (%d) to cache again", szName, iIconIndex, iIndex);
  251.             goto exit;
  252.         }
  253.         TraceMsg(TF_IMAGE, "IconCache: re-adding %s;%d (%d) to cache", szName, iIconIndex, iIndex);
  254.         _FreeEntry(p);
  255.     }
  256.     szName = AddHashItem(NULL, szName);
  257.     ASSERT(szName);
  258.     if (szName == NULL)
  259.         goto exit;
  260.     LocationEntry.szName = szName;
  261.     LocationEntry.iIconIndex = iIconIndex;
  262.     LocationEntry.iIndex = iIndex;
  263.     LocationEntry.uFlags = uFlags;
  264.     LocationEntry.Access = GetIconTime();
  265.     
  266.     if (NULL != (p = GetFreeEntry()))
  267.         *p = LocationEntry;
  268.     else
  269.         DSA_AppendItem(g_hdsaIcons, &LocationEntry);
  270. exit:
  271.     TIMESTOP(AddIcon);
  272.     LEAVECRITICAL;
  273.     return;
  274. }
  275. void RemoveFromIconTable(LPCTSTR szName)
  276. {
  277.     PLOCATION_ENTRY p;
  278.     UINT i,n;
  279.     ENTERCRITICAL;
  280.     TIMESTART(RemoveIcon);
  281.     ASSERT(szName == PathFindFileName(szName));
  282.     szName = FindHashItem(NULL, szName);
  283.     if (szName && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
  284.     {
  285.         TraceMsg(TF_IMAGE, "IconCache: flush %s", szName);
  286.         for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
  287.         {
  288.             if (p->szName == szName && i > g_iLastSysIcon)
  289.             {
  290.                 _FreeEntry(p);
  291.             }
  292.         }
  293.     }
  294.     TIMESTOP(RemoveIcon);
  295.     LEAVECRITICAL;
  296.     return;
  297. }
  298. //
  299. // empties the icon cache
  300. //
  301. void FlushIconCache(void)
  302. {
  303.     ENTERCRITICAL;
  304.     if (g_hdsaIcons != NULL)
  305.     {
  306.         PLOCATION_ENTRY p;
  307.         int i,n;
  308.         TraceMsg(TF_IMAGE, "IconCache: flush all");
  309.         n = DSA_GetItemCount(g_hdsaIcons);
  310.         for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
  311.         {
  312.             if (p->szName)
  313.                 DeleteHashItem(NULL, p->szName);
  314.         }
  315.         DSA_DeleteAllItems(g_hdsaIcons);
  316.         FreeEntryCount = 0;
  317.         FreeImageCount = 0;
  318.         IconTimeBase   = 0;
  319.         IconTimeFlush  = 0;
  320.         g_DirtyIcons   = TRUE;        // we need to save now.
  321.     }
  322.     LEAVECRITICAL;
  323. }
  324. //
  325. // if the icon cache is too big get rid of some old items.
  326. //
  327. // remember FlushIconCache() removes *all* items from the
  328. // icon table, and this function gets rid of *some* old items.
  329. //
  330. void _IconCacheFlush(BOOL fForce)
  331. {
  332.     DWORD dt;
  333.     PLOCATION_ENTRY p;
  334.     UINT i,n;
  335.     int nuked=0;
  336.     int active;
  337.     ENTERCRITICAL;
  338.     if (g_hdsaIcons)
  339.     {
  340.         //
  341.         // conpute the time from the last flush call
  342.         //
  343.         dt = GetIconTime() - IconTimeFlush;
  344.         //
  345.         // compute the number of "active" table entries.
  346.         //
  347.         active = DSA_GetItemCount(g_hdsaIcons) - FreeEntryCount - FreeImageCount;
  348.         ASSERT(active >= 0);
  349.         if (fForce || (dt > MIN_FLUSH && active >= g_MaxIcons))
  350.         {
  351.             TraceMsg(TF_IMAGE, "IconCacheFlush: removing all items older than %d", dt/2);
  352.             n = DSA_GetItemCount(g_hdsaIcons);
  353.             for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
  354.             {
  355.                 if (i <= g_iLastSysIcon)
  356.                     continue;
  357.                 if (p->szName && p->Access < (IconTimeFlush + dt/2))
  358.                 {
  359.                     nuked++;
  360.                     _FreeEntry(p);
  361.                 }
  362.             }
  363.             if (nuked > 0)
  364.             {
  365.                 IconTimeFlush = GetIconTime();
  366.                 g_DirtyIcons  = TRUE;        // we need to save now.
  367.             }
  368.         }
  369.     }
  370.     LEAVECRITICAL;
  371.     if (nuked > 0)
  372.     {
  373.         TraceMsg(TF_IMAGE, "IconCacheFlush: got rid of %d items (of %d), sending notify...", nuked, active);
  374.         FlushFileClass();
  375.         SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)-1, NULL);
  376.     }
  377. }
  378. //----------------------------- dump icon ------------------------------
  379. #ifdef DEBUG
  380. void _IconCacheDump()
  381. {
  382.     int i, cItems;
  383.     TCHAR szBuffer[MAX_PATH];
  384.     ENTERCRITICAL;
  385.     if (g_hdsaIcons && g_himlIcons &&
  386.         IsFlagSet(g_dwDumpFlags, DF_ICONCACHE)) {
  387.         cItems = DSA_GetItemCount(g_hdsaIcons);
  388.         TraceMsg(TF_IMAGE, "Icon cache: %d icons  (%d free)", cItems, FreeEntryCount);
  389.         TraceMsg(TF_IMAGE, "Icon cache: %d images (%d free)", ImageList_GetImageCount(g_himlIcons), FreeImageCount);
  390.         for (i = 0; i < cItems; i++) {
  391.             PLOCATION_ENTRY pLocEntry = DSA_GetItemPtr(g_hdsaIcons, i);
  392.             if (pLocEntry->szName)
  393.                 GetHashItemName(NULL, pLocEntry->szName, szBuffer, ARRAYSIZE(szBuffer));
  394.             else
  395.                 lstrcpy(szBuffer, TEXT("(free)"));
  396.             TraceMsg(TF_ALWAYS, "%s;%d%s%stimage=%d access=%d",
  397.                 (LPTSTR)szBuffer,
  398.                 pLocEntry->iIconIndex,
  399.                 ((pLocEntry->uFlags & GIL_SIMULATEDOC) ? TEXT(" doc"):TEXT("")),
  400.                 ((pLocEntry->uFlags & GIL_NOTFILENAME) ? TEXT(" not file"):TEXT("")),
  401.                 pLocEntry->iIndex, pLocEntry->Access);
  402.         }
  403.     }
  404.     LEAVECRITICAL;
  405. }
  406. #endif
  407. DWORD GetBuildNumber()
  408. {
  409. #ifdef USE_OS_VERSION
  410.     OSVERSIONINFO ver = {SIZEOF(ver)};
  411.     GetVersionEx(&ver);
  412.     return ver.dwBuildNumber;
  413. #else
  414.     // Need to use DLL version as we are updating this dll plus others and
  415.     // we need the cache to be invalidated as we may change the icons...
  416.     return VER_PRODUCTVERSION_DW;
  417. #endif
  418. }
  419. #ifdef _WIN64
  420. //
  421. //  ps        - stream to which to save
  422. //  hda       - DSA of LOCATION_ENTRY structures
  423. //  cle       - count of LOCATION_ENTRY32's to write
  424. //
  425. //  The structures are stored as LOCATION_ENTRY32 on disk.
  426. //
  427. HRESULT _IconCacheWriteLocations(IStream *ps, HDSA hdsa, int cle)
  428. {
  429.     HRESULT hres = E_OUTOFMEMORY;
  430.     // Convert from LOCATION_ENTRY to LOCATION_ENTRY32, then write out
  431.     // the LOCATION_ENTRY32 structures.
  432.     LOCATION_ENTRY32 *rgle32 = LocalAlloc(LPTR, cle * sizeof(LOCATION_ENTRY32));
  433.     if (rgle32)
  434.     {
  435.         LOCATION_ENTRY *rgle = DSA_GetItemPtr(hdsa, 0);
  436.         int i;
  437.         for (i = 0; i < cle; i++)
  438.         {
  439.             rgle32[i].iIconIndex = rgle[i].iIconIndex;
  440.             rgle32[i].uFlags     = rgle[i].uFlags;
  441.             rgle32[i].iIndex     = rgle[i].iIndex;
  442.             rgle32[i].Access     = rgle[i].Access;
  443.         }
  444.         hres = ps->lpVtbl->Write(ps, rgle32, cle * SIZEOF(LOCATION_ENTRY32), 0);
  445.         LocalFree(rgle32);
  446.     }
  447.     return hres;
  448. }
  449. #else
  450. __inline HRESULT _IconCacheWriteLocations(IStream *ps, HDSA hdsa, int cle)
  451. {
  452.     // LOCATION_ENTRY and LOCATION_ENTRY32 are the same, so we can
  453.     // read straight into the DSA data block
  454.     COMPILETIME_ASSERT(sizeof(LOCATION_ENTRY) == sizeof(LOCATION_ENTRY32));
  455.     return ps->lpVtbl->Write(ps, DSA_GetItemPtr(hdsa, 0), cle * SIZEOF(LOCATION_ENTRY), 0);
  456. }
  457. #endif
  458. /*
  459. ** Save the icon cache.
  460. */
  461. BOOL _IconCacheSave()
  462. {
  463.     int i;
  464.     IC_HEAD ich;
  465.     TCHAR szPath[MAX_PATH];
  466.     IStream * ps;
  467.     BOOL sts = FALSE;
  468.     DWORD dwAttr;
  469.     if (!IsMainShellProcess())
  470.         return TRUE;
  471.     //
  472.     // no icon cache nothing to save
  473.     //
  474.     if (g_hdsaIcons == NULL)
  475.     {
  476.         TraceMsg(TF_IMAGE, "IconCacheSave: no cache to save.");
  477.         return TRUE;
  478.     }
  479.     //
  480.     // if the icon cache is not dirty no need to save anything
  481.     //
  482.     if (!g_DirtyIcons)
  483.     {
  484.         TraceMsg(TF_IMAGE, "IconCacheSave: no need to save cache not dirty.");
  485.         return TRUE;
  486.     }
  487.     // if the icon cache is way too big dont save it.
  488.     // reload g_MaxIcons in case the user set it before shutting down.
  489.     //
  490.     QueryNewMaxIcons();
  491.     if ((UINT)DSA_GetItemCount(g_hdsaIcons) > (UINT)g_MaxIcons)
  492.     {
  493.         TraceMsg(TF_IMAGE, "IconCacheSave: cache is too big not saving");
  494.         return TRUE;
  495.     }
  496.     GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
  497.     PathAppend(szPath, c_szIconCacheFile);
  498.     PathQualifyDef(szPath, NULL, 0);
  499.     // Clear the hidden bit (and what the heck, readonly as well) around the write
  500.     // open, since on NT hidden prevents writing
  501.     dwAttr = GetFileAttributes(szPath);
  502.     if (0xFFFFFFFF != dwAttr)
  503.         SetFileAttributes(szPath, dwAttr & ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY));
  504.     SHCreateStreamOnFile(szPath, STGM_CREATE | STGM_WRITE | STGM_SHARE_DENY_WRITE, &ps);
  505.     // Restore the old file attributes
  506.     if (0xFFFFFFFF != dwAttr)
  507.         SetFileAttributes(szPath, dwAttr);
  508.     if (!ps)
  509.     {
  510.         TraceMsg(TF_IMAGE, "IconCacheSave: can't create %s.", szPath);
  511.         return FALSE;
  512.     }
  513.     ENTERCRITICAL;
  514.     // write out header
  515.     ich.cbSize    = 0;                  // start invalid
  516.     ich.uMagic    = ICONCACHE_MAGIC;
  517.     ich.uVersion  = ICONCACHE_VERSION;
  518.     ich.uNumIcons = DSA_GetItemCount(g_hdsaIcons);
  519.     ich.uColorRes = GetCurColorRes();
  520.     ich.flags     = g_ccIcon;
  521.     ich.dwBuild   = GetBuildNumber();
  522.     ich.TimeSave  = GetIconTime();
  523.     ich.TimeFlush = IconTimeFlush;
  524.     ich.FreeImageCount = FreeImageCount;
  525.     ich.FreeEntryCount = FreeEntryCount;
  526.     ImageList_GetIconSize(g_himlIcons, &ich.cxIcon, &ich.cyIcon);
  527.     ImageList_GetIconSize(g_himlIconsSmall, &ich.cxSmIcon, &ich.cySmIcon);
  528.     //
  529.     // BUGBUG:: This is the age old sledgehammer approach, but if it
  530.     // keeps the war team from my office...
  531.     // Basically: if we are in clean boot mode, don't save out out icon
  532.     // cache as some of the items may be refering to disks that are not
  533.     // available in clean boot mode and we end up with a blank piece of
  534.     // paper.
  535.     //
  536.     if (GetSystemMetrics(SM_CLEANBOOT))
  537.     {
  538.         TraceMsg(TF_IMAGE, "IconCacheSave: clean boot not saving");
  539.         ich.uNumIcons = 0;
  540.     }
  541.     if (FAILED(ps->lpVtbl->Write(ps, &ich, SIZEOF(ich), NULL)))
  542.         goto ErrorExit;
  543.     // write out entries (assumes all entries are contigious in memory)
  544.     if (FAILED(_IconCacheWriteLocations(ps, g_hdsaIcons, ich.uNumIcons)))
  545.         goto ErrorExit;
  546.     // write out the path names
  547.     for (i = 0; i < (int)ich.uNumIcons; i++)
  548.     {
  549.         TCHAR ach[MAX_PATH];
  550.         LOCATION_ENTRY *p = DSA_GetItemPtr(g_hdsaIcons, i);
  551.         if (p->szName)
  552.             GetHashItemName(NULL, p->szName, ach, ARRAYSIZE(ach));
  553.         else
  554.             ach[0] = 0;
  555.         if (FAILED(Stream_WriteString(ps, ach, TRUE)))
  556.             goto ErrorExit;
  557.     }
  558.     // write out the imagelist of the icons
  559.     if (!ImageList_Write(g_himlIcons, ps))
  560.         goto ErrorExit;
  561.     if (!ImageList_Write(g_himlIconsSmall, ps))
  562.         goto ErrorExit;
  563.     if (FAILED(ps->lpVtbl->Commit(ps, 0)))
  564.         goto ErrorExit;
  565.     // Now make it valid ie change the signature to be valid...
  566.     if (FAILED(ps->lpVtbl->Seek(ps, g_li0, STREAM_SEEK_SET, NULL)))
  567.         goto ErrorExit;
  568.     ich.cbSize = SIZEOF(ich);
  569.     if (FAILED(ps->lpVtbl->Write(ps, &ich, SIZEOF(ich), NULL)))
  570.         goto ErrorExit;
  571.     sts = TRUE;
  572. ErrorExit:
  573.     ps->lpVtbl->Release(ps);
  574.     if (sts && ich.uNumIcons > 0)
  575.     {
  576.         g_DirtyIcons = FALSE;
  577.         SetFileAttributes(szPath, FILE_ATTRIBUTE_HIDDEN);
  578.         TraceMsg(TF_IMAGE, "IconCacheSave: saved to %s.", szPath);
  579.     }
  580.     else
  581.     {
  582.         // saving failed.  no use leaving a bad cache around...
  583.         TraceMsg(TF_IMAGE, "IconCacheSave: cache not saved!");
  584.         DeleteFile(szPath);
  585.     }
  586.     LEAVECRITICAL;
  587.     return sts;
  588. }
  589. #ifdef _WIN64
  590. //
  591. //  ps        - stream from which to load
  592. //  hda       - DSA of LOCATION_ENTRY structures
  593. //  cle       - count of LOCATION_ENTRY32's to read
  594. //
  595. //  The structures are stored as LOCATION_ENTRY32 on disk.
  596. //
  597. HRESULT _IconCacheReadLocations(IStream *ps, HDSA hdsa, int cle)
  598. {
  599.     HRESULT hres = E_OUTOFMEMORY;
  600.     // read into a scratch buffer, then convert
  601.     // LOCATION_ENTRY32 into LOCATION_ENTRY.
  602.     LOCATION_ENTRY32 *rgle32 = LocalAlloc(LPTR, cle * sizeof(LOCATION_ENTRY32));
  603.     if (rgle32)
  604.     {
  605.         hres = ps->lpVtbl->Read(ps, rgle32, cle * SIZEOF(LOCATION_ENTRY32), 0);
  606.         if (SUCCEEDED(hres))
  607.         {
  608.             LOCATION_ENTRY *rgle = DSA_GetItemPtr(hdsa, 0);
  609.             int i;
  610.             for (i = 0; i < cle; i++)
  611.             {
  612.                 rgle[i].iIconIndex = rgle32[i].iIconIndex;
  613.                 rgle[i].uFlags     = rgle32[i].uFlags;
  614.                 rgle[i].iIndex     = rgle32[i].iIndex;
  615.                 rgle[i].Access     = rgle32[i].Access;
  616.             }
  617.         }
  618.         LocalFree(rgle32);
  619.     }
  620.     return hres;
  621. }
  622. #else
  623. __inline HRESULT _IconCacheReadLocations(IStream *ps, HDSA hdsa, int cle)
  624. {
  625.     // LOCATION_ENTRY and LOCATION_ENTRY32 are the same, so we can
  626.     // read straight into the DSA data block
  627.     COMPILETIME_ASSERT(sizeof(LOCATION_ENTRY) == sizeof(LOCATION_ENTRY32));
  628.     return ps->lpVtbl->Read(ps, DSA_GetItemPtr(hdsa, 0), cle * SIZEOF(LOCATION_ENTRY), 0);
  629. }
  630. #endif
  631. //
  632. //  get the icon cache back from disk, it must be the requested size and
  633. //  bitdepth or we will not use it.
  634. //
  635. BOOL _IconCacheRestore(int cxIcon, int cyIcon, int cxSmIcon, int cySmIcon, UINT flags)
  636. {
  637.     IStream *ps;
  638.     TCHAR szPath[MAX_PATH];
  639.     ASSERTCRITICAL;
  640.     GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
  641.     PathAppend(szPath, c_szIconCacheFile);
  642.     PathQualifyDef(szPath, NULL, 0);
  643.     if (GetSystemMetrics(SM_CLEANBOOT))
  644.         return FALSE;
  645.     if (SUCCEEDED(SHCreateStreamOnFile(szPath, STGM_READ, &ps)))
  646.     {
  647.         IC_HEAD ich;
  648.         if (SUCCEEDED(ps->lpVtbl->Read(ps, &ich, SIZEOF(ich), NULL)))
  649.         {
  650.             if (ich.cbSize    == SIZEOF(ich) &&
  651.                 ich.uVersion  == ICONCACHE_VERSION &&
  652.                 ich.uMagic    == ICONCACHE_MAGIC &&
  653.                 ich.dwBuild   == GetBuildNumber() &&
  654.                 ich.cxIcon    == (DWORD)cxIcon &&
  655.                 ich.cyIcon    == (DWORD)cyIcon &&
  656.                 ich.cxSmIcon  == (DWORD)cxSmIcon &&
  657.                 ich.cySmIcon  == (DWORD)cySmIcon &&
  658.                 ich.flags     == (DWORD)flags)
  659.             {
  660.                 HDSA hdsaTemp;
  661.                 UINT cres = GetCurColorRes();
  662.                 //
  663.                 // dont load a mono image list on a color device, and
  664.                 // dont load a color image list on a mono device, get it?
  665.                 //
  666.                 if (ich.uColorRes == 1 && cres != 1 ||
  667.                     ich.uColorRes != 1 && cres == 1)
  668.                 {
  669.                     TraceMsg(TF_IMAGE, "IconCacheRestore: mono/color depth is wrong");
  670.                     hdsaTemp = NULL;
  671.                 }
  672.                 else if (ich.uNumIcons > (UINT)g_MaxIcons)
  673.                 {
  674.                     TraceMsg(TF_IMAGE, "IconCacheRestore: icon cache is too big not loading it.");
  675.                     hdsaTemp = NULL;
  676.                 }
  677.                 else
  678.                 {
  679.                     hdsaTemp = DSA_Create(SIZEOF(LOCATION_ENTRY), 8);
  680.                 }
  681.                 // load the icon table
  682.                 if (hdsaTemp)
  683.                 {
  684.                     LOCATION_ENTRY dummy;
  685.                     // grow the array out so we can read data into it
  686.                     if (DSA_SetItem(hdsaTemp, ich.uNumIcons - 1, &dummy))
  687.                     {
  688.                         ASSERT(DSA_GetItemCount(hdsaTemp) == (int)ich.uNumIcons);
  689.                         if (SUCCEEDED(_IconCacheReadLocations(ps, hdsaTemp, ich.uNumIcons)))
  690.                         {
  691.                             HIMAGELIST himlTemp;
  692.                             int i;
  693.                             // read the paths, patching up the table with the hashitem info
  694.                             for (i = 0; i < (int)ich.uNumIcons; i++)
  695.                             {
  696.                                 PLOCATION_ENTRY pLocation = DSA_GetItemPtr(hdsaTemp, i);
  697.                                 if (SUCCEEDED(Stream_ReadString(ps, szPath, ARRAYSIZE(szPath), TRUE)) && szPath[0])
  698.                                     pLocation->szName = AddHashItem(NULL, szPath);
  699.                                 else
  700.                                     pLocation->szName = 0;
  701.                             }
  702.                             // restore the image lists
  703.                             himlTemp = ImageList_Read(ps);
  704.                             if (himlTemp)
  705.                             {
  706.                                 int cx, cy;
  707.                                 // If we read the list from disk and it does not contain the
  708.                                 // parallel mirrored list while we are on a mirrored system,
  709.                                 // let's not use the cache in this case
  710.                                 // Example of this is ARA/HEB MUI on US W2k
  711.                                 if(IS_BIDI_LOCALIZED_SYSTEM() && !(ImageList_GetFlags(himlTemp) & ILC_MIRROR))
  712.                                 {
  713.                                     ImageList_Destroy(himlTemp);
  714.                                     DSA_DeleteAllItems(hdsaTemp);
  715.                                     ps->lpVtbl->Release(ps);
  716.                                     return FALSE;
  717.                                 }
  718.                                 ImageList_GetIconSize(himlTemp, &cx, &cy);
  719.                                 if (cx == cxIcon && cy == cyIcon)
  720.                                 {
  721.                                     HIMAGELIST himlTempSmall = ImageList_Read(ps);
  722.                                     if (himlTempSmall)
  723.                                     {
  724.                                         IShellIconOverlayManager *psiom;
  725.                                         ps->lpVtbl->Release(ps);
  726.                                         if (g_himlIcons)
  727.                                             ImageList_Destroy(g_himlIcons);
  728.                                         g_himlIcons = himlTemp;
  729.                                         if (g_himlIconsSmall)
  730.                                             ImageList_Destroy(g_himlIconsSmall);
  731.                                         g_himlIconsSmall = himlTempSmall;
  732.                                         if (g_hdsaIcons)
  733.                                             DSA_DeleteAllItems(g_hdsaIcons);
  734.                                         g_hdsaIcons = hdsaTemp;
  735.                                         // init the icon overlay indices...
  736.                                         if (SUCCEEDED(GetIconOverlayManager(&psiom)))
  737.                                         {
  738.                                             psiom->lpVtbl->RefreshOverlayImages(psiom, SIOM_OVERLAYINDEX | SIOM_ICONINDEX);
  739.                                             psiom->lpVtbl->Release(psiom);
  740.                                         }
  741.                                             
  742.                                         //
  743.                                         // we want GetIconTime() to pick up
  744.                                         // where it left off when we saved.
  745.                                         //
  746.                                         IconTimeBase   = 0;     // GetIconTime() uses IconTimeBase
  747.                                         IconTimeBase   = ich.TimeSave - GetIconTime();
  748.                                         IconTimeFlush  = ich.TimeFlush;
  749.                                         FreeImageCount = ich.FreeImageCount;
  750.                                         FreeEntryCount = ich.FreeEntryCount;
  751.                                         g_DirtyIcons   = FALSE;
  752.                                         TraceMsg(TF_IMAGE, "IconCacheRestore: loaded %s", szPath);
  753.                                         return TRUE;        // success
  754.                                     }
  755.                                 }
  756.                                 ImageList_Destroy(himlTemp);
  757.                             }
  758.                         }
  759.                     }
  760.                     DSA_DeleteAllItems(hdsaTemp);
  761.                 }
  762.             }
  763.             else
  764.             {
  765.                 TraceMsg(TF_IMAGE, "IconCacheRestore: Icon cache header changed");
  766.             }
  767.         }
  768.         ps->lpVtbl->Release(ps);
  769.     }
  770.     else
  771.     {
  772.         TraceMsg(TF_IMAGE, "IconCacheRestore: unable to open file.");
  773.     }
  774.     TraceMsg(TF_IMAGE, "IconCacheRestore: cache not restored!");
  775.     return FALSE;
  776. }
  777. //------------------ file class table ------------------------
  778. PHASHTABLE g_phtClass = NULL;
  779. BOOL InitFileClassTable(void)
  780. {
  781.     ASSERTCRITICAL;
  782.     if (!g_phtClass )
  783.     {
  784.         if (!g_phtClass)
  785.             g_phtClass = CreateHashItemTable(0, 2*SIZEOF(DWORD_PTR), TRUE);
  786.     }
  787.     return BOOLIFY(g_phtClass);
  788. }
  789.         
  790.     
  791. void FlushFileClass(void)
  792. {
  793.     ENTERCRITICAL;
  794. #ifdef DEBUG
  795.     if (g_phtClass != NULL) {
  796.         
  797.         DebugMsg(DM_TRACE, TEXT("Flushing file class table"));
  798.         TIMEOUT(LookupFileClass);
  799.         TIMEOUT(AddFileClass);
  800.         TIMEOUT(LookupFileClassName);
  801.         TIMEOUT(AddFileClassName);
  802.         TIMEOUT(LookupIcon);
  803.         TIMEOUT(AddIcon);
  804.         TIMEOUT(RemoveIcon);
  805.         TIMEIN(LookupFileClass);
  806.         TIMEIN(AddFileClass);
  807.         TIMEIN(LookupFileClassName);
  808.         TIMEIN(AddFileClassName);
  809.         TIMEIN(LookupIcon);
  810.         TIMEIN(AddIcon);
  811.         TIMEIN(RemoveIcon);
  812.         DumpHashItemTable(g_phtClass);
  813.     }
  814. #endif
  815.     if (g_phtClass != NULL)
  816.     {
  817.         DestroyHashItemTable(g_phtClass);
  818.         g_phtClass = NULL;
  819.     }
  820.     LEAVECRITICAL;
  821. }
  822. DWORD LookupFileClass(LPCTSTR pszClass)
  823. {
  824.     DWORD dw = 0;
  825.     ENTERCRITICAL;
  826.     TIMESTART(LookupFileClass);
  827.     
  828.     if (g_phtClass && (NULL != (pszClass = FindHashItem(g_phtClass, pszClass))))   
  829.         dw = (DWORD) GetHashItemData(g_phtClass, pszClass, 0);
  830.     TIMESTOP(LookupFileClass);
  831.     LEAVECRITICAL;
  832.     return dw;
  833. }
  834. void AddFileClass(LPCTSTR pszClass, DWORD dw)
  835. {
  836.     ENTERCRITICAL;
  837.     TIMESTART(AddFileClass);
  838.     //
  839.     // create a hsa table to keep the file class info in.
  840.     //
  841.     //  DWORD #0 is the type flags
  842.     //  DWORD #1 is the class name
  843.     //
  844.     if (InitFileClassTable() && (NULL != (pszClass = AddHashItem(g_phtClass, pszClass))))
  845.         SetHashItemData(g_phtClass, pszClass, 0, dw);
  846.     TIMESTOP(AddFileClass);
  847.     LEAVECRITICAL;
  848.     return;
  849. }
  850. LPCTSTR LookupFileClassName(LPCTSTR pszClass)
  851. {
  852.     LPCTSTR pszClassName=NULL;
  853.     ASSERTCRITICAL
  854.     TIMESTART(LookupFileClassName);
  855.     if (g_phtClass && (NULL != (pszClass = FindHashItem(g_phtClass, pszClass))))
  856.         pszClassName = (LPCTSTR)GetHashItemData(g_phtClass, pszClass, 1);
  857.     TIMESTOP(LookupFileClassName);
  858.     return pszClassName;
  859. }
  860. LPCTSTR AddFileClassName(LPCTSTR pszClass, LPCTSTR pszClassName)
  861. {
  862.     ASSERTCRITICAL
  863.     TIMESTART(AddFileClassName);
  864.     //
  865.     // create a hsa table to keep the file class info in.
  866.     //
  867.     //  DWORD #0 is the type flags
  868.     //  DWORD #1 is the class name
  869.     //
  870.     if (InitFileClassTable() && (NULL != (pszClass = AddHashItem(g_phtClass, pszClass)))) {
  871.         pszClassName = AddHashItem(g_phtClass, pszClassName);
  872.         SetHashItemData(g_phtClass, pszClass, 1, (DWORD_PTR)pszClassName);
  873.     }
  874.     TIMESTOP(AddFileClassName);
  875.     return pszClassName;
  876. }