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