widl: Properly align name table entries.
[wine.git] / dlls / shell32 / iconcache.c
blobc122c145609ff7d22387a1b73926d76f5301168a
1 /*
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
21 #include <stdarg.h>
22 #include <string.h>
23 #include <sys/types.h>
25 #define COBJMACROS
27 #include "windef.h"
28 #include "winbase.h"
29 #include "wingdi.h"
30 #include "winuser.h"
31 #include "winreg.h"
32 #include "wine/debug.h"
34 #include "shellapi.h"
35 #include "objbase.h"
36 #include "pidl.h"
37 #include "shell32_main.h"
38 #include "shresdef.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(shell);
42 /********************** THE ICON CACHE ********************************/
44 #define INVALID_INDEX -1
46 typedef struct
48 LPWSTR sSourceFile; /* file (not path!) containing the icon */
49 DWORD dwSourceIndex; /* index within the file, if it is a resource ID it will be negated */
50 DWORD dwListIndex; /* index within the iconlist */
51 DWORD dwFlags; /* GIL_* flags */
52 DWORD dwAccessTime;
53 } SIC_ENTRY, * LPSIC_ENTRY;
55 static HDPA sic_hdpa;
56 static INIT_ONCE sic_init_once = INIT_ONCE_STATIC_INIT;
57 static HIMAGELIST shell_imagelists[SHIL_LAST+1];
59 static CRITICAL_SECTION SHELL32_SicCS;
60 static CRITICAL_SECTION_DEBUG critsect_debug =
62 0, 0, &SHELL32_SicCS,
63 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
64 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_SicCS") }
66 static CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 };
69 #define SIC_COMPARE_LISTINDEX 1
71 /*****************************************************************************
72 * SIC_CompareEntries
74 * NOTES
75 * Callback for DPA_Search
77 static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
79 LPSIC_ENTRY e1 = p1, e2 = p2;
81 TRACE("%p %p %8Ix\n", p1, p2, lparam);
83 /* Icons in the cache are keyed by the name of the file they are
84 * loaded from, their resource index and the fact if they have a shortcut
85 * icon overlay or not.
88 if (lparam & SIC_COMPARE_LISTINDEX)
89 return e1->dwListIndex != e2->dwListIndex;
91 if (e1->dwSourceIndex != e2->dwSourceIndex || /* first the faster one */
92 (e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT))
93 return 1;
95 if (wcsicmp(e1->sSourceFile,e2->sSourceFile))
96 return 1;
98 return 0;
101 /**************************************************************************************
102 * SIC_get_location
104 * Returns the source file and resource index of an icon with the given imagelist index
106 HRESULT SIC_get_location( int list_idx, WCHAR *file, DWORD *size, int *res_idx )
108 SIC_ENTRY seek, *found;
109 DWORD needed;
110 HRESULT hr = E_INVALIDARG;
111 int dpa_idx;
113 seek.dwListIndex = list_idx;
115 EnterCriticalSection( &SHELL32_SicCS );
117 dpa_idx = DPA_Search( sic_hdpa, &seek, 0, SIC_CompareEntries, SIC_COMPARE_LISTINDEX, 0 );
118 if (dpa_idx != -1)
120 found = DPA_GetPtr( sic_hdpa, dpa_idx );
121 needed = (lstrlenW( found->sSourceFile ) + 1) * sizeof(WCHAR);
122 if (needed <= *size)
124 memcpy( file, found->sSourceFile, needed );
125 *res_idx = found->dwSourceIndex;
126 hr = S_OK;
128 else
130 *size = needed;
131 hr = E_NOT_SUFFICIENT_BUFFER;
134 LeaveCriticalSection( &SHELL32_SicCS );
136 return hr;
139 /* declare SIC_LoadOverlayIcon() */
140 static int SIC_LoadOverlayIcon(int icon_idx);
142 /*****************************************************************************
143 * SIC_OverlayShortcutImage [internal]
145 * NOTES
146 * Creates a new icon as a copy of the passed-in icon, overlaid with a
147 * shortcut image.
149 static HICON SIC_OverlayShortcutImage(HICON SourceIcon, int type)
151 ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
152 HICON ShortcutIcon, TargetIcon;
153 BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
154 HDC SourceDC = NULL,
155 ShortcutDC = NULL,
156 TargetDC = NULL,
157 ScreenDC = NULL;
158 HBITMAP OldSourceBitmap = NULL,
159 OldShortcutBitmap = NULL,
160 OldTargetBitmap = NULL;
162 static int s_imgListIdx = -1;
164 /* Get information about the source icon and shortcut overlay */
165 if (! GetIconInfo(SourceIcon, &SourceIconInfo)
166 || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo))
168 return NULL;
171 /* search for the shortcut icon only once */
172 if (s_imgListIdx == -1)
173 s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT);
174 /* FIXME should use icon index 29 instead of the
175 resource id, but not all icons are present yet
176 so we can't use icon indices */
178 if (s_imgListIdx != -1)
179 ShortcutIcon = ImageList_GetIcon(shell_imagelists[type], s_imgListIdx, ILD_TRANSPARENT);
180 else
181 ShortcutIcon = NULL;
183 if (NULL == ShortcutIcon || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo)
184 || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
186 return NULL;
189 TargetIconInfo = SourceIconInfo;
190 TargetIconInfo.hbmMask = NULL;
191 TargetIconInfo.hbmColor = NULL;
193 /* Setup the source, shortcut and target masks */
194 SourceDC = CreateCompatibleDC(NULL);
195 if (NULL == SourceDC) goto fail;
196 OldSourceBitmap = SelectObject(SourceDC, SourceIconInfo.hbmMask);
197 if (NULL == OldSourceBitmap) goto fail;
199 ShortcutDC = CreateCompatibleDC(NULL);
200 if (NULL == ShortcutDC) goto fail;
201 OldShortcutBitmap = SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask);
202 if (NULL == OldShortcutBitmap) goto fail;
204 TargetDC = CreateCompatibleDC(NULL);
205 if (NULL == TargetDC) goto fail;
206 TargetIconInfo.hbmMask = CreateCompatibleBitmap(TargetDC, SourceBitmapInfo.bmWidth,
207 SourceBitmapInfo.bmHeight);
208 if (NULL == TargetIconInfo.hbmMask) goto fail;
209 ScreenDC = GetDC(NULL);
210 if (NULL == ScreenDC) goto fail;
211 TargetIconInfo.hbmColor = CreateCompatibleBitmap(ScreenDC, SourceBitmapInfo.bmWidth,
212 SourceBitmapInfo.bmHeight);
213 ReleaseDC(NULL, ScreenDC);
214 if (NULL == TargetIconInfo.hbmColor) goto fail;
215 OldTargetBitmap = SelectObject(TargetDC, TargetIconInfo.hbmMask);
216 if (NULL == OldTargetBitmap) goto fail;
218 /* Create the target mask by ANDing the source and shortcut masks */
219 if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
220 SourceDC, 0, 0, SRCCOPY) ||
221 ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
222 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
223 ShortcutDC, 0, 0, SRCAND))
225 goto fail;
228 /* Setup the source and target xor bitmap */
229 if (NULL == SelectObject(SourceDC, SourceIconInfo.hbmColor) ||
230 NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor))
232 goto fail;
235 /* Copy the source xor bitmap to the target and clear out part of it by using
236 the shortcut mask */
237 if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
238 SourceDC, 0, 0, SRCCOPY) ||
239 ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
240 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
241 ShortcutDC, 0, 0, SRCAND))
243 goto fail;
246 if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail;
248 /* Now put in the shortcut xor mask */
249 if (! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
250 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
251 ShortcutDC, 0, 0, SRCINVERT))
253 goto fail;
256 /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
257 handles to NULL */
258 SelectObject(TargetDC, OldTargetBitmap);
259 DeleteObject(TargetDC);
260 SelectObject(ShortcutDC, OldShortcutBitmap);
261 DeleteObject(ShortcutDC);
262 SelectObject(SourceDC, OldSourceBitmap);
263 DeleteObject(SourceDC);
265 /* Create the icon using the bitmaps prepared earlier */
266 TargetIcon = CreateIconIndirect(&TargetIconInfo);
268 /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
269 DeleteObject(TargetIconInfo.hbmColor);
270 DeleteObject(TargetIconInfo.hbmMask);
272 return TargetIcon;
274 fail:
275 /* Clean up scratch resources we created */
276 if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
277 if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
278 if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
279 if (NULL != TargetDC) DeleteObject(TargetDC);
280 if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
281 if (NULL != ShortcutDC) DeleteObject(ShortcutDC);
282 if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap);
283 if (NULL != SourceDC) DeleteObject(SourceDC);
285 return NULL;
288 /*****************************************************************************
289 * SIC_IconAppend [internal]
291 static INT SIC_IconAppend (const WCHAR *sourcefile, INT src_index, HICON *hicons, DWORD flags)
293 INT ret, index, index1;
294 WCHAR path[MAX_PATH];
295 SIC_ENTRY *entry;
296 unsigned int i;
298 TRACE("%s %i %p %#lx\n", debugstr_w(sourcefile), src_index, hicons, flags);
300 entry = SHAlloc(sizeof(*entry));
302 GetFullPathNameW(sourcefile, MAX_PATH, path, NULL);
303 entry->sSourceFile = wcsdup(path);
305 entry->dwSourceIndex = src_index;
306 entry->dwFlags = flags;
308 EnterCriticalSection(&SHELL32_SicCS);
310 index = DPA_InsertPtr(sic_hdpa, 0x7fff, entry);
311 if ( INVALID_INDEX == index )
313 free(entry->sSourceFile);
314 SHFree(entry);
315 ret = INVALID_INDEX;
317 else
319 index = -1;
320 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
322 index1 = ImageList_AddIcon(shell_imagelists[i], hicons[i]);
323 if (index != -1 && index1 != index)
324 WARN("Imagelists out of sync, list %d.\n", i);
325 index = index1;
328 entry->dwListIndex = index;
329 ret = entry->dwListIndex;
332 LeaveCriticalSection(&SHELL32_SicCS);
333 return ret;
336 static BOOL get_imagelist_icon_size(int list, SIZE *size)
338 int cx, cy;
339 if (list < 0 || list >= ARRAY_SIZE(shell_imagelists)) return FALSE;
341 if (!ImageList_GetIconSize( shell_imagelists[list], &cx, &cy )) return FALSE;
342 size->cx = cx;
343 size->cy = cy;
344 return TRUE;
347 /****************************************************************************
348 * SIC_LoadIcon [internal]
350 * NOTES
351 * gets icons by index from the file
353 static INT SIC_LoadIcon (const WCHAR *sourcefile, INT index, DWORD flags)
355 HICON hicons[ARRAY_SIZE(shell_imagelists)] = { 0 };
356 HICON hshortcuts[ARRAY_SIZE(hicons)] = { 0 };
357 unsigned int i;
358 SIZE size;
359 INT ret = -1;
361 for (i = 0; i < ARRAY_SIZE(hicons); i++)
363 if (!get_imagelist_icon_size( i, &size ) ||
364 !PrivateExtractIconsW( sourcefile, index, size.cx, size.cy, &hicons[i], 0, 1, 0 ))
365 WARN("Failed to load icon %d from %s.\n", index, debugstr_w(sourcefile));
366 if (!hicons[i]) goto fail;
369 if (flags & GIL_FORSHORTCUT)
371 BOOL failed = FALSE;
373 for (i = 0; i < ARRAY_SIZE(hshortcuts); i++)
375 if (!(hshortcuts[i] = SIC_OverlayShortcutImage(hicons[i], i)))
377 WARN("Failed to create shortcut overlaid icons.\n");
378 failed = TRUE;
382 if (failed)
384 for (i = 0; i < ARRAY_SIZE(hshortcuts); i++)
385 DestroyIcon(hshortcuts[i]);
386 flags &= ~GIL_FORSHORTCUT;
388 else
390 for (i = 0; i < ARRAY_SIZE(hicons); i++)
392 DestroyIcon(hicons[i]);
393 hicons[i] = hshortcuts[i];
398 ret = SIC_IconAppend( sourcefile, index, hicons, flags );
400 fail:
401 for (i = 0; i < ARRAY_SIZE(hicons); i++)
402 DestroyIcon(hicons[i]);
403 return ret;
406 static int get_shell_icon_size(void)
408 WCHAR buf[32];
409 DWORD value = 32, size = sizeof(buf), type;
410 HKEY key;
412 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Control Panel\\Desktop\\WindowMetrics", &key ))
414 if (!RegQueryValueExW( key, L"Shell Icon Size", NULL, &type, (BYTE *)buf, &size ) && type == REG_SZ)
416 if (size == sizeof(buf)) buf[size / sizeof(WCHAR) - 1] = 0;
417 value = wcstol( buf, NULL, 10 );
419 RegCloseKey( key );
421 return value;
424 /*****************************************************************************
425 * SIC_Initialize [internal]
427 static BOOL WINAPI SIC_Initialize( INIT_ONCE *once, void *param, void **context )
429 HICON hicons[ARRAY_SIZE(shell_imagelists)];
430 SIZE sizes[ARRAY_SIZE(shell_imagelists)];
431 BOOL failed = FALSE;
432 unsigned int i;
434 if (!IsProcessDPIAware())
436 sizes[SHIL_LARGE].cx = sizes[SHIL_LARGE].cy = get_shell_icon_size();
437 sizes[SHIL_SMALL].cx = GetSystemMetrics( SM_CXSMICON );
438 sizes[SHIL_SMALL].cy = GetSystemMetrics( SM_CYSMICON );
440 else
442 sizes[SHIL_LARGE].cx = GetSystemMetrics( SM_CXICON );
443 sizes[SHIL_LARGE].cy = GetSystemMetrics( SM_CYICON );
444 sizes[SHIL_SMALL].cx = sizes[SHIL_LARGE].cx / 2;
445 sizes[SHIL_SMALL].cy = sizes[SHIL_LARGE].cy / 2;
448 sizes[SHIL_EXTRALARGE].cx = (GetSystemMetrics( SM_CXICON ) * 3) / 2;
449 sizes[SHIL_EXTRALARGE].cy = (GetSystemMetrics( SM_CYICON ) * 3) / 2;
450 sizes[SHIL_SYSSMALL].cx = GetSystemMetrics( SM_CXSMICON );
451 sizes[SHIL_SYSSMALL].cy = GetSystemMetrics( SM_CYSMICON );
452 sizes[SHIL_JUMBO].cx = sizes[SHIL_JUMBO].cy = 256;
454 TRACE("large %ldx%ld small %ldx%ld\n", sizes[SHIL_LARGE].cx, sizes[SHIL_LARGE].cy, sizes[SHIL_SMALL].cx, sizes[SHIL_SMALL].cy);
456 sic_hdpa = DPA_Create(16);
457 if (!sic_hdpa)
458 return(FALSE);
460 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
462 shell_imagelists[i] = ImageList_Create(sizes[i].cx, sizes[i].cy, ILC_COLOR32 | ILC_MASK, 0, 0x20);
463 ImageList_SetBkColor(shell_imagelists[i], CLR_NONE);
465 /* Load the generic file icon, which is used as the default if an icon isn't found. */
466 if (!(hicons[i] = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_FILE),
467 IMAGE_ICON, sizes[i].cx, sizes[i].cy, LR_SHARED)))
469 failed = TRUE;
473 if (failed)
475 FIXME("Failed to load IDI_SHELL_FILE icon!\n");
476 return FALSE;
479 SIC_IconAppend(swShell32Name, IDI_SHELL_FILE - 1, hicons, 0);
480 SIC_IconAppend(swShell32Name, -IDI_SHELL_FILE, hicons, 0);
482 TRACE("small list=%p, large list=%p\n", shell_imagelists[SHIL_SMALL], shell_imagelists[SHIL_LARGE]);
484 return TRUE;
487 /*************************************************************************
488 * SIC_Destroy
490 * frees the cache
492 static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam )
494 free(((SIC_ENTRY *)ptr)->sSourceFile);
495 SHFree(ptr);
496 return TRUE;
499 void SIC_Destroy(void)
501 unsigned int i;
503 TRACE("\n");
505 EnterCriticalSection(&SHELL32_SicCS);
507 if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
509 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
511 if (shell_imagelists[i])
512 ImageList_Destroy(shell_imagelists[i]);
515 LeaveCriticalSection(&SHELL32_SicCS);
516 DeleteCriticalSection(&SHELL32_SicCS);
519 /*****************************************************************************
520 * SIC_GetIconIndex [internal]
522 * Parameters
523 * sSourceFile [IN] filename of file containing the icon
524 * index [IN] index/resID (negated) in this file
526 * NOTES
527 * look in the cache for a proper icon. if not available the icon is taken
528 * from the file and cached
530 INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
532 SIC_ENTRY sice;
533 INT ret, index = INVALID_INDEX;
534 WCHAR path[MAX_PATH];
536 TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
538 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
539 sice.sSourceFile = path;
540 sice.dwSourceIndex = dwSourceIndex;
541 sice.dwFlags = dwFlags;
543 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
545 EnterCriticalSection(&SHELL32_SicCS);
547 if (NULL != DPA_GetPtr (sic_hdpa, 0))
549 /* search linear from position 0*/
550 index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
553 if ( INVALID_INDEX == index )
555 ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
557 else
559 TRACE("-- found\n");
560 ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex;
563 LeaveCriticalSection(&SHELL32_SicCS);
564 return ret;
567 /*****************************************************************************
568 * SIC_LoadOverlayIcon [internal]
570 * Load a shell overlay icon and return its icon cache index.
572 static int SIC_LoadOverlayIcon(int icon_idx)
574 WCHAR buffer[1024], wszIdx[12];
575 HKEY hKeyShellIcons;
576 LPCWSTR iconPath;
577 int iconIdx;
579 iconPath = swShell32Name; /* default: load icon from shell32.dll */
580 iconIdx = icon_idx;
582 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons",
583 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
585 DWORD count = sizeof(buffer);
587 swprintf(wszIdx, ARRAY_SIZE(wszIdx), L"%d", icon_idx);
589 /* read icon path and index */
590 if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
592 LPWSTR p = wcschr(buffer, ',');
594 if (!p)
596 ERR("Icon index in Shell Icons/%s corrupted, no comma.\n", debugstr_w(wszIdx));
597 RegCloseKey(hKeyShellIcons);
598 return -1;
600 *p++ = 0;
601 iconPath = buffer;
602 iconIdx = wcstol(p, NULL, 10);
605 RegCloseKey(hKeyShellIcons);
608 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
610 return SIC_LoadIcon(iconPath, iconIdx, 0);
613 /*************************************************************************
614 * Shell_GetImageLists [SHELL32.71]
616 * PARAMETERS
617 * imglist[1|2] [OUT] pointer which receives imagelist handles
620 BOOL WINAPI Shell_GetImageLists(HIMAGELIST *large_list, HIMAGELIST *small_list)
622 TRACE("(%p, %p)\n", large_list, small_list);
624 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
625 if (large_list) *large_list = shell_imagelists[SHIL_LARGE];
626 if (small_list) *small_list = shell_imagelists[SHIL_SMALL];
627 return TRUE;
630 /*************************************************************************
631 * PidlToSicIndex [INTERNAL]
633 * PARAMETERS
634 * sh [IN] IShellFolder
635 * pidl [IN]
636 * bBigIcon [IN]
637 * uFlags [IN] GIL_*
638 * pIndex [OUT] index within the SIC
641 BOOL PidlToSicIndex (
642 IShellFolder * sh,
643 LPCITEMIDLIST pidl,
644 BOOL bBigIcon,
645 UINT uFlags,
646 int * pIndex)
648 IExtractIconW *ei;
649 WCHAR szIconFile[MAX_PATH]; /* file containing the icon */
650 INT iSourceIndex; /* index or resID(negated) in this file */
651 BOOL ret = FALSE;
652 UINT dwFlags = 0;
653 int iShortcutDefaultIndex = INVALID_INDEX;
655 TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
657 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
659 if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
661 if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
663 *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
664 ret = TRUE;
666 IExtractIconW_Release(ei);
669 if (INVALID_INDEX == *pIndex) /* default icon when failed */
671 if (0 == (uFlags & GIL_FORSHORTCUT))
673 *pIndex = 0;
675 else
677 if (INVALID_INDEX == iShortcutDefaultIndex)
679 iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT);
681 *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0);
685 return ret;
689 /*************************************************************************
690 * SHMapPIDLToSystemImageListIndex [SHELL32.77]
692 * PARAMETERS
693 * sh [IN] pointer to an instance of IShellFolder
694 * pidl [IN]
695 * pIndex [OUT][OPTIONAL] SIC index for big icon
698 int WINAPI SHMapPIDLToSystemImageListIndex(
699 IShellFolder *sh,
700 LPCITEMIDLIST pidl,
701 int *pIndex)
703 int Index;
704 UINT uGilFlags = 0;
706 TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
707 pdump(pidl);
709 if (SHELL_IsShortcut(pidl))
710 uGilFlags |= GIL_FORSHORTCUT;
712 if (pIndex)
713 if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
714 *pIndex = -1;
716 if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
717 return -1;
719 return Index;
722 /*************************************************************************
723 * SHMapIDListToImageListIndexAsync [SHELL32.148]
725 HRESULT WINAPI SHMapIDListToImageListIndexAsync(IUnknown *pts, IShellFolder *psf,
726 LPCITEMIDLIST pidl, UINT flags,
727 void *pfn, void *pvData, void *pvHint,
728 int *piIndex, int *piIndexSel)
730 FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n",
731 pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel);
732 return E_FAIL;
735 /*************************************************************************
736 * Shell_GetCachedImageIndex [SHELL32.72]
739 INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateDoc)
741 INT ret, len;
742 LPWSTR szTemp;
744 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
746 len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 );
747 szTemp = malloc( len * sizeof(WCHAR) );
748 MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );
750 ret = SIC_GetIconIndex( szTemp, nIndex, 0 );
752 free( szTemp );
754 return ret;
757 INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulateDoc)
759 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
761 return SIC_GetIconIndex(szPath, nIndex, 0);
764 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
765 { if( SHELL_OsIsUnicode())
766 return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
767 return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
770 /*************************************************************************
771 * ExtractIconExW [SHELL32.@]
772 * RETURNS
773 * 0 no icon found
774 * -1 file is not valid
775 * or number of icons extracted
777 UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
779 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons);
781 return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
784 /*************************************************************************
785 * ExtractIconExA [SHELL32.@]
787 UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
789 UINT ret = 0;
790 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
791 WCHAR *lpwstrFile = malloc( len * sizeof(WCHAR));
793 TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
795 if (lpwstrFile)
797 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
798 ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
799 free(lpwstrFile);
801 return ret;
804 /*************************************************************************
805 * ExtractAssociatedIconA (SHELL32.@)
807 * Return icon for given file (either from file itself or from associated
808 * executable) and patch parameters if needed.
810 HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
812 HICON hIcon = NULL;
813 INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
814 /* Note that we need to allocate MAX_PATH, since we are supposed to fill
815 * the correct executable if there is no icon in lpIconPath directly.
816 * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
817 * is large enough too. Yes, I am puking too.
819 WCHAR *lpIconPathW = malloc(MAX_PATH * sizeof(WCHAR));
821 TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon);
823 if (lpIconPathW)
825 MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len);
826 hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon);
827 WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL);
828 free(lpIconPathW);
830 return hIcon;
833 /*************************************************************************
834 * ExtractAssociatedIconW (SHELL32.@)
836 * Return icon for given file (either from file itself or from associated
837 * executable) and patch parameters if needed.
839 HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon)
841 HICON hIcon = NULL;
842 WORD wDummyIcon = 0;
844 TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon);
846 if(lpiIcon == NULL)
847 lpiIcon = &wDummyIcon;
849 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
851 if( hIcon < (HICON)2 )
852 { if( hIcon == (HICON)1 ) /* no icons found in given file */
853 { WCHAR tempPath[MAX_PATH];
854 HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath);
856 if( uRet > (HINSTANCE)32 && tempPath[0] )
857 { lstrcpyW(lpIconPath,tempPath);
858 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
859 if( hIcon > (HICON)2 )
860 return hIcon;
864 if( hIcon == (HICON)1 )
865 *lpiIcon = 2; /* MS-DOS icon - we found .exe but no icons in it */
866 else
867 *lpiIcon = 6; /* generic icon - found nothing */
869 if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH))
870 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon));
872 return hIcon;
875 /*************************************************************************
876 * ExtractAssociatedIconExW (SHELL32.@)
878 * Return icon for given file (either from file itself or from associated
879 * executable) and patch parameters if needed.
881 HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
883 FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId);
884 return 0;
887 /*************************************************************************
888 * ExtractAssociatedIconExA (SHELL32.@)
890 * Return icon for given file (either from file itself or from associated
891 * executable) and patch parameters if needed.
893 HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
895 HICON ret;
896 INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 );
897 WCHAR *lpwstrFile = malloc( len * sizeof(WCHAR) );
899 TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId);
901 MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len );
902 ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId);
903 free(lpwstrFile);
904 return ret;
908 /****************************************************************************
909 * SHDefExtractIconW [SHELL32.@]
911 HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags,
912 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
914 UINT ret;
915 HICON hIcons[2];
916 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
918 ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR);
919 /* FIXME: deal with uFlags parameter which contains GIL_ flags */
920 if (ret == 0xFFFFFFFF)
921 return E_FAIL;
922 if (ret > 0) {
923 if (phiconLarge)
924 *phiconLarge = hIcons[0];
925 else
926 DestroyIcon(hIcons[0]);
927 if (phiconSmall)
928 *phiconSmall = hIcons[1];
929 else
930 DestroyIcon(hIcons[1]);
931 return S_OK;
933 return S_FALSE;
936 /****************************************************************************
937 * SHDefExtractIconA [SHELL32.@]
939 HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags,
940 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
942 HRESULT ret;
943 INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0);
944 WCHAR *lpwstrFile = malloc(len * sizeof(WCHAR));
946 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
948 MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len);
949 ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
950 free(lpwstrFile);
951 return ret;
955 /****************************************************************************
956 * SHGetIconOverlayIndexA [SHELL32.@]
958 * Returns the index of the overlay icon in the system image list.
960 INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex)
962 FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex);
964 return -1;
967 /****************************************************************************
968 * SHGetIconOverlayIndexW [SHELL32.@]
970 * Returns the index of the overlay icon in the system image list.
972 INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
974 FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex);
976 return -1;
979 /****************************************************************************
980 * SHGetStockIconInfo [SHELL32.@]
982 * Receive information for builtin icons
984 * PARAMS
985 * id [I] selected icon-id to get information for
986 * flags [I] selects the information to receive
987 * sii [IO] SHSTOCKICONINFO structure to fill
989 * RETURNS
990 * Success: S_OK
991 * Failure: A HRESULT failure code
994 HRESULT WINAPI SHGetStockIconInfo(SHSTOCKICONID id, UINT flags, SHSTOCKICONINFO *sii)
996 FIXME("(%d, 0x%x, %p) semi-stub\n", id, flags, sii);
997 if ((id < 0) || (id >= SIID_MAX_ICONS) || !sii || (sii->cbSize != sizeof(SHSTOCKICONINFO))) {
998 return E_INVALIDARG;
1001 GetSystemDirectoryW(sii->szPath, MAX_PATH);
1003 /* no icons defined: use default */
1004 sii->iIcon = -IDI_SHELL_FILE;
1005 lstrcatW(sii->szPath, L"\\shell32.dll");
1007 if (flags)
1008 FIXME("flags 0x%x not implemented\n", flags);
1010 sii->hIcon = NULL;
1011 sii->iSysImageIndex = -1;
1013 TRACE("%3d: returning %s (%d)\n", id, debugstr_w(sii->szPath), sii->iIcon);
1015 return S_OK;
1018 /*************************************************************************
1019 * SHGetImageList (SHELL32.727)
1021 * Returns a copy of a shell image list.
1023 * NOTES
1024 * Windows XP features 4 sizes of image list, and Vista 5. Wine currently
1025 * only supports the traditional small and large image lists, so requests
1026 * for the others will currently fail.
1028 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
1030 TRACE("(%d, %s, %p)\n", iImageList, debugstr_guid(riid), ppv);
1032 if (iImageList < 0 || iImageList > SHIL_LAST)
1033 return E_FAIL;
1035 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
1036 return HIMAGELIST_QueryInterface(shell_imagelists[iImageList], riid, ppv);