Various cosmetic changes.
[wine] / dlls / shell32 / iconcache.c
1 /*
2  *      shell icon cache (SIC)
3  *
4  */
5 #include <string.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 #include "winbase.h"
9 #include "windef.h"
10 #include "wingdi.h"
11 #include "winuser.h"
12 #include "winreg.h"
13 #include "wine/winuser16.h"
14 #include "wine/winbase16.h"
15 #include "heap.h"
16 #include "debugtools.h"
17
18 #include "shellapi.h"
19 #include "shlguid.h"
20 #include "pidl.h"
21 #include "shell32_main.h"
22 #include "undocshell.h"
23 #include "shlwapi.h"
24
25 DEFAULT_DEBUG_CHANNEL(shell);
26
27 /********************** THE ICON CACHE ********************************/
28
29 #define INVALID_INDEX -1
30
31 typedef struct
32 {
33         LPSTR sSourceFile;      /* file (not path!) containing the icon */
34         DWORD dwSourceIndex;    /* index within the file, if it is a resoure ID it will be negated */
35         DWORD dwListIndex;      /* index within the iconlist */
36         DWORD dwFlags;          /* GIL_* flags */
37         DWORD dwAccessTime;
38 } SIC_ENTRY, * LPSIC_ENTRY;
39
40 static HDPA             sic_hdpa = 0;
41 static CRITICAL_SECTION SHELL32_SicCS = CRITICAL_SECTION_INIT("SHELL32_SicCS");
42
43 /*****************************************************************************
44  * SIC_CompareEntries
45  *
46  * NOTES
47  *  Callback for DPA_Search
48  */
49 static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
50 {       TRACE("%p %p\n", p1, p2);
51
52         if (((LPSIC_ENTRY)p1)->dwSourceIndex != ((LPSIC_ENTRY)p2)->dwSourceIndex) /* first the faster one*/
53           return 1;
54
55         if (strcasecmp(((LPSIC_ENTRY)p1)->sSourceFile,((LPSIC_ENTRY)p2)->sSourceFile))
56           return 1;
57
58         return 0;  
59 }
60 /*****************************************************************************
61  * SIC_IconAppend                       [internal]
62  *
63  * NOTES
64  *  appends a icon pair to the end of the cache
65  */
66 static INT SIC_IconAppend (LPCSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon)
67 {       LPSIC_ENTRY lpsice;
68         INT ret, index, index1;
69         char *path;
70         TRACE("%s %i %x %x\n", sSourceFile, dwSourceIndex, hSmallIcon ,hBigIcon);
71
72         lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY));
73
74         path = PathFindFileNameA(sSourceFile);
75         lpsice->sSourceFile = HeapAlloc( GetProcessHeap(), 0, strlen(path)+1 );
76         strcpy( lpsice->sSourceFile, path );
77
78         lpsice->dwSourceIndex = dwSourceIndex;
79         
80         EnterCriticalSection(&SHELL32_SicCS);
81
82         index = pDPA_InsertPtr(sic_hdpa, 0x7fff, lpsice);
83         if ( INVALID_INDEX == index )
84         {
85           SHFree(lpsice);
86           ret = INVALID_INDEX;
87         }
88         else
89         {
90           index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon);
91           index1= ImageList_AddIcon (ShellBigIconList, hBigIcon);
92
93           if (index!=index1)
94           {
95             FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1);
96           }
97           lpsice->dwListIndex = index;
98           ret = lpsice->dwListIndex;
99         }
100
101         LeaveCriticalSection(&SHELL32_SicCS);
102         return ret;     
103 }
104 /****************************************************************************
105  * SIC_LoadIcon                         [internal]
106  *
107  * NOTES
108  *  gets small/big icon by number from a file
109  */
110 static INT SIC_LoadIcon (LPCSTR sSourceFile, INT dwSourceIndex)
111 {       HICON   hiconLarge=0;
112         HICON   hiconSmall=0;
113
114         PrivateExtractIconsA( sSourceFile, dwSourceIndex, 32, 32, &hiconLarge, 0, 1, 0 ); 
115         PrivateExtractIconsA( sSourceFile, dwSourceIndex, 16, 16, &hiconSmall, 0, 1, 0 ); 
116
117         if ( !hiconLarge ||  !hiconSmall)
118         {
119           WARN("failure loading icon %i from %s (%x %x)\n", dwSourceIndex, sSourceFile, hiconLarge, hiconSmall);
120           return -1;
121         }
122         return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge);             
123 }
124 /*****************************************************************************
125  * SIC_GetIconIndex                     [internal]
126  *
127  * Parameters
128  *      sSourceFile     [IN]    filename of file containing the icon
129  *      index           [IN]    index/resID (negated) in this file
130  *
131  * NOTES
132  *  look in the cache for a proper icon. if not available the icon is taken
133  *  from the file and cached
134  */
135 INT SIC_GetIconIndex (LPCSTR sSourceFile, INT dwSourceIndex )
136 {       SIC_ENTRY sice;
137         INT ret, index = INVALID_INDEX;
138                 
139         TRACE("%s %i\n", sSourceFile, dwSourceIndex);
140
141         sice.sSourceFile = PathFindFileNameA(sSourceFile);
142         sice.dwSourceIndex = dwSourceIndex;
143         
144         EnterCriticalSection(&SHELL32_SicCS);
145
146         if (NULL != pDPA_GetPtr (sic_hdpa, 0))
147         {
148           index = pDPA_Search (sic_hdpa, &sice, -1L, SIC_CompareEntries, 0, 0);
149         }
150
151         if ( INVALID_INDEX == index )
152         {
153           ret = SIC_LoadIcon (sSourceFile, dwSourceIndex);
154         }
155         else
156         {
157           TRACE("-- found\n");
158           ret = ((LPSIC_ENTRY)pDPA_GetPtr(sic_hdpa, index))->dwListIndex;
159         }
160
161         LeaveCriticalSection(&SHELL32_SicCS);
162         return ret;
163 }
164 /****************************************************************************
165  * SIC_GetIcon                          [internal]
166  *
167  * NOTES
168  *  retrieves the specified icon from the iconcache. if not found tries to load the icon
169  */
170 static HICON WINE_UNUSED SIC_GetIcon (LPCSTR sSourceFile, INT dwSourceIndex, BOOL bSmallIcon )
171 {       INT index;
172
173         TRACE("%s %i\n", sSourceFile, dwSourceIndex);
174
175         index = SIC_GetIconIndex(sSourceFile, dwSourceIndex);
176
177         if (INVALID_INDEX == index)
178         {
179           return INVALID_INDEX;
180         }
181
182         if (bSmallIcon)
183           return ImageList_GetIcon(ShellSmallIconList, index, ILD_NORMAL);
184         return ImageList_GetIcon(ShellBigIconList, index, ILD_NORMAL);
185         
186 }
187 /*****************************************************************************
188  * SIC_Initialize                       [internal]
189  *
190  * NOTES
191  *  hack to load the resources from the shell32.dll under a different dll name 
192  *  will be removed when the resource-compiler is ready
193  */
194 BOOL SIC_Initialize(void)
195 {
196         HICON           hSm, hLg;
197         UINT            index;
198
199         TRACE("\n");
200
201         if (sic_hdpa)   /* already initialized?*/
202           return TRUE;
203           
204         sic_hdpa = pDPA_Create(16);
205         
206         if (!sic_hdpa)
207         {
208           return(FALSE);
209         }
210
211         ShellSmallIconList = ImageList_Create(16,16,ILC_COLORDDB | ILC_MASK,0,0x20);
212         ShellBigIconList = ImageList_Create(32,32,ILC_COLORDDB | ILC_MASK,0,0x20);
213
214         ImageList_SetBkColor(ShellSmallIconList, GetSysColor(COLOR_WINDOW));
215         ImageList_SetBkColor(ShellBigIconList, GetSysColor(COLOR_WINDOW));
216
217         for (index=1; index<39; index++)
218         {
219           hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, 16, 16,LR_SHARED);
220           hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, 32, 32,LR_SHARED);
221
222           if(!hSm)
223           {
224             hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(0), IMAGE_ICON, 16, 16,LR_SHARED);
225             hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(0), IMAGE_ICON, 32, 32,LR_SHARED);
226           }
227           SIC_IconAppend ("shell32.dll", index, hSm, hLg);
228         }
229
230         TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
231
232         return TRUE;
233 }
234 /*************************************************************************
235  * SIC_Destroy
236  *
237  * frees the cache
238  */
239 void SIC_Destroy(void)
240 {
241         LPSIC_ENTRY lpsice;
242         int i;
243
244         TRACE("\n");
245
246         EnterCriticalSection(&SHELL32_SicCS);
247
248         if (sic_hdpa && NULL != pDPA_GetPtr (sic_hdpa, 0))
249         {
250           for (i=0; i < pDPA_GetPtrCount(sic_hdpa); ++i)
251           {
252             lpsice = pDPA_GetPtr(sic_hdpa, i); 
253             SHFree(lpsice);
254           }
255           pDPA_Destroy(sic_hdpa);
256         }
257
258         sic_hdpa = NULL;
259
260         LeaveCriticalSection(&SHELL32_SicCS);
261         DeleteCriticalSection(&SHELL32_SicCS);
262 }
263 /*************************************************************************
264  * Shell_GetImageList                   [SHELL32.71]
265  *
266  * PARAMETERS
267  *  imglist[1|2] [OUT] pointer which recive imagelist handles
268  *
269  */
270 BOOL WINAPI Shell_GetImageList(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList)
271 {       TRACE("(%p,%p)\n",lpBigList,lpSmallList);
272         if (lpBigList)
273         { *lpBigList = ShellBigIconList;
274         }
275         if (lpSmallList)
276         { *lpSmallList = ShellSmallIconList;
277         }
278
279         return TRUE;
280 }
281 /*************************************************************************
282  * PidlToSicIndex                       [INTERNAL]
283  *
284  * PARAMETERS
285  *      sh      [IN]    IShellFolder
286  *      pidl    [IN]
287  *      bBigIcon [IN]
288  *      uFlags  [IN]    GIL_*
289  *      pIndex  [OUT]   index within the SIC
290  *
291  */
292 BOOL PidlToSicIndex (
293         IShellFolder * sh,
294         LPITEMIDLIST pidl,
295         BOOL bBigIcon,
296         UINT uFlags,
297         UINT * pIndex)
298 {       
299         IExtractIconA   *ei;
300         char            szIconFile[MAX_PATH];   /* file containing the icon */
301         INT             iSourceIndex;           /* index or resID(negated) in this file */
302         BOOL            ret = FALSE;
303         UINT            dwFlags = 0;
304         
305         TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
306
307         if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconA, 0, (void **)&ei)))
308         {
309           if (SUCCEEDED(IExtractIconA_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
310           {
311             *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex);
312             ret = TRUE;
313           }
314           IExtractIconA_Release(ei);
315         }
316
317         if (INVALID_INDEX == *pIndex)   /* default icon when failed */
318           *pIndex = 1;
319
320         return ret;
321
322 }
323
324 /*************************************************************************
325  * SHMapPIDLToSystemImageListIndex      [SHELL32.77]
326  *
327  * PARAMETERS
328  *      sh      [IN]            pointer to an instance of IShellFolder 
329  *      pidl    [IN]
330  *      pIndex  [OUT][OPTIONAL] SIC index for big icon
331  *
332  */
333 int WINAPI SHMapPIDLToSystemImageListIndex(
334         LPSHELLFOLDER sh,
335         LPCITEMIDLIST pidl,
336         UINT * pIndex)
337 {
338         UINT    Index;
339
340         TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
341         pdump(pidl);
342         
343         if (pIndex)
344           PidlToSicIndex ( sh, pidl, 1, 0, pIndex);
345         PidlToSicIndex ( sh, pidl, 0, 0, &Index);
346         return Index;
347 }
348
349 /*************************************************************************
350  * Shell_GetCachedImageIndex            [SHELL32.72]
351  *
352  */
353 INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateDoc) 
354 {
355         WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
356         return SIC_GetIconIndex(szPath, nIndex);
357 }
358
359 INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulateDoc) 
360 {       INT ret;
361         LPSTR sTemp = HEAP_strdupWtoA (GetProcessHeap(),0,szPath);
362         
363         WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
364
365         ret = SIC_GetIconIndex(sTemp, nIndex);
366         HeapFree(GetProcessHeap(),0,sTemp);
367         return ret;
368 }
369
370 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
371 {       if( SHELL_OsIsUnicode())
372           return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
373         return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
374 }
375
376 /*************************************************************************
377  * ExtractIconEx                        [SHELL32.@]
378  */
379 HICON WINAPI ExtractIconExAW ( LPCVOID lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons )
380 {       if (SHELL_OsIsUnicode())
381           return ExtractIconExW ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
382         return ExtractIconExA ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
383 }
384 /*************************************************************************
385  * ExtractIconExA                       [SHELL32.@]
386  * RETURNS
387  *  0 no icon found 
388  *  1 file is not valid
389  *  HICON handle of a icon (phiconLarge/Small == NULL)
390  */
391 HICON WINAPI ExtractIconExA ( LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons )
392 {       HICON ret=0;
393         
394         TRACE("file=%s idx=%i %p %p num=%i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons );
395
396         if (nIconIndex==-1)     /* Number of icons requested */
397             return PrivateExtractIconsA( lpszFile, -1, 0, 0, NULL, 0, 0, 0 );
398
399         if (phiconLarge)
400         {
401           ret = PrivateExtractIconsA( lpszFile, nIconIndex, 32, 32, phiconLarge, 0, nIcons, 0 );
402           if ( nIcons==1)
403           { ret = phiconLarge[0];           
404           }
405         }
406
407         /* if no pointers given and one icon expected, return the handle directly*/
408         if (!phiconLarge && !phiconSmall && nIcons==1 )
409           phiconSmall = &ret;
410         
411         if (phiconSmall)
412         {
413           ret = PrivateExtractIconsA( lpszFile, nIconIndex, 16, 16, phiconSmall, 0, nIcons, 0 );
414           if ( nIcons==1 )
415           { ret = phiconSmall[0];
416           }
417         }
418
419         return ret;
420 }
421 /*************************************************************************
422  * ExtractIconExW                       [SHELL32.@]
423  */
424 HICON WINAPI ExtractIconExW ( LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons )
425 {       LPSTR sFile;
426         DWORD ret;
427         
428         TRACE("file=%s idx=%i %p %p num=%i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons );
429
430         sFile = HEAP_strdupWtoA (GetProcessHeap(),0,lpszFile);
431         ret = ExtractIconExA ( sFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
432         HeapFree(GetProcessHeap(),0,sFile);
433         return ret;
434 }