shell32: Move SHCreateLinks() flags to shlfolder.c.
[wine.git] / dlls / shell32 / iconcache.c
blob1c61374a7327959f0ef6a794855a26ef97ed22ba
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 "undocshell.h"
39 #include "shresdef.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(shell);
43 /********************** THE ICON CACHE ********************************/
45 #define INVALID_INDEX -1
47 typedef struct
49 LPWSTR sSourceFile; /* file (not path!) containing the icon */
50 DWORD dwSourceIndex; /* index within the file, if it is a resource ID it will be negated */
51 DWORD dwListIndex; /* index within the iconlist */
52 DWORD dwFlags; /* GIL_* flags */
53 DWORD dwAccessTime;
54 } SIC_ENTRY, * LPSIC_ENTRY;
56 static HDPA sic_hdpa;
57 static INIT_ONCE sic_init_once = INIT_ONCE_STATIC_INIT;
58 static HIMAGELIST shell_imagelists[SHIL_LAST+1];
60 static CRITICAL_SECTION SHELL32_SicCS;
61 static CRITICAL_SECTION_DEBUG critsect_debug =
63 0, 0, &SHELL32_SicCS,
64 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
65 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_SicCS") }
67 static CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 };
70 #define SIC_COMPARE_LISTINDEX 1
72 /*****************************************************************************
73 * SIC_CompareEntries
75 * NOTES
76 * Callback for DPA_Search
78 static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
80 LPSIC_ENTRY e1 = p1, e2 = p2;
82 TRACE("%p %p %8lx\n", p1, p2, lparam);
84 /* Icons in the cache are keyed by the name of the file they are
85 * loaded from, their resource index and the fact if they have a shortcut
86 * icon overlay or not.
89 if (lparam & SIC_COMPARE_LISTINDEX)
90 return e1->dwListIndex != e2->dwListIndex;
92 if (e1->dwSourceIndex != e2->dwSourceIndex || /* first the faster one */
93 (e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT))
94 return 1;
96 if (wcsicmp(e1->sSourceFile,e2->sSourceFile))
97 return 1;
99 return 0;
102 /**************************************************************************************
103 * SIC_get_location
105 * Returns the source file and resource index of an icon with the given imagelist index
107 HRESULT SIC_get_location( int list_idx, WCHAR *file, DWORD *size, int *res_idx )
109 SIC_ENTRY seek, *found;
110 DWORD needed;
111 HRESULT hr = E_INVALIDARG;
112 int dpa_idx;
114 seek.dwListIndex = list_idx;
116 EnterCriticalSection( &SHELL32_SicCS );
118 dpa_idx = DPA_Search( sic_hdpa, &seek, 0, SIC_CompareEntries, SIC_COMPARE_LISTINDEX, 0 );
119 if (dpa_idx != -1)
121 found = DPA_GetPtr( sic_hdpa, dpa_idx );
122 needed = (lstrlenW( found->sSourceFile ) + 1) * sizeof(WCHAR);
123 if (needed <= *size)
125 memcpy( file, found->sSourceFile, needed );
126 *res_idx = found->dwSourceIndex;
127 hr = S_OK;
129 else
131 *size = needed;
132 hr = E_NOT_SUFFICIENT_BUFFER;
135 LeaveCriticalSection( &SHELL32_SicCS );
137 return hr;
140 /* declare SIC_LoadOverlayIcon() */
141 static int SIC_LoadOverlayIcon(int icon_idx);
143 /*****************************************************************************
144 * SIC_OverlayShortcutImage [internal]
146 * NOTES
147 * Creates a new icon as a copy of the passed-in icon, overlaid with a
148 * shortcut image.
150 static HICON SIC_OverlayShortcutImage(HICON SourceIcon, int type)
152 ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
153 HICON ShortcutIcon, TargetIcon;
154 BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
155 HDC SourceDC = NULL,
156 ShortcutDC = NULL,
157 TargetDC = NULL,
158 ScreenDC = NULL;
159 HBITMAP OldSourceBitmap = NULL,
160 OldShortcutBitmap = NULL,
161 OldTargetBitmap = NULL;
163 static int s_imgListIdx = -1;
165 /* Get information about the source icon and shortcut overlay */
166 if (! GetIconInfo(SourceIcon, &SourceIconInfo)
167 || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo))
169 return NULL;
172 /* search for the shortcut icon only once */
173 if (s_imgListIdx == -1)
174 s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT);
175 /* FIXME should use icon index 29 instead of the
176 resource id, but not all icons are present yet
177 so we can't use icon indices */
179 if (s_imgListIdx != -1)
180 ShortcutIcon = ImageList_GetIcon(shell_imagelists[type], s_imgListIdx, ILD_TRANSPARENT);
181 else
182 ShortcutIcon = NULL;
184 if (NULL == ShortcutIcon || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo)
185 || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
187 return NULL;
190 TargetIconInfo = SourceIconInfo;
191 TargetIconInfo.hbmMask = NULL;
192 TargetIconInfo.hbmColor = NULL;
194 /* Setup the source, shortcut and target masks */
195 SourceDC = CreateCompatibleDC(NULL);
196 if (NULL == SourceDC) goto fail;
197 OldSourceBitmap = SelectObject(SourceDC, SourceIconInfo.hbmMask);
198 if (NULL == OldSourceBitmap) goto fail;
200 ShortcutDC = CreateCompatibleDC(NULL);
201 if (NULL == ShortcutDC) goto fail;
202 OldShortcutBitmap = SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask);
203 if (NULL == OldShortcutBitmap) goto fail;
205 TargetDC = CreateCompatibleDC(NULL);
206 if (NULL == TargetDC) goto fail;
207 TargetIconInfo.hbmMask = CreateCompatibleBitmap(TargetDC, SourceBitmapInfo.bmWidth,
208 SourceBitmapInfo.bmHeight);
209 if (NULL == TargetIconInfo.hbmMask) goto fail;
210 ScreenDC = GetDC(NULL);
211 if (NULL == ScreenDC) goto fail;
212 TargetIconInfo.hbmColor = CreateCompatibleBitmap(ScreenDC, SourceBitmapInfo.bmWidth,
213 SourceBitmapInfo.bmHeight);
214 ReleaseDC(NULL, ScreenDC);
215 if (NULL == TargetIconInfo.hbmColor) goto fail;
216 OldTargetBitmap = SelectObject(TargetDC, TargetIconInfo.hbmMask);
217 if (NULL == OldTargetBitmap) goto fail;
219 /* Create the target mask by ANDing the source and shortcut masks */
220 if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
221 SourceDC, 0, 0, SRCCOPY) ||
222 ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
223 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
224 ShortcutDC, 0, 0, SRCAND))
226 goto fail;
229 /* Setup the source and target xor bitmap */
230 if (NULL == SelectObject(SourceDC, SourceIconInfo.hbmColor) ||
231 NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor))
233 goto fail;
236 /* Copy the source xor bitmap to the target and clear out part of it by using
237 the shortcut mask */
238 if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
239 SourceDC, 0, 0, SRCCOPY) ||
240 ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
241 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
242 ShortcutDC, 0, 0, SRCAND))
244 goto fail;
247 if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail;
249 /* Now put in the shortcut xor mask */
250 if (! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
251 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
252 ShortcutDC, 0, 0, SRCINVERT))
254 goto fail;
257 /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
258 handles to NULL */
259 SelectObject(TargetDC, OldTargetBitmap);
260 DeleteObject(TargetDC);
261 SelectObject(ShortcutDC, OldShortcutBitmap);
262 DeleteObject(ShortcutDC);
263 SelectObject(SourceDC, OldSourceBitmap);
264 DeleteObject(SourceDC);
266 /* Create the icon using the bitmaps prepared earlier */
267 TargetIcon = CreateIconIndirect(&TargetIconInfo);
269 /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
270 DeleteObject(TargetIconInfo.hbmColor);
271 DeleteObject(TargetIconInfo.hbmMask);
273 return TargetIcon;
275 fail:
276 /* Clean up scratch resources we created */
277 if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
278 if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
279 if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
280 if (NULL != TargetDC) DeleteObject(TargetDC);
281 if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
282 if (NULL != ShortcutDC) DeleteObject(ShortcutDC);
283 if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap);
284 if (NULL != SourceDC) DeleteObject(SourceDC);
286 return NULL;
289 /*****************************************************************************
290 * SIC_IconAppend [internal]
292 static INT SIC_IconAppend (const WCHAR *sourcefile, INT src_index, HICON *hicons, DWORD flags)
294 INT ret, index, index1;
295 WCHAR path[MAX_PATH];
296 SIC_ENTRY *entry;
297 unsigned int i;
299 TRACE("%s %i %p %#x\n", debugstr_w(sourcefile), src_index, hicons, flags);
301 entry = SHAlloc(sizeof(*entry));
303 GetFullPathNameW(sourcefile, MAX_PATH, path, NULL);
304 entry->sSourceFile = heap_alloc( (lstrlenW(path)+1)*sizeof(WCHAR) );
305 lstrcpyW( entry->sSourceFile, path );
307 entry->dwSourceIndex = src_index;
308 entry->dwFlags = flags;
310 EnterCriticalSection(&SHELL32_SicCS);
312 index = DPA_InsertPtr(sic_hdpa, 0x7fff, entry);
313 if ( INVALID_INDEX == index )
315 heap_free(entry->sSourceFile);
316 SHFree(entry);
317 ret = INVALID_INDEX;
319 else
321 index = -1;
322 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
324 index1 = ImageList_AddIcon(shell_imagelists[i], hicons[i]);
325 if (index != -1 && index1 != index)
326 WARN("Imagelists out of sync, list %d.\n", i);
327 index = index1;
330 entry->dwListIndex = index;
331 ret = entry->dwListIndex;
334 LeaveCriticalSection(&SHELL32_SicCS);
335 return ret;
338 static BOOL get_imagelist_icon_size(int list, SIZE *size)
340 int cx, cy;
341 if (list < 0 || list >= ARRAY_SIZE(shell_imagelists)) return FALSE;
343 if (!ImageList_GetIconSize( shell_imagelists[list], &cx, &cy )) return FALSE;
344 size->cx = cx;
345 size->cy = cy;
346 return TRUE;
349 /****************************************************************************
350 * SIC_LoadIcon [internal]
352 * NOTES
353 * gets icons by index from the file
355 static INT SIC_LoadIcon (const WCHAR *sourcefile, INT index, DWORD flags)
357 HICON hicons[ARRAY_SIZE(shell_imagelists)] = { 0 };
358 HICON hshortcuts[ARRAY_SIZE(hicons)] = { 0 };
359 unsigned int i;
360 SIZE size;
361 INT ret = -1;
363 for (i = 0; i < ARRAY_SIZE(hicons); i++)
365 if (!get_imagelist_icon_size( i, &size ) ||
366 !PrivateExtractIconsW( sourcefile, index, size.cx, size.cy, &hicons[i], 0, 1, 0 ))
367 WARN("Failed to load icon %d from %s.\n", index, debugstr_w(sourcefile));
368 if (!hicons[i]) goto fail;
371 if (flags & GIL_FORSHORTCUT)
373 BOOL failed = FALSE;
375 for (i = 0; i < ARRAY_SIZE(hshortcuts); i++)
377 if (!(hshortcuts[i] = SIC_OverlayShortcutImage(hicons[i], i)))
379 WARN("Failed to create shortcut overlaid icons.\n");
380 failed = TRUE;
384 if (failed)
386 for (i = 0; i < ARRAY_SIZE(hshortcuts); i++)
387 DestroyIcon(hshortcuts[i]);
388 flags &= ~GIL_FORSHORTCUT;
390 else
392 for (i = 0; i < ARRAY_SIZE(hicons); i++)
394 DestroyIcon(hicons[i]);
395 hicons[i] = hshortcuts[i];
400 ret = SIC_IconAppend( sourcefile, index, hicons, flags );
402 fail:
403 for (i = 0; i < ARRAY_SIZE(hicons); i++)
404 DestroyIcon(hicons[i]);
405 return ret;
408 static int get_shell_icon_size(void)
410 WCHAR buf[32];
411 DWORD value = 32, size = sizeof(buf), type;
412 HKEY key;
414 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Control Panel\\Desktop\\WindowMetrics", &key ))
416 if (!RegQueryValueExW( key, L"Shell Icon Size", NULL, &type, (BYTE *)buf, &size ) && type == REG_SZ)
418 if (size == sizeof(buf)) buf[size / sizeof(WCHAR) - 1] = 0;
419 value = wcstol( buf, NULL, 10 );
421 RegCloseKey( key );
423 return value;
426 /*****************************************************************************
427 * SIC_Initialize [internal]
429 static BOOL WINAPI SIC_Initialize( INIT_ONCE *once, void *param, void **context )
431 HICON hicons[ARRAY_SIZE(shell_imagelists)];
432 SIZE sizes[ARRAY_SIZE(shell_imagelists)];
433 BOOL failed = FALSE;
434 unsigned int i;
436 if (!IsProcessDPIAware())
438 sizes[SHIL_LARGE].cx = sizes[SHIL_LARGE].cy = get_shell_icon_size();
439 sizes[SHIL_SMALL].cx = GetSystemMetrics( SM_CXSMICON );
440 sizes[SHIL_SMALL].cy = GetSystemMetrics( SM_CYSMICON );
442 else
444 sizes[SHIL_LARGE].cx = GetSystemMetrics( SM_CXICON );
445 sizes[SHIL_LARGE].cy = GetSystemMetrics( SM_CYICON );
446 sizes[SHIL_SMALL].cx = sizes[SHIL_LARGE].cx / 2;
447 sizes[SHIL_SMALL].cy = sizes[SHIL_LARGE].cy / 2;
450 sizes[SHIL_EXTRALARGE].cx = (GetSystemMetrics( SM_CXICON ) * 3) / 2;
451 sizes[SHIL_EXTRALARGE].cy = (GetSystemMetrics( SM_CYICON ) * 3) / 2;
452 sizes[SHIL_SYSSMALL].cx = GetSystemMetrics( SM_CXSMICON );
453 sizes[SHIL_SYSSMALL].cy = GetSystemMetrics( SM_CYSMICON );
454 sizes[SHIL_JUMBO].cx = sizes[SHIL_JUMBO].cy = 256;
456 TRACE("large %dx%d small %dx%d\n", sizes[SHIL_LARGE].cx, sizes[SHIL_LARGE].cy, sizes[SHIL_SMALL].cx, sizes[SHIL_SMALL].cy);
458 sic_hdpa = DPA_Create(16);
459 if (!sic_hdpa)
460 return(FALSE);
462 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
464 shell_imagelists[i] = ImageList_Create(sizes[i].cx, sizes[i].cy, ILC_COLOR32 | ILC_MASK, 0, 0x20);
465 ImageList_SetBkColor(shell_imagelists[i], CLR_NONE);
467 /* Load the generic file icon, which is used as the default if an icon isn't found. */
468 if (!(hicons[i] = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_FILE),
469 IMAGE_ICON, sizes[i].cx, sizes[i].cy, LR_SHARED)))
471 failed = TRUE;
475 if (failed)
477 FIXME("Failed to load IDI_SHELL_FILE icon!\n");
478 return FALSE;
481 SIC_IconAppend(swShell32Name, IDI_SHELL_FILE - 1, hicons, 0);
482 SIC_IconAppend(swShell32Name, -IDI_SHELL_FILE, hicons, 0);
484 TRACE("small list=%p, large list=%p\n", shell_imagelists[SHIL_SMALL], shell_imagelists[SHIL_LARGE]);
486 return TRUE;
489 /*************************************************************************
490 * SIC_Destroy
492 * frees the cache
494 static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam )
496 heap_free(((LPSIC_ENTRY)ptr)->sSourceFile);
497 SHFree(ptr);
498 return TRUE;
501 void SIC_Destroy(void)
503 unsigned int i;
505 TRACE("\n");
507 EnterCriticalSection(&SHELL32_SicCS);
509 if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
511 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
513 if (shell_imagelists[i])
514 ImageList_Destroy(shell_imagelists[i]);
517 LeaveCriticalSection(&SHELL32_SicCS);
518 DeleteCriticalSection(&SHELL32_SicCS);
521 /*****************************************************************************
522 * SIC_GetIconIndex [internal]
524 * Parameters
525 * sSourceFile [IN] filename of file containing the icon
526 * index [IN] index/resID (negated) in this file
528 * NOTES
529 * look in the cache for a proper icon. if not available the icon is taken
530 * from the file and cached
532 INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
534 SIC_ENTRY sice;
535 INT ret, index = INVALID_INDEX;
536 WCHAR path[MAX_PATH];
538 TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
540 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
541 sice.sSourceFile = path;
542 sice.dwSourceIndex = dwSourceIndex;
543 sice.dwFlags = dwFlags;
545 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
547 EnterCriticalSection(&SHELL32_SicCS);
549 if (NULL != DPA_GetPtr (sic_hdpa, 0))
551 /* search linear from position 0*/
552 index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
555 if ( INVALID_INDEX == index )
557 ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
559 else
561 TRACE("-- found\n");
562 ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex;
565 LeaveCriticalSection(&SHELL32_SicCS);
566 return ret;
569 /*****************************************************************************
570 * SIC_LoadOverlayIcon [internal]
572 * Load a shell overlay icon and return its icon cache index.
574 static int SIC_LoadOverlayIcon(int icon_idx)
576 WCHAR buffer[1024], wszIdx[12];
577 HKEY hKeyShellIcons;
578 LPCWSTR iconPath;
579 int iconIdx;
581 iconPath = swShell32Name; /* default: load icon from shell32.dll */
582 iconIdx = icon_idx;
584 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons",
585 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
587 DWORD count = sizeof(buffer);
589 swprintf(wszIdx, ARRAY_SIZE(wszIdx), L"%d", icon_idx);
591 /* read icon path and index */
592 if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
594 LPWSTR p = wcschr(buffer, ',');
596 if (!p)
598 ERR("Icon index in Shell Icons/%s corrupted, no comma.\n", debugstr_w(wszIdx));
599 RegCloseKey(hKeyShellIcons);
600 return -1;
602 *p++ = 0;
603 iconPath = buffer;
604 iconIdx = wcstol(p, NULL, 10);
607 RegCloseKey(hKeyShellIcons);
610 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
612 return SIC_LoadIcon(iconPath, iconIdx, 0);
615 /*************************************************************************
616 * Shell_GetImageLists [SHELL32.71]
618 * PARAMETERS
619 * imglist[1|2] [OUT] pointer which receives imagelist handles
622 BOOL WINAPI Shell_GetImageLists(HIMAGELIST *large_list, HIMAGELIST *small_list)
624 TRACE("(%p, %p)\n", large_list, small_list);
626 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
627 if (large_list) *large_list = shell_imagelists[SHIL_LARGE];
628 if (small_list) *small_list = shell_imagelists[SHIL_SMALL];
629 return TRUE;
632 /*************************************************************************
633 * PidlToSicIndex [INTERNAL]
635 * PARAMETERS
636 * sh [IN] IShellFolder
637 * pidl [IN]
638 * bBigIcon [IN]
639 * uFlags [IN] GIL_*
640 * pIndex [OUT] index within the SIC
643 BOOL PidlToSicIndex (
644 IShellFolder * sh,
645 LPCITEMIDLIST pidl,
646 BOOL bBigIcon,
647 UINT uFlags,
648 int * pIndex)
650 IExtractIconW *ei;
651 WCHAR szIconFile[MAX_PATH]; /* file containing the icon */
652 INT iSourceIndex; /* index or resID(negated) in this file */
653 BOOL ret = FALSE;
654 UINT dwFlags = 0;
655 int iShortcutDefaultIndex = INVALID_INDEX;
657 TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
659 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
661 if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
663 if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
665 *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
666 ret = TRUE;
668 IExtractIconW_Release(ei);
671 if (INVALID_INDEX == *pIndex) /* default icon when failed */
673 if (0 == (uFlags & GIL_FORSHORTCUT))
675 *pIndex = 0;
677 else
679 if (INVALID_INDEX == iShortcutDefaultIndex)
681 iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT);
683 *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0);
687 return ret;
691 /*************************************************************************
692 * SHMapPIDLToSystemImageListIndex [SHELL32.77]
694 * PARAMETERS
695 * sh [IN] pointer to an instance of IShellFolder
696 * pidl [IN]
697 * pIndex [OUT][OPTIONAL] SIC index for big icon
700 int WINAPI SHMapPIDLToSystemImageListIndex(
701 IShellFolder *sh,
702 LPCITEMIDLIST pidl,
703 int *pIndex)
705 int Index;
706 UINT uGilFlags = 0;
708 TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
709 pdump(pidl);
711 if (SHELL_IsShortcut(pidl))
712 uGilFlags |= GIL_FORSHORTCUT;
714 if (pIndex)
715 if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
716 *pIndex = -1;
718 if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
719 return -1;
721 return Index;
724 /*************************************************************************
725 * SHMapIDListToImageListIndexAsync [SHELL32.148]
727 HRESULT WINAPI SHMapIDListToImageListIndexAsync(IUnknown *pts, IShellFolder *psf,
728 LPCITEMIDLIST pidl, UINT flags,
729 void *pfn, void *pvData, void *pvHint,
730 int *piIndex, int *piIndexSel)
732 FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n",
733 pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel);
734 return E_FAIL;
737 /*************************************************************************
738 * Shell_GetCachedImageIndex [SHELL32.72]
741 static INT Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateDoc)
743 INT ret, len;
744 LPWSTR szTemp;
746 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
748 len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 );
749 szTemp = heap_alloc( len * sizeof(WCHAR) );
750 MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );
752 ret = SIC_GetIconIndex( szTemp, nIndex, 0 );
754 heap_free( szTemp );
756 return ret;
759 static INT Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulateDoc)
761 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
763 return SIC_GetIconIndex(szPath, nIndex, 0);
766 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
767 { if( SHELL_OsIsUnicode())
768 return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
769 return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
772 /*************************************************************************
773 * ExtractIconExW [SHELL32.@]
774 * RETURNS
775 * 0 no icon found
776 * -1 file is not valid
777 * or number of icons extracted
779 UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
781 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons);
783 return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
786 /*************************************************************************
787 * ExtractIconExA [SHELL32.@]
789 UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
791 UINT ret = 0;
792 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
793 LPWSTR lpwstrFile = heap_alloc( len * sizeof(WCHAR));
795 TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
797 if (lpwstrFile)
799 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
800 ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
801 heap_free(lpwstrFile);
803 return ret;
806 /*************************************************************************
807 * ExtractAssociatedIconA (SHELL32.@)
809 * Return icon for given file (either from file itself or from associated
810 * executable) and patch parameters if needed.
812 HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
814 HICON hIcon = NULL;
815 INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
816 /* Note that we need to allocate MAX_PATH, since we are supposed to fill
817 * the correct executable if there is no icon in lpIconPath directly.
818 * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
819 * is large enough too. Yes, I am puking too.
821 LPWSTR lpIconPathW = heap_alloc(MAX_PATH * sizeof(WCHAR));
823 TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon);
825 if (lpIconPathW)
827 MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len);
828 hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon);
829 WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL);
830 heap_free(lpIconPathW);
832 return hIcon;
835 /*************************************************************************
836 * ExtractAssociatedIconW (SHELL32.@)
838 * Return icon for given file (either from file itself or from associated
839 * executable) and patch parameters if needed.
841 HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon)
843 HICON hIcon = NULL;
844 WORD wDummyIcon = 0;
846 TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon);
848 if(lpiIcon == NULL)
849 lpiIcon = &wDummyIcon;
851 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
853 if( hIcon < (HICON)2 )
854 { if( hIcon == (HICON)1 ) /* no icons found in given file */
855 { WCHAR tempPath[MAX_PATH];
856 HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath);
858 if( uRet > (HINSTANCE)32 && tempPath[0] )
859 { lstrcpyW(lpIconPath,tempPath);
860 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
861 if( hIcon > (HICON)2 )
862 return hIcon;
866 if( hIcon == (HICON)1 )
867 *lpiIcon = 2; /* MS-DOS icon - we found .exe but no icons in it */
868 else
869 *lpiIcon = 6; /* generic icon - found nothing */
871 if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH))
872 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon));
874 return hIcon;
877 /*************************************************************************
878 * ExtractAssociatedIconExW (SHELL32.@)
880 * Return icon for given file (either from file itself or from associated
881 * executable) and patch parameters if needed.
883 HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
885 FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId);
886 return 0;
889 /*************************************************************************
890 * ExtractAssociatedIconExA (SHELL32.@)
892 * Return icon for given file (either from file itself or from associated
893 * executable) and patch parameters if needed.
895 HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
897 HICON ret;
898 INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 );
899 LPWSTR lpwstrFile = heap_alloc( len * sizeof(WCHAR) );
901 TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId);
903 MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len );
904 ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId);
905 heap_free(lpwstrFile);
906 return ret;
910 /****************************************************************************
911 * SHDefExtractIconW [SHELL32.@]
913 HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags,
914 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
916 UINT ret;
917 HICON hIcons[2];
918 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
920 ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR);
921 /* FIXME: deal with uFlags parameter which contains GIL_ flags */
922 if (ret == 0xFFFFFFFF)
923 return E_FAIL;
924 if (ret > 0) {
925 if (phiconLarge)
926 *phiconLarge = hIcons[0];
927 else
928 DestroyIcon(hIcons[0]);
929 if (phiconSmall)
930 *phiconSmall = hIcons[1];
931 else
932 DestroyIcon(hIcons[1]);
933 return S_OK;
935 return S_FALSE;
938 /****************************************************************************
939 * SHDefExtractIconA [SHELL32.@]
941 HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags,
942 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
944 HRESULT ret;
945 INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0);
946 LPWSTR lpwstrFile = heap_alloc(len * sizeof(WCHAR));
948 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
950 MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len);
951 ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
952 heap_free(lpwstrFile);
953 return ret;
957 /****************************************************************************
958 * SHGetIconOverlayIndexA [SHELL32.@]
960 * Returns the index of the overlay icon in the system image list.
962 INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex)
964 FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex);
966 return -1;
969 /****************************************************************************
970 * SHGetIconOverlayIndexW [SHELL32.@]
972 * Returns the index of the overlay icon in the system image list.
974 INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
976 FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex);
978 return -1;
981 /****************************************************************************
982 * SHGetStockIconInfo [SHELL32.@]
984 * Receive information for builtin icons
986 * PARAMS
987 * id [I] selected icon-id to get information for
988 * flags [I] selects the information to receive
989 * sii [IO] SHSTOCKICONINFO structure to fill
991 * RETURNS
992 * Success: S_OK
993 * Failure: A HRESULT failure code
996 HRESULT WINAPI SHGetStockIconInfo(SHSTOCKICONID id, UINT flags, SHSTOCKICONINFO *sii)
998 FIXME("(%d, 0x%x, %p) semi-stub\n", id, flags, sii);
999 if ((id < 0) || (id >= SIID_MAX_ICONS) || !sii || (sii->cbSize != sizeof(SHSTOCKICONINFO))) {
1000 return E_INVALIDARG;
1003 GetSystemDirectoryW(sii->szPath, MAX_PATH);
1005 /* no icons defined: use default */
1006 sii->iIcon = -IDI_SHELL_FILE;
1007 lstrcatW(sii->szPath, L"\\shell32.dll");
1009 if (flags)
1010 FIXME("flags 0x%x not implemented\n", flags);
1012 sii->hIcon = NULL;
1013 sii->iSysImageIndex = -1;
1015 TRACE("%3d: returning %s (%d)\n", id, debugstr_w(sii->szPath), sii->iIcon);
1017 return S_OK;
1020 /*************************************************************************
1021 * SHGetImageList (SHELL32.727)
1023 * Returns a copy of a shell image list.
1025 * NOTES
1026 * Windows XP features 4 sizes of image list, and Vista 5. Wine currently
1027 * only supports the traditional small and large image lists, so requests
1028 * for the others will currently fail.
1030 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
1032 TRACE("(%d, %s, %p)\n", iImageList, debugstr_guid(riid), ppv);
1034 if (iImageList < 0 || iImageList > SHIL_LAST)
1035 return E_FAIL;
1037 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
1038 return HIMAGELIST_QueryInterface(shell_imagelists[iImageList], riid, ppv);