|
|
#include "shellprv.h"
#pragma hdrstop
#include "ovrlaymn.h"
#include "fstreex.h"
#include "filetbl.h"
#include "ids.h"
// REVIEW: More clean up should be done.
BOOL _ShellImageListInit(UINT flags, BOOL fRestore);
int g_ccIcon = 0; // color depth of ImageLists
int g_MaxIcons = DEF_MAX_ICONS; // panic limit for icons in cache
int g_lrFlags = 0;
int g_ccIconDEBUG = -1; int g_resDEBUG = -1;
int GetRegInt(HKEY hk, LPCTSTR szKey, int def) { TCHAR ach[20]; DWORD cb = sizeof(ach); if (ERROR_SUCCESS == SHQueryValueEx(hk, szKey, NULL, NULL, (LPBYTE)ach, &cb) && (ach[0] >= TEXT('0') && ach[0] <= TEXT('9'))) { return (int)StrToLong(ach); } else return def; }
int _GetMetricsRegInt(LPCTSTR pszKey, int iDefault) { HKEY hkey; if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_CURRENT_USER, REGSTR_PATH_METRICS, NULL, KEY_QUERY_VALUE, &hkey)) { iDefault = GetRegInt(hkey, pszKey, iDefault); RegCloseKey(hkey); } return iDefault; }
typedef void (*PSIZECALLBACK)(SIZE *psize);
void WINAPI _GetLargeIconSizeCB(SIZE *psize) { int cxIcon = GetSystemMetrics(SM_CXICON);
//
// get the user prefered icon size from the registry.
//
cxIcon = _GetMetricsRegInt(TEXT("Shell Icon Size"), cxIcon);
psize->cx = psize->cy = cxIcon; }
void WINAPI _GetSmallIconSizeCB(SIZE *psize) { int cxIcon = GetSystemMetrics(SM_CXICON)/2;
//
// get the user prefered icon size from the registry.
//
cxIcon = _GetMetricsRegInt(TEXT("Shell Small Icon Size"), cxIcon);
psize->cx = psize->cy = cxIcon; }
void WINAPI _GetSysSmallIconSizeCB(SIZE *psize) { psize->cx = GetSystemMetrics(SM_CXSMICON); psize->cy = GetSystemMetrics(SM_CYSMICON); }
void WINAPI _GetXLIconSizeCB(SIZE *psize) { psize->cx = 3 * GetSystemMetrics(SM_CXICON) / 2; psize->cy = 3 * GetSystemMetrics(SM_CYICON) / 2; }
static const PSIZECALLBACK c_rgSizeCB[SHIL_COUNT] = { _GetLargeIconSizeCB, // SHIL_LARGE
_GetSmallIconSizeCB, // SHIL_SMALL
_GetXLIconSizeCB, // SHIL_EXTRALARGE
_GetSysSmallIconSizeCB, // SHIL_SYSSMALL
};
EXTERN_C SHIMAGELIST g_rgshil[SHIL_COUNT] = {0};
BOOL _IsSHILInited() { #ifdef DEBUG
for (int i = 0; i < ARRAYSIZE(g_rgshil); i++) { // If allocation of any one image list failed, all should be NULL. So
// make sure they're either all NULL or all non-NULL.
ASSERTMSG((g_rgshil[0].himl == NULL) == (g_rgshil[i].himl == NULL), "_IsSHILInited: g_rgshil is inconsistent. g_rgshil[0].himl %x, g_rgshil[%x].himl %x", g_rgshil[0].himl, i, g_rgshil[i].himl); } #endif
return (g_rgshil[0].himl != NULL); }
int _GetSHILImageCount() { #ifdef DEBUG
for (int i = 0; i < ARRAYSIZE(g_rgshil); i++) { // If insertion of an image into one image list failed, insertion of an
// image into all image lists should have failed. So make sure the image
// counts are all the same.
ASSERTMSG(ImageList_GetImageCount(g_rgshil[0].himl) == ImageList_GetImageCount(g_rgshil[i].himl), "_GetSHILImageCount: g_rgshil is inconsistent. image counts don't line up."); } #endif
return ImageList_GetImageCount(g_rgshil[0].himl); }
//
// System imagelist - Don't change the order of this list.
// If you need to add a new icon, add it to the end of the
// array, and update shellp.h.
//
EXTERN_C UINT const c_SystemImageListIndexes[] = { IDI_DOCUMENT, IDI_DOCASSOC, IDI_APP, IDI_FOLDER, IDI_FOLDEROPEN, IDI_DRIVE525, IDI_DRIVE35, IDI_DRIVEREMOVE, IDI_DRIVEFIXED, IDI_DRIVENET, IDI_DRIVENETDISABLED, IDI_DRIVECD, IDI_DRIVERAM, IDI_WORLD, IDI_NETWORK, IDI_SERVER, IDI_PRINTER, IDI_MYNETWORK, IDI_GROUP,
IDI_STPROGS, IDI_STDOCS, IDI_STSETNGS, IDI_STFIND, IDI_STHELP, IDI_STRUN, IDI_STSUSPEND, IDI_STEJECT, IDI_STSHUTD,
IDI_SHARE, IDI_LINK, IDI_SLOWFILE, IDI_RECYCLER, IDI_RECYCLERFULL, IDI_RNA, IDI_DESKTOP,
IDI_CPLFLD, IDI_STSPROGS, IDI_PRNFLD, IDI_STFONTS, IDI_STTASKBR,
IDI_CDAUDIO, IDI_TREE, IDI_STCPROGS, IDI_STFAV, IDI_STLOGOFF, IDI_STFLDRPROP, IDI_WINUPDATE
,IDI_MU_SECURITY, IDI_MU_DISCONN };
// get g_MaxIcons from the registry, returning TRUE if it has changed
BOOL QueryNewMaxIcons(void) { int MaxIcons = -1; HKEY hk = SHGetShellKey(SHELLKEY_HKLM_EXPLORER, NULL, FALSE); if (hk) { MaxIcons = GetRegInt(hk, TEXT("Max Cached Icons"), DEF_MAX_ICONS); RegCloseKey(hk); }
if (MaxIcons < 0) MaxIcons = DEF_MAX_ICONS;
int OldMaxIcons = InterlockedExchange((LONG*)&g_MaxIcons, MaxIcons);
return (OldMaxIcons != MaxIcons); }
// Initializes shared resources for Shell_GetIconIndex and others
STDAPI_(BOOL) FileIconInit(BOOL fRestoreCache) { BOOL fNotify = FALSE; static int s_res = 32;
QueryNewMaxIcons(); // in case the size of the icon cache has changed
SIZE rgsize[ARRAYSIZE(g_rgshil)];
for (int i = 0; i < ARRAYSIZE(g_rgshil); i++) { c_rgSizeCB[i](&rgsize[i]); }
//
// get the user prefered color depth from the registry.
//
int ccIcon = _GetMetricsRegInt(TEXT("Shell Icon Bpp"), 0); g_ccIconDEBUG = ccIcon;
int res = (int)GetCurColorRes(); g_resDEBUG = res;
if (res == 0) res = s_res; s_res = res;
if (ccIcon > res) ccIcon = 0;
if (res >= 24) // Match User32. They will extract 32bpp icons in 24bpp.
ccIcon = 32;
if (res <= 8) ccIcon = 0; // wouldn't have worked anyway
ENTERCRITICAL;
//
// if we already have a icon cache make sure it is the right size etc.
//
BOOL fHadCache = _IsSHILInited();
BOOL fCacheValid = fHadCache && (ccIcon == g_ccIcon); for (int i = 0; fCacheValid && i < ARRAYSIZE(g_rgshil); i++) { if (g_rgshil[i].size.cx != rgsize[i].cx || g_rgshil[i].size.cy != rgsize[i].cy) { fCacheValid = FALSE; } }
if (!fCacheValid) { fNotify = fHadCache;
FlushIconCache(); FlushFileClass();
// if we are the desktop process (explorer.exe), then force us to re-init the cache, so we get
// the basic set of icons in the right order....
if (!fRestoreCache && _IsSHILInited() && IsWindowInProcess(GetShellWindow())) { fRestoreCache = TRUE; }
for (int i = 0; i < ARRAYSIZE(g_rgshil); i++) { g_rgshil[i].size.cx = rgsize[i].cx; g_rgshil[i].size.cy = rgsize[i].cy; }
g_ccIcon = ccIcon;
if (res > 4 && g_ccIcon <= 4) g_lrFlags = LR_VGACOLOR; else g_lrFlags = 0;
if (g_iLastSysIcon == 0) // Keep track of which icons are perm.
{ if (fRestoreCache) g_iLastSysIcon = II_LASTSYSICON; else g_iLastSysIcon = (II_OVERLAYLAST - II_OVERLAYFIRST) + 1; }
//
// if
// 1) we already have the icon cache but want to flush and re-initialize it because of size/color depth change, or
// 2) we don't have icon cache but want to initialize it, instead of restoring it from disk, or
// 3) we failed to restore icon cache from disk
// then, initialize the icon cache with c_SystemImageListIndexes
//
if (_IsSHILInited() || !fRestoreCache || !IconCacheRestore(rgsize, g_ccIcon)) { fCacheValid = _ShellImageListInit(g_ccIcon, fRestoreCache); } else { fCacheValid = TRUE; } }
LEAVECRITICAL;
if (fCacheValid && fNotify) { SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)-1, NULL); }
return fCacheValid; }
void _ShellImageListTerm() { ASSERTCRITICAL;
for (int i = 0; i < ARRAYSIZE(g_rgshil); i++) { if (g_rgshil[i].himl) { ImageList_Destroy(g_rgshil[i].himl); g_rgshil[i].himl = NULL; } } }
void FileIconTerm() { ENTERCRITICAL;
_ShellImageListTerm();
LEAVECRITICAL; }
void _DestroyIcons(HICON *phicons, int cIcons) { for (int i = 0; i < cIcons; i++) { if (phicons[i]) { DestroyIcon(phicons[i]); phicons[i] = NULL; } } }
BOOL _ShellImageListInit(UINT flags, BOOL fRestore) { ASSERTCRITICAL;
//
// Check if we need to create a mirrored imagelist. [samera]
//
if (IS_BIDI_LOCALIZED_SYSTEM()) { flags |= ILC_MIRROR; }
BOOL fFailedAlloc = FALSE; for (int i = 0; i < ARRAYSIZE(g_rgshil); i++) { if (g_rgshil[i].himl == NULL) { g_rgshil[i].himl = ImageList_Create(g_rgshil[i].size.cx, g_rgshil[i].size.cy, ILC_MASK|ILC_SHARED|flags, 0, 32); fFailedAlloc |= (g_rgshil[i].himl == NULL); } else { // set the flags incase the colour depth has changed...
// ImageList_setFlags already calls ImageList_remove on success
if (!ImageList_SetFlags(g_rgshil[i].himl, ILC_MASK|ILC_SHARED|flags)) { // Couldn't change flags; tough. At least remove them all.
ImageList_Remove(g_rgshil[i].himl, -1); } ImageList_SetIconSize(g_rgshil[i].himl, g_rgshil[i].size.cx, g_rgshil[i].size.cy); }
// set the bk colors to COLOR_WINDOW since this is what will
// be used most of the time as the bk for these lists (cabinet, tray)
// this avoids having to do ROPs when drawing, thus making it fast
if (g_rgshil[i].himl) { ImageList_SetBkColor(g_rgshil[i].himl, GetSysColor(COLOR_WINDOW)); } }
// If any imagelist allocation failed, fail the whole initialization
if (fFailedAlloc) { _ShellImageListTerm(); return FALSE; } else { // Load all of the icons with fRestore == TRUE
if (fRestore) { TCHAR szModule[MAX_PATH]; HKEY hkeyIcons;
GetModuleFileName(HINST_THISDLL, szModule, ARRAYSIZE(szModule));
// WARNING: this code assumes that these icons are the first in
// our RC file and are in this order and these indexes correspond
// to the II_ constants in shell.h.
hkeyIcons = SHGetShellKey(SHELLKEY_HKLM_EXPLORER, TEXT("Shell Icons"), FALSE);
for (i = 0; i < ARRAYSIZE(c_SystemImageListIndexes); i++) { HICON rghicon[ARRAYSIZE(g_rgshil)] = {0};
// check to see if icon is overridden in the registry
if (hkeyIcons) { TCHAR val[12]; TCHAR ach[MAX_PATH]; DWORD cb = sizeof(ach);
StringCchPrintf(val, ARRAYSIZE(val), TEXT("%d"), i); // ok to truncate
ach[0] = 0; SHQueryValueEx(hkeyIcons, val, NULL, NULL, (LPBYTE)ach, &cb);
if (ach[0]) { int iIcon = PathParseIconLocation(ach);
for (int j = 0; j < ARRAYSIZE(g_rgshil); j++) { ExtractIcons(ach, iIcon, g_rgshil[j].size.cx, g_rgshil[j].size.cy, &rghicon[j], NULL, 1, g_lrFlags); } } }
// if we got a large icon, run with that for everyone. otherwise fall back to loadimage.
if (rghicon[SHIL_LARGE] == NULL) { for (int j = 0; j < ARRAYSIZE(rghicon); j++) { if (rghicon[j] == NULL) { rghicon[j] = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(c_SystemImageListIndexes[i]), IMAGE_ICON, g_rgshil[j].size.cx, g_rgshil[j].size.cy, g_lrFlags); } } }
int iIndex = SHAddIconsToCache(rghicon, szModule, i, 0); ASSERT(iIndex == i || iIndex == -1); // assume index
_DestroyIcons(rghicon, ARRAYSIZE(rghicon));
if (iIndex == -1) { fFailedAlloc = TRUE; break; } }
if (hkeyIcons) RegCloseKey(hkeyIcons);
if (fFailedAlloc) { FlushIconCache(); _ShellImageListTerm(); return FALSE; } }
//
// Refresh the overlay image so that the overlays are added to the imaglist.
// GetIconOverlayManager() will initialize the overlay manager if necessary.
//
IShellIconOverlayManager *psiom; if (SUCCEEDED(GetIconOverlayManager(&psiom))) { psiom->RefreshOverlayImages(SIOM_OVERLAYINDEX | SIOM_ICONINDEX); psiom->Release(); }
return TRUE; } }
// get a hold of the system image lists
BOOL WINAPI Shell_GetImageLists(HIMAGELIST *phiml, HIMAGELIST *phimlSmall) { if (!_IsSHILInited()) { FileIconInit(FALSE); // make sure they are created and the right size.
if (!_IsSHILInited()) return FALSE; }
if (phiml) *phiml = g_rgshil[SHIL_LARGE].himl;
if (phimlSmall) *phimlSmall = g_rgshil[SHIL_SMALL].himl;
return TRUE; }
HRESULT SHGetImageList(int iImageList, REFIID riid, void **ppvObj) { HRESULT hr = E_OUTOFMEMORY;
if (!_IsSHILInited()) { FileIconInit(FALSE); // make sure they are created and the right size.
if (!_IsSHILInited()) return hr; }
ENTERCRITICAL;
if (iImageList >=0 && iImageList < ARRAYSIZE(g_rgshil)) { hr = HIMAGELIST_QueryInterface(g_rgshil[iImageList].himl, riid, ppvObj); } else { hr = E_INVALIDARG; }
LEAVECRITICAL;
return hr; }
void WINAPI Shell_SysColorChange(void) { COLORREF clrWindow = GetSysColor(COLOR_WINDOW);
ENTERCRITICAL; for (int i = 0; i < ARRAYSIZE(g_rgshil); i++) { ImageList_SetBkColor(g_rgshil[i].himl, clrWindow); } LEAVECRITICAL; }
// simulate the document icon by crunching a copy of an icon and putting it in the
// middle of our default document icon, then add it to the passsed image list
//
// in:
// hIcon icon to use as a basis for the simulation
//
// returns:
// hicon
HBITMAP CreateDIB(HDC h, WORD depth, int cx, int cy, RGBQUAD** pprgb) { BITMAPINFO bi = {0}; bi.bmiHeader.biSize = sizeof(bi.bmiHeader); bi.bmiHeader.biWidth = cx; bi.bmiHeader.biHeight = cy; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = depth; bi.bmiHeader.biCompression = BI_RGB;
return CreateDIBSection(h, &bi, DIB_RGB_COLORS, (void**)pprgb, NULL, 0); }
BOOL HasAlpha(RGBQUAD* prgb, int cx, int cy) { int iTotal = cx * cy;
for (int i = 0; i < iTotal; i++) { if (prgb[i].rgbReserved != 0) return TRUE; }
return FALSE; }
void DorkAlpha(RGBQUAD* prgb, int x, int y, int cx, int cy, int cxTotal) { for (int dy = y; dy < (cy + y); dy++) { for (int dx = x; dx < (cx + x); dx++) { prgb[dx + dy * cxTotal].rgbReserved = 255; } } }
HICON SimulateDocIcon(HIMAGELIST himl, HICON hIcon, int cx, int cy) { if (himl == NULL || hIcon == NULL) return NULL;
HDC hdc = GetDC(NULL); if (hdc) { RGBQUAD* prgb;
// If the display is in 24 or 32bpp mode, we may have alpha icons, so we'll need to create a dib section
BOOL fAlphaIcon = (GetDeviceCaps(hdc, BITSPIXEL) >= 24)? TRUE: FALSE; HBITMAP hbmColor; if (fAlphaIcon) { hbmColor = CreateDIB(hdc, 32, cx, cy, &prgb); } else { hbmColor = CreateCompatibleBitmap(hdc, cx, cy); }
if (hbmColor) { HBITMAP hbmMask = CreateBitmap(cx, cy, 1, 1, NULL); if (hbmMask) { HDC hdcMem = CreateCompatibleDC(hdc); if (hdcMem) { HBITMAP hbmT = (HBITMAP)SelectObject(hdcMem, hbmMask); UINT iIndex = Shell_GetCachedImageIndex(c_szShell32Dll, II_DOCNOASSOC, 0); ImageList_Draw(himl, iIndex, hdcMem, 0, 0, ILD_MASK);
SelectObject(hdcMem, hbmColor); ImageList_DrawEx(himl, iIndex, hdcMem, 0, 0, 0, 0, RGB(0,0,0), CLR_DEFAULT, ILD_NORMAL);
// Check to see if the parent has alpha. If so, we'll have to dork with the child's alpha later on.
BOOL fParentHasAlpha = fAlphaIcon?HasAlpha(prgb, cx, cy):FALSE;
HDC hdcMemChild = CreateCompatibleDC(hdcMem); if (hdcMemChild) { // Notes:
// First: create a 24bpp Dibsection. We want to merge the alpha channel into the final image,
// not preserve it.
// Second: The document icon has "Goo" in it. We remove this goo by blitting white into it, then
// merging the child bitmap
HBITMAP hbmp = CreateDIB(hdc, 24, cx/2 + 2, cy/2 + 2, NULL); if (hbmp) { HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMemChild, hbmp);
RECT rc; rc.left = 0; rc.top = 0; rc.right = cx/2 + 3; // Extra space to remove goo in the document icon
rc.bottom = cy/2 + 3;
// Fill with white. NOTE: don't use PatBlt because it actually adds an alpha channel!
SHFillRectClr(hdcMemChild, &rc, RGB(255,255,255));
DrawIconEx(hdcMemChild, 1, 1, hIcon, cx/2, cy/2, 0, NULL, DI_NORMAL);
BitBlt(hdcMem, cx/4-1, cy/4-1, cx/2+3, cy/2+3, hdcMemChild, 0, 0, SRCCOPY); SelectObject(hdcMemChild, hbmpOld); DeleteObject(hbmp); } DeleteDC(hdcMemChild); }
if (fParentHasAlpha) { // If the parent had alpha, we need to bring the child alpha to opaqe
DorkAlpha(prgb, cx/4, cy/4, cx/2, cy/2, cx); }
SelectBitmap(hdcMem, hbmT); DeleteDC(hdcMem); }
ICONINFO ii = {0}; ii.fIcon = TRUE; ii.hbmColor = hbmColor; ii.hbmMask = hbmMask; hIcon = CreateIconIndirect(&ii);
DeleteObject(hbmMask); } DeleteObject(hbmColor); } ReleaseDC(NULL, hdc); }
return hIcon; }
// Check if the same number of images is present in all of the image lists.
// If any of the imagelists have less icons than the others, fill the imagelist
// in with the document icon to make them all consistent.
//
// Eg: WebZip v3.80 and v4.00 queries for the large and small image lists,
// and adds 2 icons to it. However, it doesn't know to add these icons to the
// newer image lists. Hence, the image lists are out of sync, and later on,
// the wrong icon appears in their treeview.
//
// Allaire Homesite 4.5 does the same thing.
void CheckConsistencyOfImageLists(void) { // This has to be done under the critical section to avoid race conditions.
// Otherwise, if another thread is adding icons to the image list,
// we will think it is corrupted when in fact it is just fine, and
// then our attempts to repair it will corrupt it!
ASSERTCRITICAL;
int i, iMax = 0, iImageListsCounts[ARRAYSIZE(g_rgshil)]; BOOL bIdentical = TRUE;
// Loop through all the image lists getting:
//
// 1) the image count for each list
// 2) Compare the count against the count of the first (large)
// imagelist to see if there are any differences.
// 3) Determine the max number of images (in a single list) across all the image lists
for (i = 0; i < ARRAYSIZE(g_rgshil); i++) { iImageListsCounts[i] = ImageList_GetImageCount (g_rgshil[i].himl);
if (iImageListsCounts[i] != iImageListsCounts[0]) { bIdentical = FALSE; }
if (iImageListsCounts[i] > iMax) { iMax = iImageListsCounts[i]; } }
if (bIdentical) { return; }
// For each imagelist, add the document icon as filler to bring it upto iMax in size
for (i = 0; i < ARRAYSIZE(g_rgshil); i++) { if (iImageListsCounts[i] < iMax) { HICON hIcon = (HICON) LoadImage (HINST_THISDLL, MAKEINTRESOURCE(IDI_DOCUMENT), IMAGE_ICON, g_rgshil[i].size.cx, g_rgshil[i].size.cy, LR_DEFAULTCOLOR); if (hIcon) { while (iImageListsCounts[i] < iMax) { ImageList_ReplaceIcon (g_rgshil[i].himl, -1, hIcon); iImageListsCounts[i]++; }
DestroyIcon (hIcon); } } } }
// add icons to the system imagelist (icon cache) and put the location
// in the location cache
//
// in:
// hIcon, hIconSmall the icons, hIconSmall can be NULL
// pszIconPath locations (for location cache)
// iIconIndex index in pszIconPath (for location cache)
// uIconFlags GIL_ flags (for location cahce)
// returns:
// location in system image list
//
int SHAddIconsToCache(HICON rghicon[SHIL_COUNT], LPCTSTR pszIconPath, int iIconIndex, UINT uIconFlags) { int iImage = -1;
if (!_IsSHILInited()) { FileIconInit(FALSE); // make sure they are created and the right size.
if (!_IsSHILInited()) return iImage; }
//
// NOTE: user should call SHLookupIconIndex or RemoveFromIconTable first to make sure
// it isn't already in shell icon cache, or use Shell_GetCachedImageIndex to add icons to
// the cache. Adding the same icon to icon cache several times may cause shell to flash.
//
if (!(uIconFlags & GIL_DONTCACHE)) { iImage = LookupIconIndex(pszIconPath, iIconIndex, uIconFlags); if (-1 != iImage) { return iImage; } }
HICON rghiconT[ARRAYSIZE(g_rgshil)] = {0};
BOOL fFailure = FALSE; int i;
for (i = 0; i < ARRAYSIZE(g_rgshil); i++) { if (rghicon == NULL) { SHDefExtractIcon(pszIconPath, iIconIndex, uIconFlags, &rghiconT[i], NULL, g_rgshil[i].size.cx); } else { if (rghicon[i]) { rghiconT[i] = rghicon[i]; } else { rghiconT[i] = rghicon[SHIL_LARGE]; } }
if (rghiconT[i] == NULL) { fFailure = TRUE; break; } }
ENTERCRITICAL;
// test again in case there was a race between the test at the top and the
// icon loading code.
if (!(uIconFlags & GIL_DONTCACHE)) { iImage = LookupIconIndex(pszIconPath, iIconIndex, uIconFlags); }
if (!fFailure && _IsSHILInited() && (-1 == iImage)) { // still not in the table so we
CheckConsistencyOfImageLists();
int iImageFree = GetFreeImageIndex();
TraceMsg(TF_IMAGE, "FreeImageIndex = %d", iImageFree);
for (i = 0; i < ARRAYSIZE(g_rgshil); i++) { int iImageT = ImageList_ReplaceIcon(g_rgshil[i].himl, iImageFree, rghiconT[i]);
TraceMsg(TF_IMAGE, "ImageList_ReplaceIcon(%d) returned = %d", i, iImageT);
if (iImageT < 0) { // failure -- break and undo changes
break; } else { ASSERT(iImage == -1 || iImage == iImageT); iImage = iImageT; } }
if (i < ARRAYSIZE(g_rgshil)) { // failure
if (iImageFree == -1) { // only remove it if it was added at the end otherwise all the
// index's above iImage will change.
// ImageList_ReplaceIcon should only fail on the end anyway.
for (int j = 0; j < i; j++) { ImageList_Remove(g_rgshil[j].himl, iImage); } } iImage = -1; } else { // success
ASSERT(iImage >= 0); AddToIconTable(pszIconPath, iIconIndex, uIconFlags, iImage); } }
LEAVECRITICAL;
if (rghicon == NULL) { // destroy the icons we allocated
_DestroyIcons(rghiconT, ARRAYSIZE(rghiconT)); }
return iImage; }
//
// default handler to extract a icon from a file
//
// supports GIL_SIMULATEDOC
//
// returns S_OK if success
// returns S_FALSE if the file has no icons (or not the asked for icon)
// returns E_FAIL for files on a slow link.
// returns E_FAIL if cant access the file
//
// LOWORD(nIconSize) = normal icon size
// HIWORD(nIconSize) = smal icon size
//
STDAPI SHDefExtractIcon(LPCTSTR pszIconFile, int iIndex, UINT uFlags, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) { HICON hIcons[2] = {0, 0};
UINT u;
#ifdef DEBUG
TCHAR ach[128]; GetModuleFileName(HINST_THISDLL, ach, ARRAYSIZE(ach));
if (lstrcmpi(pszIconFile, ach) == 0 && iIndex >= 0) { TraceMsg(TF_WARNING, "Re-extracting %d from SHELL32.DLL", iIndex); } #endif
HIMAGELIST himlLarge, himlSmall; Shell_GetImageLists(&himlLarge, &himlSmall);
//
// get the icon from the file
//
if (PathIsSlow(pszIconFile, -1)) { DebugMsg(DM_TRACE, TEXT("not extracting icon from '%s' because of slow link"), pszIconFile); return E_FAIL; }
#ifdef XXDEBUG
TraceMsg(TF_ALWAYS, "Extracting icon %d from %s.", iIndex, pszIconFile); Sleep(500); #endif
//
// nIconSize == 0 means use the default size.
// Backup is passing nIconSize == 1 need to support them too.
//
if (nIconSize <= 2) nIconSize = MAKELONG(g_cxIcon, g_cxSmIcon);
if (uFlags & GIL_SIMULATEDOC) { HICON hIconSmall;
u = ExtractIcons(pszIconFile, iIndex, g_cxSmIcon, g_cySmIcon, &hIconSmall, NULL, 1, g_lrFlags);
if (u == -1) return E_FAIL;
hIcons[0] = SimulateDocIcon(himlLarge, hIconSmall, g_cxIcon, g_cyIcon); hIcons[1] = SimulateDocIcon(himlSmall, hIconSmall, g_cxSmIcon, g_cySmIcon);
if (hIconSmall) DestroyIcon(hIconSmall); } else { u = ExtractIcons(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, g_lrFlags);
if (-1 == u) return E_FAIL;
#ifdef DEBUG
if (0 == u) { TraceMsg(TF_WARNING, "Failed to extract icon %d from %s.", iIndex, pszIconFile); } #endif
}
if (phiconLarge) *phiconLarge = hIcons[0]; else if (hIcons[0]) DestroyIcon(hIcons[0]);
if (phiconSmall) *phiconSmall = hIcons[1]; else if (hIcons[1]) DestroyIcon(hIcons[1]);
return u == 0 ? S_FALSE : S_OK; }
#ifdef UNICODE
STDAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) { HRESULT hr = E_INVALIDARG;
if (IS_VALID_STRING_PTRA(pszIconFile, -1)) { WCHAR wsz[MAX_PATH];
SHAnsiToUnicode(pszIconFile, wsz, ARRAYSIZE(wsz)); hr = SHDefExtractIcon(wsz, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); } return hr; }
#else
STDAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize) { HRESULT hr = E_INVALIDARG;
if (IS_VALID_STRING_PTRW(pszIconFile, -1)) { char sz[MAX_PATH];
SHUnicodeToAnsi(pszIconFile, sz, ARRAYSIZE(sz)); hr = SHDefExtractIcon(sz, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); } return hr; }
#endif
//
// in:
// pszIconPath file to get icon from (eg. cabinet.exe)
// iIconIndex icon index in pszIconPath to get
// uIconFlags GIL_ values indicating simulate doc icon, etc.
int WINAPI Shell_GetCachedImageIndex(LPCTSTR pszIconPath, int iIconIndex, UINT uIconFlags) { // lots of random codepaths from APIs end up here before init
if (!_IsSHILInited()) { FileIconInit(FALSE); if (!_IsSHILInited()) { return -1; } }
int iImageIndex = LookupIconIndex(pszIconPath, iIconIndex, uIconFlags); if (iImageIndex == -1) { iImageIndex = SHAddIconsToCache(NULL, pszIconPath, iIconIndex, uIconFlags); }
return iImageIndex; }
STDAPI_(void) FixPlusIcons() { // nuke all of the shell internal icons
HKEY hkeyIcons = SHGetShellKey(SHELLKEY_HKLM_EXPLORER, TEXT("Shell Icons"), FALSE); if (hkeyIcons) { for (int i = 0; i < ARRAYSIZE(c_SystemImageListIndexes); i++) { TCHAR szRegPath[12], szBuf[MAX_PATH]; DWORD cb = sizeof(szBuf);
StringCchPrintf(szRegPath, ARRAYSIZE(szRegPath), TEXT("%d"), i); // ok to truncate
if (SHQueryValueEx(hkeyIcons, szRegPath, NULL, NULL, (LPBYTE)szBuf, &cb) == ERROR_SUCCESS && StrStrI(szBuf, TEXT("cool.dll"))) { RegDeleteValue(hkeyIcons, szRegPath); } } RegCloseKey(hkeyIcons); } static const struct { const CLSID* pclsid; LPCTSTR pszIcon; } c_rgCLSID[] = { { &CLSID_NetworkPlaces, TEXT("shell32.dll,17") }, { &CLSID_ControlPanel, TEXT("shell32.dll,-137") }, { &CLSID_Printers, TEXT("shell32.dll,-138") }, { &CLSID_MyComputer, TEXT("explorer.exe,0") }, { &CLSID_Remote, TEXT("rnaui.dll,0") }, { &CLSID_CFonts, TEXT("fontext.dll,-101") }, { &CLSID_RecycleBin, NULL }, { &CLSID_Briefcase, NULL }, };
for (int i = 0; i < ARRAYSIZE(c_rgCLSID); i++) { TCHAR szCLSID[64], szRegPath[128], szBuf[MAX_PATH]; DWORD cb = sizeof(szBuf);
SHStringFromGUID(*c_rgCLSID[i].pclsid, szCLSID, ARRAYSIZE(szCLSID)); StringCchPrintf(szRegPath, ARRAYSIZE(szRegPath), TEXT("CLSID\\%s\\DefaultIcon"), szCLSID); // should fit always 64 + 18 < 128
if (SHRegGetValue(HKEY_CLASSES_ROOT, szRegPath, NULL, SRRF_RT_REG_SZ, NULL, szBuf, &cb) == ERROR_SUCCESS && StrStrI(szBuf, TEXT("cool.dll"))) { if (IsEqualGUID(*c_rgCLSID[i].pclsid, CLSID_RecycleBin)) { RegSetValueString(HKEY_CLASSES_ROOT, szRegPath, TEXT("Empty"), TEXT("shell32.dll,31")); RegSetValueString(HKEY_CLASSES_ROOT, szRegPath, TEXT("Full"), TEXT("shell32.dll,32")); if (StrStr(szBuf, TEXT("20"))) RegSetString(HKEY_CLASSES_ROOT, szRegPath, TEXT("shell32.dll,31")); // empty
else RegSetString(HKEY_CLASSES_ROOT, szRegPath, TEXT("shell32.dll,32")); // full
} else { if (c_rgCLSID[i].pszIcon) RegSetString(HKEY_CLASSES_ROOT, szRegPath, c_rgCLSID[i].pszIcon); else RegDeleteValue(HKEY_CLASSES_ROOT, szRegPath); } } }
static const struct { LPCTSTR pszProgID; LPCTSTR pszIcon; } c_rgProgID[] = { { TEXT("Folder"), TEXT("shell32.dll,3") }, { TEXT("Directory"),TEXT("shell32.dll,3") }, { TEXT("Drive"), TEXT("shell32.dll,8") }, { TEXT("drvfile"), TEXT("shell32.dll,-154") }, { TEXT("vxdfile"), TEXT("shell32.dll,-154") }, { TEXT("dllfile"), TEXT("shell32.dll,-154") }, { TEXT("sysfile"), TEXT("shell32.dll,-154") }, { TEXT("txtfile"), TEXT("shell32.dll,-152") }, { TEXT("inifile"), TEXT("shell32.dll,-151") }, { TEXT("inffile"), TEXT("shell32.dll,-151") }, };
for (i = 0; i < ARRAYSIZE(c_rgProgID); i++) { TCHAR szRegPath[128], szBuf[MAX_PATH]; DWORD cb = sizeof(szBuf);
HRESULT hr = StringCchPrintf(szRegPath, ARRAYSIZE(szRegPath), TEXT("%s\\DefaultIcon"), c_rgProgID[i].pszProgID); if (SUCCEEDED(hr)) { if (SHRegGetValue(HKEY_CLASSES_ROOT, szRegPath, NULL, SRRF_RT_REG_SZ, NULL, szBuf, &cb) == ERROR_SUCCESS && StrStrI(szBuf, TEXT("cool.dll"))) { RegSetString(HKEY_CLASSES_ROOT, szRegPath, c_rgProgID[i].pszIcon); } } }
FlushIconCache(); }
|