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