Francois Gouget <fgouget@free.fr>
[reactos.git] / reactos / lib / 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 #include "wine/port.h"
23
24 #include <stdarg.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #ifdef HAVE_UNISTD_H
28 # include <unistd.h>
29 #endif
30
31 #define COBJMACROS
32
33 #include "windef.h"
34 #include "winbase.h"
35 #include "wingdi.h"
36 #include "winuser.h"
37 #include "winreg.h"
38 #include "wine/debug.h"
39
40 #include "shellapi.h"
41 #include "objbase.h"
42 #include "shlguid.h"
43 #include "pidl.h"
44 #include "shell32_main.h"
45 #include "undocshell.h"
46 #include "shlwapi.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(shell);
49
50 /********************** THE ICON CACHE ********************************/
51
52 #define INVALID_INDEX -1
53
54 typedef struct
55 {
56 LPWSTR sSourceFile; /* file (not path!) containing the icon */
57 DWORD dwSourceIndex; /* index within the file, if it is a resoure ID it will be negated */
58 DWORD dwListIndex; /* index within the iconlist */
59 DWORD dwFlags; /* GIL_* flags */
60 DWORD dwAccessTime;
61 } SIC_ENTRY, * LPSIC_ENTRY;
62
63 static HDPA sic_hdpa = 0;
64
65 static CRITICAL_SECTION SHELL32_SicCS;
66 static CRITICAL_SECTION_DEBUG critsect_debug =
67 {
68 0, 0, &SHELL32_SicCS,
69 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
70 0, 0, { 0, (DWORD)(__FILE__ ": SHELL32_SicCS") }
71 };
72 static CRITICAL_SECTION SHELL32_SicCS = { &critsect_debug, -1, 0, 0, 0, 0 };
73
74 /*****************************************************************************
75 * SIC_CompareEntries
76 *
77 * NOTES
78 * Callback for DPA_Search
79 */
80 static INT CALLBACK SIC_CompareEntries( LPVOID p1, LPVOID p2, LPARAM lparam)
81 { TRACE("%p %p %8lx\n", p1, p2, lparam);
82
83 if (((LPSIC_ENTRY)p1)->dwSourceIndex != ((LPSIC_ENTRY)p2)->dwSourceIndex) /* first the faster one*/
84 return 1;
85
86 if (strcmpiW(((LPSIC_ENTRY)p1)->sSourceFile,((LPSIC_ENTRY)p2)->sSourceFile))
87 return 1;
88
89 return 0;
90 }
91 /*****************************************************************************
92 * SIC_IconAppend [internal]
93 *
94 * NOTES
95 * appends an icon pair to the end of the cache
96 */
97 static INT SIC_IconAppend (LPCWSTR sSourceFile, INT dwSourceIndex, HICON hSmallIcon, HICON hBigIcon)
98 { LPSIC_ENTRY lpsice;
99 INT ret, index, index1;
100 WCHAR path[MAX_PATH];
101 TRACE("%s %i %p %p\n", debugstr_w(sSourceFile), dwSourceIndex, hSmallIcon ,hBigIcon);
102
103 lpsice = (LPSIC_ENTRY) SHAlloc (sizeof (SIC_ENTRY));
104
105 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
106 lpsice->sSourceFile = HeapAlloc( GetProcessHeap(), 0, (strlenW(path)+1)*sizeof(WCHAR) );
107 strcpyW( lpsice->sSourceFile, path );
108
109 lpsice->dwSourceIndex = dwSourceIndex;
110
111 EnterCriticalSection(&SHELL32_SicCS);
112
113 index = DPA_InsertPtr(sic_hdpa, 0x7fff, lpsice);
114 if ( INVALID_INDEX == index )
115 {
116 HeapFree(GetProcessHeap(), 0, lpsice->sSourceFile);
117 SHFree(lpsice);
118 ret = INVALID_INDEX;
119 }
120 else
121 {
122 index = ImageList_AddIcon (ShellSmallIconList, hSmallIcon);
123 index1= ImageList_AddIcon (ShellBigIconList, hBigIcon);
124
125 if (index!=index1)
126 {
127 FIXME("iconlists out of sync 0x%x 0x%x\n", index, index1);
128 }
129 lpsice->dwListIndex = index;
130 ret = lpsice->dwListIndex;
131 }
132
133 LeaveCriticalSection(&SHELL32_SicCS);
134 return ret;
135 }
136 /****************************************************************************
137 * SIC_LoadIcon [internal]
138 *
139 * NOTES
140 * gets small/big icon by number from a file
141 */
142 static INT SIC_LoadIcon (LPCWSTR sSourceFile, INT dwSourceIndex)
143 { HICON hiconLarge=0;
144 HICON hiconSmall=0;
145
146 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
147 static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL;
148
149 if (!PrivateExtractIconExW) {
150 HMODULE hUser32 = GetModuleHandleA("user32");
151 PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW");
152 }
153
154 if (PrivateExtractIconExW)
155 PrivateExtractIconExW(sSourceFile, dwSourceIndex, &hiconLarge, &hiconSmall, 1);
156 else
157 #endif
158 {
159 PrivateExtractIconsW(sSourceFile, dwSourceIndex, 32, 32, &hiconLarge, NULL, 1, 0);
160 PrivateExtractIconsW(sSourceFile, dwSourceIndex, 16, 16, &hiconSmall, NULL, 1, 0);
161 }
162
163 if ( !hiconLarge || !hiconSmall)
164 {
165 WARN("failure loading icon %i from %s (%p %p)\n", dwSourceIndex, debugstr_w(sSourceFile), hiconLarge, hiconSmall);
166 return -1;
167 }
168 return SIC_IconAppend (sSourceFile, dwSourceIndex, hiconSmall, hiconLarge);
169 }
170 /*****************************************************************************
171 * SIC_GetIconIndex [internal]
172 *
173 * Parameters
174 * sSourceFile [IN] filename of file containing the icon
175 * index [IN] index/resID (negated) in this file
176 *
177 * NOTES
178 * look in the cache for a proper icon. if not available the icon is taken
179 * from the file and cached
180 */
181 INT SIC_GetIconIndex (LPCWSTR sSourceFile, INT dwSourceIndex )
182 {
183 SIC_ENTRY sice;
184 INT ret, index = INVALID_INDEX;
185 WCHAR path[MAX_PATH];
186
187 TRACE("%s %i\n", debugstr_w(sSourceFile), dwSourceIndex);
188
189 GetFullPathNameW(sSourceFile, MAX_PATH, path, NULL);
190 sice.sSourceFile = path;
191 sice.dwSourceIndex = dwSourceIndex;
192
193 EnterCriticalSection(&SHELL32_SicCS);
194
195 if (NULL != DPA_GetPtr (sic_hdpa, 0))
196 {
197 /* search linear from position 0*/
198 index = DPA_Search (sic_hdpa, &sice, 0, SIC_CompareEntries, 0, 0);
199 }
200
201 if ( INVALID_INDEX == index )
202 {
203 ret = SIC_LoadIcon (sSourceFile, dwSourceIndex);
204 }
205 else
206 {
207 TRACE("-- found\n");
208 ret = ((LPSIC_ENTRY)DPA_GetPtr(sic_hdpa, index))->dwListIndex;
209 }
210
211 LeaveCriticalSection(&SHELL32_SicCS);
212 return ret;
213 }
214 /*****************************************************************************
215 * SIC_Initialize [internal]
216 *
217 * NOTES
218 * hack to load the resources from the shell32.dll under a different dll name
219 * will be removed when the resource-compiler is ready
220 */
221 BOOL SIC_Initialize(void)
222 {
223 HICON hSm, hLg;
224 UINT index;
225 int cx_small, cy_small;
226 int cx_large, cy_large;
227
228 cx_small = GetSystemMetrics(SM_CXSMICON);
229 cy_small = GetSystemMetrics(SM_CYSMICON);
230 cx_large = GetSystemMetrics(SM_CXICON);
231 cy_large = GetSystemMetrics(SM_CYICON);
232
233 TRACE("\n");
234
235 if (sic_hdpa) /* already initialized?*/
236 return TRUE;
237
238 sic_hdpa = DPA_Create(16);
239
240 if (!sic_hdpa)
241 {
242 return(FALSE);
243 }
244
245 ShellSmallIconList = ImageList_Create(16,16,ILC_COLOR32|ILC_MASK,0,0x20);
246 ShellBigIconList = ImageList_Create(32,32,ILC_COLOR32|ILC_MASK,0,0x20);
247
248 ImageList_SetBkColor(ShellSmallIconList, CLR_NONE);
249 ImageList_SetBkColor(ShellBigIconList, CLR_NONE);
250
251 for (index=1; index<39; index++)
252 {
253 hSm = (HICON)LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, cx_small, cy_small, LR_SHARED);
254 hLg = (HICON)LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(index), IMAGE_ICON, cx_large, cy_large, LR_SHARED);
255
256 if(!hSm)
257 {
258 hSm = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(1), IMAGE_ICON, cx_small, cy_small, LR_SHARED);
259 hLg = LoadImageA(shell32_hInstance, MAKEINTRESOURCEA(1), IMAGE_ICON, cx_large, cy_large, LR_SHARED);
260 }
261 SIC_IconAppend (swShell32Name, index, hSm, hLg);
262 }
263
264 TRACE("hIconSmall=%p hIconBig=%p\n",ShellSmallIconList, ShellBigIconList);
265
266 return TRUE;
267 }
268 /*************************************************************************
269 * SIC_Destroy
270 *
271 * frees the cache
272 */
273 static INT CALLBACK sic_free( LPVOID ptr, LPVOID lparam )
274 {
275 HeapFree(GetProcessHeap(), 0, ((LPSIC_ENTRY)ptr)->sSourceFile);
276 SHFree(ptr);
277 return TRUE;
278 }
279
280 void SIC_Destroy(void)
281 {
282 TRACE("\n");
283
284 EnterCriticalSection(&SHELL32_SicCS);
285
286 if (sic_hdpa) DPA_DestroyCallback(sic_hdpa, sic_free, NULL );
287
288 sic_hdpa = NULL;
289 ImageList_Destroy(ShellSmallIconList);
290 ShellSmallIconList = 0;
291 ImageList_Destroy(ShellBigIconList);
292 ShellBigIconList = 0;
293
294 LeaveCriticalSection(&SHELL32_SicCS);
295 DeleteCriticalSection(&SHELL32_SicCS);
296 }
297
298 /*************************************************************************
299 * Shell_GetImageList [SHELL32.71]
300 *
301 * PARAMETERS
302 * imglist[1|2] [OUT] pointer which receives imagelist handles
303 *
304 */
305 BOOL WINAPI Shell_GetImageList(HIMAGELIST * lpBigList, HIMAGELIST * lpSmallList)
306 { TRACE("(%p,%p)\n",lpBigList,lpSmallList);
307 if (lpBigList)
308 { *lpBigList = ShellBigIconList;
309 }
310 if (lpSmallList)
311 { *lpSmallList = ShellSmallIconList;
312 }
313
314 return TRUE;
315 }
316
317 /*************************************************************************
318 * PidlToSicIndex [INTERNAL]
319 *
320 * PARAMETERS
321 * sh [IN] IShellFolder
322 * pidl [IN]
323 * bBigIcon [IN]
324 * uFlags [IN] GIL_*
325 * pIndex [OUT] index within the SIC
326 *
327 */
328 BOOL PidlToSicIndex (
329 IShellFolder * sh,
330 LPCITEMIDLIST pidl,
331 BOOL bBigIcon,
332 UINT uFlags,
333 int * pIndex)
334 {
335 IExtractIconW *ei;
336 WCHAR szIconFile[MAX_PATH]; /* file containing the icon */
337 INT iSourceIndex; /* index or resID(negated) in this file */
338 BOOL ret = FALSE;
339 UINT dwFlags = 0;
340
341 TRACE("sf=%p pidl=%p %s\n", sh, pidl, bBigIcon?"Big":"Small");
342
343 if (SUCCEEDED (IShellFolder_GetUIObjectOf(sh, 0, 1, &pidl, &IID_IExtractIconW, 0, (void **)&ei)))
344 {
345 if (SUCCEEDED(IExtractIconW_GetIconLocation(ei, uFlags, szIconFile, MAX_PATH, &iSourceIndex, &dwFlags)))
346 {
347 *pIndex = SIC_GetIconIndex(szIconFile, iSourceIndex);
348 ret = TRUE;
349 }
350 IExtractIconW_Release(ei);
351 }
352
353 if (INVALID_INDEX == *pIndex) /* default icon when failed */
354 *pIndex = 0;
355
356 return ret;
357 }
358
359 /*************************************************************************
360 * SHMapPIDLToSystemImageListIndex [SHELL32.77]
361 *
362 * PARAMETERS
363 * sh [IN] pointer to an instance of IShellFolder
364 * pidl [IN]
365 * pIndex [OUT][OPTIONAL] SIC index for big icon
366 *
367 */
368 int WINAPI SHMapPIDLToSystemImageListIndex(
369 IShellFolder *sh,
370 LPCITEMIDLIST pidl,
371 int *pIndex)
372 {
373 int Index;
374
375 TRACE("(SF=%p,pidl=%p,%p)\n",sh,pidl,pIndex);
376 pdump(pidl);
377
378 if (pIndex)
379 if (!PidlToSicIndex ( sh, pidl, 1, 0, pIndex))
380 *pIndex = -1;
381
382 if (!PidlToSicIndex ( sh, pidl, 0, 0, &Index))
383 return -1;
384
385 return Index;
386 }
387
388 /*************************************************************************
389 * Shell_GetCachedImageIndex [SHELL32.72]
390 *
391 */
392 INT WINAPI Shell_GetCachedImageIndexA(LPCSTR szPath, INT nIndex, BOOL bSimulateDoc)
393 {
394 INT ret, len;
395 LPWSTR szTemp;
396
397 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_a(szPath), nIndex, bSimulateDoc);
398
399 len = MultiByteToWideChar( CP_ACP, 0, szPath, -1, NULL, 0 );
400 szTemp = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
401 MultiByteToWideChar( CP_ACP, 0, szPath, -1, szTemp, len );
402
403 ret = SIC_GetIconIndex( szTemp, nIndex );
404
405 HeapFree( GetProcessHeap(), 0, szTemp );
406
407 return ret;
408 }
409
410 INT WINAPI Shell_GetCachedImageIndexW(LPCWSTR szPath, INT nIndex, BOOL bSimulateDoc)
411 {
412 WARN("(%s,%08x,%08x) semi-stub.\n",debugstr_w(szPath), nIndex, bSimulateDoc);
413
414 return SIC_GetIconIndex(szPath, nIndex);
415 }
416
417 INT WINAPI Shell_GetCachedImageIndexAW(LPCVOID szPath, INT nIndex, BOOL bSimulateDoc)
418 { if( SHELL_OsIsUnicode())
419 return Shell_GetCachedImageIndexW(szPath, nIndex, bSimulateDoc);
420 return Shell_GetCachedImageIndexA(szPath, nIndex, bSimulateDoc);
421 }
422
423 /*************************************************************************
424 * ExtractIconEx [SHELL32.@]
425 */
426 UINT WINAPI ExtractIconExAW(LPCVOID lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
427 { if (SHELL_OsIsUnicode())
428 return ExtractIconExW ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
429 return ExtractIconExA ( lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
430 }
431
432 /*************************************************************************
433 * ExtractIconExW [SHELL32.@]
434 * RETURNS
435 * 0 no icon found
436 * -1 file is not valid
437 * or number of icons extracted
438 */
439 UINT WINAPI ExtractIconExW(LPCWSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
440 {
441 /* get entry point of undocumented function PrivateExtractIconExW() in user32 */
442 #if defined(__CYGWIN__) || defined (__MINGW32__) || defined(_MSC_VER)
443 static UINT (WINAPI*PrivateExtractIconExW)(LPCWSTR,int,HICON*,HICON*,UINT) = NULL;
444
445 if (!PrivateExtractIconExW) {
446 HMODULE hUser32 = GetModuleHandleA("user32");
447 PrivateExtractIconExW = (UINT(WINAPI*)(LPCWSTR,int,HICON*,HICON*,UINT)) GetProcAddress(hUser32, "PrivateExtractIconExW");
448
449 if (!PrivateExtractIconExW)
450 return 0;
451 }
452 #endif
453
454 TRACE("%s %i %p %p %i\n", debugstr_w(lpszFile), nIconIndex, phiconLarge, phiconSmall, nIcons);
455
456 return PrivateExtractIconExW(lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
457 }
458
459 /*************************************************************************
460 * ExtractIconExA [SHELL32.@]
461 */
462 UINT WINAPI ExtractIconExA(LPCSTR lpszFile, INT nIconIndex, HICON * phiconLarge, HICON * phiconSmall, UINT nIcons)
463 {
464 UINT ret;
465 INT len = MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, NULL, 0);
466 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
467
468 TRACE("%s %i %p %p %i\n", lpszFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
469
470 MultiByteToWideChar(CP_ACP, 0, lpszFile, -1, lpwstrFile, len);
471 ret = ExtractIconExW (lpwstrFile, nIconIndex, phiconLarge, phiconSmall, nIcons);
472 HeapFree(GetProcessHeap(), 0, lpwstrFile);
473 return ret;
474 }
475
476 /*************************************************************************
477 * ExtractAssociatedIconA (SHELL32.@)
478 *
479 * Return icon for given file (either from file itself or from associated
480 * executable) and patch parameters if needed.
481 */
482 HICON WINAPI ExtractAssociatedIconA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIcon)
483 {
484 HICON hIcon;
485 WORD wDummyIcon = 0;
486
487 TRACE("\n");
488
489 if(lpiIcon == NULL)
490 lpiIcon = &wDummyIcon;
491
492 hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
493
494 if( hIcon < (HICON)2 )
495 { if( hIcon == (HICON)1 ) /* no icons found in given file */
496 { char tempPath[0x80];
497 HINSTANCE uRet = FindExecutableA(lpIconPath,NULL,tempPath);
498
499 if( uRet > (HINSTANCE)32 && tempPath[0] )
500 { strcpy(lpIconPath,tempPath);
501 hIcon = ExtractIconA(hInst, lpIconPath, *lpiIcon);
502 if( hIcon > (HICON)2 )
503 return hIcon;
504 }
505 else hIcon = 0;
506 }
507
508 if( hIcon == (HICON)1 )
509 *lpiIcon = 2; /* MSDOS icon - we found .exe but no icons in it */
510 else
511 *lpiIcon = 6; /* generic icon - found nothing */
512
513 if (GetModuleFileNameA(hInst, lpIconPath, 0x80))
514 {
515 /* terminate string (GetModuleFileName doesn't do if buffer is too small) */
516 lpIconPath[0x80 - 1] = '\0';
517 hIcon = LoadIconA( hInst, MAKEINTRESOURCEA(*lpiIcon));
518 }
519 }
520 return hIcon;
521 }
522
523 /*************************************************************************
524 * ExtractAssociatedIconExW (SHELL32.@)
525 *
526 * Return icon for given file (either from file itself or from associated
527 * executable) and patch parameters if needed.
528 */
529 HICON WINAPI ExtractAssociatedIconExW(HINSTANCE hInst, LPWSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
530 {
531 FIXME("%p %s %p %p): stub\n", hInst, debugstr_w(lpIconPath), lpiIconIdx, lpiIconId);
532 return 0;
533 }
534
535 /*************************************************************************
536 * ExtractAssociatedIconExA (SHELL32.@)
537 *
538 * Return icon for given file (either from file itself or from associated
539 * executable) and patch parameters if needed.
540 */
541 HICON WINAPI ExtractAssociatedIconExA(HINSTANCE hInst, LPSTR lpIconPath, LPWORD lpiIconIdx, LPWORD lpiIconId)
542 {
543 HICON ret;
544 INT len = MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, NULL, 0 );
545 LPWSTR lpwstrFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
546
547 TRACE("%p %s %p %p)\n", hInst, lpIconPath, lpiIconIdx, lpiIconId);
548
549 MultiByteToWideChar( CP_ACP, 0, lpIconPath, -1, lpwstrFile, len );
550 ret = ExtractAssociatedIconExW(hInst, lpwstrFile, lpiIconIdx, lpiIconId);
551 HeapFree(GetProcessHeap(), 0, lpwstrFile);
552 return ret;
553 }
554
555
556 /****************************************************************************
557 * SHDefExtractIconW [SHELL32.@]
558 */
559 HRESULT WINAPI SHDefExtractIconW(LPCWSTR pszIconFile, int iIndex, UINT uFlags,
560 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
561 {
562 UINT ret;
563 HICON hIcons[2];
564 WARN("%s %d 0x%08x %p %p %d, semi-stub\n", debugstr_w(pszIconFile), iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
565
566 ret = PrivateExtractIconsW(pszIconFile, iIndex, nIconSize, nIconSize, hIcons, NULL, 2, LR_DEFAULTCOLOR);
567 /* FIXME: deal with uFlags parameter which contains GIL_ flags */
568 if (ret == 0xFFFFFFFF)
569 return E_FAIL;
570 if (ret > 0) {
571 *phiconLarge = hIcons[0];
572 *phiconSmall = hIcons[1];
573 return S_OK;
574 }
575 return S_FALSE;
576 }
577
578 /****************************************************************************
579 * SHDefExtractIconA [SHELL32.@]
580 */
581 HRESULT WINAPI SHDefExtractIconA(LPCSTR pszIconFile, int iIndex, UINT uFlags,
582 HICON* phiconLarge, HICON* phiconSmall, UINT nIconSize)
583 {
584 HRESULT ret;
585 INT len = MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, NULL, 0);
586 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
587
588 TRACE("%s %d 0x%08x %p %p %d\n", pszIconFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
589
590 MultiByteToWideChar(CP_ACP, 0, pszIconFile, -1, lpwstrFile, len);
591 ret = SHDefExtractIconW(lpwstrFile, iIndex, uFlags, phiconLarge, phiconSmall, nIconSize);
592 HeapFree(GetProcessHeap(), 0, lpwstrFile);
593 return ret;
594 }