Reactos
at master 1083 lines 36 kB view raw
1/* 2 * PROJECT: ReactOS shell32 3 * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) 4 * PURPOSE: Shell Icon Cache (SIC) 5 * COPYRIGHT: Copyright 1998, 1999 Juergen Schmied 6 * Copyright 2025 Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 7 */ 8 9#include "precomp.h" 10 11WINE_DEFAULT_DEBUG_CHANNEL(shell); 12 13/********************** THE ICON CACHE ********************************/ 14 15#define INVALID_INDEX -1 16 17typedef struct 18{ 19 LPWSTR sSourceFile; /* file (not path!) containing the icon */ 20 DWORD dwSourceIndex; /* index within the file, if it is a resoure ID it will be negated */ 21 DWORD dwListIndex; /* index within the iconlist */ 22 DWORD dwFlags; /* GIL_* flags */ 23 DWORD dwAccessTime; 24} SIC_ENTRY, * LPSIC_ENTRY; 25 26static HDPA sic_hdpa = 0; 27 28static HIMAGELIST ShellSmallIconList; 29static HIMAGELIST ShellBigIconList; 30INT ShellSmallIconSize = 0; 31INT ShellLargeIconSize = 0; 32INT ShellIconBPP = 0; // Bits Per Pixel 33 34namespace 35{ 36extern CRITICAL_SECTION SHELL32_SicCS; 37CRITICAL_SECTION_DEBUG critsect_debug = 38{ 39 0, 0, &SHELL32_SicCS, 40 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 41 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_SicCS") } 42}; 43CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 }; 44} 45 46// Load metric value from registry 47static INT 48SIC_GetMetricsValue( 49 _In_ PCWSTR pszValueName, 50 _In_ INT nDefaultValue) 51{ 52 WCHAR szValue[64]; 53 DWORD cbValue = sizeof(szValue); 54 DWORD error = SHGetValueW(HKEY_CURRENT_USER, L"Control Panel\\Desktop\\WindowMetrics", 55 pszValueName, NULL, szValue, &cbValue); 56 if (error) 57 return nDefaultValue; 58 szValue[_countof(szValue) - 1] = UNICODE_NULL; // Avoid buffer overrun 59 return _wtoi(szValue); 60} 61 62static INT 63SIC_GetLargeIconSize(VOID) 64{ 65 // NOTE: Shell icon size is always square 66 INT nDefaultSize = GetSystemMetrics(SM_CXICON); 67 INT nIconSize = SIC_GetMetricsValue(L"Shell Icon Size", nDefaultSize); 68 return (nIconSize > 0) ? nIconSize : nDefaultSize; 69} 70 71static INT 72SIC_GetSmallIconSize(VOID) 73{ 74 // NOTE: Shell icon size is always square 75 INT nDefaultSize = GetSystemMetrics(SM_CXSMICON); 76 INT nIconSize = SIC_GetMetricsValue(L"Shell Small Icon Size", nDefaultSize); 77 return (nIconSize > 0) ? nIconSize : nDefaultSize; 78} 79 80static INT 81SIC_GetIconBPP(VOID) // Bits Per Pixel 82{ 83 INT nDefaultBPP = SHGetCurColorRes(); 84 INT nIconBPP = SIC_GetMetricsValue(L"Shell Icon BPP", nDefaultBPP); 85 return (nIconBPP > 0) ? nIconBPP : nDefaultBPP; 86} 87 88/***************************************************************************** 89 * SIC_CompareEntries 90 * 91 * NOTES 92 * Callback for DPA_Search 93 */ 94static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam) 95{ LPSIC_ENTRY e1 = (LPSIC_ENTRY)p1, e2 = (LPSIC_ENTRY)p2; 96 97 TRACE("%p %p %8lx\n", p1, p2, lparam); 98 99 /* Icons in the cache are keyed by the name of the file they are 100 * loaded from, their resource index and the fact if they have a shortcut 101 * icon overlay or not. 102 */ 103 /* first the faster one */ 104 if (e1->dwSourceIndex != e2->dwSourceIndex) 105 return (e1->dwSourceIndex < e2->dwSourceIndex) ? -1 : 1; 106 107 if ((e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT)) 108 return ((e1->dwFlags & GIL_FORSHORTCUT) < (e2->dwFlags & GIL_FORSHORTCUT)) ? -1 : 1; 109 110 return _wcsicmp(e1->sSourceFile,e2->sSourceFile); 111} 112 113/* declare SIC_LoadOverlayIcon() */ 114static int SIC_LoadOverlayIcon(int icon_idx); 115 116/***************************************************************************** 117 * SIC_OverlayShortcutImage [internal] 118 * 119 * NOTES 120 * Creates a new icon as a copy of the passed-in icon, overlayed with a 121 * shortcut image. 122 * FIXME: This should go to the ImageList implementation! 123 */ 124static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large) 125{ 126 ICONINFO ShortcutIconInfo, TargetIconInfo; 127 HICON ShortcutIcon = NULL, TargetIcon; 128 BITMAP TargetBitmapInfo, ShortcutBitmapInfo; 129 HDC ShortcutDC = NULL, 130 TargetDC = NULL; 131 HBITMAP OldShortcutBitmap = NULL, 132 OldTargetBitmap = NULL; 133 134 static int s_imgListIdx = -1; 135 ZeroMemory(&ShortcutIconInfo, sizeof(ShortcutIconInfo)); 136 ZeroMemory(&TargetIconInfo, sizeof(TargetIconInfo)); 137 138 /* Get information about the source icon and shortcut overlay. 139 * We will write over the source bitmaps to get the final ones */ 140 if (! GetIconInfo(SourceIcon, &TargetIconInfo)) 141 return NULL; 142 143 /* Is it possible with the ImageList implementation? */ 144 if(!TargetIconInfo.hbmColor) 145 { 146 /* Maybe we'll support this at some point */ 147 FIXME("1bpp icon wants its overlay!\n"); 148 goto fail; 149 } 150 151 if(!GetObjectW(TargetIconInfo.hbmColor, sizeof(BITMAP), &TargetBitmapInfo)) 152 { 153 goto fail; 154 } 155 156 /* search for the shortcut icon only once */ 157 if (s_imgListIdx == -1) 158 s_imgListIdx = SIC_LoadOverlayIcon(IDI_SHELL_SHORTCUT - 1); 159 160 if (s_imgListIdx != -1) 161 { 162 if (large) 163 ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT); 164 else 165 ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT); 166 } else 167 ShortcutIcon = NULL; 168 169 if (!ShortcutIcon || !GetIconInfo(ShortcutIcon, &ShortcutIconInfo)) 170 { 171 goto fail; 172 } 173 174 /* Is it possible with the ImageLists ? */ 175 if(!ShortcutIconInfo.hbmColor) 176 { 177 /* Maybe we'll support this at some point */ 178 FIXME("Should draw 1bpp overlay!\n"); 179 goto fail; 180 } 181 182 if(!GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo)) 183 { 184 goto fail; 185 } 186 187 /* Setup the masks */ 188 ShortcutDC = CreateCompatibleDC(NULL); 189 if (NULL == ShortcutDC) goto fail; 190 OldShortcutBitmap = (HBITMAP)SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask); 191 if (NULL == OldShortcutBitmap) goto fail; 192 193 TargetDC = CreateCompatibleDC(NULL); 194 if (NULL == TargetDC) goto fail; 195 OldTargetBitmap = (HBITMAP)SelectObject(TargetDC, TargetIconInfo.hbmMask); 196 if (NULL == OldTargetBitmap) goto fail; 197 198 /* Create the complete mask by ANDing the source and shortcut masks. 199 * NOTE: in an ImageList, all icons have the same dimensions */ 200 if (!BitBlt(TargetDC, 0, 0, ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight, 201 ShortcutDC, 0, 0, SRCAND)) 202 { 203 goto fail; 204 } 205 206 /* 207 * We must remove or add the alpha component to the shortcut overlay: 208 * If we don't, SRCCOPY will copy it to our resulting icon, resulting in a 209 * partially transparent icons where it shouldn't be, and to an invisible icon 210 * if the underlying icon don't have any alpha channel information. (16bpp only icon for instance). 211 * But if the underlying icon has alpha channel information, then we must mark the overlay information 212 * as opaque. 213 * NOTE: This code sucks(tm) and should belong to the ImageList implementation. 214 * NOTE2: there are better ways to do this. 215 */ 216 if(ShortcutBitmapInfo.bmBitsPixel == 32) 217 { 218 BOOL add_alpha; 219 BYTE buffer[sizeof(BITMAPINFO) + 256 * sizeof(RGBQUAD)]; 220 BITMAPINFO* lpbmi = (BITMAPINFO*)buffer; 221 PVOID bits; 222 PULONG pixel; 223 INT i, j; 224 225 /* Find if the source bitmap has an alpha channel */ 226 if(TargetBitmapInfo.bmBitsPixel != 32) add_alpha = FALSE; 227 else 228 { 229 ZeroMemory(buffer, sizeof(buffer)); 230 lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 231 lpbmi->bmiHeader.biWidth = TargetBitmapInfo.bmWidth; 232 lpbmi->bmiHeader.biHeight = TargetBitmapInfo.bmHeight; 233 lpbmi->bmiHeader.biPlanes = 1; 234 lpbmi->bmiHeader.biBitCount = 32; 235 236 bits = HeapAlloc(GetProcessHeap(), 0, TargetBitmapInfo.bmHeight * TargetBitmapInfo.bmWidthBytes); 237 238 if(!bits) goto fail; 239 240 if(!GetDIBits(TargetDC, TargetIconInfo.hbmColor, 0, TargetBitmapInfo.bmHeight, bits, lpbmi, DIB_RGB_COLORS)) 241 { 242 ERR("GetBIBits failed!\n"); 243 HeapFree(GetProcessHeap(), 0, bits); 244 goto fail; 245 } 246 247 i = j = 0; 248 pixel = (PULONG)bits; 249 250 for(i=0; i<TargetBitmapInfo.bmHeight; i++) 251 { 252 for(j=0; j<TargetBitmapInfo.bmWidth; j++) 253 { 254 add_alpha = (*pixel++ & 0xFF000000) != 0; 255 if(add_alpha) break; 256 } 257 if(add_alpha) break; 258 } 259 HeapFree(GetProcessHeap(), 0, bits); 260 } 261 262 /* Allocate the bits */ 263 bits = HeapAlloc(GetProcessHeap(), 0, ShortcutBitmapInfo.bmHeight*ShortcutBitmapInfo.bmWidthBytes); 264 if(!bits) goto fail; 265 266 ZeroMemory(buffer, sizeof(buffer)); 267 lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 268 lpbmi->bmiHeader.biWidth = ShortcutBitmapInfo.bmWidth; 269 lpbmi->bmiHeader.biHeight = ShortcutBitmapInfo.bmHeight; 270 lpbmi->bmiHeader.biPlanes = 1; 271 lpbmi->bmiHeader.biBitCount = 32; 272 273 if(!GetDIBits(TargetDC, ShortcutIconInfo.hbmColor, 0, ShortcutBitmapInfo.bmHeight, bits, lpbmi, DIB_RGB_COLORS)) 274 { 275 ERR("GetBIBits failed!\n"); 276 HeapFree(GetProcessHeap(), 0, bits); 277 goto fail; 278 } 279 280 pixel = (PULONG)bits; 281 /* Remove alpha channel component or make it totally opaque */ 282 for(i=0; i<ShortcutBitmapInfo.bmHeight; i++) 283 { 284 for(j=0; j<ShortcutBitmapInfo.bmWidth; j++) 285 { 286 if(add_alpha) *pixel++ |= 0xFF000000; 287 else *pixel++ &= 0x00FFFFFF; 288 } 289 } 290 291 /* GetDIBits return BI_BITFIELDS with masks set to 0, and SetDIBits fails when masks are 0. The irony... */ 292 lpbmi->bmiHeader.biCompression = BI_RGB; 293 294 /* Set the bits again */ 295 if(!SetDIBits(TargetDC, ShortcutIconInfo.hbmColor, 0, ShortcutBitmapInfo.bmHeight, bits, lpbmi, DIB_RGB_COLORS)) 296 { 297 ERR("SetBIBits failed!, %lu\n", GetLastError()); 298 HeapFree(GetProcessHeap(), 0, bits); 299 goto fail; 300 } 301 HeapFree(GetProcessHeap(), 0, bits); 302 } 303 304 /* Now do the copy. We overwrite the original icon data */ 305 if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor) || 306 NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor)) 307 goto fail; 308 if (!MaskBlt(TargetDC, 0, 0, ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight, 309 ShortcutDC, 0, 0, ShortcutIconInfo.hbmMask, 0, 0, 310 MAKEROP4(0xAA0000, SRCCOPY))) 311 { 312 goto fail; 313 } 314 315 /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set 316 handles to NULL */ 317 SelectObject(TargetDC, OldTargetBitmap); 318 DeleteDC(TargetDC); 319 SelectObject(ShortcutDC, OldShortcutBitmap); 320 DeleteDC(ShortcutDC); 321 322 /* Create the icon using the bitmaps prepared earlier */ 323 TargetIcon = CreateIconIndirect(&TargetIconInfo); 324 325 /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */ 326 DeleteObject(TargetIconInfo.hbmColor); 327 DeleteObject(TargetIconInfo.hbmMask); 328 /* Delete what GetIconInfo gave us */ 329 DeleteObject(ShortcutIconInfo.hbmColor); 330 DeleteObject(ShortcutIconInfo.hbmMask); 331 DestroyIcon(ShortcutIcon); 332 333 return TargetIcon; 334 335fail: 336 /* Clean up scratch resources we created */ 337 if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap); 338 if (NULL != TargetDC) DeleteDC(TargetDC); 339 if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap); 340 if (NULL != ShortcutDC) DeleteDC(ShortcutDC); 341 if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor); 342 if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask); 343 if (NULL != ShortcutIconInfo.hbmColor) DeleteObject(ShortcutIconInfo.hbmColor); 344 if (NULL != ShortcutIconInfo.hbmMask) DeleteObject(ShortcutIconInfo.hbmMask); 345 if (NULL != ShortcutIcon) DestroyIcon(ShortcutIcon); 346 347 return NULL; 348} 349 350/***************************************************************************** 351 * SIC_IconAppend [internal] 352 * 353 * NOTES 354 * appends an icon pair to the end of the cache 355 */ 356static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon, DWORD dwFlags) 357{ 358 LPSIC_ENTRY lpsice; 359 INT ret, index, index1, indexDPA; 360 WCHAR path[MAX_PATH]; 361 TRACE("%s %i %p %p\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon ,hBigIcon); 362 363 lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY)); 364 365 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL); 366 lpsice->sSourceFile = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, (wcslen(path)+1)*sizeof(WCHAR) ); 367 wcscpy( lpsice->sSourceFile, path ); 368 369 lpsice->dwSourceIndex = dwSourceIndex; 370 lpsice->dwFlags = dwFlags; 371 372 EnterCriticalSection(&SHELL32_SicCS); 373 374 indexDPA = DPA_Search (sic_hdpa, lpsice, 0, SIC_CompareEntries, 0, DPAS_SORTED|DPAS_INSERTAFTER); 375 indexDPA = DPA_InsertPtr(sic_hdpa, indexDPA, lpsice); 376 if ( -1 == indexDPA ) 377 { 378 ret = INVALID_INDEX; 379 goto leave; 380 } 381 382 index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon); 383 index1= ImageList_AddIcon (ShellBigIconList, hBigIcon); 384 385 /* Something went wrong when allocating a new image in the list. Abort. */ 386 if((index == -1) || (index1 == -1)) 387 { 388 WARN("Something went wrong when adding the icon to the list: small - 0x%x, big - 0x%x.\n", 389 index, index1); 390 if(index != -1) ImageList_Remove(ShellSmallIconList, index); 391 if(index1 != -1) ImageList_Remove(ShellBigIconList, index1); 392 ret = INVALID_INDEX; 393 goto leave; 394 } 395 396 if (index!=index1) 397 { 398 FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1); 399 /* What to do ???? */ 400 } 401 lpsice->dwListIndex = index; 402 ret = lpsice->dwListIndex; 403 404leave: 405 if(ret == INVALID_INDEX) 406 { 407 if(indexDPA != -1) DPA_DeletePtr(sic_hdpa, indexDPA); 408 HeapFree(GetProcessHeap(), 0, lpsice->sSourceFile); 409 SHFree(lpsice); 410 } 411 LeaveCriticalSection(&SHELL32_SicCS); 412 return ret; 413} 414/**************************************************************************** 415 * SIC_LoadIcon [internal] 416 * 417 * NOTES 418 * gets small/big icon by number from a file 419 */ 420static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags) 421{ 422 HICON hiconLarge = NULL, hiconSmall = NULL; 423 UINT ret; 424 425 PrivateExtractIconsW(sSourceFile, dwSourceIndex, ShellLargeIconSize, ShellLargeIconSize, 426 &hiconLarge, NULL, 1, LR_COPYFROMRESOURCE); 427 PrivateExtractIconsW(sSourceFile, dwSourceIndex, ShellSmallIconSize, ShellSmallIconSize, 428 &hiconSmall, NULL, 1, LR_COPYFROMRESOURCE); 429 430 if (!hiconLarge || !hiconSmall) 431 { 432 WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall); 433 if(hiconLarge) DestroyIcon(hiconLarge); 434 if(hiconSmall) DestroyIcon(hiconSmall); 435 return INVALID_INDEX; 436 } 437 438 if (0 != (dwFlags & GIL_FORSHORTCUT)) 439 { 440 HICON hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE); 441 HICON hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE); 442 if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut) 443 { 444 DestroyIcon(hiconLarge); 445 DestroyIcon(hiconSmall); 446 hiconLarge = hiconLargeShortcut; 447 hiconSmall = hiconSmallShortcut; 448 } 449 else 450 { 451 WARN("Failed to create shortcut overlayed icons\n"); 452 if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut); 453 if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut); 454 dwFlags &= ~ GIL_FORSHORTCUT; 455 } 456 } 457 458 ret = SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags); 459 DestroyIcon(hiconLarge); 460 DestroyIcon(hiconSmall); 461 return ret; 462} 463/***************************************************************************** 464 * SIC_GetIconIndex [internal] 465 * 466 * Parameters 467 * sSourceFile [IN] filename of file containing the icon 468 * index [IN] index/resID (negated) in this file 469 * 470 * NOTES 471 * look in the cache for a proper icon. if not available the icon is taken 472 * from the file and cached 473 */ 474INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags ) 475{ 476 SIC_ENTRY sice; 477 INT ret, index = INVALID_INDEX; 478 WCHAR path[MAX_PATH]; 479 480 TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex); 481 482 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL); 483 sice.sSourceFile = path; 484 sice.dwSourceIndex = dwSourceIndex; 485 sice.dwFlags = dwFlags; 486 487 if (!sic_hdpa) 488 SIC_Initialize(); 489 490 EnterCriticalSection(&SHELL32_SicCS); 491 492 if (NULL != DPA_GetPtr (sic_hdpa, 0)) 493 { 494 /* search linear from position 0*/ 495 index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, DPAS_SORTED); 496 } 497 498 if ( INVALID_INDEX == index ) 499 { 500 ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags); 501 } 502 else 503 { 504 TRACE("-- found\n"); 505 ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex; 506 } 507 508 LeaveCriticalSection(&SHELL32_SicCS); 509 return ret; 510} 511 512/***************************************************************************** 513 * SIC_Initialize [internal] 514 */ 515BOOL SIC_Initialize(void) 516{ 517 HICON hSm = NULL, hLg = NULL; 518 INT bpp; 519 DWORD ilMask; 520 BOOL result = FALSE; 521 522 TRACE("Entered SIC_Initialize\n"); 523 524 if (sic_hdpa) 525 { 526 TRACE("Icon cache already initialized\n"); 527 return TRUE; 528 } 529 530 sic_hdpa = DPA_Create(16); 531 if (!sic_hdpa) 532 { 533 return FALSE; 534 } 535 536 ShellSmallIconSize = SIC_GetSmallIconSize(); 537 ShellLargeIconSize = SIC_GetLargeIconSize(); 538 539 bpp = ShellIconBPP = SIC_GetIconBPP(); // Bits Per Pixel 540 if (bpp <= 4) 541 ilMask = ILC_COLOR4; 542 else if (bpp <= 8) 543 ilMask = ILC_COLOR8; 544 else if (bpp <= 16) 545 ilMask = ILC_COLOR16; 546 else if (bpp <= 24) 547 ilMask = ILC_COLOR24; 548 else if (bpp <= 32) 549 ilMask = ILC_COLOR32; 550 else 551 ilMask = ILC_COLOR; 552 553 ilMask |= ILC_MASK; 554 555 ShellSmallIconList = ImageList_Create(ShellSmallIconSize, ShellSmallIconSize, ilMask, 100, 100); 556 if (!ShellSmallIconList) 557 { 558 ERR("Failed to create the small icon list.\n"); 559 goto end; 560 } 561 562 ShellBigIconList = ImageList_Create(ShellLargeIconSize, ShellLargeIconSize, ilMask, 100, 100); 563 if (!ShellBigIconList) 564 { 565 ERR("Failed to create the big icon list.\n"); 566 goto end; 567 } 568 569 /* Load the document icon, which is used as the default if an icon isn't found. */ 570 hSm = (HICON)LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT), 571 IMAGE_ICON, ShellSmallIconSize, ShellSmallIconSize, 572 LR_SHARED | LR_DEFAULTCOLOR); 573 if (!hSm) 574 { 575 ERR("Failed to load small IDI_SHELL_DOCUMENT icon!\n"); 576 goto end; 577 } 578 579 hLg = (HICON)LoadImageW(shell32_hInstance, MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT), 580 IMAGE_ICON, ShellLargeIconSize, ShellLargeIconSize, 581 LR_SHARED | LR_DEFAULTCOLOR); 582 if (!hLg) 583 { 584 ERR("Failed to load large IDI_SHELL_DOCUMENT icon!\n"); 585 goto end; 586 } 587 588 if(SIC_IconAppend(swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, 0) == INVALID_INDEX) 589 { 590 ERR("Failed to add IDI_SHELL_DOCUMENT icon to cache.\n"); 591 goto end; 592 } 593 if(SIC_IconAppend(swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, 0) == INVALID_INDEX) 594 { 595 ERR("Failed to add IDI_SHELL_DOCUMENT icon to cache.\n"); 596 goto end; 597 } 598 599 /* Everything went fine */ 600 result = TRUE; 601 602end: 603 /* The image list keeps a copy of the icons, we must destroy them */ 604 if(hSm) DestroyIcon(hSm); 605 if(hLg) DestroyIcon(hLg); 606 607 /* Clean everything if something went wrong */ 608 if(!result) 609 { 610 if(sic_hdpa) DPA_Destroy(sic_hdpa); 611 if(ShellSmallIconList) ImageList_Destroy(ShellSmallIconList); 612 if(ShellBigIconList) ImageList_Destroy(ShellSmallIconList); 613 sic_hdpa = NULL; 614 ShellSmallIconList = NULL; 615 ShellBigIconList = NULL; 616 } 617 618 TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList); 619 620 return result; 621} 622 623/************************************************************************* 624 * SIC_Destroy 625 * 626 * frees the cache 627 */ 628static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam ) 629{ 630 HeapFree(GetProcessHeap(), 0, ((LPSIC_ENTRY)ptr)->sSourceFile); 631 SHFree(ptr); 632 return TRUE; 633} 634 635void SIC_Destroy(void) 636{ 637 TRACE("\n"); 638 639 EnterCriticalSection(&SHELL32_SicCS); 640 641 if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL ); 642 643 sic_hdpa = NULL; 644 ImageList_Destroy(ShellSmallIconList); 645 ShellSmallIconList = 0; 646 ImageList_Destroy(ShellBigIconList); 647 ShellBigIconList = 0; 648 649 LeaveCriticalSection(&SHELL32_SicCS); 650 //DeleteCriticalSection(&SHELL32_SicCS); //static 651} 652 653/***************************************************************************** 654 * SIC_LoadOverlayIcon [internal] 655 * 656 * Load a shell overlay icon and return its icon cache index. 657 */ 658static int SIC_LoadOverlayIcon(int icon_idx) 659{ 660 WCHAR buffer[1024]; 661 LPWSTR iconPath; 662 int iconIdx; 663 664 iconPath = swShell32Name; /* default: load icon from shell32.dll */ 665 iconIdx = icon_idx; 666 667 if (HLM_GetIconW(icon_idx, buffer, _countof(buffer), &iconIdx)) 668 { 669 iconPath = buffer; 670 } 671 else 672 { 673 WARN("Failed to load icon with index %d, using default one\n", icon_idx); 674 } 675 676 if (!sic_hdpa) 677 SIC_Initialize(); 678 679 return SIC_LoadIcon(iconPath, iconIdx, 0); 680} 681 682/************************************************************************* 683 * Shell_GetImageLists [SHELL32.71] 684 * 685 * PARAMETERS 686 * imglist[1|2] [OUT] pointer which receives imagelist handles 687 * 688 */ 689BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList) 690{ 691 TRACE("(%p,%p)\n",lpBigList,lpSmallList); 692 693 if (!sic_hdpa) 694 SIC_Initialize(); 695 696 if (lpBigList) 697 *lpBigList = ShellBigIconList; 698 699 if (lpSmallList) 700 *lpSmallList = ShellSmallIconList; 701 702 return TRUE; 703} 704/************************************************************************* 705 * PidlToSicIndex [INTERNAL] 706 * 707 * PARAMETERS 708 * sh [IN] IShellFolder 709 * pidl [IN] 710 * bBigIcon [IN] 711 * uFlags [IN] GIL_* 712 * pIndex [OUT] index within the SIC 713 * 714 */ 715BOOL PidlToSicIndex ( 716 IShellFolder * sh, 717 LPCITEMIDLIST pidl, 718 BOOL bBigIcon, 719 UINT uFlags, 720 int * pIndex) 721{ 722 CComPtr<IExtractIconW> ei; 723 WCHAR szIconFile[MAX_PATH]; /* file containing the icon */ 724 INT iSourceIndex; /* index or resID(negated) in this file */ 725 BOOL ret = FALSE; 726 UINT dwFlags = 0; 727 int iShortcutDefaultIndex = INVALID_INDEX; 728 729 TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small"); 730 731 if (!sic_hdpa) 732 SIC_Initialize(); 733 734 if (SUCCEEDED (sh->GetUIObjectOf(0, 1, &pidl, IID_NULL_PPV_ARG(IExtractIconW, &ei)))) 735 { 736 if (SUCCEEDED(ei->GetIconLocation(uFlags &~ GIL_FORSHORTCUT, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags))) 737 { 738 *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags); 739 ret = TRUE; 740 } 741 } 742 743 if (INVALID_INDEX == *pIndex) /* default icon when failed */ 744 { 745 if (0 == (uFlags & GIL_FORSHORTCUT)) 746 { 747 *pIndex = 0; 748 } 749 else 750 { 751 if (INVALID_INDEX == iShortcutDefaultIndex) 752 { 753 iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT); 754 } 755 *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0); 756 } 757 } 758 759 return ret; 760 761} 762 763/************************************************************************* 764 * SHMapPIDLToSystemImageListIndex [SHELL32.77] 765 * 766 * PARAMETERS 767 * sh [IN] pointer to an instance of IShellFolder 768 * pidl [IN] 769 * pIndex [OUT][OPTIONAL] SIC index for big icon 770 * 771 */ 772int WINAPI SHMapPIDLToSystemImageListIndex( 773 IShellFolder *sh, 774 LPCITEMIDLIST pidl, 775 int *pIndex) 776{ 777 int Index; 778 UINT uGilFlags = 0; 779 780 TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex); 781 pdump(pidl); 782 783 if (SHELL_IsShortcut(pidl)) 784 uGilFlags |= GIL_FORSHORTCUT; 785 786 if (pIndex) 787 if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex)) 788 *pIndex = -1; 789 790 if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index)) 791 return -1; 792 793 return Index; 794} 795 796/************************************************************************* 797 * SHMapIDListToImageListIndexAsync [SHELL32.148] 798 */ 799EXTERN_C HRESULT WINAPI SHMapIDListToImageListIndexAsync(IShellTaskScheduler *pts, IShellFolder *psf, 800 LPCITEMIDLIST pidl, UINT flags, 801 PFNASYNCICONTASKBALLBACK pfn, void *pvData, void *pvHint, 802 int *piIndex, int *piIndexSel) 803{ 804 FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n", 805 pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel); 806 return E_FAIL; 807} 808 809/************************************************************************* 810 * Shell_GetCachedImageIndex [SHELL32.72] 811 * 812 */ 813INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, UINT bSimulateDoc) 814{ 815 INT ret, len; 816 LPWSTR szTemp; 817 818 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc); 819 820 len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 ); 821 szTemp = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 822 MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len ); 823 824 ret = SIC_GetIconIndex( szTemp, nIndex, 0 ); 825 826 HeapFree( GetProcessHeap(), 0, szTemp ); 827 828 return ret; 829} 830 831INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, UINT bSimulateDoc) 832{ 833 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc); 834 835 return SIC_GetIconIndex(szPath, nIndex, 0); 836} 837 838EXTERN_C INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc) 839{ if( SHELL_OsIsUnicode()) 840 return Shell_GetCachedImageIndexW((LPCWSTR)szPath, nIndex, bSimulateDoc); 841 return Shell_GetCachedImageIndexA((LPCSTR)szPath, nIndex, bSimulateDoc); 842} 843 844EXTERN_C INT WINAPI Shell_GetCachedImageIndex(LPCWSTR szPath, INT nIndex, UINT bSimulateDoc) 845{ 846 return Shell_GetCachedImageIndexAW(szPath, nIndex, bSimulateDoc); 847} 848 849/************************************************************************* 850 * ExtractIconExW [SHELL32.@] 851 * RETURNS 852 * 0 no icon found (or the file is not valid) 853 * or number of icons extracted 854 */ 855UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons) 856{ 857 UINT ret = 0; 858 859 /* get entry point of undocumented function PrivateExtractIconExW() in user32 */ 860#if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER) 861 static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL; 862 863 if (!PrivateExtractIconExW) { 864 HMODULE hUser32 = GetModuleHandleA("user32"); 865 PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW"); 866 867 if (!PrivateExtractIconExW) 868 return ret; 869 } 870#endif 871 872 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons); 873 ret = PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons); 874 875 /* PrivateExtractIconExW() may return -1 if the provided file is not a valid PE image file or the said 876 * file couldn't be found. The behaviour is correct although ExtractIconExW() only returns the successfully 877 * extracted icons from a file. In such scenario, simply return 0. 878 */ 879 if (ret == 0xFFFFFFFF) 880 { 881 WARN("Invalid file or couldn't be found - %s\n", debugstr_w(lpszFile)); 882 ret = 0; 883 } 884 885 return ret; 886} 887 888/************************************************************************* 889 * ExtractIconExA [SHELL32.@] 890 */ 891UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons) 892{ 893 UINT ret = 0; 894 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0); 895 LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 896 897 TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons); 898 899 if (lpwstrFile) 900 { 901 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len); 902 ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons); 903 HeapFree(GetProcessHeap(), 0, lpwstrFile); 904 } 905 return ret; 906} 907 908/************************************************************************* 909 * ExtractAssociatedIconA (SHELL32.@) 910 * 911 * Return icon for given file (either from file itself or from associated 912 * executable) and patch parameters if needed. 913 */ 914HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon) 915{ 916 HICON hIcon = NULL; 917 INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0); 918 /* Note that we need to allocate MAX_PATH, since we are supposed to fill 919 * the correct executable if there is no icon in lpIconPath directly. 920 * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW 921 * is large enough too. Yes, I am puking too. 922 */ 923 LPWSTR lpIconPathW = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR)); 924 925 TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon); 926 927 if (lpIconPathW) 928 { 929 MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len); 930 hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon); 931 WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL); 932 HeapFree(GetProcessHeap(), 0, lpIconPathW); 933 } 934 return hIcon; 935} 936 937/************************************************************************* 938 * ExtractAssociatedIconW (SHELL32.@) 939 * 940 * Return icon for given file (either from file itself or from associated 941 * executable) and patch parameters if needed. 942 */ 943HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon) 944{ 945 HICON hIcon = NULL; 946 WORD wDummyIcon = 0; 947 948 TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon); 949 950 if(lpiIcon == NULL) 951 lpiIcon = &wDummyIcon; 952 953 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon); 954 955 if( hIcon < (HICON)2 ) 956 { if( hIcon == (HICON)1 ) /* no icons found in given file */ 957 { WCHAR tempPath[MAX_PATH]; 958 HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath); 959 960 if( uRet > (HINSTANCE)32 && tempPath[0] ) 961 { wcscpy(lpIconPath,tempPath); 962 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon); 963 if( hIcon > (HICON)2 ) 964 return hIcon; 965 } 966 } 967 968 if( hIcon == (HICON)1 ) 969 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */ 970 else 971 *lpiIcon = 6; /* generic icon - found nothing */ 972 973 if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH)) 974 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon)); 975 } 976 return hIcon; 977} 978 979/************************************************************************* 980 * ExtractAssociatedIconExW (SHELL32.@) 981 * 982 * Return icon for given file (either from file itself or from associated 983 * executable) and patch parameters if needed. 984 */ 985EXTERN_C HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId) 986{ 987 FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId); 988 return 0; 989} 990 991/************************************************************************* 992 * ExtractAssociatedIconExA (SHELL32.@) 993 * 994 * Return icon for given file (either from file itself or from associated 995 * executable) and patch parameters if needed. 996 */ 997EXTERN_C HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId) 998{ 999 HICON ret; 1000 INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 ); 1001 LPWSTR lpwstrFile = (LPWSTR)HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); 1002 1003 TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId); 1004 1005 MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len ); 1006 ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId); 1007 HeapFree(GetProcessHeap(), 0, lpwstrFile); 1008 return ret; 1009} 1010 1011 1012/**************************************************************************** 1013 * SHDefExtractIconW [SHELL32.@] 1014 */ 1015HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags, 1016 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize) 1017{ 1018 UINT ret; 1019 HICON hIcons[2]; 1020 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); 1021 1022 if (!nIconSize) 1023 nIconSize = MAKELONG(GetSystemMetrics(SM_CXICON), GetSystemMetrics(SM_CXSMICON)); 1024 1025 ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR); 1026 /* FIXME: deal with uFlags parameter which contains GIL_ flags */ 1027 if (ret == 0xFFFFFFFF) 1028 return E_FAIL; 1029 if (ret > 0) { 1030 if (phiconLarge) 1031 *phiconLarge = hIcons[0]; 1032 else 1033 DestroyIcon(hIcons[0]); 1034 if (phiconSmall) 1035 *phiconSmall = hIcons[1]; 1036 else 1037 DestroyIcon(hIcons[1]); 1038 return S_OK; 1039 } 1040 return S_FALSE; 1041} 1042 1043/**************************************************************************** 1044 * SHDefExtractIconA [SHELL32.@] 1045 */ 1046HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags, 1047 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize) 1048{ 1049 HRESULT ret; 1050 INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0); 1051 LPWSTR lpwstrFile = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 1052 1053 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); 1054 1055 MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len); 1056 ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize); 1057 HeapFree(GetProcessHeap(), 0, lpwstrFile); 1058 return ret; 1059} 1060 1061/**************************************************************************** 1062 * SHGetIconOverlayIndexA [SHELL32.@] 1063 * 1064 * Returns the index of the overlay icon in the system image list. 1065 */ 1066EXTERN_C INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex) 1067{ 1068 FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex); 1069 1070 return -1; 1071} 1072 1073/**************************************************************************** 1074 * SHGetIconOverlayIndexW [SHELL32.@] 1075 * 1076 * Returns the index of the overlay icon in the system image list. 1077 */ 1078EXTERN_C INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex) 1079{ 1080 FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex); 1081 1082 return -1; 1083}