Sync with trunk (r48414)
[reactos.git] / dll / win32 / shell32 / iconcache.c
1 /*
2 * shell icon cache (SIC)
3 *
4 * Copyright 1998, 1999 Juergen Schmied
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <precomp.h>
22
23 WINE_DEFAULT_DEBUG_CHANNEL(shell);
24
25 /********************** THE ICON CACHE ********************************/
26
27 #define INVALID_INDEX -1
28
29 typedef struct
30 {
31 LPWSTR sSourceFile; /* file (not path!) containing the icon */
32 DWORD dwSourceIndex; /* index within the file, if it is a resoure ID it will be negated */
33 DWORD dwListIndex; /* index within the iconlist */
34 DWORD dwFlags; /* GIL_* flags */
35 DWORD dwAccessTime;
36 } SIC_ENTRY, * LPSIC_ENTRY;
37
38 static HDPA sic_hdpa = 0;
39
40 static CRITICAL_SECTION SHELL32_SicCS;
41 static CRITICAL_SECTION_DEBUG critsect_debug =
42 {
43 0, 0, &SHELL32_SicCS,
44 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
45 0, 0, { (DWORD_PTR)(__FILE__ ": SHELL32_SicCS") }
46 };
47 static CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 };
48
49 /*****************************************************************************
50 * SIC_CompareEntries
51 *
52 * NOTES
53 * Callback for DPA_Search
54 */
55 static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
56 { LPSIC_ENTRY e1 = (LPSIC_ENTRY)p1, e2 = (LPSIC_ENTRY)p2;
57
58 TRACE("%p %p %8lx\n", p1, p2, lparam);
59
60 /* Icons in the cache are keyed by the name of the file they are
61 * loaded from, their resource index and the fact if they have a shortcut
62 * icon overlay or not.
63 */
64 if (e1->dwSourceIndex != e2->dwSourceIndex || /* first the faster one */
65 (e1->dwFlags & GIL_FORSHORTCUT) != (e2->dwFlags & GIL_FORSHORTCUT))
66 return 1;
67
68 if (wcsicmp(e1->sSourceFile,e2->sSourceFile))
69 return 1;
70
71 return 0;
72 }
73
74 /* declare SIC_LoadOverlayIcon() */
75 static int SIC_LoadOverlayIcon(int icon_idx);
76
77 /*****************************************************************************
78 * SIC_OverlayShortcutImage [internal]
79 *
80 * NOTES
81 * Creates a new icon as a copy of the passed-in icon, overlayed with a
82 * shortcut image.
83 */
84 static HICON SIC_OverlayShortcutImage(HICON SourceIcon, BOOL large)
85 { ICONINFO SourceIconInfo, ShortcutIconInfo, TargetIconInfo;
86 HICON ShortcutIcon, TargetIcon;
87 BITMAP SourceBitmapInfo, ShortcutBitmapInfo;
88 HDC SourceDC = NULL,
89 ShortcutDC = NULL,
90 TargetDC = NULL,
91 ScreenDC = NULL;
92 HBITMAP OldSourceBitmap = NULL,
93 OldShortcutBitmap = NULL,
94 OldTargetBitmap = NULL;
95
96 static int s_imgListIdx = -1;
97
98 /* Get information about the source icon and shortcut overlay */
99 if (! GetIconInfo(SourceIcon, &SourceIconInfo)
100 || 0 == GetObjectW(SourceIconInfo.hbmColor, sizeof(BITMAP), &SourceBitmapInfo))
101 {
102 return NULL;
103 }
104
105 /* search for the shortcut icon only once */
106 if (s_imgListIdx == -1)
107 s_imgListIdx = SIC_LoadOverlayIcon(- IDI_SHELL_SHORTCUT);
108 /* FIXME should use icon index 29 instead of the
109 resource id, but not all icons are present yet
110 so we can't use icon indices */
111
112 if (s_imgListIdx != -1)
113 {
114 if (large)
115 ShortcutIcon = ImageList_GetIcon(ShellBigIconList, s_imgListIdx, ILD_TRANSPARENT);
116 else
117 ShortcutIcon = ImageList_GetIcon(ShellSmallIconList, s_imgListIdx, ILD_TRANSPARENT);
118 } else
119 ShortcutIcon = NULL;
120
121 if (NULL == ShortcutIcon
122 || ! GetIconInfo(ShortcutIcon, &ShortcutIconInfo)
123 || 0 == GetObjectW(ShortcutIconInfo.hbmColor, sizeof(BITMAP), &ShortcutBitmapInfo))
124 {
125 return NULL;
126 }
127
128 TargetIconInfo = SourceIconInfo;
129 TargetIconInfo.hbmMask = NULL;
130 TargetIconInfo.hbmColor = NULL;
131
132 /* Setup the source, shortcut and target masks */
133 SourceDC = CreateCompatibleDC(NULL);
134 if (NULL == SourceDC) goto fail;
135 OldSourceBitmap = SelectObject(SourceDC, SourceIconInfo.hbmMask);
136 if (NULL == OldSourceBitmap) goto fail;
137
138 ShortcutDC = CreateCompatibleDC(NULL);
139 if (NULL == ShortcutDC) goto fail;
140 OldShortcutBitmap = SelectObject(ShortcutDC, ShortcutIconInfo.hbmMask);
141 if (NULL == OldShortcutBitmap) goto fail;
142
143 TargetDC = CreateCompatibleDC(NULL);
144 if (NULL == TargetDC) goto fail;
145 TargetIconInfo.hbmMask = CreateCompatibleBitmap(TargetDC, SourceBitmapInfo.bmWidth,
146 SourceBitmapInfo.bmHeight);
147 if (NULL == TargetIconInfo.hbmMask) goto fail;
148 ScreenDC = GetDC(NULL);
149 if (NULL == ScreenDC) goto fail;
150 TargetIconInfo.hbmColor = CreateCompatibleBitmap(ScreenDC, SourceBitmapInfo.bmWidth,
151 SourceBitmapInfo.bmHeight);
152 ReleaseDC(NULL, ScreenDC);
153 if (NULL == TargetIconInfo.hbmColor) goto fail;
154 OldTargetBitmap = SelectObject(TargetDC, TargetIconInfo.hbmMask);
155 if (NULL == OldTargetBitmap) goto fail;
156
157 /* Create the target mask by ANDing the source and shortcut masks */
158 if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
159 SourceDC, 0, 0, SRCCOPY) ||
160 ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
161 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
162 ShortcutDC, 0, 0, SRCAND))
163 {
164 goto fail;
165 }
166
167 /* Setup the source and target xor bitmap */
168 if (NULL == SelectObject(SourceDC, SourceIconInfo.hbmColor) ||
169 NULL == SelectObject(TargetDC, TargetIconInfo.hbmColor))
170 {
171 goto fail;
172 }
173
174 /* Copy the source xor bitmap to the target and clear out part of it by using
175 the shortcut mask */
176 if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
177 SourceDC, 0, 0, SRCCOPY) ||
178 ! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
179 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
180 ShortcutDC, 0, 0, SRCAND))
181 {
182 goto fail;
183 }
184
185 if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail;
186
187 /* Now put in the shortcut xor mask */
188 if (! BitBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
189 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
190 ShortcutDC, 0, 0, SRCINVERT))
191 {
192 goto fail;
193 }
194
195 /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
196 handles to NULL */
197 SelectObject(TargetDC, OldTargetBitmap);
198 DeleteObject(TargetDC);
199 SelectObject(ShortcutDC, OldShortcutBitmap);
200 DeleteObject(ShortcutDC);
201 SelectObject(SourceDC, OldSourceBitmap);
202 DeleteObject(SourceDC);
203
204 /* Create the icon using the bitmaps prepared earlier */
205 TargetIcon = CreateIconIndirect(&TargetIconInfo);
206
207 /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
208 DeleteObject(TargetIconInfo.hbmColor);
209 DeleteObject(TargetIconInfo.hbmMask);
210
211 return TargetIcon;
212
213 fail:
214 /* Clean up scratch resources we created */
215 if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
216 if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
217 if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
218 if (NULL != TargetDC) DeleteObject(TargetDC);
219 if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
220 if (NULL != ShortcutDC) DeleteObject(ShortcutDC);
221 if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap);
222 if (NULL != SourceDC) DeleteObject(SourceDC);
223
224 return NULL;
225 }
226
227 /*****************************************************************************
228 * SIC_IconAppend [internal]
229 *
230 * NOTES
231 * appends an icon pair to the end of the cache
232 */
233 static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon, DWORD dwFlags)
234 { LPSIC_ENTRY lpsice;
235 INT ret, index, index1;
236 WCHAR path[MAX_PATH];
237 TRACE("%s %i %p %p\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon ,hBigIcon);
238
239 lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY));
240
241 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
242 lpsice->sSourceFile = HeapAlloc( GetProcessHeap(), 0, (wcslen(path)+1)*sizeof(WCHAR) );
243 wcscpy( lpsice->sSourceFile, path );
244
245 lpsice->dwSourceIndex = dwSourceIndex;
246 lpsice->dwFlags = dwFlags;
247
248 EnterCriticalSection(&SHELL32_SicCS);
249
250 index = DPA_InsertPtr(sic_hdpa, 0x7fff, lpsice);
251 if ( INVALID_INDEX == index )
252 {
253 HeapFree(GetProcessHeap(), 0, lpsice->sSourceFile);
254 SHFree(lpsice);
255 ret = INVALID_INDEX;
256 }
257 else
258 {
259 index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon);
260 index1= ImageList_AddIcon (ShellBigIconList, hBigIcon);
261
262 if (index!=index1)
263 {
264 FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1);
265 }
266 lpsice->dwListIndex = index;
267 ret = lpsice->dwListIndex;
268 }
269
270 LeaveCriticalSection(&SHELL32_SicCS);
271 return ret;
272 }
273 /****************************************************************************
274 * SIC_LoadIcon [internal]
275 *
276 * NOTES
277 * gets small/big icon by number from a file
278 */
279 static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags)
280 { HICON hiconLarge=0;
281 HICON hiconSmall=0;
282 HICON hiconLargeShortcut;
283 HICON hiconSmallShortcut;
284
285 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
286 static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL;
287
288 if (!PrivateExtractIconExW) {
289 HMODULE hUser32 = GetModuleHandleA("user32");
290 PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW");
291 }
292
293 if (PrivateExtractIconExW)
294 PrivateExtractIconExW(sSourceFile, dwSourceIndex, &hiconLarge, &hiconSmall, 1);
295 else
296 #endif
297 {
298 PrivateExtractIconsW(sSourceFile, dwSourceIndex, 32, 32, &hiconLarge, NULL, 1, 0);
299 PrivateExtractIconsW(sSourceFile, dwSourceIndex, 16, 16, &hiconSmall, NULL, 1, 0);
300 }
301
302 if ( !hiconLarge || !hiconSmall)
303 {
304 WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall);
305 return -1;
306 }
307
308 if (0 != (dwFlags & GIL_FORSHORTCUT))
309 {
310 hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE);
311 hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE);
312 if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut)
313 {
314 hiconLarge = hiconLargeShortcut;
315 hiconSmall = hiconSmallShortcut;
316 }
317 else
318 {
319 WARN("Failed to create shortcut overlayed icons\n");
320 if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut);
321 if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut);
322 dwFlags &= ~ GIL_FORSHORTCUT;
323 }
324 }
325
326 return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags);
327 }
328 /*****************************************************************************
329 * SIC_GetIconIndex [internal]
330 *
331 * Parameters
332 * sSourceFile [IN] filename of file containing the icon
333 * index [IN] index/resID (negated) in this file
334 *
335 * NOTES
336 * look in the cache for a proper icon. if not available the icon is taken
337 * from the file and cached
338 */
339 INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
340 {
341 SIC_ENTRY sice;
342 INT ret, index = INVALID_INDEX;
343 WCHAR path[MAX_PATH];
344
345 TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
346
347 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
348 sice.sSourceFile = path;
349 sice.dwSourceIndex = dwSourceIndex;
350 sice.dwFlags = dwFlags;
351
352 EnterCriticalSection(&SHELL32_SicCS);
353
354 if (NULL != DPA_GetPtr (sic_hdpa, 0))
355 {
356 /* search linear from position 0*/
357 index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
358 }
359
360 if ( INVALID_INDEX == index )
361 {
362 ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
363 }
364 else
365 {
366 TRACE("-- found\n");
367 ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex;
368 }
369
370 LeaveCriticalSection(&SHELL32_SicCS);
371 return ret;
372 }
373 /*****************************************************************************
374 * SIC_Initialize [internal]
375 */
376 BOOL SIC_Initialize(void)
377 {
378 HICON hSm = NULL, hLg = NULL;
379 INT cx_small, cy_small;
380 INT cx_large, cy_large;
381 HDC hDC;
382 INT bpp;
383 DWORD ilMask;
384
385 TRACE("Entered SIC_Initialize\n");
386
387 if (sic_hdpa)
388 {
389 TRACE("Icon cache already initialized\n");
390 return TRUE;
391 }
392
393 sic_hdpa = DPA_Create(16);
394 if (!sic_hdpa)
395 {
396 return FALSE;
397 }
398
399 hDC = CreateICW(L"DISPLAY", NULL, NULL, NULL);
400 if (!hDC)
401 {
402 ERR("Failed to create information context (error %d)\n", GetLastError());
403 return FALSE;
404 }
405
406 bpp = GetDeviceCaps(hDC, BITSPIXEL);
407 ReleaseDC(NULL, hDC);
408
409 if (bpp <= 4)
410 ilMask = ILC_COLOR4;
411 else if (bpp <= 8)
412 ilMask = ILC_COLOR8;
413 else if (bpp <= 16)
414 ilMask = ILC_COLOR16;
415 else if (bpp <= 24)
416 ilMask = ILC_COLOR24;
417 else if (bpp <= 32)
418 ilMask = ILC_COLOR32;
419 else
420 ilMask = ILC_COLOR;
421
422 ilMask |= ILC_MASK;
423
424 cx_small = GetSystemMetrics(SM_CXSMICON);
425 cy_small = GetSystemMetrics(SM_CYSMICON);
426 cx_large = GetSystemMetrics(SM_CXICON);
427 cy_large = GetSystemMetrics(SM_CYICON);
428
429 ShellSmallIconList = ImageList_Create(cx_small,
430 cy_small,
431 ilMask,
432 100,
433 100);
434
435 ShellBigIconList = ImageList_Create(cx_large,
436 cy_large,
437 ilMask,
438 100,
439 100);
440 if (ShellSmallIconList)
441 {
442 /* Load the document icon, which is used as the default if an icon isn't found. */
443 hSm = (HICON)LoadImageW(shell32_hInstance,
444 MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT),
445 IMAGE_ICON,
446 cx_small,
447 cy_small,
448 LR_SHARED | LR_DEFAULTCOLOR);
449 if (!hSm)
450 {
451 ERR("Failed to load IDI_SHELL_DOCUMENT icon1!\n");
452 return FALSE;
453 }
454 }
455 else
456 {
457 ERR("Failed to load ShellSmallIconList\n");
458 return FALSE;
459 }
460
461 if (ShellBigIconList)
462 {
463 hLg = (HICON)LoadImageW(shell32_hInstance,
464 MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT),
465 IMAGE_ICON,
466 cx_large,
467 cy_large,
468 LR_SHARED | LR_DEFAULTCOLOR);
469 if (!hLg)
470 {
471 ERR("Failed to load IDI_SHELL_DOCUMENT icon2!\n");
472 DestroyIcon(hSm);
473 return FALSE;
474 }
475 }
476 else
477 {
478 ERR("Failed to load ShellBigIconList\n");
479 return FALSE;
480 }
481
482 SIC_IconAppend(swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, 0);
483 SIC_IconAppend(swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, 0);
484
485 TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
486
487 return TRUE;
488 }
489 /*************************************************************************
490 * SIC_Destroy
491 *
492 * frees the cache
493 */
494 static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam )
495 {
496 HeapFree(GetProcessHeap(), 0, ((LPSIC_ENTRY)ptr)->sSourceFile);
497 SHFree(ptr);
498 return TRUE;
499 }
500
501 void SIC_Destroy(void)
502 {
503 TRACE("\n");
504
505 EnterCriticalSection(&SHELL32_SicCS);
506
507 if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
508
509 sic_hdpa = NULL;
510 ImageList_Destroy(ShellSmallIconList);
511 ShellSmallIconList = 0;
512 ImageList_Destroy(ShellBigIconList);
513 ShellBigIconList = 0;
514
515 LeaveCriticalSection(&SHELL32_SicCS);
516 //DeleteCriticalSection(&SHELL32_SicCS); //static
517 }
518
519 /*****************************************************************************
520 * SIC_LoadOverlayIcon [internal]
521 *
522 * Load a shell overlay icon and return its icon cache index.
523 */
524 static int SIC_LoadOverlayIcon(int icon_idx)
525 {
526 WCHAR buffer[1024], wszIdx[8];
527 HKEY hKeyShellIcons;
528 LPCWSTR iconPath;
529 int iconIdx;
530
531 static const WCHAR wszShellIcons[] = {
532 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
533 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
534 'E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','I','c','o','n','s',0
535 };
536 static const WCHAR wszNumFmt[] = {'%','d',0};
537
538 iconPath = swShell32Name; /* default: load icon from shell32.dll */
539 iconIdx = icon_idx;
540
541 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszShellIcons, 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
542 {
543 DWORD count = sizeof(buffer);
544
545 swprintf(wszIdx, wszNumFmt, icon_idx);
546
547 /* read icon path and index */
548 if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
549 {
550 LPWSTR p = wcschr(buffer, ',');
551
552 if (p)
553 *p++ = 0;
554
555 iconPath = buffer;
556 iconIdx = _wtoi(p);
557 }
558
559 RegCloseKey(hKeyShellIcons);
560 }
561
562 return SIC_LoadIcon(iconPath, iconIdx, 0);
563 }
564
565 /*************************************************************************
566 * Shell_GetImageLists [SHELL32.71]
567 *
568 * PARAMETERS
569 * imglist[1|2] [OUT] pointer which receives imagelist handles
570 *
571 */
572 BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList)
573 { TRACE("(%p,%p)\n",lpBigList,lpSmallList);
574 if (lpBigList)
575 { *lpBigList = ShellBigIconList;
576 }
577 if (lpSmallList)
578 { *lpSmallList = ShellSmallIconList;
579 }
580
581 return TRUE;
582 }
583 /*************************************************************************
584 * PidlToSicIndex [INTERNAL]
585 *
586 * PARAMETERS
587 * sh [IN] IShellFolder
588 * pidl [IN]
589 * bBigIcon [IN]
590 * uFlags [IN] GIL_*
591 * pIndex [OUT] index within the SIC
592 *
593 */
594 BOOL PidlToSicIndex (
595 IShellFolder * sh,
596 LPCITEMIDLIST pidl,
597 BOOL bBigIcon,
598 UINT uFlags,
599 int * pIndex)
600 {
601 IExtractIconW *ei;
602 WCHAR szIconFile[MAX_PATH]; /* file containing the icon */
603 INT iSourceIndex; /* index or resID(negated) in this file */
604 BOOL ret = FALSE;
605 UINT dwFlags = 0;
606 int iShortcutDefaultIndex = INVALID_INDEX;
607
608 TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
609
610 if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
611 {
612 if (SUCCEEDED(ei->lpVtbl->GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
613 {
614 *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
615 ret = TRUE;
616 }
617 ei->lpVtbl->Release(ei);
618 }
619
620 if (INVALID_INDEX == *pIndex) /* default icon when failed */
621 {
622 if (0 == (uFlags & GIL_FORSHORTCUT))
623 {
624 *pIndex = 0;
625 }
626 else
627 {
628 if (INVALID_INDEX == iShortcutDefaultIndex)
629 {
630 iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT);
631 }
632 *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0);
633 }
634 }
635
636 return ret;
637
638 }
639
640 /*************************************************************************
641 * SHMapPIDLToSystemImageListIndex [SHELL32.77]
642 *
643 * PARAMETERS
644 * sh [IN] pointer to an instance of IShellFolder
645 * pidl [IN]
646 * pIndex [OUT][OPTIONAL] SIC index for big icon
647 *
648 */
649 int WINAPI SHMapPIDLToSystemImageListIndex(
650 IShellFolder *sh,
651 LPCITEMIDLIST pidl,
652 int *pIndex)
653 {
654 int Index;
655 UINT uGilFlags = 0;
656
657 TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
658 pdump(pidl);
659
660 if (SHELL_IsShortcut(pidl))
661 uGilFlags |= GIL_FORSHORTCUT;
662
663 if (pIndex)
664 if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
665 *pIndex = -1;
666
667 if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
668 return -1;
669
670 return Index;
671 }
672
673 /*************************************************************************
674 * SHMapIDListToImageListIndexAsync [SHELL32.148]
675 */
676 HRESULT WINAPI SHMapIDListToImageListIndexAsync(IUnknown *pts, IShellFolder *psf,
677 LPCITEMIDLIST pidl, UINT flags,
678 void *pfn, void *pvData, void *pvHint,
679 int *piIndex, int *piIndexSel)
680 {
681 FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n",
682 pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel);
683 return E_FAIL;
684 }
685
686 /*************************************************************************
687 * Shell_GetCachedImageIndex [SHELL32.72]
688 *
689 */
690 INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, UINT bSimulateDoc)
691 {
692 INT ret, len;
693 LPWSTR szTemp;
694
695 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
696
697 len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 );
698 szTemp = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
699 MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );
700
701 ret = SIC_GetIconIndex( szTemp, nIndex, 0 );
702
703 HeapFree( GetProcessHeap(), 0, szTemp );
704
705 return ret;
706 }
707
708 INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, UINT bSimulateDoc)
709 {
710 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
711
712 return SIC_GetIconIndex(szPath, nIndex, 0);
713 }
714
715 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
716 { if( SHELL_OsIsUnicode())
717 return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
718 return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
719 }
720
721 /*************************************************************************
722 * ExtractIconExW [SHELL32.@]
723 * RETURNS
724 * 0 no icon found
725 * -1 file is not valid
726 * or number of icons extracted
727 */
728 UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
729 {
730 /* get entry point of undocumented function PrivateExtractIconExW() in user32 */
731 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
732 static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL;
733
734 if (!PrivateExtractIconExW) {
735 HMODULE hUser32 = GetModuleHandleA("user32");
736 PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW");
737
738 if (!PrivateExtractIconExW)
739 return 0;
740 }
741 #endif
742
743 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons);
744
745 return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
746 }
747
748 /*************************************************************************
749 * ExtractIconExA [SHELL32.@]
750 */
751 UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
752 {
753 UINT ret = 0;
754 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
755 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
756
757 TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
758
759 if (lpwstrFile)
760 {
761 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
762 ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
763 HeapFree(GetProcessHeap(), 0, lpwstrFile);
764 }
765 return ret;
766 }
767
768 /*************************************************************************
769 * ExtractAssociatedIconA (SHELL32.@)
770 *
771 * Return icon for given file (either from file itself or from associated
772 * executable) and patch parameters if needed.
773 */
774 HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
775 {
776 HICON hIcon = NULL;
777 INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
778 /* Note that we need to allocate MAX_PATH, since we are supposed to fill
779 * the correct executable if there is no icon in lpIconPath directly.
780 * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
781 * is large enough too. Yes, I am puking too.
782 */
783 LPWSTR lpIconPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
784
785 TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon);
786
787 if (lpIconPathW)
788 {
789 MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len);
790 hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon);
791 WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL);
792 HeapFree(GetProcessHeap(), 0, lpIconPathW);
793 }
794 return hIcon;
795 }
796
797 /*************************************************************************
798 * ExtractAssociatedIconW (SHELL32.@)
799 *
800 * Return icon for given file (either from file itself or from associated
801 * executable) and patch parameters if needed.
802 */
803 HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon)
804 {
805 HICON hIcon = NULL;
806 WORD wDummyIcon = 0;
807
808 TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon);
809
810 if(lpiIcon == NULL)
811 lpiIcon = &wDummyIcon;
812
813 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
814
815 if( hIcon < (HICON)2 )
816 { if( hIcon == (HICON)1 ) /* no icons found in given file */
817 { WCHAR tempPath[MAX_PATH];
818 HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath);
819
820 if( uRet > (HINSTANCE)32 && tempPath[0] )
821 { wcscpy(lpIconPath,tempPath);
822 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
823 if( hIcon > (HICON)2 )
824 return hIcon;
825 }
826 }
827
828 if( hIcon == (HICON)1 )
829 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
830 else
831 *lpiIcon = 6; /* generic icon - found nothing */
832
833 if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH))
834 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon));
835 }
836 return hIcon;
837 }
838
839 /*************************************************************************
840 * ExtractAssociatedIconExW (SHELL32.@)
841 *
842 * Return icon for given file (either from file itself or from associated
843 * executable) and patch parameters if needed.
844 */
845 HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
846 {
847 FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId);
848 return 0;
849 }
850
851 /*************************************************************************
852 * ExtractAssociatedIconExA (SHELL32.@)
853 *
854 * Return icon for given file (either from file itself or from associated
855 * executable) and patch parameters if needed.
856 */
857 HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
858 {
859 HICON ret;
860 INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 );
861 LPWSTR lpwstrFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
862
863 TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId);
864
865 MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len );
866 ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId);
867 HeapFree(GetProcessHeap(), 0, lpwstrFile);
868 return ret;
869 }
870
871
872 /****************************************************************************
873 * SHDefExtractIconW [SHELL32.@]
874 */
875 HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags,
876 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
877 {
878 UINT ret;
879 HICON hIcons[2];
880 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
881
882 ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR);
883 /* FIXME: deal with uFlags parameter which contains GIL_ flags */
884 if (ret == 0xFFFFFFFF)
885 return E_FAIL;
886 if (ret > 0) {
887 if (phiconLarge)
888 *phiconLarge = hIcons[0];
889 else
890 DestroyIcon(hIcons[0]);
891 if (phiconSmall)
892 *phiconSmall = hIcons[1];
893 else
894 DestroyIcon(hIcons[1]);
895 return S_OK;
896 }
897 return S_FALSE;
898 }
899
900 /****************************************************************************
901 * SHDefExtractIconA [SHELL32.@]
902 */
903 HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags,
904 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
905 {
906 HRESULT ret;
907 INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0);
908 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
909
910 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
911
912 MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len);
913 ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
914 HeapFree(GetProcessHeap(), 0, lpwstrFile);
915 return ret;
916 }
917
918 /****************************************************************************
919 * SHGetIconOverlayIndexA [SHELL32.@]
920 *
921 * Returns the index of the overlay icon in the system image list.
922 */
923 INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex)
924 {
925 FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex);
926
927 return -1;
928 }
929
930 /****************************************************************************
931 * SHGetIconOverlayIndexW [SHELL32.@]
932 *
933 * Returns the index of the overlay icon in the system image list.
934 */
935 INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
936 {
937 FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex);
938
939 return -1;
940 }