2 * shell icon cache (SIC)
4 * Copyright 1998, 1999 Juergen Schmied
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.
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.
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
23 WINE_DEFAULT_DEBUG_CHANNEL(shell
);
25 /********************** THE ICON CACHE ********************************/
27 #define INVALID_INDEX -1
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 */
36 } SIC_ENTRY
, * LPSIC_ENTRY
;
38 static HDPA sic_hdpa
= 0;
40 static HIMAGELIST ShellSmallIconList
;
41 static HIMAGELIST ShellBigIconList
;
45 extern CRITICAL_SECTION SHELL32_SicCS
;
46 CRITICAL_SECTION_DEBUG critsect_debug
=
49 { &critsect_debug
.ProcessLocksList
, &critsect_debug
.ProcessLocksList
},
50 0, 0, { (DWORD_PTR
)(__FILE__
": SHELL32_SicCS") }
52 CRITICAL_SECTION SHELL32_SicCS
= { &critsect_debug
, -1, 0, 0, 0, 0 };
55 /*****************************************************************************
59 * Callback for DPA_Search
61 static INT CALLBACK
SIC_CompareEntries( LPVOID p1
, LPVOID p2
, LPARAM lparam
)
62 { LPSIC_ENTRY e1
= (LPSIC_ENTRY
)p1
, e2
= (LPSIC_ENTRY
)p2
;
64 TRACE("%p %p %8lx\n", p1
, p2
, lparam
);
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.
70 /* first the faster one */
71 if (e1
->dwSourceIndex
!= e2
->dwSourceIndex
)
72 return (e1
->dwSourceIndex
< e2
->dwSourceIndex
) ? -1 : 1;
74 if ((e1
->dwFlags
& GIL_FORSHORTCUT
) != (e2
->dwFlags
& GIL_FORSHORTCUT
))
75 return ((e1
->dwFlags
& GIL_FORSHORTCUT
) < (e2
->dwFlags
& GIL_FORSHORTCUT
)) ? -1 : 1;
77 return wcsicmp(e1
->sSourceFile
,e2
->sSourceFile
);
80 /* declare SIC_LoadOverlayIcon() */
81 static int SIC_LoadOverlayIcon(int icon_idx
);
83 /*****************************************************************************
84 * SIC_OverlayShortcutImage [internal]
87 * Creates a new icon as a copy of the passed-in icon, overlayed with a
89 * FIXME: This should go to the ImageList implementation!
91 static HICON
SIC_OverlayShortcutImage(HICON SourceIcon
, BOOL large
)
93 ICONINFO ShortcutIconInfo
, TargetIconInfo
;
94 HICON ShortcutIcon
= NULL
, TargetIcon
;
95 BITMAP TargetBitmapInfo
, ShortcutBitmapInfo
;
96 HDC ShortcutDC
= NULL
,
98 HBITMAP OldShortcutBitmap
= NULL
,
99 OldTargetBitmap
= NULL
;
101 static int s_imgListIdx
= -1;
102 ZeroMemory(&ShortcutIconInfo
, sizeof(ShortcutIconInfo
));
103 ZeroMemory(&TargetIconInfo
, sizeof(TargetIconInfo
));
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
))
110 /* Is it possible with the ImageList implementation? */
111 if(!TargetIconInfo
.hbmColor
)
113 /* Maybe we'll support this at some point */
114 FIXME("1bpp icon wants its overlay!\n");
118 if(!GetObjectW(TargetIconInfo
.hbmColor
, sizeof(BITMAP
), &TargetBitmapInfo
))
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 */
130 if (s_imgListIdx
!= -1)
133 ShortcutIcon
= ImageList_GetIcon(ShellBigIconList
, s_imgListIdx
, ILD_TRANSPARENT
);
135 ShortcutIcon
= ImageList_GetIcon(ShellSmallIconList
, s_imgListIdx
, ILD_TRANSPARENT
);
139 if (!ShortcutIcon
|| !GetIconInfo(ShortcutIcon
, &ShortcutIconInfo
))
144 /* Is it possible with the ImageLists ? */
145 if(!ShortcutIconInfo
.hbmColor
)
147 /* Maybe we'll support this at some point */
148 FIXME("Should draw 1bpp overlay!\n");
152 if(!GetObjectW(ShortcutIconInfo
.hbmColor
, sizeof(BITMAP
), &ShortcutBitmapInfo
))
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
;
163 TargetDC
= CreateCompatibleDC(NULL
);
164 if (NULL
== TargetDC
) goto fail
;
165 OldTargetBitmap
= (HBITMAP
)SelectObject(TargetDC
, TargetIconInfo
.hbmMask
);
166 if (NULL
== OldTargetBitmap
) goto fail
;
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
))
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
183 * NOTE: This code sucks(tm) and should belong to the ImageList implementation.
184 * NOTE2: there are better ways to do this.
186 if(ShortcutBitmapInfo
.bmBitsPixel
== 32)
189 BYTE buffer
[sizeof(BITMAPINFO
) + 256 * sizeof(RGBQUAD
)];
190 BITMAPINFO
* lpbmi
= (BITMAPINFO
*)buffer
;
195 /* Find if the source bitmap has an alpha channel */
196 if(TargetBitmapInfo
.bmBitsPixel
!= 32) add_alpha
= FALSE
;
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;
206 bits
= HeapAlloc(GetProcessHeap(), 0, TargetBitmapInfo
.bmHeight
* TargetBitmapInfo
.bmWidthBytes
);
210 if(!GetDIBits(TargetDC
, TargetIconInfo
.hbmColor
, 0, TargetBitmapInfo
.bmHeight
, bits
, lpbmi
, DIB_RGB_COLORS
))
212 ERR("GetBIBits failed!\n");
213 HeapFree(GetProcessHeap(), 0, bits
);
218 pixel
= (PULONG
)bits
;
220 for(i
=0; i
<TargetBitmapInfo
.bmHeight
; i
++)
222 for(j
=0; j
<TargetBitmapInfo
.bmWidth
; j
++)
224 add_alpha
= (*pixel
++ & 0xFF000000) != 0;
229 HeapFree(GetProcessHeap(), 0, bits
);
232 /* Allocate the bits */
233 bits
= HeapAlloc(GetProcessHeap(), 0, ShortcutBitmapInfo
.bmHeight
*ShortcutBitmapInfo
.bmWidthBytes
);
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;
243 if(!GetDIBits(TargetDC
, ShortcutIconInfo
.hbmColor
, 0, ShortcutBitmapInfo
.bmHeight
, bits
, lpbmi
, DIB_RGB_COLORS
))
245 ERR("GetBIBits failed!\n");
246 HeapFree(GetProcessHeap(), 0, bits
);
250 pixel
= (PULONG
)bits
;
251 /* Remove alpha channel component or make it totally opaque */
252 for(i
=0; i
<ShortcutBitmapInfo
.bmHeight
; i
++)
254 for(j
=0; j
<ShortcutBitmapInfo
.bmWidth
; j
++)
256 if(add_alpha
) *pixel
++ |= 0xFF000000;
257 else *pixel
++ &= 0x00FFFFFF;
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
;
264 /* Set the bits again */
265 if(!SetDIBits(TargetDC
, ShortcutIconInfo
.hbmColor
, 0, ShortcutBitmapInfo
.bmHeight
, bits
, lpbmi
, DIB_RGB_COLORS
))
267 ERR("SetBIBits failed!, %lu\n", GetLastError());
268 HeapFree(GetProcessHeap(), 0, bits
);
271 HeapFree(GetProcessHeap(), 0, bits
);
274 /* Now do the copy. We overwrite the original icon data */
275 if (NULL
== SelectObject(ShortcutDC
, ShortcutIconInfo
.hbmColor
) ||
276 NULL
== SelectObject(TargetDC
, TargetIconInfo
.hbmColor
))
278 if (!MaskBlt(TargetDC
, 0, 0, ShortcutBitmapInfo
.bmWidth
, ShortcutBitmapInfo
.bmHeight
,
279 ShortcutDC
, 0, 0, ShortcutIconInfo
.hbmMask
, 0, 0,
280 MAKEROP4(0xAA0000, SRCCOPY
)))
285 /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
287 SelectObject(TargetDC
, OldTargetBitmap
);
289 SelectObject(ShortcutDC
, OldShortcutBitmap
);
290 DeleteDC(ShortcutDC
);
292 /* Create the icon using the bitmaps prepared earlier */
293 TargetIcon
= CreateIconIndirect(&TargetIconInfo
);
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
);
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
);
320 /*****************************************************************************
321 * SIC_IconAppend [internal]
324 * appends an icon pair to the end of the cache
326 static INT
SIC_IconAppend (LPCWSTR sSourceFile
, INT dwSourceIndex
, HICON hSmallIcon
, HICON hBigIcon
, DWORD dwFlags
)
329 INT ret
, index
, index1
, indexDPA
;
330 WCHAR path
[MAX_PATH
];
331 TRACE("%s %i %p %p\n", debugstr_w(sSourceFile
), dwSourceIndex
, hSmallIcon
,hBigIcon
);
333 lpsice
= (LPSIC_ENTRY
) SHAlloc (sizeof (SIC_ENTRY
));
335 GetFullPathNameW(sSourceFile
, MAX_PATH
, path
, NULL
);
336 lpsice
->sSourceFile
= (LPWSTR
)HeapAlloc( GetProcessHeap(), 0, (wcslen(path
)+1)*sizeof(WCHAR
) );
337 wcscpy( lpsice
->sSourceFile
, path
);
339 lpsice
->dwSourceIndex
= dwSourceIndex
;
340 lpsice
->dwFlags
= dwFlags
;
342 EnterCriticalSection(&SHELL32_SicCS
);
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
)
352 index
= ImageList_AddIcon (ShellSmallIconList
, hSmallIcon
);
353 index1
= ImageList_AddIcon (ShellBigIconList
, hBigIcon
);
355 /* Something went wrong when allocating a new image in the list. Abort. */
356 if((index
== -1) || (index1
== -1))
358 WARN("Something went wrong when adding the icon to the list: small - 0x%x, big - 0x%x.\n",
360 if(index
!= -1) ImageList_Remove(ShellSmallIconList
, index
);
361 if(index1
!= -1) ImageList_Remove(ShellBigIconList
, index1
);
368 FIXME("iconlists out of sync 0x%x 0x%x\n", index
, index1
);
369 /* What to do ???? */
371 lpsice
->dwListIndex
= index
;
372 ret
= lpsice
->dwListIndex
;
375 if(ret
== INVALID_INDEX
)
377 if(indexDPA
!= -1) DPA_DeletePtr(sic_hdpa
, indexDPA
);
378 HeapFree(GetProcessHeap(), 0, lpsice
->sSourceFile
);
381 LeaveCriticalSection(&SHELL32_SicCS
);
384 /****************************************************************************
385 * SIC_LoadIcon [internal]
388 * gets small/big icon by number from a file
390 static INT
SIC_LoadIcon (LPCWSTR sSourceFile
, INT dwSourceIndex
, DWORD dwFlags
)
395 static UINT (WINAPI
*PrivateExtractIconExW
)(LPCWSTR
,int,HICON
*,HICON
*,UINT
) = NULL
;
397 if (!PrivateExtractIconExW
)
399 HMODULE hUser32
= GetModuleHandleA("user32");
400 PrivateExtractIconExW
= (UINT(WINAPI
*)(LPCWSTR
,int,HICON
*,HICON
*,UINT
)) GetProcAddress(hUser32
, "PrivateExtractIconExW");
403 if (PrivateExtractIconExW
)
405 PrivateExtractIconExW(sSourceFile
, dwSourceIndex
, &hiconLarge
, &hiconSmall
, 1);
409 PrivateExtractIconsW(sSourceFile
, dwSourceIndex
, 32, 32, &hiconLarge
, NULL
, 1, 0);
410 PrivateExtractIconsW(sSourceFile
, dwSourceIndex
, 16, 16, &hiconSmall
, NULL
, 1, 0);
413 if ( !hiconLarge
|| !hiconSmall
)
415 WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex
, debugstr_w(sSourceFile
), hiconLarge
, hiconSmall
);
416 if(hiconLarge
) DestroyIcon(hiconLarge
);
417 if(hiconSmall
) DestroyIcon(hiconSmall
);
418 return INVALID_INDEX
;
421 if (0 != (dwFlags
& GIL_FORSHORTCUT
))
423 HICON hiconLargeShortcut
= SIC_OverlayShortcutImage(hiconLarge
, TRUE
);
424 HICON hiconSmallShortcut
= SIC_OverlayShortcutImage(hiconSmall
, FALSE
);
425 if (NULL
!= hiconLargeShortcut
&& NULL
!= hiconSmallShortcut
)
427 DestroyIcon(hiconLarge
);
428 DestroyIcon(hiconSmall
);
429 hiconLarge
= hiconLargeShortcut
;
430 hiconSmall
= hiconSmallShortcut
;
434 WARN("Failed to create shortcut overlayed icons\n");
435 if (NULL
!= hiconLargeShortcut
) DestroyIcon(hiconLargeShortcut
);
436 if (NULL
!= hiconSmallShortcut
) DestroyIcon(hiconSmallShortcut
);
437 dwFlags
&= ~ GIL_FORSHORTCUT
;
441 ret
= SIC_IconAppend (sSourceFile
, dwSourceIndex
, hiconSmall
, hiconLarge
, dwFlags
);
442 DestroyIcon(hiconLarge
);
443 DestroyIcon(hiconSmall
);
446 /*****************************************************************************
447 * SIC_GetIconIndex [internal]
450 * sSourceFile [IN] filename of file containing the icon
451 * index [IN] index/resID (negated) in this file
454 * look in the cache for a proper icon. if not available the icon is taken
455 * from the file and cached
457 INT
SIC_GetIconIndex (LPCWSTR sSourceFile
, INT dwSourceIndex
, DWORD dwFlags
)
460 INT ret
, index
= INVALID_INDEX
;
461 WCHAR path
[MAX_PATH
];
463 TRACE("%s %i\n", debugstr_w(sSourceFile
), dwSourceIndex
);
465 GetFullPathNameW(sSourceFile
, MAX_PATH
, path
, NULL
);
466 sice
.sSourceFile
= path
;
467 sice
.dwSourceIndex
= dwSourceIndex
;
468 sice
.dwFlags
= dwFlags
;
470 EnterCriticalSection(&SHELL32_SicCS
);
472 if (NULL
!= DPA_GetPtr (sic_hdpa
, 0))
474 /* search linear from position 0*/
475 index
= DPA_Search (sic_hdpa
, &sice
, 0, SIC_CompareEntries
, 0, DPAS_SORTED
);
478 if ( INVALID_INDEX
== index
)
480 ret
= SIC_LoadIcon (sSourceFile
, dwSourceIndex
, dwFlags
);
485 ret
= ((LPSIC_ENTRY
)DPA_GetPtr(sic_hdpa
, index
))->dwListIndex
;
488 LeaveCriticalSection(&SHELL32_SicCS
);
492 /*****************************************************************************
493 * SIC_Initialize [internal]
495 BOOL
SIC_Initialize(void)
497 HICON hSm
= NULL
, hLg
= NULL
;
498 INT cx_small
, cy_small
;
499 INT cx_large
, cy_large
;
505 TRACE("Entered SIC_Initialize\n");
509 TRACE("Icon cache already initialized\n");
513 sic_hdpa
= DPA_Create(16);
519 hDC
= CreateICW(L
"DISPLAY", NULL
, NULL
, NULL
);
522 ERR("Failed to create information context (error %d)\n", GetLastError());
526 bpp
= GetDeviceCaps(hDC
, BITSPIXEL
);
534 ilMask
= ILC_COLOR16
;
536 ilMask
= ILC_COLOR24
;
538 ilMask
= ILC_COLOR32
;
544 cx_small
= GetSystemMetrics(SM_CXSMICON
);
545 cy_small
= GetSystemMetrics(SM_CYSMICON
);
546 cx_large
= GetSystemMetrics(SM_CXICON
);
547 cy_large
= GetSystemMetrics(SM_CYICON
);
549 ShellSmallIconList
= ImageList_Create(cx_small
,
554 if (!ShellSmallIconList
)
556 ERR("Failed to create the small icon list.\n");
560 ShellBigIconList
= ImageList_Create(cx_large
,
565 if (!ShellBigIconList
)
567 ERR("Failed to create the big icon list.\n");
571 /* Load the document icon, which is used as the default if an icon isn't found. */
572 hSm
= (HICON
)LoadImageW(shell32_hInstance
,
573 MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT
),
577 LR_SHARED
| LR_DEFAULTCOLOR
);
580 ERR("Failed to load small IDI_SHELL_DOCUMENT icon!\n");
584 hLg
= (HICON
)LoadImageW(shell32_hInstance
,
585 MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT
),
589 LR_SHARED
| LR_DEFAULTCOLOR
);
592 ERR("Failed to load large IDI_SHELL_DOCUMENT icon!\n");
596 if(SIC_IconAppend(swShell32Name
, IDI_SHELL_DOCUMENT
-1, hSm
, hLg
, 0) == INVALID_INDEX
)
598 ERR("Failed to add IDI_SHELL_DOCUMENT icon to cache.\n");
601 if(SIC_IconAppend(swShell32Name
, -IDI_SHELL_DOCUMENT
, hSm
, hLg
, 0) == INVALID_INDEX
)
603 ERR("Failed to add IDI_SHELL_DOCUMENT icon to cache.\n");
607 /* Everything went fine */
611 /* The image list keeps a copy of the icons, we must destroy them */
612 if(hSm
) DestroyIcon(hSm
);
613 if(hLg
) DestroyIcon(hLg
);
615 /* Clean everything if something went wrong */
618 if(sic_hdpa
) DPA_Destroy(sic_hdpa
);
619 if(ShellSmallIconList
) ImageList_Destroy(ShellSmallIconList
);
620 if(ShellBigIconList
) ImageList_Destroy(ShellSmallIconList
);
622 ShellSmallIconList
= NULL
;
623 ShellBigIconList
= NULL
;
626 TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList
, ShellBigIconList
);
631 /*************************************************************************
636 static INT CALLBACK
sic_free( LPVOID ptr
, LPVOID lparam
)
638 HeapFree(GetProcessHeap(), 0, ((LPSIC_ENTRY
)ptr
)->sSourceFile
);
643 void SIC_Destroy(void)
647 EnterCriticalSection(&SHELL32_SicCS
);
649 if (sic_hdpa
) DPA_DestroyCallback(sic_hdpa
, sic_free
, NULL
);
652 ImageList_Destroy(ShellSmallIconList
);
653 ShellSmallIconList
= 0;
654 ImageList_Destroy(ShellBigIconList
);
655 ShellBigIconList
= 0;
657 LeaveCriticalSection(&SHELL32_SicCS
);
658 //DeleteCriticalSection(&SHELL32_SicCS); //static
661 /*****************************************************************************
662 * SIC_LoadOverlayIcon [internal]
664 * Load a shell overlay icon and return its icon cache index.
666 static int SIC_LoadOverlayIcon(int icon_idx
)
668 WCHAR buffer
[1024], wszIdx
[8];
673 static const WCHAR wszShellIcons
[] = {
674 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
675 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
676 'E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','I','c','o','n','s',0
678 static const WCHAR wszNumFmt
[] = {'%','d',0};
680 iconPath
= swShell32Name
; /* default: load icon from shell32.dll */
683 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE
, wszShellIcons
, 0, KEY_READ
, &hKeyShellIcons
) == ERROR_SUCCESS
)
685 DWORD count
= sizeof(buffer
);
687 swprintf(wszIdx
, wszNumFmt
, icon_idx
);
689 /* read icon path and index */
690 if (RegQueryValueExW(hKeyShellIcons
, wszIdx
, NULL
, NULL
, (LPBYTE
)buffer
, &count
) == ERROR_SUCCESS
)
692 LPWSTR p
= wcschr(buffer
, ',');
701 RegCloseKey(hKeyShellIcons
);
704 return SIC_LoadIcon(iconPath
, iconIdx
, 0);
707 /*************************************************************************
708 * Shell_GetImageLists [SHELL32.71]
711 * imglist[1|2] [OUT] pointer which receives imagelist handles
714 BOOL WINAPI
Shell_GetImageLists(HIMAGELIST
* lpBigList
, HIMAGELIST
* lpSmallList
)
715 { TRACE("(%p,%p)\n",lpBigList
,lpSmallList
);
717 { *lpBigList
= ShellBigIconList
;
720 { *lpSmallList
= ShellSmallIconList
;
725 /*************************************************************************
726 * PidlToSicIndex [INTERNAL]
729 * sh [IN] IShellFolder
733 * pIndex [OUT] index within the SIC
736 BOOL
PidlToSicIndex (
743 CComPtr
<IExtractIconW
> ei
;
744 WCHAR szIconFile
[MAX_PATH
]; /* file containing the icon */
745 INT iSourceIndex
; /* index or resID(negated) in this file */
748 int iShortcutDefaultIndex
= INVALID_INDEX
;
750 TRACE("sf=%p pidl=%p %s\n", sh
, pidl
, bBigIcon
?"Big":"Small");
752 if (SUCCEEDED (sh
->GetUIObjectOf(0, 1, &pidl
, IID_NULL_PPV_ARG(IExtractIconW
, &ei
))))
754 if (SUCCEEDED(ei
->GetIconLocation(uFlags
, szIconFile
, MAX_PATH
, &iSourceIndex
, &dwFlags
)))
756 *pIndex
= SIC_GetIconIndex(szIconFile
, iSourceIndex
, uFlags
);
761 if (INVALID_INDEX
== *pIndex
) /* default icon when failed */
763 if (0 == (uFlags
& GIL_FORSHORTCUT
))
769 if (INVALID_INDEX
== iShortcutDefaultIndex
)
771 iShortcutDefaultIndex
= SIC_LoadIcon(swShell32Name
, 0, GIL_FORSHORTCUT
);
773 *pIndex
= (INVALID_INDEX
!= iShortcutDefaultIndex
? iShortcutDefaultIndex
: 0);
781 /*************************************************************************
782 * SHMapPIDLToSystemImageListIndex [SHELL32.77]
785 * sh [IN] pointer to an instance of IShellFolder
787 * pIndex [OUT][OPTIONAL] SIC index for big icon
790 int WINAPI
SHMapPIDLToSystemImageListIndex(
798 TRACE("(SF=%p,pidl=%p,%p)\n",sh
,pidl
,pIndex
);
801 if (SHELL_IsShortcut(pidl
))
802 uGilFlags
|= GIL_FORSHORTCUT
;
805 if (!PidlToSicIndex ( sh
, pidl
, 1, uGilFlags
, pIndex
))
808 if (!PidlToSicIndex ( sh
, pidl
, 0, uGilFlags
, &Index
))
814 /*************************************************************************
815 * SHMapIDListToImageListIndexAsync [SHELL32.148]
817 EXTERN_C HRESULT WINAPI
SHMapIDListToImageListIndexAsync(IShellTaskScheduler
*pts
, IShellFolder
*psf
,
818 LPCITEMIDLIST pidl
, UINT flags
,
819 PFNASYNCICONTASKBALLBACK pfn
, void *pvData
, void *pvHint
,
820 int *piIndex
, int *piIndexSel
)
822 FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n",
823 pts
, psf
, pidl
, flags
, pfn
, pvData
, pvHint
, piIndex
, piIndexSel
);
827 /*************************************************************************
828 * Shell_GetCachedImageIndex [SHELL32.72]
831 INT WINAPI
Shell_GetCachedImageIndexA(LPCSTR szPath
, INT nIndex
, UINT bSimulateDoc
)
836 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath
), nIndex
, bSimulateDoc
);
838 len
= MultiByteToWideChar( CP_ACP
, 0, szPath
, -1, NULL
, 0 );
839 szTemp
= (LPWSTR
)HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
840 MultiByteToWideChar( CP_ACP
, 0, szPath
, -1, szTemp
, len
);
842 ret
= SIC_GetIconIndex( szTemp
, nIndex
, 0 );
844 HeapFree( GetProcessHeap(), 0, szTemp
);
849 INT WINAPI
Shell_GetCachedImageIndexW(LPCWSTR szPath
, INT nIndex
, UINT bSimulateDoc
)
851 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath
), nIndex
, bSimulateDoc
);
853 return SIC_GetIconIndex(szPath
, nIndex
, 0);
856 EXTERN_C INT WINAPI
Shell_GetCachedImageIndexAW(LPCVOID szPath
, INT nIndex
, BOOL bSimulateDoc
)
857 { if( SHELL_OsIsUnicode())
858 return Shell_GetCachedImageIndexW((LPCWSTR
)szPath
, nIndex
, bSimulateDoc
);
859 return Shell_GetCachedImageIndexA((LPCSTR
)szPath
, nIndex
, bSimulateDoc
);
862 /*************************************************************************
863 * ExtractIconExW [SHELL32.@]
866 * -1 file is not valid
867 * or number of icons extracted
869 UINT WINAPI
ExtractIconExW(LPCWSTR lpszFile
, INT nIconIndex
, HICON
* phiconLarge
, HICON
* phiconSmall
, UINT nIcons
)
871 /* get entry point of undocumented function PrivateExtractIconExW() in user32 */
872 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
873 static UINT (WINAPI
*PrivateExtractIconExW
)(LPCWSTR
,int,HICON
*,HICON
*,UINT
) = NULL
;
875 if (!PrivateExtractIconExW
) {
876 HMODULE hUser32
= GetModuleHandleA("user32");
877 PrivateExtractIconExW
= (UINT(WINAPI
*)(LPCWSTR
,int,HICON
*,HICON
*,UINT
)) GetProcAddress(hUser32
, "PrivateExtractIconExW");
879 if (!PrivateExtractIconExW
)
884 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile
), nIconIndex
, phiconLarge
, phiconSmall
, nIcons
);
886 return PrivateExtractIconExW(lpszFile
, nIconIndex
, phiconLarge
, phiconSmall
, nIcons
);
889 /*************************************************************************
890 * ExtractIconExA [SHELL32.@]
892 UINT WINAPI
ExtractIconExA(LPCSTR lpszFile
, INT nIconIndex
, HICON
* phiconLarge
, HICON
* phiconSmall
, UINT nIcons
)
895 INT len
= MultiByteToWideChar(CP_ACP
, 0, lpszFile
, -1, NULL
, 0);
896 LPWSTR lpwstrFile
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
898 TRACE("%s %i %p %p %i\n", lpszFile
, nIconIndex
, phiconLarge
, phiconSmall
, nIcons
);
902 MultiByteToWideChar(CP_ACP
, 0, lpszFile
, -1, lpwstrFile
, len
);
903 ret
= ExtractIconExW(lpwstrFile
, nIconIndex
, phiconLarge
, phiconSmall
, nIcons
);
904 HeapFree(GetProcessHeap(), 0, lpwstrFile
);
909 /*************************************************************************
910 * ExtractAssociatedIconA (SHELL32.@)
912 * Return icon for given file (either from file itself or from associated
913 * executable) and patch parameters if needed.
915 HICON WINAPI
ExtractAssociatedIconA(HINSTANCE hInst
, LPSTR lpIconPath
, LPWORD lpiIcon
)
918 INT len
= MultiByteToWideChar(CP_ACP
, 0, lpIconPath
, -1, NULL
, 0);
919 /* Note that we need to allocate MAX_PATH, since we are supposed to fill
920 * the correct executable if there is no icon in lpIconPath directly.
921 * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
922 * is large enough too. Yes, I am puking too.
924 LPWSTR lpIconPathW
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, MAX_PATH
* sizeof(WCHAR
));
926 TRACE("%p %s %p\n", hInst
, debugstr_a(lpIconPath
), lpiIcon
);
930 MultiByteToWideChar(CP_ACP
, 0, lpIconPath
, -1, lpIconPathW
, len
);
931 hIcon
= ExtractAssociatedIconW(hInst
, lpIconPathW
, lpiIcon
);
932 WideCharToMultiByte(CP_ACP
, 0, lpIconPathW
, -1, lpIconPath
, MAX_PATH
, NULL
, NULL
);
933 HeapFree(GetProcessHeap(), 0, lpIconPathW
);
938 /*************************************************************************
939 * ExtractAssociatedIconW (SHELL32.@)
941 * Return icon for given file (either from file itself or from associated
942 * executable) and patch parameters if needed.
944 HICON WINAPI
ExtractAssociatedIconW(HINSTANCE hInst
, LPWSTR lpIconPath
, LPWORD lpiIcon
)
949 TRACE("%p %s %p\n", hInst
, debugstr_w(lpIconPath
), lpiIcon
);
952 lpiIcon
= &wDummyIcon
;
954 hIcon
= ExtractIconW(hInst
, lpIconPath
, *lpiIcon
);
956 if( hIcon
< (HICON
)2 )
957 { if( hIcon
== (HICON
)1 ) /* no icons found in given file */
958 { WCHAR tempPath
[MAX_PATH
];
959 HINSTANCE uRet
= FindExecutableW(lpIconPath
,NULL
,tempPath
);
961 if( uRet
> (HINSTANCE
)32 && tempPath
[0] )
962 { wcscpy(lpIconPath
,tempPath
);
963 hIcon
= ExtractIconW(hInst
, lpIconPath
, *lpiIcon
);
964 if( hIcon
> (HICON
)2 )
969 if( hIcon
== (HICON
)1 )
970 *lpiIcon
= 2; /* MSDOS icon - we found .exe but no icons in it */
972 *lpiIcon
= 6; /* generic icon - found nothing */
974 if (GetModuleFileNameW(hInst
, lpIconPath
, MAX_PATH
))
975 hIcon
= LoadIconW(hInst
, MAKEINTRESOURCEW(*lpiIcon
));
980 /*************************************************************************
981 * ExtractAssociatedIconExW (SHELL32.@)
983 * Return icon for given file (either from file itself or from associated
984 * executable) and patch parameters if needed.
986 EXTERN_C HICON WINAPI
ExtractAssociatedIconExW(HINSTANCE hInst
, LPWSTR lpIconPath
, LPWORD lpiIconIdx
, LPWORD lpiIconId
)
988 FIXME("%p %s %p %p): stub\n", hInst
, debugstr_w(lpIconPath
), lpiIconIdx
, lpiIconId
);
992 /*************************************************************************
993 * ExtractAssociatedIconExA (SHELL32.@)
995 * Return icon for given file (either from file itself or from associated
996 * executable) and patch parameters if needed.
998 EXTERN_C HICON WINAPI
ExtractAssociatedIconExA(HINSTANCE hInst
, LPSTR lpIconPath
, LPWORD lpiIconIdx
, LPWORD lpiIconId
)
1001 INT len
= MultiByteToWideChar( CP_ACP
, 0, lpIconPath
, -1, NULL
, 0 );
1002 LPWSTR lpwstrFile
= (LPWSTR
)HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
1004 TRACE("%p %s %p %p)\n", hInst
, lpIconPath
, lpiIconIdx
, lpiIconId
);
1006 MultiByteToWideChar( CP_ACP
, 0, lpIconPath
, -1, lpwstrFile
, len
);
1007 ret
= ExtractAssociatedIconExW(hInst
, lpwstrFile
, lpiIconIdx
, lpiIconId
);
1008 HeapFree(GetProcessHeap(), 0, lpwstrFile
);
1013 /****************************************************************************
1014 * SHDefExtractIconW [SHELL32.@]
1016 HRESULT WINAPI
SHDefExtractIconW(LPCWSTR pszIconFile
, int iIndex
, UINT uFlags
,
1017 HICON
* phiconLarge
, HICON
* phiconSmall
, UINT nIconSize
)
1021 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile
), iIndex
, uFlags
, phiconLarge
, phiconSmall
, nIconSize
);
1023 ret
= PrivateExtractIconsW(pszIconFile
, iIndex
, nIconSize
, nIconSize
, hIcons
, NULL
, 2, LR_DEFAULTCOLOR
);
1024 /* FIXME: deal with uFlags parameter which contains GIL_ flags */
1025 if (ret
== 0xFFFFFFFF)
1029 *phiconLarge
= hIcons
[0];
1031 DestroyIcon(hIcons
[0]);
1033 *phiconSmall
= hIcons
[1];
1035 DestroyIcon(hIcons
[1]);
1041 /****************************************************************************
1042 * SHDefExtractIconA [SHELL32.@]
1044 HRESULT WINAPI
SHDefExtractIconA(LPCSTR pszIconFile
, int iIndex
, UINT uFlags
,
1045 HICON
* phiconLarge
, HICON
* phiconSmall
, UINT nIconSize
)
1048 INT len
= MultiByteToWideChar(CP_ACP
, 0, pszIconFile
, -1, NULL
, 0);
1049 LPWSTR lpwstrFile
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
1051 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile
, iIndex
, uFlags
, phiconLarge
, phiconSmall
, nIconSize
);
1053 MultiByteToWideChar(CP_ACP
, 0, pszIconFile
, -1, lpwstrFile
, len
);
1054 ret
= SHDefExtractIconW(lpwstrFile
, iIndex
, uFlags
, phiconLarge
, phiconSmall
, nIconSize
);
1055 HeapFree(GetProcessHeap(), 0, lpwstrFile
);
1059 /****************************************************************************
1060 * SHGetIconOverlayIndexA [SHELL32.@]
1062 * Returns the index of the overlay icon in the system image list.
1064 EXTERN_C INT WINAPI
SHGetIconOverlayIndexA(LPCSTR pszIconPath
, INT iIconIndex
)
1066 FIXME("%s, %d\n", debugstr_a(pszIconPath
), iIconIndex
);
1071 /****************************************************************************
1072 * SHGetIconOverlayIndexW [SHELL32.@]
1074 * Returns the index of the overlay icon in the system image list.
1076 EXTERN_C INT WINAPI
SHGetIconOverlayIndexW(LPCWSTR pszIconPath
, INT iIconIndex
)
1078 FIXME("%s, %d\n", debugstr_w(pszIconPath
), iIconIndex
);