Source code of Windows XP (NT5)
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.

1180 lines
34 KiB

  1. #include "shellprv.h"
  2. #pragma hdrstop
  3. #include "ovrlaymn.h"
  4. #include "fstreex.h"
  5. #include "filetbl.h"
  6. #include "ids.h"
  7. // REVIEW: More clean up should be done.
  8. BOOL _ShellImageListInit(UINT flags, BOOL fRestore);
  9. int g_ccIcon = 0; // color depth of ImageLists
  10. int g_MaxIcons = DEF_MAX_ICONS; // panic limit for icons in cache
  11. int g_lrFlags = 0;
  12. int g_ccIconDEBUG = -1;
  13. int g_resDEBUG = -1;
  14. int GetRegInt(HKEY hk, LPCTSTR szKey, int def)
  15. {
  16. TCHAR ach[20];
  17. DWORD cb = sizeof(ach);
  18. if (ERROR_SUCCESS == SHQueryValueEx(hk, szKey, NULL, NULL, (LPBYTE)ach, &cb)
  19. && (ach[0] >= TEXT('0') && ach[0] <= TEXT('9')))
  20. {
  21. return (int)StrToLong(ach);
  22. }
  23. else
  24. return def;
  25. }
  26. int _GetMetricsRegInt(LPCTSTR pszKey, int iDefault)
  27. {
  28. HKEY hkey;
  29. if (RegOpenKey(HKEY_CURRENT_USER, REGSTR_PATH_METRICS, &hkey) == 0)
  30. {
  31. iDefault = GetRegInt(hkey, pszKey, iDefault);
  32. RegCloseKey(hkey);
  33. }
  34. return iDefault;
  35. }
  36. typedef void (*PSIZECALLBACK)(SIZE *psize);
  37. void WINAPI _GetLargeIconSizeCB(SIZE *psize)
  38. {
  39. int cxIcon = GetSystemMetrics(SM_CXICON);
  40. //
  41. // get the user prefered icon size from the registry.
  42. //
  43. cxIcon = _GetMetricsRegInt(TEXT("Shell Icon Size"), cxIcon);
  44. psize->cx = psize->cy = cxIcon;
  45. }
  46. void WINAPI _GetSmallIconSizeCB(SIZE *psize)
  47. {
  48. int cxIcon = GetSystemMetrics(SM_CXICON)/2;
  49. //
  50. // get the user prefered icon size from the registry.
  51. //
  52. cxIcon = _GetMetricsRegInt(TEXT("Shell Small Icon Size"), cxIcon);
  53. psize->cx = psize->cy = cxIcon;
  54. }
  55. void WINAPI _GetSysSmallIconSizeCB(SIZE *psize)
  56. {
  57. psize->cx = GetSystemMetrics(SM_CXSMICON);
  58. psize->cy = GetSystemMetrics(SM_CYSMICON);
  59. }
  60. void WINAPI _GetXLIconSizeCB(SIZE *psize)
  61. {
  62. psize->cx = 3 * GetSystemMetrics(SM_CXICON) / 2;
  63. psize->cy = 3 * GetSystemMetrics(SM_CYICON) / 2;
  64. }
  65. static const PSIZECALLBACK c_rgSizeCB[SHIL_COUNT] =
  66. {
  67. _GetLargeIconSizeCB, // SHIL_LARGE
  68. _GetSmallIconSizeCB, // SHIL_SMALL
  69. _GetXLIconSizeCB, // SHIL_EXTRALARGE
  70. _GetSysSmallIconSizeCB, // SHIL_SYSSMALL
  71. };
  72. EXTERN_C SHIMAGELIST g_rgshil[SHIL_COUNT] = {0};
  73. BOOL _IsSHILInited()
  74. {
  75. #ifdef DEBUG
  76. for (int i = 0; i < ARRAYSIZE(g_rgshil); i++)
  77. {
  78. // If allocation of any one image list failed, all should be NULL. So
  79. // make sure they're either all NULL or all non-NULL.
  80. ASSERTMSG((g_rgshil[0].himl == NULL) == (g_rgshil[i].himl == NULL),
  81. "_IsSHILInited: g_rgshil is inconsistent. g_rgshil[0].himl %x, g_rgshil[%x].himl %x", g_rgshil[0].himl, i, g_rgshil[i].himl);
  82. }
  83. #endif
  84. return (g_rgshil[0].himl != NULL);
  85. }
  86. int _GetSHILImageCount()
  87. {
  88. #ifdef DEBUG
  89. for (int i = 0; i < ARRAYSIZE(g_rgshil); i++)
  90. {
  91. // If insertion of an image into one image list failed, insertion of an
  92. // image into all image lists should have failed. So make sure the image
  93. // counts are all the same.
  94. ASSERTMSG(ImageList_GetImageCount(g_rgshil[0].himl) == ImageList_GetImageCount(g_rgshil[i].himl),
  95. "_GetSHILImageCount: g_rgshil is inconsistent. image counts don't line up.");
  96. }
  97. #endif
  98. return ImageList_GetImageCount(g_rgshil[0].himl);
  99. }
  100. //
  101. // System imagelist - Don't change the order of this list.
  102. // If you need to add a new icon, add it to the end of the
  103. // array, and update shellp.h.
  104. //
  105. EXTERN_C UINT const c_SystemImageListIndexes[] = { IDI_DOCUMENT,
  106. IDI_DOCASSOC,
  107. IDI_APP,
  108. IDI_FOLDER,
  109. IDI_FOLDEROPEN,
  110. IDI_DRIVE525,
  111. IDI_DRIVE35,
  112. IDI_DRIVEREMOVE,
  113. IDI_DRIVEFIXED,
  114. IDI_DRIVENET,
  115. IDI_DRIVENETDISABLED,
  116. IDI_DRIVECD,
  117. IDI_DRIVERAM,
  118. IDI_WORLD,
  119. IDI_NETWORK,
  120. IDI_SERVER,
  121. IDI_PRINTER,
  122. IDI_MYNETWORK,
  123. IDI_GROUP,
  124. IDI_STPROGS,
  125. IDI_STDOCS,
  126. IDI_STSETNGS,
  127. IDI_STFIND,
  128. IDI_STHELP,
  129. IDI_STRUN,
  130. IDI_STSUSPEND,
  131. IDI_STEJECT,
  132. IDI_STSHUTD,
  133. IDI_SHARE,
  134. IDI_LINK,
  135. IDI_SLOWFILE,
  136. IDI_RECYCLER,
  137. IDI_RECYCLERFULL,
  138. IDI_RNA,
  139. IDI_DESKTOP,
  140. IDI_CPLFLD,
  141. IDI_STSPROGS,
  142. IDI_PRNFLD,
  143. IDI_STFONTS,
  144. IDI_STTASKBR,
  145. IDI_CDAUDIO,
  146. IDI_TREE,
  147. IDI_STCPROGS,
  148. IDI_STFAV,
  149. IDI_STLOGOFF,
  150. IDI_STFLDRPROP,
  151. IDI_WINUPDATE
  152. ,IDI_MU_SECURITY,
  153. IDI_MU_DISCONN
  154. };
  155. // get g_MaxIcons from the registry, returning TRUE if it has changed
  156. BOOL QueryNewMaxIcons(void)
  157. {
  158. int MaxIcons = -1;
  159. HKEY hk = SHGetShellKey(SHELLKEY_HKLM_EXPLORER, NULL, FALSE);
  160. if (hk)
  161. {
  162. MaxIcons = GetRegInt(hk, TEXT("Max Cached Icons"), DEF_MAX_ICONS);
  163. RegCloseKey(hk);
  164. }
  165. if (MaxIcons < 0)
  166. MaxIcons = DEF_MAX_ICONS;
  167. int OldMaxIcons = InterlockedExchange((LONG*)&g_MaxIcons, MaxIcons);
  168. return (OldMaxIcons != MaxIcons);
  169. }
  170. // Initializes shared resources for Shell_GetIconIndex and others
  171. STDAPI_(BOOL) FileIconInit(BOOL fRestoreCache)
  172. {
  173. BOOL fNotify = FALSE;
  174. static int s_res = 32;
  175. QueryNewMaxIcons(); // in case the size of the icon cache has changed
  176. SIZE rgsize[ARRAYSIZE(g_rgshil)];
  177. for (int i = 0; i < ARRAYSIZE(g_rgshil); i++)
  178. {
  179. c_rgSizeCB[i](&rgsize[i]);
  180. }
  181. //
  182. // get the user prefered color depth from the registry.
  183. //
  184. int ccIcon = _GetMetricsRegInt(TEXT("Shell Icon Bpp"), 0);
  185. g_ccIconDEBUG = ccIcon;
  186. int res = (int)GetCurColorRes();
  187. g_resDEBUG = res;
  188. if (res == 0)
  189. res = s_res;
  190. s_res = res;
  191. if (ccIcon > res)
  192. ccIcon = 0;
  193. if (res >= 24) // Match User32. They will extract 32bpp icons in 24bpp.
  194. ccIcon = 32;
  195. if (res <= 8)
  196. ccIcon = 0; // wouldn't have worked anyway
  197. ENTERCRITICAL;
  198. //
  199. // if we already have a icon cache make sure it is the right size etc.
  200. //
  201. BOOL fHadCache = _IsSHILInited();
  202. BOOL fCacheValid = fHadCache && (ccIcon == g_ccIcon);
  203. for (int i = 0; fCacheValid && i < ARRAYSIZE(g_rgshil); i++)
  204. {
  205. if (g_rgshil[i].size.cx != rgsize[i].cx ||
  206. g_rgshil[i].size.cy != rgsize[i].cy)
  207. {
  208. fCacheValid = FALSE;
  209. }
  210. }
  211. if (!fCacheValid)
  212. {
  213. fNotify = fHadCache;
  214. FlushIconCache();
  215. FlushFileClass();
  216. // if we are the desktop process (explorer.exe), then force us to re-init the cache, so we get
  217. // the basic set of icons in the right order....
  218. if (!fRestoreCache && _IsSHILInited() && IsWindowInProcess(GetShellWindow()))
  219. {
  220. fRestoreCache = TRUE;
  221. }
  222. for (int i = 0; i < ARRAYSIZE(g_rgshil); i++)
  223. {
  224. g_rgshil[i].size.cx = rgsize[i].cx;
  225. g_rgshil[i].size.cy = rgsize[i].cy;
  226. }
  227. g_ccIcon = ccIcon;
  228. if (res > 4 && g_ccIcon <= 4)
  229. g_lrFlags = LR_VGACOLOR;
  230. else
  231. g_lrFlags = 0;
  232. if (g_iLastSysIcon == 0) // Keep track of which icons are perm.
  233. {
  234. if (fRestoreCache)
  235. g_iLastSysIcon = II_LASTSYSICON;
  236. else
  237. g_iLastSysIcon = (II_OVERLAYLAST - II_OVERLAYFIRST) + 1;
  238. }
  239. //
  240. // if
  241. // 1) we already have the icon cache but want to flush and re-initialize it because of size/color depth change, or
  242. // 2) we don't have icon cache but want to initialize it, instead of restoring it from disk, or
  243. // 3) we failed to restore icon cache from disk
  244. // then, initialize the icon cache with c_SystemImageListIndexes
  245. //
  246. if (_IsSHILInited() || !fRestoreCache || !IconCacheRestore(rgsize, g_ccIcon))
  247. {
  248. fCacheValid = _ShellImageListInit(g_ccIcon, fRestoreCache);
  249. }
  250. else
  251. {
  252. fCacheValid = TRUE;
  253. }
  254. }
  255. LEAVECRITICAL;
  256. if (fCacheValid && fNotify)
  257. {
  258. SHChangeNotify(SHCNE_UPDATEIMAGE, SHCNF_DWORD, (LPCVOID)-1, NULL);
  259. }
  260. return fCacheValid;
  261. }
  262. void _ShellImageListTerm()
  263. {
  264. ASSERTCRITICAL;
  265. for (int i = 0; i < ARRAYSIZE(g_rgshil); i++)
  266. {
  267. if (g_rgshil[i].himl)
  268. {
  269. ImageList_Destroy(g_rgshil[i].himl);
  270. g_rgshil[i].himl = NULL;
  271. }
  272. }
  273. }
  274. void FileIconTerm()
  275. {
  276. ENTERCRITICAL;
  277. _ShellImageListTerm();
  278. LEAVECRITICAL;
  279. }
  280. void _DestroyIcons(HICON *phicons, int cIcons)
  281. {
  282. for (int i = 0; i < cIcons; i++)
  283. {
  284. if (phicons[i])
  285. {
  286. DestroyIcon(phicons[i]);
  287. phicons[i] = NULL;
  288. }
  289. }
  290. }
  291. BOOL _ShellImageListInit(UINT flags, BOOL fRestore)
  292. {
  293. ASSERTCRITICAL;
  294. //
  295. // Check if we need to create a mirrored imagelist. [samera]
  296. //
  297. if (IS_BIDI_LOCALIZED_SYSTEM())
  298. {
  299. flags |= ILC_MIRROR;
  300. }
  301. BOOL fFailedAlloc = FALSE;
  302. for (int i = 0; i < ARRAYSIZE(g_rgshil); i++)
  303. {
  304. if (g_rgshil[i].himl == NULL)
  305. {
  306. g_rgshil[i].himl = ImageList_Create(g_rgshil[i].size.cx, g_rgshil[i].size.cy, ILC_MASK|ILC_SHARED|flags, 0, 32);
  307. fFailedAlloc |= (g_rgshil[i].himl == NULL);
  308. }
  309. else
  310. {
  311. // set the flags incase the colour depth has changed...
  312. // ImageList_setFlags already calls ImageList_remove on success
  313. if (!ImageList_SetFlags(g_rgshil[i].himl, ILC_MASK|ILC_SHARED|flags))
  314. {
  315. // Couldn't change flags; tough. At least remove them all.
  316. ImageList_Remove(g_rgshil[i].himl, -1);
  317. }
  318. ImageList_SetIconSize(g_rgshil[i].himl, g_rgshil[i].size.cx, g_rgshil[i].size.cy);
  319. }
  320. // set the bk colors to COLOR_WINDOW since this is what will
  321. // be used most of the time as the bk for these lists (cabinet, tray)
  322. // this avoids having to do ROPs when drawing, thus making it fast
  323. if (g_rgshil[i].himl)
  324. {
  325. ImageList_SetBkColor(g_rgshil[i].himl, GetSysColor(COLOR_WINDOW));
  326. }
  327. }
  328. // If any imagelist allocation failed, fail the whole initialization
  329. if (fFailedAlloc)
  330. {
  331. _ShellImageListTerm();
  332. return FALSE;
  333. }
  334. else
  335. {
  336. // Load all of the icons with fRestore == TRUE
  337. if (fRestore)
  338. {
  339. TCHAR szModule[MAX_PATH];
  340. HKEY hkeyIcons;
  341. GetModuleFileName(HINST_THISDLL, szModule, ARRAYSIZE(szModule));
  342. // WARNING: this code assumes that these icons are the first in
  343. // our RC file and are in this order and these indexes correspond
  344. // to the II_ constants in shell.h.
  345. hkeyIcons = SHGetShellKey(SHELLKEY_HKLM_EXPLORER, TEXT("Shell Icons"), FALSE);
  346. for (i = 0; i < ARRAYSIZE(c_SystemImageListIndexes); i++)
  347. {
  348. HICON rghicon[ARRAYSIZE(g_rgshil)] = {0};
  349. // check to see if icon is overridden in the registry
  350. if (hkeyIcons)
  351. {
  352. TCHAR val[10];
  353. TCHAR ach[MAX_PATH];
  354. DWORD cb = sizeof(ach);
  355. wsprintf(val, TEXT("%d"), i);
  356. ach[0] = 0;
  357. SHQueryValueEx(hkeyIcons, val, NULL, NULL, (LPBYTE)ach, &cb);
  358. if (ach[0])
  359. {
  360. int iIcon = PathParseIconLocation(ach);
  361. for (int j = 0; j < ARRAYSIZE(g_rgshil); j++)
  362. {
  363. ExtractIcons(ach, iIcon, g_rgshil[j].size.cx, g_rgshil[j].size.cy,
  364. &rghicon[j], NULL, 1, g_lrFlags);
  365. }
  366. }
  367. }
  368. // if we got a large icon, run with that for everyone. otherwise fall back to loadimage.
  369. if (rghicon[SHIL_LARGE] == NULL)
  370. {
  371. for (int j = 0; j < ARRAYSIZE(rghicon); j++)
  372. {
  373. if (rghicon[j] == NULL)
  374. {
  375. rghicon[j] = (HICON)LoadImage(HINST_THISDLL, MAKEINTRESOURCE(c_SystemImageListIndexes[i]),
  376. IMAGE_ICON, g_rgshil[j].size.cx, g_rgshil[j].size.cy, g_lrFlags);
  377. }
  378. }
  379. }
  380. int iIndex = SHAddIconsToCache(rghicon, szModule, i, 0);
  381. ASSERT(iIndex == i || iIndex == -1); // assume index
  382. _DestroyIcons(rghicon, ARRAYSIZE(rghicon));
  383. if (iIndex == -1)
  384. {
  385. fFailedAlloc = TRUE;
  386. break;
  387. }
  388. }
  389. if (hkeyIcons)
  390. RegCloseKey(hkeyIcons);
  391. if (fFailedAlloc)
  392. {
  393. FlushIconCache();
  394. _ShellImageListTerm();
  395. return FALSE;
  396. }
  397. }
  398. //
  399. // Refresh the overlay image so that the overlays are added to the imaglist.
  400. // GetIconOverlayManager() will initialize the overlay manager if necessary.
  401. //
  402. IShellIconOverlayManager *psiom;
  403. if (SUCCEEDED(GetIconOverlayManager(&psiom)))
  404. {
  405. psiom->RefreshOverlayImages(SIOM_OVERLAYINDEX | SIOM_ICONINDEX);
  406. psiom->Release();
  407. }
  408. return TRUE;
  409. }
  410. }
  411. // get a hold of the system image lists
  412. BOOL WINAPI Shell_GetImageLists(HIMAGELIST *phiml, HIMAGELIST *phimlSmall)
  413. {
  414. if (!_IsSHILInited())
  415. {
  416. FileIconInit(FALSE); // make sure they are created and the right size.
  417. if (!_IsSHILInited())
  418. return FALSE;
  419. }
  420. if (phiml)
  421. *phiml = g_rgshil[SHIL_LARGE].himl;
  422. if (phimlSmall)
  423. *phimlSmall = g_rgshil[SHIL_SMALL].himl;
  424. return TRUE;
  425. }
  426. HRESULT SHGetImageList(int iImageList, REFIID riid, void **ppvObj)
  427. {
  428. HRESULT hr = E_OUTOFMEMORY;
  429. if (!_IsSHILInited())
  430. {
  431. FileIconInit(FALSE); // make sure they are created and the right size.
  432. if (!_IsSHILInited())
  433. return hr;
  434. }
  435. ENTERCRITICAL;
  436. if (iImageList >=0 && iImageList < ARRAYSIZE(g_rgshil))
  437. {
  438. hr = HIMAGELIST_QueryInterface(g_rgshil[iImageList].himl, riid, ppvObj);
  439. }
  440. else
  441. {
  442. hr = E_INVALIDARG;
  443. }
  444. LEAVECRITICAL;
  445. return hr;
  446. }
  447. void WINAPI Shell_SysColorChange(void)
  448. {
  449. COLORREF clrWindow = GetSysColor(COLOR_WINDOW);
  450. ENTERCRITICAL;
  451. for (int i = 0; i < ARRAYSIZE(g_rgshil); i++)
  452. {
  453. ImageList_SetBkColor(g_rgshil[i].himl, clrWindow);
  454. }
  455. LEAVECRITICAL;
  456. }
  457. // simulate the document icon by crunching a copy of an icon and putting it in the
  458. // middle of our default document icon, then add it to the passsed image list
  459. //
  460. // in:
  461. // hIcon icon to use as a basis for the simulation
  462. //
  463. // returns:
  464. // hicon
  465. HBITMAP CreateDIB(HDC h, WORD depth, int cx, int cy, RGBQUAD** pprgb)
  466. {
  467. BITMAPINFO bi = {0};
  468. bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
  469. bi.bmiHeader.biWidth = cx;
  470. bi.bmiHeader.biHeight = cy;
  471. bi.bmiHeader.biPlanes = 1;
  472. bi.bmiHeader.biBitCount = depth;
  473. bi.bmiHeader.biCompression = BI_RGB;
  474. return CreateDIBSection(h, &bi, DIB_RGB_COLORS, (void**)pprgb, NULL, 0);
  475. }
  476. BOOL HasAlpha(RGBQUAD* prgb, int cx, int cy)
  477. {
  478. int iTotal = cx * cy;
  479. for (int i = 0; i < iTotal; i++)
  480. {
  481. if (prgb[i].rgbReserved != 0)
  482. return TRUE;
  483. }
  484. return FALSE;
  485. }
  486. void DorkAlpha(RGBQUAD* prgb, int x, int y, int cx, int cy, int cxTotal)
  487. {
  488. for (int dy = y; dy < (cy + y); dy++)
  489. {
  490. for (int dx = x; dx < (cx + x); dx++)
  491. {
  492. prgb[dx + dy * cxTotal].rgbReserved = 255;
  493. }
  494. }
  495. }
  496. HICON SimulateDocIcon(HIMAGELIST himl, HICON hIcon, int cx, int cy)
  497. {
  498. if (himl == NULL || hIcon == NULL)
  499. return NULL;
  500. HDC hdc = GetDC(NULL);
  501. if (hdc)
  502. {
  503. RGBQUAD* prgb;
  504. // If the display is in 24 or 32bpp mode, we may have alpha icons, so we'll need to create a dib section
  505. BOOL fAlphaIcon = (GetDeviceCaps(hdc, BITSPIXEL) >= 24)? TRUE: FALSE;
  506. HBITMAP hbmColor;
  507. if (fAlphaIcon)
  508. {
  509. hbmColor = CreateDIB(hdc, 32, cx, cy, &prgb);
  510. }
  511. else
  512. {
  513. hbmColor = CreateCompatibleBitmap(hdc, cx, cy);
  514. }
  515. if (hbmColor)
  516. {
  517. HBITMAP hbmMask = CreateBitmap(cx, cy, 1, 1, NULL);
  518. if (hbmMask)
  519. {
  520. HDC hdcMem = CreateCompatibleDC(hdc);
  521. if (hdcMem)
  522. {
  523. HBITMAP hbmT = (HBITMAP)SelectObject(hdcMem, hbmMask);
  524. UINT iIndex = Shell_GetCachedImageIndex(c_szShell32Dll, II_DOCNOASSOC, 0);
  525. ImageList_Draw(himl, iIndex, hdcMem, 0, 0, ILD_MASK);
  526. SelectObject(hdcMem, hbmColor);
  527. ImageList_DrawEx(himl, iIndex, hdcMem, 0, 0, 0, 0, RGB(0,0,0), CLR_DEFAULT, ILD_NORMAL);
  528. // Check to see if the parent has alpha. If so, we'll have to dork with the child's alpha later on.
  529. BOOL fParentHasAlpha = fAlphaIcon?HasAlpha(prgb, cx, cy):FALSE;
  530. HDC hdcMemChild = CreateCompatibleDC(hdcMem);
  531. if (hdcMemChild)
  532. {
  533. // Notes:
  534. // First: create a 24bpp Dibsection. We want to merge the alpha channel into the final image,
  535. // not preserve it.
  536. // Second: The document icon has "Goo" in it. We remove this goo by blitting white into it, then
  537. // merging the child bitmap
  538. HBITMAP hbmp = CreateDIB(hdc, 24, cx/2 + 2, cy/2 + 2, NULL);
  539. if (hbmp)
  540. {
  541. HBITMAP hbmpOld = (HBITMAP)SelectObject(hdcMemChild, hbmp);
  542. RECT rc;
  543. rc.left = 0;
  544. rc.top = 0;
  545. rc.right = cx/2 + 3; // Extra space to remove goo in the document icon
  546. rc.bottom = cy/2 + 3;
  547. // Fill with white. NOTE: don't use PatBlt because it actually adds an alpha channel!
  548. SHFillRectClr(hdcMemChild, &rc, RGB(255,255,255));
  549. DrawIconEx(hdcMemChild, 1, 1, hIcon, cx/2, cy/2, 0, NULL, DI_NORMAL);
  550. BitBlt(hdcMem, cx/4-1, cy/4-1, cx/2+3, cy/2+3, hdcMemChild, 0, 0, SRCCOPY);
  551. SelectObject(hdcMemChild, hbmpOld);
  552. DeleteObject(hbmp);
  553. }
  554. DeleteDC(hdcMemChild);
  555. }
  556. if (fParentHasAlpha)
  557. {
  558. // If the parent had alpha, we need to bring the child alpha to opaqe
  559. DorkAlpha(prgb, cx/4, cy/4, cx/2, cy/2, cx);
  560. }
  561. SelectBitmap(hdcMem, hbmT);
  562. DeleteDC(hdcMem);
  563. }
  564. ICONINFO ii = {0};
  565. ii.fIcon = TRUE;
  566. ii.hbmColor = hbmColor;
  567. ii.hbmMask = hbmMask;
  568. hIcon = CreateIconIndirect(&ii);
  569. DeleteObject(hbmMask);
  570. }
  571. DeleteObject(hbmColor);
  572. }
  573. ReleaseDC(NULL, hdc);
  574. }
  575. return hIcon;
  576. }
  577. // Check if the same number of images is present in all of the image lists.
  578. // If any of the imagelists have less icons than the others, fill the imagelist
  579. // in with the document icon to make them all consistent.
  580. //
  581. // Eg: WebZip v3.80 and v4.00 queries for the large and small image lists,
  582. // and adds 2 icons to it. However, it doesn't know to add these icons to the
  583. // newer image lists. Hence, the image lists are out of sync, and later on,
  584. // the wrong icon appears in their treeview.
  585. //
  586. // Allaire Homesite 4.5 does the same thing.
  587. void CheckConsistencyOfImageLists(void)
  588. {
  589. // This has to be done under the critical section to avoid race conditions.
  590. // Otherwise, if another thread is adding icons to the image list,
  591. // we will think it is corrupted when in fact it is just fine, and
  592. // then our attempts to repair it will corrupt it!
  593. ASSERTCRITICAL;
  594. int i, iMax = 0, iImageListsCounts[ARRAYSIZE(g_rgshil)];
  595. BOOL bIdentical = TRUE;
  596. // Loop through all the image lists getting:
  597. //
  598. // 1) the image count for each list
  599. // 2) Compare the count against the count of the first (large)
  600. // imagelist to see if there are any differences.
  601. // 3) Determine the max number of images (in a single list) across all the image lists
  602. for (i = 0; i < ARRAYSIZE(g_rgshil); i++)
  603. {
  604. iImageListsCounts[i] = ImageList_GetImageCount (g_rgshil[i].himl);
  605. if (iImageListsCounts[i] != iImageListsCounts[0])
  606. {
  607. bIdentical = FALSE;
  608. }
  609. if (iImageListsCounts[i] > iMax)
  610. {
  611. iMax = iImageListsCounts[i];
  612. }
  613. }
  614. if (bIdentical)
  615. {
  616. return;
  617. }
  618. // For each imagelist, add the document icon as filler to bring it upto iMax in size
  619. for (i = 0; i < ARRAYSIZE(g_rgshil); i++)
  620. {
  621. if (iImageListsCounts[i] < iMax)
  622. {
  623. HICON hIcon = (HICON) LoadImage (HINST_THISDLL, MAKEINTRESOURCE(IDI_DOCUMENT),
  624. IMAGE_ICON, g_rgshil[i].size.cx,
  625. g_rgshil[i].size.cy, LR_DEFAULTCOLOR);
  626. if (hIcon)
  627. {
  628. while (iImageListsCounts[i] < iMax)
  629. {
  630. ImageList_ReplaceIcon (g_rgshil[i].himl, -1, hIcon);
  631. iImageListsCounts[i]++;
  632. }
  633. DestroyIcon (hIcon);
  634. }
  635. }
  636. }
  637. }
  638. // add icons to the system imagelist (icon cache) and put the location
  639. // in the location cache
  640. //
  641. // in:
  642. // hIcon, hIconSmall the icons, hIconSmall can be NULL
  643. // pszIconPath locations (for location cache)
  644. // iIconIndex index in pszIconPath (for location cache)
  645. // uIconFlags GIL_ flags (for location cahce)
  646. // returns:
  647. // location in system image list
  648. //
  649. int SHAddIconsToCache(HICON rghicon[SHIL_COUNT], LPCTSTR pszIconPath, int iIconIndex, UINT uIconFlags)
  650. {
  651. int iImage = -1;
  652. if (!_IsSHILInited())
  653. {
  654. FileIconInit(FALSE); // make sure they are created and the right size.
  655. if (!_IsSHILInited())
  656. return iImage;
  657. }
  658. //
  659. // NOTE: user should call SHLookupIconIndex or RemoveFromIconTable first to make sure
  660. // it isn't already in shell icon cache, or use Shell_GetCachedImageIndex to add icons to
  661. // the cache. Adding the same icon to icon cache several times may cause shell to flash.
  662. //
  663. if (!(uIconFlags & GIL_DONTCACHE))
  664. {
  665. iImage = LookupIconIndex(pszIconPath, iIconIndex, uIconFlags);
  666. if (-1 != iImage)
  667. {
  668. return iImage;
  669. }
  670. }
  671. HICON rghiconT[ARRAYSIZE(g_rgshil)] = {0};
  672. BOOL fFailure = FALSE;
  673. int i;
  674. for (i = 0; i < ARRAYSIZE(g_rgshil); i++)
  675. {
  676. if (rghicon == NULL)
  677. {
  678. SHDefExtractIcon(pszIconPath, iIconIndex, uIconFlags, &rghiconT[i], NULL, g_rgshil[i].size.cx);
  679. }
  680. else
  681. {
  682. if (rghicon[i])
  683. {
  684. rghiconT[i] = rghicon[i];
  685. }
  686. else
  687. {
  688. rghiconT[i] = rghicon[SHIL_LARGE];
  689. }
  690. }
  691. if (rghiconT[i] == NULL)
  692. {
  693. fFailure = TRUE;
  694. break;
  695. }
  696. }
  697. ENTERCRITICAL;
  698. // test again in case there was a race between the test at the top and the
  699. // icon loading code.
  700. if (!(uIconFlags & GIL_DONTCACHE))
  701. {
  702. iImage = LookupIconIndex(pszIconPath, iIconIndex, uIconFlags);
  703. }
  704. if (!fFailure && _IsSHILInited() && (-1 == iImage))
  705. {
  706. // still not in the table so we
  707. CheckConsistencyOfImageLists();
  708. int iImageFree = GetFreeImageIndex();
  709. TraceMsg(TF_IMAGE, "FreeImageIndex = %d", iImageFree);
  710. for (i = 0; i < ARRAYSIZE(g_rgshil); i++)
  711. {
  712. int iImageT = ImageList_ReplaceIcon(g_rgshil[i].himl, iImageFree, rghiconT[i]);
  713. TraceMsg(TF_IMAGE, "ImageList_ReplaceIcon(%d) returned = %d", i, iImageT);
  714. if (iImageT < 0)
  715. {
  716. // failure -- break and undo changes
  717. break;
  718. }
  719. else
  720. {
  721. ASSERT(iImage == -1 || iImage == iImageT);
  722. iImage = iImageT;
  723. }
  724. }
  725. if (i < ARRAYSIZE(g_rgshil))
  726. {
  727. // failure
  728. if (iImageFree == -1)
  729. {
  730. // only remove it if it was added at the end otherwise all the
  731. // index's above iImage will change.
  732. // ImageList_ReplaceIcon should only fail on the end anyway.
  733. for (int j = 0; j < i; j++)
  734. {
  735. ImageList_Remove(g_rgshil[j].himl, iImage);
  736. }
  737. }
  738. iImage = -1;
  739. }
  740. else
  741. {
  742. // success
  743. ASSERT(iImage >= 0);
  744. AddToIconTable(pszIconPath, iIconIndex, uIconFlags, iImage);
  745. }
  746. }
  747. LEAVECRITICAL;
  748. if (rghicon == NULL)
  749. {
  750. // destroy the icons we allocated
  751. _DestroyIcons(rghiconT, ARRAYSIZE(rghiconT));
  752. }
  753. return iImage;
  754. }
  755. //
  756. // default handler to extract a icon from a file
  757. //
  758. // supports GIL_SIMULATEDOC
  759. //
  760. // returns S_OK if success
  761. // returns S_FALSE if the file has no icons (or not the asked for icon)
  762. // returns E_FAIL for files on a slow link.
  763. // returns E_FAIL if cant access the file
  764. //
  765. // LOWORD(nIconSize) = normal icon size
  766. // HIWORD(nIconSize) = smal icon size
  767. //
  768. STDAPI SHDefExtractIcon(LPCTSTR pszIconFile, int iIndex, UINT uFlags,
  769. HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
  770. {
  771. HICON hIcons[2] = {0, 0};
  772. UINT u;
  773. #ifdef DEBUG
  774. TCHAR ach[128];
  775. GetModuleFileName(HINST_THISDLL, ach, ARRAYSIZE(ach));
  776. if (lstrcmpi(pszIconFile, ach) == 0 && iIndex >= 0)
  777. {
  778. TraceMsg(TF_WARNING, "Re-extracting %d from SHELL32.DLL", iIndex);
  779. }
  780. #endif
  781. HIMAGELIST himlLarge, himlSmall;
  782. Shell_GetImageLists(&himlLarge, &himlSmall);
  783. //
  784. // get the icon from the file
  785. //
  786. if (PathIsSlow(pszIconFile, -1))
  787. {
  788. DebugMsg(DM_TRACE, TEXT("not extracting icon from '%s' because of slow link"), pszIconFile);
  789. return E_FAIL;
  790. }
  791. #ifdef XXDEBUG
  792. TraceMsg(TF_ALWAYS, "Extracting icon %d from %s.", iIndex, pszIconFile);
  793. Sleep(500);
  794. #endif
  795. //
  796. // nIconSize == 0 means use the default size.
  797. // Backup is passing nIconSize == 1 need to support them too.
  798. //
  799. if (nIconSize <= 2)
  800. nIconSize = MAKELONG(g_cxIcon, g_cxSmIcon);
  801. if (uFlags & GIL_SIMULATEDOC)
  802. {
  803. HICON hIconSmall;
  804. u = ExtractIcons(pszIconFile, iIndex, g_cxSmIcon, g_cySmIcon,
  805. &hIconSmall, NULL, 1, g_lrFlags);
  806. if (u == -1)
  807. return E_FAIL;
  808. hIcons[0] = SimulateDocIcon(himlLarge, hIconSmall, g_cxIcon, g_cyIcon);
  809. hIcons[1] = SimulateDocIcon(himlSmall, hIconSmall, g_cxSmIcon, g_cySmIcon);
  810. if (hIconSmall)
  811. DestroyIcon(hIconSmall);
  812. }
  813. else
  814. {
  815. u = ExtractIcons(pszIconFile, iIndex, nIconSize, nIconSize,
  816. hIcons, NULL, 2, g_lrFlags);
  817. if (-1 == u)
  818. return E_FAIL;
  819. #ifdef DEBUG
  820. if (0 == u)
  821. {
  822. TraceMsg(TF_WARNING, "Failed to extract icon %d from %s.", iIndex, pszIconFile);
  823. }
  824. #endif
  825. }
  826. if (phiconLarge)
  827. *phiconLarge = hIcons[0];
  828. else if (hIcons[0])
  829. DestroyIcon(hIcons[0]);
  830. if (phiconSmall)
  831. *phiconSmall = hIcons[1];
  832. else if (hIcons[1])
  833. DestroyIcon(hIcons[1]);
  834. return u == 0 ? S_FALSE : S_OK;
  835. }
  836. #ifdef UNICODE
  837. STDAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
  838. {
  839. HRESULT hr = E_INVALIDARG;
  840. if (IS_VALID_STRING_PTRA(pszIconFile, -1))
  841. {
  842. WCHAR wsz[MAX_PATH];
  843. SHAnsiToUnicode(pszIconFile, wsz, ARRAYSIZE(wsz));
  844. hr = SHDefExtractIcon(wsz, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
  845. }
  846. return hr;
  847. }
  848. #else
  849. STDAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, HICON *phiconLarge, HICON *phiconSmall, UINT nIconSize)
  850. {
  851. HRESULT hr = E_INVALIDARG;
  852. if (IS_VALID_STRING_PTRW(pszIconFile, -1))
  853. {
  854. char sz[MAX_PATH];
  855. SHUnicodeToAnsi(pszIconFile, sz, ARRAYSIZE(sz));
  856. hr = SHDefExtractIcon(sz, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
  857. }
  858. return hr;
  859. }
  860. #endif
  861. //
  862. // in:
  863. // pszIconPath file to get icon from (eg. cabinet.exe)
  864. // iIconIndex icon index in pszIconPath to get
  865. // uIconFlags GIL_ values indicating simulate doc icon, etc.
  866. int WINAPI Shell_GetCachedImageIndex(LPCTSTR pszIconPath, int iIconIndex, UINT uIconFlags)
  867. {
  868. // lots of random codepaths from APIs end up here before init
  869. if (!_IsSHILInited())
  870. {
  871. FileIconInit(FALSE);
  872. if (!_IsSHILInited())
  873. {
  874. return -1;
  875. }
  876. }
  877. int iImageIndex = LookupIconIndex(pszIconPath, iIconIndex, uIconFlags);
  878. if (iImageIndex == -1)
  879. {
  880. iImageIndex = SHAddIconsToCache(NULL, pszIconPath, iIconIndex, uIconFlags);
  881. }
  882. return iImageIndex;
  883. }
  884. STDAPI_(void) FixPlusIcons()
  885. {
  886. // nuke all of the shell internal icons
  887. HKEY hkeyIcons = SHGetShellKey(SHELLKEY_HKLM_EXPLORER, TEXT("Shell Icons"), FALSE);
  888. if (hkeyIcons)
  889. {
  890. for (int i = 0; i < ARRAYSIZE(c_SystemImageListIndexes); i++)
  891. {
  892. TCHAR szRegPath[10], szBuf[MAX_PATH];
  893. DWORD cb = sizeof(szBuf);
  894. wsprintf(szRegPath, TEXT("%d"), i);
  895. if (SHQueryValueEx(hkeyIcons, szRegPath, NULL, NULL, (LPBYTE)szBuf, &cb) == ERROR_SUCCESS &&
  896. StrStrI(szBuf, TEXT("cool.dll")))
  897. {
  898. RegDeleteValue(hkeyIcons, szRegPath);
  899. }
  900. }
  901. RegCloseKey(hkeyIcons);
  902. }
  903. static const struct
  904. {
  905. const CLSID* pclsid;
  906. LPCTSTR pszIcon;
  907. }
  908. c_rgCLSID[] =
  909. {
  910. { &CLSID_NetworkPlaces, TEXT("shell32.dll,17") },
  911. { &CLSID_ControlPanel, TEXT("shell32.dll,-137") },
  912. { &CLSID_Printers, TEXT("shell32.dll,-138") },
  913. { &CLSID_MyComputer, TEXT("explorer.exe,0") },
  914. { &CLSID_Remote, TEXT("rnaui.dll,0") },
  915. { &CLSID_CFonts, TEXT("fontext.dll,-101") },
  916. { &CLSID_RecycleBin, NULL },
  917. { &CLSID_Briefcase, NULL },
  918. };
  919. for (int i = 0; i < ARRAYSIZE(c_rgCLSID); i++)
  920. {
  921. TCHAR szCLSID[64], szRegPath[128], szBuf[MAX_PATH];
  922. LONG cb = sizeof(szBuf);
  923. SHStringFromGUID(*c_rgCLSID[i].pclsid, szCLSID, ARRAYSIZE(szCLSID));
  924. wsprintf(szRegPath, TEXT("CLSID\\%s\\DefaultIcon"), szCLSID);
  925. if (SHRegQueryValue(HKEY_CLASSES_ROOT, szRegPath, szBuf, &cb) == ERROR_SUCCESS &&
  926. StrStrI(szBuf, TEXT("cool.dll")))
  927. {
  928. if (IsEqualGUID(*c_rgCLSID[i].pclsid, CLSID_RecycleBin))
  929. {
  930. RegSetValueString(HKEY_CLASSES_ROOT, szRegPath, TEXT("Empty"), TEXT("shell32.dll,31"));
  931. RegSetValueString(HKEY_CLASSES_ROOT, szRegPath, TEXT("Full"), TEXT("shell32.dll,32"));
  932. if (StrStr(szBuf, TEXT("20")))
  933. RegSetString(HKEY_CLASSES_ROOT, szRegPath, TEXT("shell32.dll,31")); // empty
  934. else
  935. RegSetString(HKEY_CLASSES_ROOT, szRegPath, TEXT("shell32.dll,32")); // full
  936. }
  937. else
  938. {
  939. if (c_rgCLSID[i].pszIcon)
  940. RegSetString(HKEY_CLASSES_ROOT, szRegPath, c_rgCLSID[i].pszIcon);
  941. else
  942. RegDeleteValue(HKEY_CLASSES_ROOT, szRegPath);
  943. }
  944. }
  945. }
  946. static const struct
  947. {
  948. LPCTSTR pszProgID;
  949. LPCTSTR pszIcon;
  950. }
  951. c_rgProgID[] =
  952. {
  953. { TEXT("Folder"), TEXT("shell32.dll,3") },
  954. { TEXT("Directory"),TEXT("shell32.dll,3") },
  955. { TEXT("Drive"), TEXT("shell32.dll,8") },
  956. { TEXT("drvfile"), TEXT("shell32.dll,-154") },
  957. { TEXT("vxdfile"), TEXT("shell32.dll,-154") },
  958. { TEXT("dllfile"), TEXT("shell32.dll,-154") },
  959. { TEXT("sysfile"), TEXT("shell32.dll,-154") },
  960. { TEXT("txtfile"), TEXT("shell32.dll,-152") },
  961. { TEXT("inifile"), TEXT("shell32.dll,-151") },
  962. { TEXT("inffile"), TEXT("shell32.dll,-151") },
  963. };
  964. for (i = 0; i < ARRAYSIZE(c_rgProgID); i++)
  965. {
  966. TCHAR szRegPath[128], szBuf[MAX_PATH];
  967. LONG cb = sizeof(szBuf);
  968. wsprintf(szRegPath, TEXT("%s\\DefaultIcon"), c_rgProgID[i].pszProgID);
  969. if (SHRegQueryValue(HKEY_CLASSES_ROOT, szRegPath, szBuf, &cb) == ERROR_SUCCESS &&
  970. StrStrI(szBuf, TEXT("cool.dll")))
  971. {
  972. RegSetString(HKEY_CLASSES_ROOT, szRegPath, c_rgProgID[i].pszIcon);
  973. }
  974. }
  975. FlushIconCache();
  976. }