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