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