dinput: Clear DIA_APPNOMAP BuildActionMap flag with specific device semantic.
[wine.git] / dlls / shell32 / iconcache.c
blobd75daa3fa8d09f4ff4c7389bcdf3cc44fee94a3b
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 = heap_alloc( (lstrlenW(path)+1)*sizeof(WCHAR) );
304 lstrcpyW( entry->sSourceFile, path );
306 entry->dwSourceIndex = src_index;
307 entry->dwFlags = flags;
309 EnterCriticalSection(&SHELL32_SicCS);
311 index = DPA_InsertPtr(sic_hdpa, 0x7fff, entry);
312 if ( INVALID_INDEX == index )
314 heap_free(entry->sSourceFile);
315 SHFree(entry);
316 ret = INVALID_INDEX;
318 else
320 index = -1;
321 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
323 index1 = ImageList_AddIcon(shell_imagelists[i], hicons[i]);
324 if (index != -1 && index1 != index)
325 WARN("Imagelists out of sync, list %d.\n", i);
326 index = index1;
329 entry->dwListIndex = index;
330 ret = entry->dwListIndex;
333 LeaveCriticalSection(&SHELL32_SicCS);
334 return ret;
337 static BOOL get_imagelist_icon_size(int list, SIZE *size)
339 int cx, cy;
340 if (list < 0 || list >= ARRAY_SIZE(shell_imagelists)) return FALSE;
342 if (!ImageList_GetIconSize( shell_imagelists[list], &cx, &cy )) return FALSE;
343 size->cx = cx;
344 size->cy = cy;
345 return TRUE;
348 /****************************************************************************
349 * SIC_LoadIcon [internal]
351 * NOTES
352 * gets icons by index from the file
354 static INT SIC_LoadIcon (const WCHAR *sourcefile, INT index, DWORD flags)
356 HICON hicons[ARRAY_SIZE(shell_imagelists)] = { 0 };
357 HICON hshortcuts[ARRAY_SIZE(hicons)] = { 0 };
358 unsigned int i;
359 SIZE size;
360 INT ret = -1;
362 for (i = 0; i < ARRAY_SIZE(hicons); i++)
364 if (!get_imagelist_icon_size( i, &size ) ||
365 !PrivateExtractIconsW( sourcefile, index, size.cx, size.cy, &hicons[i], 0, 1, 0 ))
366 WARN("Failed to load icon %d from %s.\n", index, debugstr_w(sourcefile));
367 if (!hicons[i]) goto fail;
370 if (flags & GIL_FORSHORTCUT)
372 BOOL failed = FALSE;
374 for (i = 0; i < ARRAY_SIZE(hshortcuts); i++)
376 if (!(hshortcuts[i] = SIC_OverlayShortcutImage(hicons[i], i)))
378 WARN("Failed to create shortcut overlaid icons.\n");
379 failed = TRUE;
383 if (failed)
385 for (i = 0; i < ARRAY_SIZE(hshortcuts); i++)
386 DestroyIcon(hshortcuts[i]);
387 flags &= ~GIL_FORSHORTCUT;
389 else
391 for (i = 0; i < ARRAY_SIZE(hicons); i++)
393 DestroyIcon(hicons[i]);
394 hicons[i] = hshortcuts[i];
399 ret = SIC_IconAppend( sourcefile, index, hicons, flags );
401 fail:
402 for (i = 0; i < ARRAY_SIZE(hicons); i++)
403 DestroyIcon(hicons[i]);
404 return ret;
407 static int get_shell_icon_size(void)
409 WCHAR buf[32];
410 DWORD value = 32, size = sizeof(buf), type;
411 HKEY key;
413 if (!RegOpenKeyW( HKEY_CURRENT_USER, L"Control Panel\\Desktop\\WindowMetrics", &key ))
415 if (!RegQueryValueExW( key, L"Shell Icon Size", NULL, &type, (BYTE *)buf, &size ) && type == REG_SZ)
417 if (size == sizeof(buf)) buf[size / sizeof(WCHAR) - 1] = 0;
418 value = wcstol( buf, NULL, 10 );
420 RegCloseKey( key );
422 return value;
425 /*****************************************************************************
426 * SIC_Initialize [internal]
428 static BOOL WINAPI SIC_Initialize( INIT_ONCE *once, void *param, void **context )
430 HICON hicons[ARRAY_SIZE(shell_imagelists)];
431 SIZE sizes[ARRAY_SIZE(shell_imagelists)];
432 BOOL failed = FALSE;
433 unsigned int i;
435 if (!IsProcessDPIAware())
437 sizes[SHIL_LARGE].cx = sizes[SHIL_LARGE].cy = get_shell_icon_size();
438 sizes[SHIL_SMALL].cx = GetSystemMetrics( SM_CXSMICON );
439 sizes[SHIL_SMALL].cy = GetSystemMetrics( SM_CYSMICON );
441 else
443 sizes[SHIL_LARGE].cx = GetSystemMetrics( SM_CXICON );
444 sizes[SHIL_LARGE].cy = GetSystemMetrics( SM_CYICON );
445 sizes[SHIL_SMALL].cx = sizes[SHIL_LARGE].cx / 2;
446 sizes[SHIL_SMALL].cy = sizes[SHIL_LARGE].cy / 2;
449 sizes[SHIL_EXTRALARGE].cx = (GetSystemMetrics( SM_CXICON ) * 3) / 2;
450 sizes[SHIL_EXTRALARGE].cy = (GetSystemMetrics( SM_CYICON ) * 3) / 2;
451 sizes[SHIL_SYSSMALL].cx = GetSystemMetrics( SM_CXSMICON );
452 sizes[SHIL_SYSSMALL].cy = GetSystemMetrics( SM_CYSMICON );
453 sizes[SHIL_JUMBO].cx = sizes[SHIL_JUMBO].cy = 256;
455 TRACE("large %ldx%ld small %ldx%ld\n", sizes[SHIL_LARGE].cx, sizes[SHIL_LARGE].cy, sizes[SHIL_SMALL].cx, sizes[SHIL_SMALL].cy);
457 sic_hdpa = DPA_Create(16);
458 if (!sic_hdpa)
459 return(FALSE);
461 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
463 shell_imagelists[i] = ImageList_Create(sizes[i].cx, sizes[i].cy, ILC_COLOR32 | ILC_MASK, 0, 0x20);
464 ImageList_SetBkColor(shell_imagelists[i], CLR_NONE);
466 /* Load the generic file icon, which is used as the default if an icon isn't found. */
467 if (!(hicons[i] = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(IDI_SHELL_FILE),
468 IMAGE_ICON, sizes[i].cx, sizes[i].cy, LR_SHARED)))
470 failed = TRUE;
474 if (failed)
476 FIXME("Failed to load IDI_SHELL_FILE icon!\n");
477 return FALSE;
480 SIC_IconAppend(swShell32Name, IDI_SHELL_FILE - 1, hicons, 0);
481 SIC_IconAppend(swShell32Name, -IDI_SHELL_FILE, hicons, 0);
483 TRACE("small list=%p, large list=%p\n", shell_imagelists[SHIL_SMALL], shell_imagelists[SHIL_LARGE]);
485 return TRUE;
488 /*************************************************************************
489 * SIC_Destroy
491 * frees the cache
493 static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam )
495 heap_free(((LPSIC_ENTRY)ptr)->sSourceFile);
496 SHFree(ptr);
497 return TRUE;
500 void SIC_Destroy(void)
502 unsigned int i;
504 TRACE("\n");
506 EnterCriticalSection(&SHELL32_SicCS);
508 if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
510 for (i = 0; i < ARRAY_SIZE(shell_imagelists); i++)
512 if (shell_imagelists[i])
513 ImageList_Destroy(shell_imagelists[i]);
516 LeaveCriticalSection(&SHELL32_SicCS);
517 DeleteCriticalSection(&SHELL32_SicCS);
520 /*****************************************************************************
521 * SIC_GetIconIndex [internal]
523 * Parameters
524 * sSourceFile [IN] filename of file containing the icon
525 * index [IN] index/resID (negated) in this file
527 * NOTES
528 * look in the cache for a proper icon. if not available the icon is taken
529 * from the file and cached
531 INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
533 SIC_ENTRY sice;
534 INT ret, index = INVALID_INDEX;
535 WCHAR path[MAX_PATH];
537 TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
539 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
540 sice.sSourceFile = path;
541 sice.dwSourceIndex = dwSourceIndex;
542 sice.dwFlags = dwFlags;
544 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
546 EnterCriticalSection(&SHELL32_SicCS);
548 if (NULL != DPA_GetPtr (sic_hdpa, 0))
550 /* search linear from position 0*/
551 index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
554 if ( INVALID_INDEX == index )
556 ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
558 else
560 TRACE("-- found\n");
561 ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex;
564 LeaveCriticalSection(&SHELL32_SicCS);
565 return ret;
568 /*****************************************************************************
569 * SIC_LoadOverlayIcon [internal]
571 * Load a shell overlay icon and return its icon cache index.
573 static int SIC_LoadOverlayIcon(int icon_idx)
575 WCHAR buffer[1024], wszIdx[12];
576 HKEY hKeyShellIcons;
577 LPCWSTR iconPath;
578 int iconIdx;
580 iconPath = swShell32Name; /* default: load icon from shell32.dll */
581 iconIdx = icon_idx;
583 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Icons",
584 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
586 DWORD count = sizeof(buffer);
588 swprintf(wszIdx, ARRAY_SIZE(wszIdx), L"%d", icon_idx);
590 /* read icon path and index */
591 if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
593 LPWSTR p = wcschr(buffer, ',');
595 if (!p)
597 ERR("Icon index in Shell Icons/%s corrupted, no comma.\n", debugstr_w(wszIdx));
598 RegCloseKey(hKeyShellIcons);
599 return -1;
601 *p++ = 0;
602 iconPath = buffer;
603 iconIdx = wcstol(p, NULL, 10);
606 RegCloseKey(hKeyShellIcons);
609 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
611 return SIC_LoadIcon(iconPath, iconIdx, 0);
614 /*************************************************************************
615 * Shell_GetImageLists [SHELL32.71]
617 * PARAMETERS
618 * imglist[1|2] [OUT] pointer which receives imagelist handles
621 BOOL WINAPI Shell_GetImageLists(HIMAGELIST *large_list, HIMAGELIST *small_list)
623 TRACE("(%p, %p)\n", large_list, small_list);
625 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
626 if (large_list) *large_list = shell_imagelists[SHIL_LARGE];
627 if (small_list) *small_list = shell_imagelists[SHIL_SMALL];
628 return TRUE;
631 /*************************************************************************
632 * PidlToSicIndex [INTERNAL]
634 * PARAMETERS
635 * sh [IN] IShellFolder
636 * pidl [IN]
637 * bBigIcon [IN]
638 * uFlags [IN] GIL_*
639 * pIndex [OUT] index within the SIC
642 BOOL PidlToSicIndex (
643 IShellFolder * sh,
644 LPCITEMIDLIST pidl,
645 BOOL bBigIcon,
646 UINT uFlags,
647 int * pIndex)
649 IExtractIconW *ei;
650 WCHAR szIconFile[MAX_PATH]; /* file containing the icon */
651 INT iSourceIndex; /* index or resID(negated) in this file */
652 BOOL ret = FALSE;
653 UINT dwFlags = 0;
654 int iShortcutDefaultIndex = INVALID_INDEX;
656 TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
658 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
660 if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
662 if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
664 *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
665 ret = TRUE;
667 IExtractIconW_Release(ei);
670 if (INVALID_INDEX == *pIndex) /* default icon when failed */
672 if (0 == (uFlags & GIL_FORSHORTCUT))
674 *pIndex = 0;
676 else
678 if (INVALID_INDEX == iShortcutDefaultIndex)
680 iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT);
682 *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0);
686 return ret;
690 /*************************************************************************
691 * SHMapPIDLToSystemImageListIndex [SHELL32.77]
693 * PARAMETERS
694 * sh [IN] pointer to an instance of IShellFolder
695 * pidl [IN]
696 * pIndex [OUT][OPTIONAL] SIC index for big icon
699 int WINAPI SHMapPIDLToSystemImageListIndex(
700 IShellFolder *sh,
701 LPCITEMIDLIST pidl,
702 int *pIndex)
704 int Index;
705 UINT uGilFlags = 0;
707 TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
708 pdump(pidl);
710 if (SHELL_IsShortcut(pidl))
711 uGilFlags |= GIL_FORSHORTCUT;
713 if (pIndex)
714 if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
715 *pIndex = -1;
717 if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
718 return -1;
720 return Index;
723 /*************************************************************************
724 * SHMapIDListToImageListIndexAsync [SHELL32.148]
726 HRESULT WINAPI SHMapIDListToImageListIndexAsync(IUnknown *pts, IShellFolder *psf,
727 LPCITEMIDLIST pidl, UINT flags,
728 void *pfn, void *pvData, void *pvHint,
729 int *piIndex, int *piIndexSel)
731 FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n",
732 pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel);
733 return E_FAIL;
736 /*************************************************************************
737 * Shell_GetCachedImageIndex [SHELL32.72]
740 INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateDoc)
742 INT ret, len;
743 LPWSTR szTemp;
745 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
747 len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 );
748 szTemp = heap_alloc( len * sizeof(WCHAR) );
749 MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );
751 ret = SIC_GetIconIndex( szTemp, nIndex, 0 );
753 heap_free( szTemp );
755 return ret;
758 INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulateDoc)
760 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
762 return SIC_GetIconIndex(szPath, nIndex, 0);
765 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
766 { if( SHELL_OsIsUnicode())
767 return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
768 return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
771 /*************************************************************************
772 * ExtractIconExW [SHELL32.@]
773 * RETURNS
774 * 0 no icon found
775 * -1 file is not valid
776 * or number of icons extracted
778 UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
780 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons);
782 return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
785 /*************************************************************************
786 * ExtractIconExA [SHELL32.@]
788 UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
790 UINT ret = 0;
791 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
792 LPWSTR lpwstrFile = heap_alloc( len * sizeof(WCHAR));
794 TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
796 if (lpwstrFile)
798 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
799 ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
800 heap_free(lpwstrFile);
802 return ret;
805 /*************************************************************************
806 * ExtractAssociatedIconA (SHELL32.@)
808 * Return icon for given file (either from file itself or from associated
809 * executable) and patch parameters if needed.
811 HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
813 HICON hIcon = NULL;
814 INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
815 /* Note that we need to allocate MAX_PATH, since we are supposed to fill
816 * the correct executable if there is no icon in lpIconPath directly.
817 * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
818 * is large enough too. Yes, I am puking too.
820 LPWSTR lpIconPathW = heap_alloc(MAX_PATH * sizeof(WCHAR));
822 TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon);
824 if (lpIconPathW)
826 MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len);
827 hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon);
828 WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL);
829 heap_free(lpIconPathW);
831 return hIcon;
834 /*************************************************************************
835 * ExtractAssociatedIconW (SHELL32.@)
837 * Return icon for given file (either from file itself or from associated
838 * executable) and patch parameters if needed.
840 HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon)
842 HICON hIcon = NULL;
843 WORD wDummyIcon = 0;
845 TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon);
847 if(lpiIcon == NULL)
848 lpiIcon = &wDummyIcon;
850 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
852 if( hIcon < (HICON)2 )
853 { if( hIcon == (HICON)1 ) /* no icons found in given file */
854 { WCHAR tempPath[MAX_PATH];
855 HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath);
857 if( uRet > (HINSTANCE)32 && tempPath[0] )
858 { lstrcpyW(lpIconPath,tempPath);
859 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
860 if( hIcon > (HICON)2 )
861 return hIcon;
865 if( hIcon == (HICON)1 )
866 *lpiIcon = 2; /* MS-DOS icon - we found .exe but no icons in it */
867 else
868 *lpiIcon = 6; /* generic icon - found nothing */
870 if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH))
871 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon));
873 return hIcon;
876 /*************************************************************************
877 * ExtractAssociatedIconExW (SHELL32.@)
879 * Return icon for given file (either from file itself or from associated
880 * executable) and patch parameters if needed.
882 HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
884 FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId);
885 return 0;
888 /*************************************************************************
889 * ExtractAssociatedIconExA (SHELL32.@)
891 * Return icon for given file (either from file itself or from associated
892 * executable) and patch parameters if needed.
894 HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
896 HICON ret;
897 INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 );
898 LPWSTR lpwstrFile = heap_alloc( len * sizeof(WCHAR) );
900 TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId);
902 MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len );
903 ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId);
904 heap_free(lpwstrFile);
905 return ret;
909 /****************************************************************************
910 * SHDefExtractIconW [SHELL32.@]
912 HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags,
913 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
915 UINT ret;
916 HICON hIcons[2];
917 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
919 ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR);
920 /* FIXME: deal with uFlags parameter which contains GIL_ flags */
921 if (ret == 0xFFFFFFFF)
922 return E_FAIL;
923 if (ret > 0) {
924 if (phiconLarge)
925 *phiconLarge = hIcons[0];
926 else
927 DestroyIcon(hIcons[0]);
928 if (phiconSmall)
929 *phiconSmall = hIcons[1];
930 else
931 DestroyIcon(hIcons[1]);
932 return S_OK;
934 return S_FALSE;
937 /****************************************************************************
938 * SHDefExtractIconA [SHELL32.@]
940 HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags,
941 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
943 HRESULT ret;
944 INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0);
945 LPWSTR lpwstrFile = heap_alloc(len * sizeof(WCHAR));
947 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
949 MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len);
950 ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
951 heap_free(lpwstrFile);
952 return ret;
956 /****************************************************************************
957 * SHGetIconOverlayIndexA [SHELL32.@]
959 * Returns the index of the overlay icon in the system image list.
961 INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex)
963 FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex);
965 return -1;
968 /****************************************************************************
969 * SHGetIconOverlayIndexW [SHELL32.@]
971 * Returns the index of the overlay icon in the system image list.
973 INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
975 FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex);
977 return -1;
980 /****************************************************************************
981 * SHGetStockIconInfo [SHELL32.@]
983 * Receive information for builtin icons
985 * PARAMS
986 * id [I] selected icon-id to get information for
987 * flags [I] selects the information to receive
988 * sii [IO] SHSTOCKICONINFO structure to fill
990 * RETURNS
991 * Success: S_OK
992 * Failure: A HRESULT failure code
995 HRESULT WINAPI SHGetStockIconInfo(SHSTOCKICONID id, UINT flags, SHSTOCKICONINFO *sii)
997 FIXME("(%d, 0x%x, %p) semi-stub\n", id, flags, sii);
998 if ((id < 0) || (id >= SIID_MAX_ICONS) || !sii || (sii->cbSize != sizeof(SHSTOCKICONINFO))) {
999 return E_INVALIDARG;
1002 GetSystemDirectoryW(sii->szPath, MAX_PATH);
1004 /* no icons defined: use default */
1005 sii->iIcon = -IDI_SHELL_FILE;
1006 lstrcatW(sii->szPath, L"\\shell32.dll");
1008 if (flags)
1009 FIXME("flags 0x%x not implemented\n", flags);
1011 sii->hIcon = NULL;
1012 sii->iSysImageIndex = -1;
1014 TRACE("%3d: returning %s (%d)\n", id, debugstr_w(sii->szPath), sii->iIcon);
1016 return S_OK;
1019 /*************************************************************************
1020 * SHGetImageList (SHELL32.727)
1022 * Returns a copy of a shell image list.
1024 * NOTES
1025 * Windows XP features 4 sizes of image list, and Vista 5. Wine currently
1026 * only supports the traditional small and large image lists, so requests
1027 * for the others will currently fail.
1029 HRESULT WINAPI SHGetImageList(int iImageList, REFIID riid, void **ppv)
1031 TRACE("(%d, %s, %p)\n", iImageList, debugstr_guid(riid), ppv);
1033 if (iImageList < 0 || iImageList > SHIL_LAST)
1034 return E_FAIL;
1036 InitOnceExecuteOnce( &sic_init_once, SIC_Initialize, NULL, NULL );
1037 return HIMAGELIST_QueryInterface(shell_imagelists[iImageList], riid, ppv);