a57c33e52c6673d9a07b0d01bae90fc5f939ca0c
[reactos.git] / reactos / 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 color bitmap to the target */
175 if (! BitBlt(TargetDC, 0, 0, SourceBitmapInfo.bmWidth, SourceBitmapInfo.bmHeight,
176 SourceDC, 0, 0, SRCCOPY)) goto fail;
177
178 /* Copy the source xor bitmap to the target and clear out part of it by using
179 the shortcut mask */
180 if (NULL == SelectObject(ShortcutDC, ShortcutIconInfo.hbmColor)) goto fail;
181 if (!MaskBlt(TargetDC, 0, SourceBitmapInfo.bmHeight - ShortcutBitmapInfo.bmHeight,
182 ShortcutBitmapInfo.bmWidth, ShortcutBitmapInfo.bmHeight,
183 ShortcutDC, 0, 0, ShortcutIconInfo.hbmMask, 0, 0,
184 MAKEROP4(SRCCOPY, 0xAA0000)))
185 {
186 goto fail;
187 }
188
189 /* Clean up, we're not goto'ing to 'fail' after this so we can be lazy and not set
190 handles to NULL */
191 SelectObject(TargetDC, OldTargetBitmap);
192 DeleteObject(TargetDC);
193 SelectObject(ShortcutDC, OldShortcutBitmap);
194 DeleteObject(ShortcutDC);
195 SelectObject(SourceDC, OldSourceBitmap);
196 DeleteObject(SourceDC);
197
198 /* Create the icon using the bitmaps prepared earlier */
199 TargetIcon = CreateIconIndirect(&TargetIconInfo);
200
201 /* CreateIconIndirect copies the bitmaps, so we can release our bitmaps now */
202 DeleteObject(TargetIconInfo.hbmColor);
203 DeleteObject(TargetIconInfo.hbmMask);
204
205 return TargetIcon;
206
207 fail:
208 /* Clean up scratch resources we created */
209 if (NULL != OldTargetBitmap) SelectObject(TargetDC, OldTargetBitmap);
210 if (NULL != TargetIconInfo.hbmColor) DeleteObject(TargetIconInfo.hbmColor);
211 if (NULL != TargetIconInfo.hbmMask) DeleteObject(TargetIconInfo.hbmMask);
212 if (NULL != TargetDC) DeleteObject(TargetDC);
213 if (NULL != OldShortcutBitmap) SelectObject(ShortcutDC, OldShortcutBitmap);
214 if (NULL != ShortcutDC) DeleteObject(ShortcutDC);
215 if (NULL != OldSourceBitmap) SelectObject(SourceDC, OldSourceBitmap);
216 if (NULL != SourceDC) DeleteObject(SourceDC);
217
218 return NULL;
219 }
220
221 /*****************************************************************************
222 * SIC_IconAppend [internal]
223 *
224 * NOTES
225 * appends an icon pair to the end of the cache
226 */
227 static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon, DWORD dwFlags)
228 { LPSIC_ENTRY lpsice;
229 INT ret, index, index1;
230 WCHAR path[MAX_PATH];
231 TRACE("%s %i %p %p\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon ,hBigIcon);
232
233 lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY));
234
235 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
236 lpsice->sSourceFile = HeapAlloc( GetProcessHeap(), 0, (wcslen(path)+1)*sizeof(WCHAR) );
237 wcscpy( lpsice->sSourceFile, path );
238
239 lpsice->dwSourceIndex = dwSourceIndex;
240 lpsice->dwFlags = dwFlags;
241
242 EnterCriticalSection(&SHELL32_SicCS);
243
244 index = DPA_InsertPtr(sic_hdpa, 0x7fff, lpsice);
245 if ( INVALID_INDEX == index )
246 {
247 HeapFree(GetProcessHeap(), 0, lpsice->sSourceFile);
248 SHFree(lpsice);
249 ret = INVALID_INDEX;
250 }
251 else
252 {
253 index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon);
254 index1= ImageList_AddIcon (ShellBigIconList, hBigIcon);
255
256 if (index!=index1)
257 {
258 FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1);
259 }
260 lpsice->dwListIndex = index;
261 ret = lpsice->dwListIndex;
262 }
263
264 LeaveCriticalSection(&SHELL32_SicCS);
265 return ret;
266 }
267 /****************************************************************************
268 * SIC_LoadIcon [internal]
269 *
270 * NOTES
271 * gets small/big icon by number from a file
272 */
273 static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags)
274 { HICON hiconLarge=0;
275 HICON hiconSmall=0;
276 HICON hiconLargeShortcut;
277 HICON hiconSmallShortcut;
278
279 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
280 static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL;
281
282 if (!PrivateExtractIconExW) {
283 HMODULE hUser32 = GetModuleHandleA("user32");
284 PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW");
285 }
286
287 if (PrivateExtractIconExW)
288 PrivateExtractIconExW(sSourceFile, dwSourceIndex, &hiconLarge, &hiconSmall, 1);
289 else
290 #endif
291 {
292 PrivateExtractIconsW(sSourceFile, dwSourceIndex, 32, 32, &hiconLarge, NULL, 1, 0);
293 PrivateExtractIconsW(sSourceFile, dwSourceIndex, 16, 16, &hiconSmall, NULL, 1, 0);
294 }
295
296 if ( !hiconLarge || !hiconSmall)
297 {
298 WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall);
299 return -1;
300 }
301
302 if (0 != (dwFlags & GIL_FORSHORTCUT))
303 {
304 hiconLargeShortcut = SIC_OverlayShortcutImage(hiconLarge, TRUE);
305 hiconSmallShortcut = SIC_OverlayShortcutImage(hiconSmall, FALSE);
306 if (NULL != hiconLargeShortcut && NULL != hiconSmallShortcut)
307 {
308 hiconLarge = hiconLargeShortcut;
309 hiconSmall = hiconSmallShortcut;
310 }
311 else
312 {
313 WARN("Failed to create shortcut overlayed icons\n");
314 if (NULL != hiconLargeShortcut) DestroyIcon(hiconLargeShortcut);
315 if (NULL != hiconSmallShortcut) DestroyIcon(hiconSmallShortcut);
316 dwFlags &= ~ GIL_FORSHORTCUT;
317 }
318 }
319
320 return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge, dwFlags);
321 }
322 /*****************************************************************************
323 * SIC_GetIconIndex [internal]
324 *
325 * Parameters
326 * sSourceFile [IN] filename of file containing the icon
327 * index [IN] index/resID (negated) in this file
328 *
329 * NOTES
330 * look in the cache for a proper icon. if not available the icon is taken
331 * from the file and cached
332 */
333 INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex, DWORD dwFlags )
334 {
335 SIC_ENTRY sice;
336 INT ret, index = INVALID_INDEX;
337 WCHAR path[MAX_PATH];
338
339 TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
340
341 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
342 sice.sSourceFile = path;
343 sice.dwSourceIndex = dwSourceIndex;
344 sice.dwFlags = dwFlags;
345
346 EnterCriticalSection(&SHELL32_SicCS);
347
348 if (NULL != DPA_GetPtr (sic_hdpa, 0))
349 {
350 /* search linear from position 0*/
351 index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
352 }
353
354 if ( INVALID_INDEX == index )
355 {
356 ret = SIC_LoadIcon (sSourceFile, dwSourceIndex, dwFlags);
357 }
358 else
359 {
360 TRACE("-- found\n");
361 ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex;
362 }
363
364 LeaveCriticalSection(&SHELL32_SicCS);
365 return ret;
366 }
367 /*****************************************************************************
368 * SIC_Initialize [internal]
369 */
370 BOOL SIC_Initialize(void)
371 {
372 HICON hSm = NULL, hLg = NULL;
373 INT cx_small, cy_small;
374 INT cx_large, cy_large;
375 HDC hDC;
376 INT bpp;
377 DWORD ilMask;
378
379 TRACE("Entered SIC_Initialize\n");
380
381 if (sic_hdpa)
382 {
383 TRACE("Icon cache already initialized\n");
384 return TRUE;
385 }
386
387 sic_hdpa = DPA_Create(16);
388 if (!sic_hdpa)
389 {
390 return FALSE;
391 }
392
393 hDC = CreateICW(L"DISPLAY", NULL, NULL, NULL);
394 if (!hDC)
395 {
396 ERR("Failed to create information context (error %d)\n", GetLastError());
397 return FALSE;
398 }
399
400 bpp = GetDeviceCaps(hDC, BITSPIXEL);
401 ReleaseDC(NULL, hDC);
402
403 if (bpp <= 4)
404 ilMask = ILC_COLOR4;
405 else if (bpp <= 8)
406 ilMask = ILC_COLOR8;
407 else if (bpp <= 16)
408 ilMask = ILC_COLOR16;
409 else if (bpp <= 24)
410 ilMask = ILC_COLOR24;
411 else if (bpp <= 32)
412 ilMask = ILC_COLOR32;
413 else
414 ilMask = ILC_COLOR;
415
416 ilMask |= ILC_MASK;
417
418 cx_small = GetSystemMetrics(SM_CXSMICON);
419 cy_small = GetSystemMetrics(SM_CYSMICON);
420 cx_large = GetSystemMetrics(SM_CXICON);
421 cy_large = GetSystemMetrics(SM_CYICON);
422
423 ShellSmallIconList = ImageList_Create(cx_small,
424 cy_small,
425 ilMask,
426 100,
427 100);
428
429 ShellBigIconList = ImageList_Create(cx_large,
430 cy_large,
431 ilMask,
432 100,
433 100);
434 if (ShellSmallIconList)
435 {
436 /* Load the document icon, which is used as the default if an icon isn't found. */
437 hSm = (HICON)LoadImageW(shell32_hInstance,
438 MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT),
439 IMAGE_ICON,
440 cx_small,
441 cy_small,
442 LR_SHARED | LR_DEFAULTCOLOR);
443 if (!hSm)
444 {
445 ERR("Failed to load IDI_SHELL_DOCUMENT icon1!\n");
446 return FALSE;
447 }
448 }
449 else
450 {
451 ERR("Failed to load ShellSmallIconList\n");
452 return FALSE;
453 }
454
455 if (ShellBigIconList)
456 {
457 hLg = (HICON)LoadImageW(shell32_hInstance,
458 MAKEINTRESOURCEW(IDI_SHELL_DOCUMENT),
459 IMAGE_ICON,
460 cx_large,
461 cy_large,
462 LR_SHARED | LR_DEFAULTCOLOR);
463 if (!hLg)
464 {
465 ERR("Failed to load IDI_SHELL_DOCUMENT icon2!\n");
466 DestroyIcon(hSm);
467 return FALSE;
468 }
469 }
470 else
471 {
472 ERR("Failed to load ShellBigIconList\n");
473 return FALSE;
474 }
475
476 SIC_IconAppend(swShell32Name, IDI_SHELL_DOCUMENT-1, hSm, hLg, 0);
477 SIC_IconAppend(swShell32Name, -IDI_SHELL_DOCUMENT, hSm, hLg, 0);
478
479 TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
480
481 return TRUE;
482 }
483 /*************************************************************************
484 * SIC_Destroy
485 *
486 * frees the cache
487 */
488 static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam )
489 {
490 HeapFree(GetProcessHeap(), 0, ((LPSIC_ENTRY)ptr)->sSourceFile);
491 SHFree(ptr);
492 return TRUE;
493 }
494
495 void SIC_Destroy(void)
496 {
497 TRACE("\n");
498
499 EnterCriticalSection(&SHELL32_SicCS);
500
501 if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
502
503 sic_hdpa = NULL;
504 ImageList_Destroy(ShellSmallIconList);
505 ShellSmallIconList = 0;
506 ImageList_Destroy(ShellBigIconList);
507 ShellBigIconList = 0;
508
509 LeaveCriticalSection(&SHELL32_SicCS);
510 //DeleteCriticalSection(&SHELL32_SicCS); //static
511 }
512
513 /*****************************************************************************
514 * SIC_LoadOverlayIcon [internal]
515 *
516 * Load a shell overlay icon and return its icon cache index.
517 */
518 static int SIC_LoadOverlayIcon(int icon_idx)
519 {
520 WCHAR buffer[1024], wszIdx[8];
521 HKEY hKeyShellIcons;
522 LPCWSTR iconPath;
523 int iconIdx;
524
525 static const WCHAR wszShellIcons[] = {
526 'S','o','f','t','w','a','r','e','\\','M','i','c','r','o','s','o','f','t','\\',
527 'W','i','n','d','o','w','s','\\','C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
528 'E','x','p','l','o','r','e','r','\\','S','h','e','l','l',' ','I','c','o','n','s',0
529 };
530 static const WCHAR wszNumFmt[] = {'%','d',0};
531
532 iconPath = swShell32Name; /* default: load icon from shell32.dll */
533 iconIdx = icon_idx;
534
535 if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, wszShellIcons, 0, KEY_READ, &hKeyShellIcons) == ERROR_SUCCESS)
536 {
537 DWORD count = sizeof(buffer);
538
539 swprintf(wszIdx, wszNumFmt, icon_idx);
540
541 /* read icon path and index */
542 if (RegQueryValueExW(hKeyShellIcons, wszIdx, NULL, NULL, (LPBYTE)buffer, &count) == ERROR_SUCCESS)
543 {
544 LPWSTR p = wcschr(buffer, ',');
545
546 if (p)
547 *p++ = 0;
548
549 iconPath = buffer;
550 iconIdx = _wtoi(p);
551 }
552
553 RegCloseKey(hKeyShellIcons);
554 }
555
556 return SIC_LoadIcon(iconPath, iconIdx, 0);
557 }
558
559 /*************************************************************************
560 * Shell_GetImageLists [SHELL32.71]
561 *
562 * PARAMETERS
563 * imglist[1|2] [OUT] pointer which receives imagelist handles
564 *
565 */
566 BOOL WINAPI Shell_GetImageLists(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList)
567 { TRACE("(%p,%p)\n",lpBigList,lpSmallList);
568 if (lpBigList)
569 { *lpBigList = ShellBigIconList;
570 }
571 if (lpSmallList)
572 { *lpSmallList = ShellSmallIconList;
573 }
574
575 return TRUE;
576 }
577 /*************************************************************************
578 * PidlToSicIndex [INTERNAL]
579 *
580 * PARAMETERS
581 * sh [IN] IShellFolder
582 * pidl [IN]
583 * bBigIcon [IN]
584 * uFlags [IN] GIL_*
585 * pIndex [OUT] index within the SIC
586 *
587 */
588 BOOL PidlToSicIndex (
589 IShellFolder * sh,
590 LPCITEMIDLIST pidl,
591 BOOL bBigIcon,
592 UINT uFlags,
593 int * pIndex)
594 {
595 IExtractIconW *ei;
596 WCHAR szIconFile[MAX_PATH]; /* file containing the icon */
597 INT iSourceIndex; /* index or resID(negated) in this file */
598 BOOL ret = FALSE;
599 UINT dwFlags = 0;
600 int iShortcutDefaultIndex = INVALID_INDEX;
601
602 TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
603
604 if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
605 {
606 if (SUCCEEDED(ei->lpVtbl->GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
607 {
608 *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex, uFlags);
609 ret = TRUE;
610 }
611 ei->lpVtbl->Release(ei);
612 }
613
614 if (INVALID_INDEX == *pIndex) /* default icon when failed */
615 {
616 if (0 == (uFlags & GIL_FORSHORTCUT))
617 {
618 *pIndex = 0;
619 }
620 else
621 {
622 if (INVALID_INDEX == iShortcutDefaultIndex)
623 {
624 iShortcutDefaultIndex = SIC_LoadIcon(swShell32Name, 0, GIL_FORSHORTCUT);
625 }
626 *pIndex = (INVALID_INDEX != iShortcutDefaultIndex ? iShortcutDefaultIndex : 0);
627 }
628 }
629
630 return ret;
631
632 }
633
634 /*************************************************************************
635 * SHMapPIDLToSystemImageListIndex [SHELL32.77]
636 *
637 * PARAMETERS
638 * sh [IN] pointer to an instance of IShellFolder
639 * pidl [IN]
640 * pIndex [OUT][OPTIONAL] SIC index for big icon
641 *
642 */
643 int WINAPI SHMapPIDLToSystemImageListIndex(
644 IShellFolder *sh,
645 LPCITEMIDLIST pidl,
646 int *pIndex)
647 {
648 int Index;
649 UINT uGilFlags = 0;
650
651 TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
652 pdump(pidl);
653
654 if (SHELL_IsShortcut(pidl))
655 uGilFlags |= GIL_FORSHORTCUT;
656
657 if (pIndex)
658 if (!PidlToSicIndex ( sh, pidl, 1, uGilFlags, pIndex))
659 *pIndex = -1;
660
661 if (!PidlToSicIndex ( sh, pidl, 0, uGilFlags, &Index))
662 return -1;
663
664 return Index;
665 }
666
667 /*************************************************************************
668 * SHMapIDListToImageListIndexAsync [SHELL32.148]
669 */
670 HRESULT WINAPI SHMapIDListToImageListIndexAsync(IUnknown *pts, IShellFolder *psf,
671 LPCITEMIDLIST pidl, UINT flags,
672 void *pfn, void *pvData, void *pvHint,
673 int *piIndex, int *piIndexSel)
674 {
675 FIXME("(%p, %p, %p, 0x%08x, %p, %p, %p, %p, %p)\n",
676 pts, psf, pidl, flags, pfn, pvData, pvHint, piIndex, piIndexSel);
677 return E_FAIL;
678 }
679
680 /*************************************************************************
681 * Shell_GetCachedImageIndex [SHELL32.72]
682 *
683 */
684 INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, UINT bSimulateDoc)
685 {
686 INT ret, len;
687 LPWSTR szTemp;
688
689 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
690
691 len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 );
692 szTemp = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
693 MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );
694
695 ret = SIC_GetIconIndex( szTemp, nIndex, 0 );
696
697 HeapFree( GetProcessHeap(), 0, szTemp );
698
699 return ret;
700 }
701
702 INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, UINT bSimulateDoc)
703 {
704 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
705
706 return SIC_GetIconIndex(szPath, nIndex, 0);
707 }
708
709 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
710 { if( SHELL_OsIsUnicode())
711 return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
712 return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
713 }
714
715 /*************************************************************************
716 * ExtractIconExW [SHELL32.@]
717 * RETURNS
718 * 0 no icon found
719 * -1 file is not valid
720 * or number of icons extracted
721 */
722 UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
723 {
724 /* get entry point of undocumented function PrivateExtractIconExW() in user32 */
725 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
726 static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL;
727
728 if (!PrivateExtractIconExW) {
729 HMODULE hUser32 = GetModuleHandleA("user32");
730 PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW");
731
732 if (!PrivateExtractIconExW)
733 return 0;
734 }
735 #endif
736
737 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons);
738
739 return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
740 }
741
742 /*************************************************************************
743 * ExtractIconExA [SHELL32.@]
744 */
745 UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
746 {
747 UINT ret = 0;
748 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
749 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
750
751 TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
752
753 if (lpwstrFile)
754 {
755 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
756 ret = ExtractIconExW(lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
757 HeapFree(GetProcessHeap(), 0, lpwstrFile);
758 }
759 return ret;
760 }
761
762 /*************************************************************************
763 * ExtractAssociatedIconA (SHELL32.@)
764 *
765 * Return icon for given file (either from file itself or from associated
766 * executable) and patch parameters if needed.
767 */
768 HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
769 {
770 HICON hIcon = NULL;
771 INT len = MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, NULL, 0);
772 /* Note that we need to allocate MAX_PATH, since we are supposed to fill
773 * the correct executable if there is no icon in lpIconPath directly.
774 * lpIconPath itself is supposed to be large enough, so make sure lpIconPathW
775 * is large enough too. Yes, I am puking too.
776 */
777 LPWSTR lpIconPathW = HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
778
779 TRACE("%p %s %p\n", hInst, debugstr_a(lpIconPath), lpiIcon);
780
781 if (lpIconPathW)
782 {
783 MultiByteToWideChar(CP_ACP, 0, lpIconPath, -1, lpIconPathW, len);
784 hIcon = ExtractAssociatedIconW(hInst, lpIconPathW, lpiIcon);
785 WideCharToMultiByte(CP_ACP, 0, lpIconPathW, -1, lpIconPath, MAX_PATH , NULL, NULL);
786 HeapFree(GetProcessHeap(), 0, lpIconPathW);
787 }
788 return hIcon;
789 }
790
791 /*************************************************************************
792 * ExtractAssociatedIconW (SHELL32.@)
793 *
794 * Return icon for given file (either from file itself or from associated
795 * executable) and patch parameters if needed.
796 */
797 HICON WINAPI ExtractAssociatedIconW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIcon)
798 {
799 HICON hIcon = NULL;
800 WORD wDummyIcon = 0;
801
802 TRACE("%p %s %p\n", hInst, debugstr_w(lpIconPath), lpiIcon);
803
804 if(lpiIcon == NULL)
805 lpiIcon = &wDummyIcon;
806
807 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
808
809 if( hIcon < (HICON)2 )
810 { if( hIcon == (HICON)1 ) /* no icons found in given file */
811 { WCHAR tempPath[MAX_PATH];
812 HINSTANCE uRet = FindExecutableW(lpIconPath,NULL,tempPath);
813
814 if( uRet > (HINSTANCE)32 && tempPath[0] )
815 { wcscpy(lpIconPath,tempPath);
816 hIcon = ExtractIconW(hInst, lpIconPath, *lpiIcon);
817 if( hIcon > (HICON)2 )
818 return hIcon;
819 }
820 }
821
822 if( hIcon == (HICON)1 )
823 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
824 else
825 *lpiIcon = 6; /* generic icon - found nothing */
826
827 if (GetModuleFileNameW(hInst, lpIconPath, MAX_PATH))
828 hIcon = LoadIconW(hInst, MAKEINTRESOURCEW(*lpiIcon));
829 }
830 return hIcon;
831 }
832
833 /*************************************************************************
834 * ExtractAssociatedIconExW (SHELL32.@)
835 *
836 * Return icon for given file (either from file itself or from associated
837 * executable) and patch parameters if needed.
838 */
839 HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
840 {
841 FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId);
842 return 0;
843 }
844
845 /*************************************************************************
846 * ExtractAssociatedIconExA (SHELL32.@)
847 *
848 * Return icon for given file (either from file itself or from associated
849 * executable) and patch parameters if needed.
850 */
851 HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
852 {
853 HICON ret;
854 INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 );
855 LPWSTR lpwstrFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
856
857 TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId);
858
859 MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len );
860 ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId);
861 HeapFree(GetProcessHeap(), 0, lpwstrFile);
862 return ret;
863 }
864
865
866 /****************************************************************************
867 * SHDefExtractIconW [SHELL32.@]
868 */
869 HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags,
870 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
871 {
872 UINT ret;
873 HICON hIcons[2];
874 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
875
876 ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR);
877 /* FIXME: deal with uFlags parameter which contains GIL_ flags */
878 if (ret == 0xFFFFFFFF)
879 return E_FAIL;
880 if (ret > 0) {
881 if (phiconLarge)
882 *phiconLarge = hIcons[0];
883 else
884 DestroyIcon(hIcons[0]);
885 if (phiconSmall)
886 *phiconSmall = hIcons[1];
887 else
888 DestroyIcon(hIcons[1]);
889 return S_OK;
890 }
891 return S_FALSE;
892 }
893
894 /****************************************************************************
895 * SHDefExtractIconA [SHELL32.@]
896 */
897 HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags,
898 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
899 {
900 HRESULT ret;
901 INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0);
902 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
903
904 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
905
906 MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len);
907 ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
908 HeapFree(GetProcessHeap(), 0, lpwstrFile);
909 return ret;
910 }
911
912 /****************************************************************************
913 * SHGetIconOverlayIndexA [SHELL32.@]
914 *
915 * Returns the index of the overlay icon in the system image list.
916 */
917 INT WINAPI SHGetIconOverlayIndexA(LPCSTR pszIconPath, INT iIconIndex)
918 {
919 FIXME("%s, %d\n", debugstr_a(pszIconPath), iIconIndex);
920
921 return -1;
922 }
923
924 /****************************************************************************
925 * SHGetIconOverlayIndexW [SHELL32.@]
926 *
927 * Returns the index of the overlay icon in the system image list.
928 */
929 INT WINAPI SHGetIconOverlayIndexW(LPCWSTR pszIconPath, INT iIconIndex)
930 {
931 FIXME("%s, %d\n", debugstr_w(pszIconPath), iIconIndex);
932
933 return -1;
934 }