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