SHGetFileInfo32A: get SHGFI_SYSICONINDEX implemented.
[wine] / dlls / shell32 / iconcache.c
1 /*
2  *      shell icon cache (SIC)
3  *
4  *
5  */
6 #include <string.h>
7 #include "windows.h"
8 #include "neexe.h"
9 #include "cursoricon.h"
10 #include "module.h"
11 #include "heap.h"
12 #include "debug.h"
13 #include "sysmetrics.h"
14 #include "winversion.h"
15 #include "shell.h"
16 #include "shlobj.h"
17 #include "pidl.h"
18 #include "shell32_main.h"
19
20 #pragma pack(1)
21
22 typedef struct
23 {
24     BYTE        bWidth;          /* Width, in pixels, of the image      */
25     BYTE        bHeight;         /* Height, in pixels, of the image     */
26     BYTE        bColorCount;     /* Number of colors in image (0 if >=8bpp) */
27     BYTE        bReserved;       /* Reserved ( must be 0)               */
28     WORD        wPlanes;         /* Color Planes                        */
29     WORD        wBitCount;       /* Bits per pixel                      */
30     DWORD       dwBytesInRes;    /* How many bytes in this resource?    */
31     DWORD       dwImageOffset;   /* Where in the file is this image?    */
32 } icoICONDIRENTRY, *LPicoICONDIRENTRY;
33
34 typedef struct
35 {
36     WORD            idReserved;   /* Reserved (must be 0)               */
37     WORD            idType;       /* Resource Type (1 for icons)        */
38     WORD            idCount;      /* How many images?                   */
39     icoICONDIRENTRY idEntries[1]; /* An entry for each image (idCount of 'em) */
40 } icoICONDIR, *LPicoICONDIR;
41
42 #pragma pack(4)
43
44 /*************************************************************************
45  *                              SHELL_GetResourceTable
46  */
47 static DWORD SHELL_GetResourceTable(HFILE32 hFile,LPBYTE *retptr)
48 {       IMAGE_DOS_HEADER        mz_header;
49         char                    magic[4];
50         int                     size;
51
52         TRACE(shell,"\n");  
53
54         *retptr = NULL;
55         _llseek32( hFile, 0, SEEK_SET );
56         if ((_lread32(hFile,&mz_header,sizeof(mz_header)) != sizeof(mz_header)) || (mz_header.e_magic != IMAGE_DOS_SIGNATURE))
57         { if (mz_header.e_cblp == 1)    /* .ICO file ? */
58           { *retptr = (LPBYTE)-1;       /* ICONHEADER.idType, must be 1 */
59             return 1;
60           }
61           else
62             return 0; /* failed */
63         }
64         _llseek32( hFile, mz_header.e_lfanew, SEEK_SET );
65
66         if (_lread32( hFile, magic, sizeof(magic) ) != sizeof(magic))
67           return 0;
68
69         _llseek32( hFile, mz_header.e_lfanew, SEEK_SET);
70
71         if (*(DWORD*)magic  == IMAGE_NT_SIGNATURE)
72           return IMAGE_NT_SIGNATURE;
73
74         if (*(WORD*)magic == IMAGE_OS2_SIGNATURE)
75         { IMAGE_OS2_HEADER      ne_header;
76           LPBYTE                pTypeInfo = (LPBYTE)-1;
77
78           if (_lread32(hFile,&ne_header,sizeof(ne_header))!=sizeof(ne_header))
79             return 0;
80
81           if (ne_header.ne_magic != IMAGE_OS2_SIGNATURE)
82             return 0;
83
84           size = ne_header.rname_tab_offset - ne_header.resource_tab_offset;
85
86           if( size > sizeof(NE_TYPEINFO) )
87           { pTypeInfo = (BYTE*)HeapAlloc( GetProcessHeap(), 0, size);
88             if( pTypeInfo ) 
89             { _llseek32(hFile, mz_header.e_lfanew+ne_header.resource_tab_offset, SEEK_SET);
90               if( _lread32( hFile, (char*)pTypeInfo, size) != size )
91               { HeapFree( GetProcessHeap(), 0, pTypeInfo); 
92                 pTypeInfo = NULL;
93               }
94             }
95           }
96           *retptr = pTypeInfo;
97           return IMAGE_OS2_SIGNATURE;
98         }
99         return 0; /* failed */
100 }
101 /*************************************************************************
102  *                      SHELL_LoadResource
103  */
104 static HGLOBAL16 SHELL_LoadResource(HINSTANCE32 hInst, HFILE32 hFile, NE_NAMEINFO* pNInfo, WORD sizeShift)
105 {       BYTE*  ptr;
106         HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, (DWORD)pNInfo->length << sizeShift);
107
108         TRACE(shell,"\n");
109
110         if( (ptr = (BYTE*)GlobalLock16( handle )) )
111         { _llseek32( hFile, (DWORD)pNInfo->offset << sizeShift, SEEK_SET);
112           _lread32( hFile, (char*)ptr, pNInfo->length << sizeShift);
113           return handle;
114         }
115         return 0;
116 }
117
118 /*************************************************************************
119  *                      ICO_LoadIcon
120  */
121 static HGLOBAL16 ICO_LoadIcon(HINSTANCE32 hInst, HFILE32 hFile, LPicoICONDIRENTRY lpiIDE)
122 {       BYTE*  ptr;
123         HGLOBAL16 handle = DirectResAlloc( hInst, 0x10, lpiIDE->dwBytesInRes);
124         TRACE(shell,"\n");
125         if( (ptr = (BYTE*)GlobalLock16( handle )) )
126         { _llseek32( hFile, lpiIDE->dwImageOffset, SEEK_SET);
127           _lread32( hFile, (char*)ptr, lpiIDE->dwBytesInRes);
128           return handle;
129         }
130         return 0;
131 }
132
133 /*************************************************************************
134  *                      ICO_GetIconDirectory
135  *
136  *  Read .ico file and build phony ICONDIR struct for GetIconID
137  */
138 static HGLOBAL16 ICO_GetIconDirectory(HINSTANCE32 hInst, HFILE32 hFile, LPicoICONDIR* lplpiID ) 
139 {       WORD    id[3];  /* idReserved, idType, idCount */
140         LPicoICONDIR    lpiID;
141         int             i;
142  
143         TRACE(shell,"\n"); 
144         _llseek32( hFile, 0, SEEK_SET );
145         if( _lread32(hFile,(char*)id,sizeof(id)) != sizeof(id) ) 
146           return 0;
147
148         /* check .ICO header 
149         *
150         * - see http://www.microsoft.com/win32dev/ui/icons.htm
151         */
152
153         if( id[0] || id[1] != 1 || !id[2] ) 
154           return 0;
155
156         i = id[2]*sizeof(icoICONDIRENTRY) + sizeof(id);
157
158         lpiID = (LPicoICONDIR)HeapAlloc( GetProcessHeap(), 0, i);
159
160         if( _lread32(hFile,(char*)lpiID->idEntries,i) == i )
161         { HGLOBAL16 handle = DirectResAlloc( hInst, 0x10,id[2]*sizeof(ICONDIRENTRY) + sizeof(id) );
162           if( handle ) 
163           { CURSORICONDIR*     lpID = (CURSORICONDIR*)GlobalLock16( handle );
164             lpID->idReserved = lpiID->idReserved = id[0];
165             lpID->idType = lpiID->idType = id[1];
166             lpID->idCount = lpiID->idCount = id[2];
167             for( i=0; i < lpiID->idCount; i++ )
168             { memcpy((void*)(lpID->idEntries + i),(void*)(lpiID->idEntries + i), sizeof(ICONDIRENTRY) - 2);
169               lpID->idEntries[i].icon.wResId = i;
170             }
171             *lplpiID = lpiID;
172             return handle;
173           }
174         }
175         /* fail */
176
177         HeapFree( GetProcessHeap(), 0, lpiID);
178         return 0;
179 }
180
181 /*************************************************************************
182  *                      InternalExtractIcon             [SHELL.39]
183  *
184  * This abortion is called directly by Progman
185  *  fixme: the icon section is broken (don't have a handle for
186  *    ICO_GetIconDirectory....)
187  *
188  */
189 #define ICO_INVALID_FILE        1
190 #define ICO_NO_ICONS            0
191
192 HGLOBAL32 WINAPI ICO_ExtractIconEx(LPCSTR lpszExeFileName, HICON32* RetPtr, UINT32 nIconIndex, UINT32 n, UINT32 cxDesired, UINT32 cyDesired )
193 {       HGLOBAL32       hRet = ICO_NO_ICONS;
194         LPBYTE          pData;
195         OFSTRUCT        ofs;
196         DWORD           sig;
197         HFILE32         hFile = OpenFile32( lpszExeFileName, &ofs, OF_READ );
198         UINT16          iconDirCount = 0,iconCount = 0;
199         LPBYTE          peimage;
200         HANDLE32        fmapping;
201         
202         TRACE(shell,"(file %s,start %d,extract %d\n", lpszExeFileName, nIconIndex, n);
203
204         if( hFile == HFILE_ERROR32 || !n )
205           return ICO_INVALID_FILE;
206
207         sig = SHELL_GetResourceTable(hFile,&pData);
208
209 /* ico file */
210         if( sig==IMAGE_OS2_SIGNATURE || sig==1 ) /* .ICO file */
211         { HICON16       hIcon = 0;
212           NE_TYPEINFO*  pTInfo = (NE_TYPEINFO*)(pData + 2);
213           NE_NAMEINFO*  pIconStorage = NULL;
214           NE_NAMEINFO*  pIconDir = NULL;
215           LPicoICONDIR  lpiID = NULL;
216  
217           if( pData == (BYTE*)-1 )
218           { hIcon = ICO_GetIconDirectory(0, hFile, &lpiID);     /* check for .ICO file */
219             if( hIcon ) 
220             { iconDirCount = 1; iconCount = lpiID->idCount; 
221             }
222           }
223           else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
224           { if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON )      /* find icon directory and icon repository */
225             { iconDirCount = pTInfo->count;
226               pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
227               TRACE(shell,"\tfound directory - %i icon families\n", iconDirCount);
228             }
229             if( pTInfo->type_id == NE_RSCTYPE_ICON ) 
230             { iconCount = pTInfo->count;
231               pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
232               TRACE(shell,"\ttotal icons - %i\n", iconCount);
233             }
234             pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
235           }
236
237           if( (pIconStorage && pIconDir) || lpiID )       /* load resources and create icons */
238           { if( nIconIndex == (UINT16)-1 )
239             { RetPtr[0] = iconDirCount;
240             }
241             else if( nIconIndex < iconDirCount )
242             { UINT16   i, icon;
243               if( n > iconDirCount - nIconIndex ) 
244                 n = iconDirCount - nIconIndex;
245
246               for( i = nIconIndex; i < nIconIndex + n; i++ ) 
247               { /* .ICO files have only one icon directory */
248
249                 if( lpiID == NULL )
250                   hIcon = SHELL_LoadResource( 0, hFile, pIconDir + i, *(WORD*)pData );
251                 RetPtr[i-nIconIndex] = GetIconID( hIcon, 3 );
252                 GlobalFree16(hIcon); 
253               }
254
255               for( icon = nIconIndex; icon < nIconIndex + n; icon++ )
256               { hIcon = 0;
257                 if( lpiID )
258                 { hIcon = ICO_LoadIcon( 0, hFile, lpiID->idEntries + RetPtr[icon-nIconIndex]);
259                 }
260                 else
261                 { for( i = 0; i < iconCount; i++ )
262                   { if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
263                     { hIcon = SHELL_LoadResource( 0, hFile, pIconStorage + i,*(WORD*)pData );
264                     }
265                   }
266                 }
267                 if( hIcon )
268                 { RetPtr[icon-nIconIndex] = LoadIconHandler( hIcon, TRUE ); 
269                 }
270                 else
271                 { RetPtr[icon-nIconIndex] = 0;
272                 }
273               }
274             }
275           }
276           if( lpiID ) 
277             HeapFree( GetProcessHeap(), 0, lpiID);
278           else 
279             HeapFree( GetProcessHeap(), 0, pData);
280         } 
281 /* end ico file */
282
283 /* exe/dll */
284         if( sig == IMAGE_NT_SIGNATURE)
285         { LPBYTE                idata,igdata;
286           PIMAGE_DOS_HEADER     dheader;
287           PIMAGE_NT_HEADERS     pe_header;
288           PIMAGE_SECTION_HEADER pe_sections;
289           PIMAGE_RESOURCE_DIRECTORY     rootresdir,iconresdir,icongroupresdir;
290           PIMAGE_RESOURCE_DATA_ENTRY    idataent,igdataent;
291           PIMAGE_RESOURCE_DIRECTORY_ENTRY       xresent;
292           int                   i,j;
293                   
294           if ( !(fmapping = CreateFileMapping32A(hFile,NULL,PAGE_READONLY|SEC_COMMIT,0,0,NULL))) 
295           { WARN(shell,"failed to create filemap.\n");  /* FIXME, INVALID_HANDLE_VALUE? */
296             hRet = ICO_INVALID_FILE;
297             goto end_2;         /* failure */
298           }
299
300           if ( !(peimage = MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0))) 
301           { WARN(shell,"failed to mmap filemap.\n");
302             hRet = ICO_INVALID_FILE;
303             goto end_2;         /* failure */
304           }
305
306           dheader = (PIMAGE_DOS_HEADER)peimage;
307           pe_header = (PIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew);     /* it is a pe header, SHELL_GetResourceTable checked that */
308           pe_sections = (PIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header)); /* probably makes problems with short PE headers...*/
309           rootresdir = NULL;
310
311           for (i=0;i<pe_header->FileHeader.NumberOfSections;i++) 
312           { if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
313               continue;
314             /* FIXME: doesn't work when the resources are not in a seperate section */
315             if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress) 
316             { rootresdir = (PIMAGE_RESOURCE_DIRECTORY)((char*)peimage+pe_sections[i].PointerToRawData);
317               break;
318             }
319           }
320
321           if (!rootresdir) 
322           { WARN(shell,"haven't found section for resource directory.\n");
323             goto end_4;         /* failure */
324           }
325   /* search the group icon dir*/
326           if (!(icongroupresdir = GetResDirEntryW(rootresdir,RT_GROUP_ICON32W, (DWORD)rootresdir,FALSE))) 
327           { WARN(shell,"No Icongroupresourcedirectory!\n");
328             goto end_4;         /* failure */
329           }
330           iconDirCount = icongroupresdir->NumberOfNamedEntries+icongroupresdir->NumberOfIdEntries;
331
332   /* number of icons requested */
333           if( nIconIndex == -1 )
334           { hRet = iconDirCount;
335             goto end_3;         /* success */
336           }
337   
338           if (nIconIndex >= iconDirCount) 
339           { WARN(shell,"nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount);
340             goto end_4;         /* failure */
341           }
342
343           xresent = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);       /* caller just wanted the number of entries */
344
345           if( n > iconDirCount - nIconIndex )   /* assure we don't get too much ... */
346           { n = iconDirCount - nIconIndex;
347           }
348
349           xresent = xresent+nIconIndex;         /* starting from specified index ... */
350
351           for (i=0;i<n;i++,xresent++) 
352           { PIMAGE_RESOURCE_DIRECTORY   resdir;
353
354             /* go down this resource entry, name */
355             resdir = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s.OffsetToDirectory));
356
357             /* default language (0) */
358             resdir = GetResDirEntryW(resdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
359             igdataent = (PIMAGE_RESOURCE_DATA_ENTRY)resdir;
360
361             /* lookup address in mapped image for virtual address */
362             igdata = NULL;
363
364             for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) 
365             { if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
366                 continue;
367               if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
368                 continue;
369               igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
370             }
371
372             if (!igdata) 
373             { WARN(shell,"no matching real address for icongroup!\n");
374               goto end_4;       /* failure */
375             }
376             RetPtr[i] = LookupIconIdFromDirectoryEx32(igdata, TRUE, cxDesired, cyDesired, LR_DEFAULTCOLOR);
377           }
378
379           if (!(iconresdir=GetResDirEntryW(rootresdir,RT_ICON32W,(DWORD)rootresdir,FALSE))) 
380           { WARN(shell,"No Iconresourcedirectory!\n");
381             goto end_4;         /* failure */
382           }
383
384           for (i=0;i<n;i++) 
385           { PIMAGE_RESOURCE_DIRECTORY   xresdir;
386             xresdir = GetResDirEntryW(iconresdir,(LPWSTR)(DWORD)RetPtr[i],(DWORD)rootresdir,FALSE);
387             xresdir = GetResDirEntryW(xresdir,(LPWSTR)0,(DWORD)rootresdir,TRUE);
388             idataent = (PIMAGE_RESOURCE_DATA_ENTRY)xresdir;
389             idata = NULL;
390
391             /* map virtual to address in image */
392             for (j=0;j<pe_header->FileHeader.NumberOfSections;j++) 
393             { if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
394                 continue;
395               if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
396                 continue;
397               idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
398             }
399             if (!idata) 
400             { WARN(shell,"no matching real address found for icondata!\n");
401               RetPtr[i]=0;
402               continue;
403             }
404             RetPtr[i] = CreateIconFromResourceEx32(idata,idataent->Size,TRUE,0x00030000, cxDesired, cyDesired, LR_DEFAULTCOLOR);
405           }
406           hRet = RetPtr[0];     /* return first icon */
407           goto end_3;           /* sucess */
408         }
409         hRet = ICO_INVALID_FILE;
410         goto end_1;             /* unknown filetype */
411
412 /* cleaning up (try & catch would be nicer:-) ) */
413 end_4:  hRet = 0;       /* failure */
414 end_3:  UnmapViewOfFile(peimage);       /* success */
415 end_2:  CloseHandle(fmapping);
416 end_1:  _lclose32( hFile);
417         return hRet;
418 }
419
420 /********************** THE ICON CACHE ********************************/
421 HIMAGELIST ShellSmallIconList = 0;
422 HIMAGELIST ShellBigIconList = 0;
423 HDPA    hdpa=0;
424
425 #define INVALID_INDEX -1
426
427 typedef struct
428 {       LPCSTR sSourceFile;     /* file icon is from */
429         DWORD dwSourceIndex;    /* index within the file */
430         DWORD dwListIndex;      /* index within the iconlist */
431 } SIC_ENTRY, * LPSIC_ENTRY;
432
433 /*****************************************************************************
434 *       SIC_CompareEntrys [called by comctl32.dll]
435 * NOTES
436 *  Callback for DPA_Search
437 */
438 INT32 CALLBACK SIC_CompareEntrys( LPVOID p1, LPVOID p2, LPARAM lparam)
439 {       TRACE(shell,"%p %p\n", p1, p2);
440
441         if (((LPSIC_ENTRY)p1)->dwSourceIndex != ((LPSIC_ENTRY)p2)->dwSourceIndex) /* first the faster one*/
442           return 1;
443
444         if (strcasecmp(((LPSIC_ENTRY)p1)->sSourceFile,((LPSIC_ENTRY)p2)->sSourceFile))
445           return 1;
446
447         return 0;  
448 }
449 /*****************************************************************************
450 *       SIC_IconAppend (internal)
451 * NOTES
452 *  appends a icon pair to the end of the cache
453 */
454 static INT32 SIC_IconAppend (LPCSTR sSourceFile, INT32 dwSourceIndex, HICON32 hSmallIcon, HICON32 hBigIcon)
455 {       LPSIC_ENTRY lpsice;
456         INT32 index, index1;
457         
458         TRACE(shell,"%s %i %x %x\n", sSourceFile, dwSourceIndex, hSmallIcon ,hBigIcon);
459
460         lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY));
461
462         lpsice->sSourceFile = HEAP_strdupA (GetProcessHeap(),0,sSourceFile);
463         lpsice->dwSourceIndex = dwSourceIndex;
464         
465 /*      index = pDPA_Search (hdpa, lpsice, -1, SIC_CompareEntrys, 0, 0);
466
467         if ( INVALID_INDEX != index )
468         { TRACE(shell, "-- allready inserted\n");
469           SHFree(lpsice);
470           return index;
471         }
472 */
473         index = pDPA_InsertPtr(hdpa, 0x7fff, lpsice);
474         if ( INVALID_INDEX == index )
475         { SHFree(lpsice);
476           return INVALID_INDEX;
477         } 
478
479         index = pImageList_AddIcon (ShellSmallIconList, hSmallIcon);
480         index1= pImageList_AddIcon (ShellBigIconList, hBigIcon);
481
482         if (index!=index1)
483         { FIXME(shell,"iconlists out of sync 0x%x 0x%x\n", index, index1);
484         }
485         lpsice->dwListIndex = index;
486         
487         return lpsice->dwListIndex;
488         
489 }
490 /****************************************************************************
491 *       SIC_LoadIcon    [internal]
492 * NOTES
493 *  gets small/big icon by number from a file
494 */
495 static INT32 SIC_LoadIcon (LPCSTR sSourceFile, INT32 dwSourceIndex)
496 {       HICON32 hiconLarge=0;
497         HICON32 hiconSmall=0;
498
499         ICO_ExtractIconEx(sSourceFile, &hiconLarge, dwSourceIndex, 1, 32, 32  );
500         ICO_ExtractIconEx(sSourceFile, &hiconSmall, dwSourceIndex, 1, 16, 16  );
501
502
503         if ( !hiconLarge ||  !hiconSmall)
504         { FIXME(shell, "*** failure loading icon %i from %s (%x %x)\n", dwSourceIndex, sSourceFile, hiconLarge, hiconSmall);
505           return -1;
506         }
507         return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge);             
508 }
509 /*****************************************************************************
510 *       SIC_GetIconIndex [internal]
511 * NOTES
512 *  look in the cache for a proper icon. if not available the icon is taken
513 *  from the file and cached
514 */
515 static INT32 SIC_GetIconIndex (LPCSTR sSourceFile, INT32 dwSourceIndex )
516 {       SIC_ENTRY sice;
517         INT32 index;
518                 
519         TRACE(shell,"%s %i\n", sSourceFile, dwSourceIndex);
520
521         sice.sSourceFile = sSourceFile;
522         sice.dwSourceIndex = dwSourceIndex;
523         
524         index = pDPA_Search (hdpa, &sice, -1, SIC_CompareEntrys, 0, 0);
525
526         if ( INVALID_INDEX == index )
527         {  return SIC_LoadIcon (sSourceFile, dwSourceIndex);
528         }
529         
530         TRACE(shell, "-- found\n");
531         return ((LPSIC_ENTRY)pDPA_GetPtr(hdpa, index))->dwListIndex;
532 }
533 /****************************************************************************
534 *       SIC_LoadIcon    [internal]
535 * NOTES
536 *  retrives the specified icon from the iconcache. if not found try's to load the icon
537 */
538 static HICON32 SIC_GetIcon (LPCSTR sSourceFile, INT32 dwSourceIndex, BOOL32 bSmallIcon )
539 {       INT32 index;
540
541         TRACE(shell,"%s %i\n", sSourceFile, dwSourceIndex);
542
543         index = SIC_GetIconIndex(sSourceFile, dwSourceIndex);
544         if (INVALID_INDEX == index)
545         { return INVALID_INDEX;
546         }
547
548         if (bSmallIcon)
549           return pImageList_GetIcon(ShellSmallIconList, index, ILD_NORMAL);
550         return pImageList_GetIcon(ShellBigIconList, index, ILD_NORMAL);
551         
552 }
553 /*****************************************************************************
554 *       SIC_Initialize [internal]
555 * NOTES
556 *  hack to load the resources from the shell32.dll under a different dll name 
557 *  will be removed when the resource-compiler is ready
558 */
559 BOOL32 SIC_Initialize(void)
560 {       CHAR            szShellPath[MAX_PATH];
561         HGLOBAL32       hSmRet, hLgRet;
562         HICON32         *pSmRet, *pLgRet;
563         UINT32          index;
564  
565         TRACE(shell,"\n");
566
567         if (hdpa)       /* already initialized?*/
568           return TRUE;
569           
570         hdpa = pDPA_Create(16);
571
572         if (!hdpa)
573         { return(FALSE);
574         }
575
576         GetWindowsDirectory32A(szShellPath,MAX_PATH);
577         PathAddBackslash32A(szShellPath);
578         strcat(szShellPath,"system\\shell32.dll");
579        
580         hSmRet = GlobalAlloc32( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON32)*40);
581         hLgRet = GlobalAlloc32( GMEM_FIXED | GMEM_ZEROINIT, sizeof(HICON32)*40);
582
583         pSmRet = (HICON32*)GlobalLock32(hSmRet);
584         pLgRet = (HICON32*)GlobalLock32(hLgRet);
585
586         ExtractIconEx32A ( szShellPath, 0, pLgRet, pSmRet, 40 );
587
588         ShellSmallIconList = pImageList_Create(16,16,ILC_COLORDDB | ILC_MASK,0,0x20);
589         ShellBigIconList = pImageList_Create(32,32,ILC_COLORDDB | ILC_MASK,0,0x20);
590
591         for (index=0; index<40; index++)
592         { if (! pSmRet[index] )
593           { MSG("*** failure loading resources from %s\n", szShellPath );
594             MSG("*** this is a hack for loading the internal and external dll at the same time\n");
595             MSG("*** you can ignore it but you will miss some icons in win95 dialogs\n\n");
596             break;
597           }
598           SIC_IconAppend (szShellPath, index, pSmRet[index], pLgRet[index]);
599         }
600                 
601         GlobalUnlock32(hLgRet);
602         GlobalFree32(hLgRet);
603
604         GlobalUnlock32(hSmRet);
605         GlobalFree32(hSmRet);
606
607         TRACE(shell,"hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
608
609         return TRUE;
610 }
611
612 /*************************************************************************
613  * Shell_GetImageList [SHELL32.71]
614  *
615  * PARAMETERS
616  *  imglist[1|2] [OUT] pointer which recive imagelist handles
617  *
618  */
619 DWORD WINAPI Shell_GetImageList(HIMAGELIST * imglist1,HIMAGELIST * imglist2)
620 {       TRACE(shell,"(%p,%p)\n",imglist1,imglist2);
621         if (imglist1)
622         { *imglist1=ShellBigIconList;
623         }
624         if (imglist2)
625         { *imglist2=ShellSmallIconList;
626         }
627
628         return TRUE;
629 }
630
631 /*************************************************************************
632  * SHMapPIDLToSystemImageListIndex [SHELL32.77]
633  *
634  * PARAMETERS
635  * x  pointer to an instance of IShellFolder 
636  * 
637  * NOTES
638  *     first hack
639  *
640  */
641 DWORD WINAPI SHMapPIDLToSystemImageListIndex(LPSHELLFOLDER sh,LPITEMIDLIST pidl,DWORD z)
642 {       char    sTemp[MAX_PATH];
643         DWORD   dwNr, ret = INVALID_INDEX;
644         LPITEMIDLIST pidltemp = ILFindLastID(pidl);
645
646         WARN(shell,"(SF=%p,pidl=%p,%08lx)\n",sh,pidl,z);
647         pdump(pidl);
648
649         if (_ILIsDesktop(pidltemp))
650         { return 34;
651         }
652         else if (_ILIsMyComputer(pidltemp))
653         { if (HCR_GetDefaultIcon("CLSID\\{20D04FE0-3AEA-1069-A2D8-08002B30309D}", sTemp, 64, &dwNr))
654           { ret = SIC_GetIconIndex(sTemp, dwNr);
655             return (( INVALID_INDEX == ret) ? 20 : ret);
656           }
657         }
658         else if (_ILIsDrive (pidltemp))
659         { if (HCR_GetDefaultIcon("Drive", sTemp, MAX_PATH, &dwNr))
660           { ret = SIC_GetIconIndex(sTemp, dwNr);
661             return (( INVALID_INDEX == ret) ? 8 : ret);
662           }
663         }
664         else if (_ILIsFolder (pidltemp))
665         { if (HCR_GetDefaultIcon("Folder", sTemp, MAX_PATH, &dwNr))
666           { ret = SIC_GetIconIndex(sTemp, dwNr);
667             return (( INVALID_INDEX == ret) ? 3 : ret);
668           }
669         }
670
671         if (_ILGetExtension (pidltemp, sTemp, MAX_PATH))                /* object is file */
672         { if ( HCR_MapTypeToValue(sTemp, sTemp, MAX_PATH))
673           { if (HCR_GetDefaultIcon(sTemp, sTemp, MAX_PATH, &dwNr))
674             { if (!strcmp("%1",sTemp))                                  /* icon is in the file */
675               { _ILGetPidlPath(pidl, sTemp, MAX_PATH);
676                 dwNr = 0;
677               }
678               ret = SIC_GetIconIndex(sTemp, dwNr);
679             }
680           }
681         }
682         return (( INVALID_INDEX == ret) ? 1 : ret);
683 }
684
685 /*************************************************************************
686 *       ExtracticonEx32         [shell32.189]
687 */
688 HICON32 WINAPI ExtractIconEx32AW ( LPVOID lpszFile, INT32 nIconIndex, HICON32 * phiconLarge, HICON32 * phiconSmall, UINT32 nIcons )
689 {       if (VERSION_OsIsUnicode())
690           return ExtractIconEx32W ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
691         return ExtractIconEx32A ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
692 }
693 /*************************************************************************
694 *       ExtracticonEx32A        [shell32.190]
695 * RETURNS
696 *  0 no icon found 
697 *  1 file is not valid
698 *  HICON32 handle of a icon (phiconLarge/Small == NULL)
699 */
700 HICON32 WINAPI ExtractIconEx32A ( LPSTR lpszFile, INT32 nIconIndex, HICON32 * phiconLarge, HICON32 * phiconSmall, UINT32 nIcons )
701 {       HICON32 ret=0;
702         
703         TRACE(shell,"file=%s idx=%i %p %p num=%i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons );
704
705         if (nIconIndex==-1)     /* Number of icons requested */
706           return ICO_ExtractIconEx(lpszFile, NULL, -1, 0, 0, 0  );
707           
708         
709         if (phiconLarge)
710         { ret = ICO_ExtractIconEx(lpszFile, phiconLarge, nIconIndex, nIcons, 32, 32  );
711           if ( nIcons==1)
712           { ret = phiconLarge[0];           
713           }
714         }
715
716         /* if no pointers given and one icon expected, return the handle directly*/
717         if (!phiconLarge && ! phiconSmall && nIcons==1 )
718           phiconSmall = &ret;
719         
720         if (phiconSmall)
721         { ret = ICO_ExtractIconEx(lpszFile, phiconSmall, nIconIndex, nIcons, 16, 16  );
722           if ( nIcons==1 )
723           { ret = phiconLarge[0];
724           }
725         }
726
727         return ret;
728 }
729 /*************************************************************************
730 *       ExtracticonEx32W        [shell32.191]
731 */
732 HICON32 WINAPI ExtractIconEx32W ( LPWSTR lpszFile, INT32 nIconIndex, HICON32 * phiconLarge, HICON32 * phiconSmall, UINT32 nIcons )
733 {       LPSTR sFile;
734         DWORD ret;
735         
736         TRACE(shell,"file=%s idx=%i %p %p num=%i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons );
737
738         sFile = HEAP_strdupWtoA (GetProcessHeap(),0,lpszFile);
739         ret = ExtractIconEx32A ( sFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
740         HeapFree(GetProcessHeap(),0,sFile);
741         return ret;
742 }