Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

987 lines
27 KiB

// routines for managing the icon cache tables, and file type tables.
// Jan 95, ToddLa
//
// icon cache
//
// the icon cache is two ImageLists (himlIcons and himlIconsSmall)
// and a table mapping a name/icon number/flags to a ImageList
// index, the global hash table (pht==NULL) is used to hold
// the names.
//
// AddToIconTable - associate a name/number/flags with a image index
// LookupIconIndex - return a image index, given name/number/flags
// RemoveFromIconTable - remove all entries with the given name
// FlushIconCache - remove all entries.
// GetFreeImageIndex - return a free ImageList index.
//
// the worst part about the whole icon cache design is that people
// can add or lookup a image index (given a name/number/flags) but
// they never have to release it. we never know if a ImageList index
// is currently in use or not. this should be the first thing
// fixed about the shell. currently we use a MRU type scheme when
// we need to remove a entry from the icon cache, it is far from
// perfect.
//
// file type cache
//
// the file type cache is a hash table with two DWORDs of extra data.
// DWORD #0 holds flags, DWORD #1 holds a pointer to the name of
// the class.
//
// LookupFileClass - given a file class (ie ".doc" or "Directory")
// maps it to a DWORD of flags, return 0 if not found.
//
// AddFileClass - adds a class (and flags) to cache
//
// LookupFileClassName - given a file class, returns it name.
// AddFileClassName - sets the name of a class.
// FlushFileClass - removes all items in cache.
//
#include "shellprv.h"
#pragma hdrstop
extern int g_ccIcon;
TIMEVAR(LookupFileClass);
TIMEVAR(AddFileClass);
TIMEVAR(LookupFileClassName);
TIMEVAR(AddFileClassName);
TIMEVAR(LookupIcon);
TIMEVAR(RemoveIcon);
TIMEVAR(AddIcon);
TIMEVAR(IconFlush);
DWORD IconTimeBase = ICONTIME_ZERO;
DWORD IconTimeFlush = ICONTIME_ZERO;
DWORD FreeImageCount = 0;
DWORD FreeEntryCount = 0;
TCHAR const c_szIconCacheFile[] = TEXT("ShellIconCache");
static HDSA g_hdsaIcons = NULL;
static BOOL g_DirtyIcons = FALSE;
UINT g_iLastSysIcon = 0;
LOCATION_ENTRY *_LookupIcon(LPCTSTR szName, int iIconIndex, UINT uFlags)
{
LOCATION_ENTRY *p=NULL;
int i,n;
ASSERTCRITICAL
Assert(szName == PathFindFileName(szName));
szName = FindHashItem(NULL, szName);
if (szName && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
{
for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
{
if ((p->szName == szName) &&
((UINT)(p->uFlags&GIL_COMPARE) == (uFlags&GIL_COMPARE)) &&
(p->iIconIndex == iIconIndex))
{
p->Access = GetIconTime();
goto exit;
}
}
p = NULL; // not found
}
exit:
return p;
}
int LookupIconIndex(LPCTSTR szName, int iIconIndex, UINT uFlags)
{
PLOCATION_ENTRY p;
int iIndex=-1;
Assert(szName == PathFindFileName(szName));
ENTERCRITICAL
TIMESTART(LookupIcon);
if (NULL != (p = _LookupIcon(szName, iIconIndex, uFlags)))
iIndex = p->iIndex;
TIMESTOP(LookupIcon);
LEAVECRITICAL
return iIndex;
}
//
// GetFreeImageIndex()
//
// returns a free image index, or -1 if none
//
int GetFreeImageIndex(void)
{
PLOCATION_ENTRY p=NULL;
int i,n;
int iIndex=-1;
ASSERTCRITICAL
if (FreeImageCount && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
{
for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
{
if (p->szName == NULL && p->iIndex != 0)
{
iIndex = p->iIndex; // get free index
p->iIndex=0; // claim it.
p->Access=ICONTIME_ZERO;// mark unused entry.
FreeImageCount--;
FreeEntryCount++;
break;
}
}
}
return iIndex;
}
//
// GetImageIndexUsage()
//
int GetImageIndexUsage(int iIndex)
{
PLOCATION_ENTRY p=NULL;
int i,n,usage=0;
Assert(g_hdsaIcons);
ASSERTCRITICAL
if (g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
{
for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
{
if (p->iIndex == iIndex)
{
usage++;
}
}
}
return usage;
}
void _FreeEntry(LOCATION_ENTRY *p)
{
ASSERTCRITICAL
g_DirtyIcons = TRUE; // we need to save now.
Assert(p->szName);
DeleteHashItem(NULL, p->szName);
p->szName = 0;
if (GetImageIndexUsage(p->iIndex) > 1)
{
FreeEntryCount++;
p->iIndex = 0; // unused entry
p->Access=ICONTIME_ZERO;
}
else
{
FreeImageCount++;
p->Access=ICONTIME_ZERO;
}
}
//
// GetFreeEntry()
//
LOCATION_ENTRY *GetFreeEntry(void)
{
PLOCATION_ENTRY p;
int i,n;
ASSERTCRITICAL
if (FreeEntryCount && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
{
for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
{
if (p->szName == NULL && p->iIndex == 0)
{
FreeEntryCount--;
return p;
}
}
}
return NULL;
}
//
// AddToIconTable - add a item the the cache
//
// lpszIconFile - filename to add
// iIconIndex - icon index in file.
// uFlags - flags
// GIL_SIMULATEDOC - this is a simulated doc icon
// GIL_NOTFILENAME - file is not a path/index that
// ExtractIcon can deal with
// iIndex - image index to use.
//
// returns:
// image index for new entry.
//
// notes:
// if the item already exists it is replaced.
//
void AddToIconTable(LPCTSTR szName, int iIconIndex, UINT uFlags, int iIndex)
{
LOCATION_ENTRY LocationEntry;
LOCATION_ENTRY *p;
szName = PathFindFileName(szName);
ENTERCRITICAL
TIMESTART(AddIcon);
if (g_hdsaIcons == NULL)
{
g_hdsaIcons = DSA_Create(SIZEOF(LOCATION_ENTRY), 8);
FreeEntryCount = 0;
FreeImageCount = 0;
IconTimeBase = 0;
IconTimeFlush = 0;
if (g_hdsaIcons == NULL)
goto exit;
}
g_DirtyIcons = TRUE; // we need to save now.
if (NULL != (p = _LookupIcon(szName, iIconIndex, uFlags)))
{
if (p->iIndex == iIndex)
{
DebugMsg(DM_TRACE, TEXT("IconCache: adding %s;%d (%d) to cache again"), szName, iIconIndex, iIndex);
goto exit;
}
DebugMsg(DM_TRACE, TEXT("IconCache: re-adding %s;%d (%d) to cache"), szName, iIconIndex, iIndex);
_FreeEntry(p);
}
szName = AddHashItem(NULL, szName);
Assert(szName);
if (szName == NULL)
goto exit;
LocationEntry.szName = szName;
LocationEntry.iIconIndex = iIconIndex;
LocationEntry.iIndex = iIndex;
LocationEntry.uFlags = uFlags;
LocationEntry.Access = GetIconTime();
if (NULL != (p = GetFreeEntry()))
*p = LocationEntry;
else
DSA_InsertItem(g_hdsaIcons, 0x7FFF, &LocationEntry);
exit:
TIMESTOP(AddIcon);
LEAVECRITICAL
return;
}
void RemoveFromIconTable(LPCTSTR szName, BOOL fNotify)
{
PLOCATION_ENTRY p;
UINT i,n;
ENTERCRITICAL
TIMESTART(RemoveIcon);
Assert(szName == PathFindFileName(szName));
szName = FindHashItem(NULL, szName);
if (szName && g_hdsaIcons && (n = DSA_GetItemCount(g_hdsaIcons)) > 0)
{
DebugMsg(DM_TRACE, TEXT("IconCache: flush %s"), szName);
for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
{
if (p->szName == szName && i > g_iLastSysIcon)
{
_FreeEntry(p);
//
// if after calling _FreeEntry, if p->iIndex!=0,
// the index is not in use by any one else and it is now.
// free (or we think it is now free) send a notify in case
// anyone is using it.
//
if (fNotify && p->iIndex!=0)
{
DebugMsg(DM_TRACE, TEXT(" sending SHCNE_UPDATEIMAGE(%d)"), p->iIndex);
SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)p->iIndex, NULL);
}
}
}
}
TIMESTOP(RemoveIcon);
LEAVECRITICAL
return;
}
//
// empties the icon cache
//
void FlushIconCache(void)
{
ENTERCRITICAL
if (g_hdsaIcons != NULL)
{
PLOCATION_ENTRY p;
int i,n;
DebugMsg(DM_TRACE, TEXT("IconCache: flush all"));
n = DSA_GetItemCount(g_hdsaIcons);
for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
{
if (p->szName)
DeleteHashItem(NULL, p->szName);
}
DSA_DeleteAllItems(g_hdsaIcons);
FreeEntryCount = 0;
FreeImageCount = 0;
IconTimeBase = 0;
IconTimeFlush = 0;
}
LEAVECRITICAL
}
//
// if the icon cache is too big get rid of some old items.
//
// remember FlushIconCache() removes *all* items from the
// icon table, and this function gets rid of *some* old items.
//
void _IconCacheFlush(BOOL fForce)
{
DWORD dt;
PLOCATION_ENTRY p;
UINT i,n;
int nuked=0;
int active;
ENTERCRITICAL
if (g_hdsaIcons)
{
//
// conpute the time from the last flush call
//
dt = GetIconTime() - IconTimeFlush;
//
// compute the number of "active" table entries.
//
active = DSA_GetItemCount(g_hdsaIcons) - FreeEntryCount - FreeImageCount;
Assert(active >= 0);
if (fForce || (dt > MIN_FLUSH && active >= g_MaxIcons))
{
DebugMsg(DM_TRACE, TEXT("IconCacheFlush: removing all items older than %d"), dt/2);
n = DSA_GetItemCount(g_hdsaIcons);
for (i=0,p=DSA_GetItemPtr(g_hdsaIcons, 0); i<n; i++,p++)
{
if (i <= g_iLastSysIcon)
continue;
if (p->szName && p->Access < (IconTimeFlush + dt/2))
{
nuked++;
_FreeEntry(p);
}
}
if (nuked > 0)
{
IconTimeFlush = GetIconTime();
}
}
}
LEAVECRITICAL
if (nuked > 0)
{
DebugMsg(DM_TRACE, TEXT("IconCacheFlush: got rid of %d items (of %d), sending notify..."), nuked, active);
FlushFileClass();
SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)-1, NULL);
}
}
//----------------------------- dump icon ------------------------------
#ifdef DEBUG
void _IconCacheDump()
{
int i, cItems;
TCHAR szBuffer[MAX_PATH];
ENTERCRITICAL
if (g_hdsaIcons && himlIcons) {
cItems = DSA_GetItemCount(g_hdsaIcons);
DebugMsg(DM_TRACE, TEXT("Icon cache: %d icons (%d free)"), cItems, FreeEntryCount);
DebugMsg(DM_TRACE, TEXT("Icon cache: %d images (%d free)"), ImageList_GetImageCount(himlIcons), FreeImageCount);
for (i = 0; i < cItems; i++) {
PLOCATION_ENTRY pLocEntry = DSA_GetItemPtr(g_hdsaIcons, i);
if (pLocEntry->szName)
GetHashItemName(NULL, pLocEntry->szName, szBuffer, ARRAYSIZE(szBuffer));
else
lstrcpy(szBuffer, TEXT("(free)"));
DebugMsg(DM_TRACE, TEXT("%s;%d%s%s\timage=%d access=%d"),
(LPTSTR)szBuffer,
pLocEntry->iIconIndex,
((pLocEntry->uFlags & GIL_SIMULATEDOC) ? TEXT(" doc"):TEXT("")),
((pLocEntry->uFlags & GIL_NOTFILENAME) ? TEXT(" not file"):TEXT("")),
pLocEntry->iIndex, pLocEntry->Access);
}
}
LEAVECRITICAL
}
#endif
/*
** get color resolution of the current display
*/
UINT GetCurColorRes(void)
{
HDC hdc;
UINT uColorRes;
hdc = GetDC(NULL);
uColorRes = GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc, BITSPIXEL);
ReleaseDC(NULL, hdc);
return uColorRes;
}
DWORD GetBuildNumber()
{
OSVERSIONINFO ver = {SIZEOF(ver)};
GetVersionEx(&ver);
return ver.dwBuildNumber;
}
/*
** Save the icon cache.
*/
BOOL _IconCacheSave()
{
int i;
IC_HEAD ich;
TCHAR szPath[MAX_PATH];
TCHAR ach[MAX_PATH];
IStream * ps;
BOOL sts = FALSE;
LARGE_INTEGER dlibMove = {0, 0};
DWORD dwAttr;
DWORD dwProcId;
HWND hwndDesktop;
hwndDesktop = GetShellWindow();
if (!hwndDesktop)
return TRUE;
GetWindowThreadProcessId(hwndDesktop, &dwProcId);
if (GetCurrentProcessId() != dwProcId)
{
return TRUE; // Blow off saving anybody else's icon cache
}
//
// no icon cache nothing to save
//
if (g_hdsaIcons == NULL)
{
DebugMsg(DM_TRACE, TEXT("IconCacheSave: no cache to save."));
return TRUE;
}
//
// if the icon cache is not dirty no need to save anything
//
if (!g_DirtyIcons)
{
DebugMsg(DM_TRACE, TEXT("IconCacheSave: no need to save cache not dirty."));
return TRUE;
}
// if the icon cache is way too big dont save it.
// reload g_MaxIcons in case the user set it before shutting down.
//
QueryNewMaxIcons();
if ((UINT)DSA_GetItemCount(g_hdsaIcons) > (UINT)g_MaxIcons)
{
DebugMsg(DM_TRACE, TEXT("IconCacheSave: cache is too big not saving"));
return TRUE;
}
GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
PathAppend(szPath, c_szIconCacheFile);
PathQualifyDef(szPath, NULL, 0);
// Clear the hidden bit (and what the heck, readonly as well) around the write
// open, since on NT hidden prevents writing
dwAttr = GetFileAttributes(szPath);
if (0xFFFFFFFF != dwAttr)
{
SetFileAttributes(szPath, dwAttr & ~(FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY));
}
ps = OpenFileStream(szPath, OF_CREATE | OF_WRITE | OF_SHARE_DENY_WRITE);
// Restore the old file attributes
if (0xFFFFFFFF != dwAttr)
{
SetFileAttributes(szPath, dwAttr);
}
if (!ps)
{
DebugMsg(DM_TRACE, TEXT("IconCacheSave: can't create %s."), szPath);
return FALSE;
}
ENTERCRITICAL
// write out header
ich.cbSize = 0; // start invalid
ich.uMagic = ICONCACHE_MAGIC;
ich.uVersion = ICONCACHE_VERSION;
ich.uNumIcons = DSA_GetItemCount(g_hdsaIcons);
ich.uColorRes = GetCurColorRes();
ich.flags = g_ccIcon;
ich.dwBuild = GetBuildNumber();
ich.TimeSave = GetIconTime();
ich.TimeFlush = IconTimeFlush;
ich.FreeImageCount = FreeImageCount;
ich.FreeEntryCount = FreeEntryCount;
ImageList_GetIconSize(himlIcons, &ich.cxIcon, &ich.cyIcon);
ImageList_GetIconSize(himlIconsSmall, &ich.cxSmIcon, &ich.cySmIcon);
//
// BUGBUG:: This is the age old sledgehammer approach, but if it
// keeps the war team from my office...
// Basically: if we are in clean boot mode, don't save out out icon
// cache as some of the items may be refering to disks that are not
// available in clean boot mode and we end up with a blank piece of
// paper.
//
if (GetSystemMetrics(SM_CLEANBOOT))
{
DebugMsg(DM_TRACE, TEXT("IconCacheSave: clean boot not saving"));
ich.uNumIcons = 0;
}
if (!Stream_Write(ps, &ich, SIZEOF(ich)))
goto ErrorExit;
// write out entries (assumes all entries are contigious in memory)
if (!Stream_Write(ps, DSA_GetItemPtr(g_hdsaIcons, 0), (int)ich.uNumIcons * SIZEOF(LOCATION_ENTRY)))
goto ErrorExit;
// write out the path names
for (i = 0; i < (int)ich.uNumIcons; i++)
{
LOCATION_ENTRY *p = DSA_GetItemPtr(g_hdsaIcons, i);
if (p->szName)
GetHashItemName(NULL, p->szName, ach, ARRAYSIZE(ach));
else
ach[0] = 0;
if (FAILED(Stream_WriteString(ps, ach)))
goto ErrorExit;
}
// write out the imagelist of the icons
if (!ImageList_Write(himlIcons, ps))
goto ErrorExit;
if (!ImageList_Write(himlIconsSmall, ps))
goto ErrorExit;
if (!Stream_Flush(ps))
goto ErrorExit;
// Now make it valid ie change the signature to be valid...
if (!Stream_Seek(ps, dlibMove, STREAM_SEEK_SET, NULL))
goto ErrorExit;
ich.cbSize = SIZEOF(ich);
if (!Stream_Write(ps, &ich, SIZEOF(ich)))
goto ErrorExit;
sts = TRUE;
ErrorExit:
Stream_Close(ps);
if (sts && ich.uNumIcons > 0)
{
g_DirtyIcons = FALSE;
SetFileAttributes(szPath, FILE_ATTRIBUTE_HIDDEN);
DebugMsg(DM_TRACE, TEXT("IconCacheSave: saved to %s."), szPath);
}
else
{
// saving failed. no use leaving a bad cache around...
DebugMsg(DM_TRACE, TEXT("IconCacheSave: cache not saved!"));
DeleteFile(szPath);
}
LEAVECRITICAL
return sts;
}
//
// get the icon cache back from disk, it must be the requested size and
// bitdepth or we will not use it.
//
BOOL _IconCacheRestore(int cxIcon, int cyIcon, int cxSmIcon, int cySmIcon, UINT flags)
{
IStream *ps;
TCHAR szPath[MAX_PATH];
ASSERTCRITICAL
GetWindowsDirectory(szPath, ARRAYSIZE(szPath));
PathAppend(szPath, c_szIconCacheFile);
PathQualifyDef(szPath, NULL, 0);
if (GetSystemMetrics(SM_CLEANBOOT))
return FALSE;
ps = OpenFileStream(szPath, OF_READ);
if (ps != NULL)
{
IC_HEAD ich;
if (Stream_Read(ps, &ich, SIZEOF(ich)))
{
if (ich.cbSize == SIZEOF(ich) &&
ich.uVersion == ICONCACHE_VERSION &&
ich.uMagic == ICONCACHE_MAGIC &&
ich.dwBuild == GetBuildNumber() &&
ich.cxIcon == (DWORD)cxIcon &&
ich.cyIcon == (DWORD)cyIcon &&
ich.cxSmIcon == (DWORD)cxSmIcon &&
ich.cySmIcon == (DWORD)cySmIcon &&
ich.flags == (DWORD)flags)
{
HDSA hdsaTemp;
UINT cres = GetCurColorRes();
//
// dont load a mono image list on a color device, and
// dont load a color image list on a mono device, get it?
//
if (ich.uColorRes == 1 && cres != 1 ||
ich.uColorRes != 1 && cres == 1)
{
DebugMsg(DM_TRACE, TEXT("IconCacheRestore: mono/color depth is wrong"));
hdsaTemp = NULL;
}
else if (ich.uNumIcons > (UINT)g_MaxIcons)
{
DebugMsg(DM_TRACE, TEXT("IconCacheRestore: icon cache is too big not loading it."));
hdsaTemp = NULL;
}
else
{
hdsaTemp = DSA_Create(SIZEOF(LOCATION_ENTRY), 8);
}
// load the icon table
if (hdsaTemp)
{
LOCATION_ENTRY dummy;
// grow the array out so we can read data into it
if (DSA_SetItem(hdsaTemp, ich.uNumIcons - 1, &dummy))
{
Assert(DSA_GetItemCount(hdsaTemp) == (int)ich.uNumIcons);
// read straight into the DSA data block
if (Stream_Read(ps, DSA_GetItemPtr(hdsaTemp, 0), ich.uNumIcons * SIZEOF(LOCATION_ENTRY)))
{
HIMAGELIST himlTemp;
int i;
// read the paths, patching up the table with the hashitem info
for (i = 0; i < (int)ich.uNumIcons; i++)
{
PLOCATION_ENTRY pLocation = DSA_GetItemPtr(hdsaTemp, i);
Stream_ReadStringBuffer(ps, szPath, ARRAYSIZE(szPath));
if (szPath[0])
pLocation->szName = AddHashItem(NULL, szPath);
else
pLocation->szName = 0;
}
// restore the image lists
himlTemp = ImageList_Read(ps);
if (himlTemp)
{
int cx, cy;
ImageList_GetIconSize(himlTemp, &cx, &cy);
if (cx == cxIcon && cy == cyIcon)
{
HIMAGELIST himlTempSmall = ImageList_Read(ps);
if (himlTempSmall)
{
Stream_Close(ps);
if (himlIcons)
ImageList_Destroy(himlIcons);
himlIcons = himlTemp;
if (himlIconsSmall)
ImageList_Destroy(himlIconsSmall);
himlIconsSmall = himlTempSmall;
if (g_hdsaIcons)
DSA_DeleteAllItems(g_hdsaIcons);
g_hdsaIcons = hdsaTemp;
//
// we want GetIconTime() to pick up
// where it left off when we saved.
//
IconTimeBase = 0; // GetIconTime() uses IconTimeBase
IconTimeBase = ich.TimeSave - GetIconTime();
IconTimeFlush = ich.TimeFlush;
FreeImageCount = ich.FreeImageCount;
FreeEntryCount = ich.FreeEntryCount;
g_DirtyIcons = FALSE;
DebugMsg(DM_TRACE, TEXT("IconCacheRestore: loaded %s"), szPath);
return TRUE; // success
}
}
ImageList_Destroy(himlTemp);
}
}
}
DSA_DeleteAllItems(hdsaTemp);
}
}
else
{
DebugMsg(DM_TRACE, TEXT("IconCacheRestore: Icon cache header changed"));
}
}
Stream_Close(ps);
}
else
{
DebugMsg(DM_TRACE, TEXT("IconCacheRestore: unable to open file."));
}
DebugMsg(DM_TRACE, TEXT("IconCacheRestore: cache not restored!"));
return FALSE;
}
//------------------ file class table ------------------------
static PHASHTABLE g_phtClass = NULL;
void FlushFileClass(void)
{
ENTERCRITICAL
#ifdef DEBUG
if (g_phtClass != NULL) {
DebugMsg(DM_TRACE, TEXT("Flushing file class table"));
TIMEOUT(LookupFileClass);
TIMEOUT(AddFileClass);
TIMEOUT(LookupFileClassName);
TIMEOUT(AddFileClassName);
TIMEOUT(LookupIcon);
TIMEOUT(AddIcon);
TIMEOUT(RemoveIcon);
TIMEIN(LookupFileClass);
TIMEIN(AddFileClass);
TIMEIN(LookupFileClassName);
TIMEIN(AddFileClassName);
TIMEIN(LookupIcon);
TIMEIN(AddIcon);
TIMEIN(RemoveIcon);
DumpHashItemTable(g_phtClass);
}
#endif
if (g_phtClass != NULL)
{
DestroyHashItemTable(g_phtClass);
g_phtClass = NULL;
}
LEAVECRITICAL
}
DWORD LookupFileClass(LPCTSTR szClass)
{
DWORD dw=0;
ENTERCRITICAL
TIMESTART(LookupFileClass);
if (g_phtClass && (NULL != (szClass = FindHashItem(g_phtClass, szClass))))
dw = GetHashItemData(g_phtClass, szClass, 0);
TIMESTOP(LookupFileClass);
LEAVECRITICAL
return dw;
}
void AddFileClass(LPCTSTR szClass, DWORD dw)
{
ENTERCRITICAL
TIMESTART(AddFileClass);
//
// create a hsa table to keep the file class info in.
//
// DWORD #0 is the type flags
// DWORD #1 is the class name
//
if (g_phtClass == NULL)
g_phtClass = CreateHashItemTable(0, 2*SIZEOF(DWORD), FALSE);
Assert(g_phtClass);
if (g_phtClass && (NULL != (szClass = AddHashItem(g_phtClass, szClass))))
SetHashItemData(g_phtClass, szClass, 0, dw);
TIMESTOP(AddFileClass);
LEAVECRITICAL
return;
}
LPCTSTR LookupFileClassName(LPCTSTR szClass)
{
LPCTSTR szClassName=NULL;
ASSERTCRITICAL
TIMESTART(LookupFileClassName);
if (g_phtClass && (NULL != (szClass = FindHashItem(g_phtClass, szClass))))
szClassName = (LPCTSTR)GetHashItemData(g_phtClass, szClass, 1);
TIMESTOP(LookupFileClassName);
return szClassName;
}
LPCTSTR AddFileClassName(LPCTSTR szClass, LPCTSTR szClassName)
{
ASSERTCRITICAL
TIMESTART(AddFileClassName);
//
// create a hsa table to keep the file class info in.
//
// DWORD #0 is the type flags
// DWORD #1 is the class name
//
if (g_phtClass == NULL)
g_phtClass = CreateHashItemTable(0, 2*SIZEOF(DWORD), FALSE);
Assert(g_phtClass);
if (g_phtClass && (NULL != (szClass = AddHashItem(g_phtClass, szClass)))) {
szClassName = AddHashItem(g_phtClass, szClassName);
SetHashItemData(g_phtClass, szClass, 1, (DWORD)szClassName);
}
TIMESTOP(AddFileClassName);
return szClassName;
}
/*
** Icon_FSEvent()
**
** watch FS events, and make sure our cache gets updated
**
** this is also called by defviewx.c (with SHCNE_UPDATEITEM)
** to remove a PIDL from the icon cache.
**
** fNotify should be FALSE for SHCNE_UPDATEITEM to avoid generating
** other SHCNE_ events.
*/
void Icon_FSEvent(LONG lEvent, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExtra)
{
BOOL fNotify=FALSE;
switch (lEvent)
{
case SHCNE_ASSOCCHANGED:
FlushFileClass(); // flush them all
break;
#if 0 // this generates way too much notify trafic.
// lets just let the cache fill up, and get flushed
case SHCNE_DELETE:
case SHCNE_RENAMEITEM:
fNotify=TRUE;
// fall through to SHCNE_UPDATEITEM
#endif
case SHCNE_UPDATEITEM:
if (pidl == NULL)
return;
pidl = ILFindLastID(pidl);
if (pidl != NULL && FS_IsValidID(pidl))
{
TCHAR szName[MAX_PATH];
FS_CopyName((LPIDFOLDER)pidl,szName,ARRAYSIZE(szName));
DebugMsg(DM_TRACE, TEXT("IconCache: flush %s"), szName);
RemoveFromIconTable(szName, fNotify);
}
break;
}
}