4 * taken and slightly changed from shell
5 * this should replace the icon extraction code in shell32 and shell16 once
6 * it needs a serious test for compliance with the native API
8 * Copyright 2000 Juergen Schmied
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 #include <stdlib.h> /* abs() */
30 #include <sys/types.h>
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
42 #include "user_private.h"
43 #include "wine/debug.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(icon
);
51 BYTE bWidth
; /* Width, in pixels, of the image */
52 BYTE bHeight
; /* Height, in pixels, of the image */
53 BYTE bColorCount
; /* Number of colors in image (0 if >=8bpp) */
54 BYTE bReserved
; /* Reserved ( must be 0) */
55 WORD wPlanes
; /* Color Planes */
56 WORD wBitCount
; /* Bits per pixel */
57 DWORD dwBytesInRes
; /* How many bytes in this resource? */
58 DWORD dwImageOffset
; /* Where in the file is this image? */
59 } icoICONDIRENTRY
, *LPicoICONDIRENTRY
;
63 WORD idReserved
; /* Reserved (must be 0) */
64 WORD idType
; /* Resource Type (RES_ICON or RES_CURSOR) */
65 WORD idCount
; /* How many images */
66 icoICONDIRENTRY idEntries
[1]; /* An entry for each image (idCount of 'em) */
67 } icoICONDIR
, *LPicoICONDIR
;
86 #define NE_RSCTYPE_ICON 0x8003
87 #define NE_RSCTYPE_GROUP_ICON 0x800e
92 static void dumpIcoDirEnty ( LPicoICONDIRENTRY entry
)
94 TRACE("width = 0x%08x height = 0x%08x\n", entry
->bWidth
, entry
->bHeight
);
95 TRACE("colors = 0x%08x planes = 0x%08x\n", entry
->bColorCount
, entry
->wPlanes
);
96 TRACE("bitcount = 0x%08x bytesinres = 0x%08lx offset = 0x%08lx\n",
97 entry
->wBitCount
, entry
->dwBytesInRes
, entry
->dwImageOffset
);
99 static void dumpIcoDir ( LPicoICONDIR entry
)
101 TRACE("type = 0x%08x count = 0x%08x\n", entry
->idType
, entry
->idCount
);
105 /**********************************************************************
108 * Find an entry by id in a resource directory
109 * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
111 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
112 WORD id
, const void *root
)
114 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
117 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
118 min
= dir
->NumberOfNamedEntries
;
119 max
= min
+ dir
->NumberOfIdEntries
- 1;
122 pos
= (min
+ max
) / 2;
123 if (entry
[pos
].u
.Id
== id
)
124 return (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ entry
[pos
].u2
.s2
.OffsetToDirectory
);
125 if (entry
[pos
].u
.Id
> id
) max
= pos
- 1;
131 /**********************************************************************
134 * Find a default entry in a resource directory
135 * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
137 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
140 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
141 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
142 return (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ entry
->u2
.s2
.OffsetToDirectory
);
145 /*************************************************************************
146 * USER32_GetResourceTable
148 static DWORD
USER32_GetResourceTable(LPBYTE peimage
,DWORD pesize
,LPBYTE
*retptr
)
150 IMAGE_DOS_HEADER
* mz_header
;
152 TRACE("%p %p\n", peimage
, retptr
);
156 mz_header
= (IMAGE_DOS_HEADER
*) peimage
;
158 if (mz_header
->e_magic
!= IMAGE_DOS_SIGNATURE
)
160 if (mz_header
->e_cblp
== 1) /* .ICO file ? */
162 *retptr
= (LPBYTE
)-1; /* ICONHEADER.idType, must be 1 */
166 return 0; /* failed */
168 if (mz_header
->e_lfanew
>= pesize
) {
169 return 0; /* failed, happens with PKZIP DOS Exes for instance. */
171 if (*((DWORD
*)(peimage
+ mz_header
->e_lfanew
)) == IMAGE_NT_SIGNATURE
)
172 return IMAGE_NT_SIGNATURE
;
174 if (*((WORD
*)(peimage
+ mz_header
->e_lfanew
)) == IMAGE_OS2_SIGNATURE
)
176 IMAGE_OS2_HEADER
* ne_header
;
178 ne_header
= (IMAGE_OS2_HEADER
*)(peimage
+ mz_header
->e_lfanew
);
180 if (ne_header
->ne_magic
!= IMAGE_OS2_SIGNATURE
)
183 if( (ne_header
->ne_restab
- ne_header
->ne_rsrctab
) <= sizeof(NE_TYPEINFO
) )
184 *retptr
= (LPBYTE
)-1;
186 *retptr
= peimage
+ mz_header
->e_lfanew
+ ne_header
->ne_rsrctab
;
188 return IMAGE_OS2_SIGNATURE
;
190 return 0; /* failed */
192 /*************************************************************************
193 * USER32_LoadResource
195 static BYTE
* USER32_LoadResource( LPBYTE peimage
, NE_NAMEINFO
* pNInfo
, WORD sizeShift
, ULONG
*uSize
)
197 TRACE("%p %p 0x%08x\n", peimage
, pNInfo
, sizeShift
);
199 *uSize
= (DWORD
)pNInfo
->length
<< sizeShift
;
200 return peimage
+ ((DWORD
)pNInfo
->offset
<< sizeShift
);
203 /*************************************************************************
206 static BYTE
* ICO_LoadIcon( LPBYTE peimage
, LPicoICONDIRENTRY lpiIDE
, ULONG
*uSize
)
208 TRACE("%p %p\n", peimage
, lpiIDE
);
210 *uSize
= lpiIDE
->dwBytesInRes
;
211 return peimage
+ lpiIDE
->dwImageOffset
;
214 /*************************************************************************
215 * ICO_GetIconDirectory
217 * Reads .ico file and build phony ICONDIR struct
219 static BYTE
* ICO_GetIconDirectory( LPBYTE peimage
, LPicoICONDIR
* lplpiID
, ULONG
*uSize
)
221 CURSORICONFILEDIR
*lpcid
; /* icon resource in resource-dir format */
222 CURSORICONDIR
* lpID
; /* icon resource in resource format */
225 TRACE("%p %p\n", peimage
, lplpiID
);
227 lpcid
= (CURSORICONFILEDIR
*)peimage
;
229 if( lpcid
->idReserved
|| (lpcid
->idType
!= 1) || (!lpcid
->idCount
) )
232 /* allocate the phony ICONDIR structure */
233 *uSize
= FIELD_OFFSET(CURSORICONDIR
, idEntries
[lpcid
->idCount
]);
234 if( (lpID
= HeapAlloc(GetProcessHeap(),0, *uSize
) ))
236 /* copy the header */
237 lpID
->idReserved
= lpcid
->idReserved
;
238 lpID
->idType
= lpcid
->idType
;
239 lpID
->idCount
= lpcid
->idCount
;
241 /* copy the entries */
242 for( i
=0; i
< lpcid
->idCount
; i
++ )
244 memcpy(&lpID
->idEntries
[i
], &lpcid
->idEntries
[i
], sizeof(CURSORICONDIRENTRY
) - 2);
245 lpID
->idEntries
[i
].wResId
= i
;
248 *lplpiID
= (LPicoICONDIR
)peimage
;
254 /*************************************************************************
255 * ICO_ExtractIconExW [internal]
258 * nIcons = 0: returns number of Icons in file
263 * success: number of icons in file (nIcons = 0) or nr of icons retrieved
265 static UINT
ICO_ExtractIconExW(
266 LPCWSTR lpszExeFileName
,
276 UINT cx1
, cx2
, cy1
, cy2
;
280 UINT16 iconDirCount
= 0,iconCount
= 0;
284 WCHAR szExePath
[MAX_PATH
];
285 DWORD dwSearchReturn
;
287 TRACE("%s, %d, %d %p 0x%08x\n", debugstr_w(lpszExeFileName
), nIconIndex
, nIcons
, pIconId
, flags
);
289 dwSearchReturn
= SearchPathW(NULL
, lpszExeFileName
, NULL
, sizeof(szExePath
) / sizeof(szExePath
[0]), szExePath
, NULL
);
290 if ((dwSearchReturn
== 0) || (dwSearchReturn
> sizeof(szExePath
) / sizeof(szExePath
[0])))
292 WARN("File %s not found or path too long\n", debugstr_w(lpszExeFileName
));
296 hFile
= CreateFileW(szExePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
297 if (hFile
== INVALID_HANDLE_VALUE
) return ret
;
298 fsizel
= GetFileSize(hFile
,&fsizeh
);
301 fmapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
| SEC_COMMIT
, 0, 0, NULL
);
305 WARN("CreateFileMapping error %d\n", GetLastError() );
309 if (!(peimage
= MapViewOfFile(fmapping
, FILE_MAP_READ
, 0, 0, 0)))
311 WARN("MapViewOfFile error %d\n", GetLastError() );
312 CloseHandle(fmapping
);
315 CloseHandle(fmapping
);
317 cx1
= LOWORD(cxDesired
);
318 cx2
= HIWORD(cxDesired
);
319 cy1
= LOWORD(cyDesired
);
320 cy2
= HIWORD(cyDesired
);
322 if (pIconId
) /* Invalidate first icon identifier */
323 *pIconId
= 0xFFFFFFFF;
325 if (!pIconId
) /* if no icon identifier array present use the icon handle array as intermediate storage */
326 pIconId
= (UINT
*)RetPtr
;
328 sig
= USER32_GetResourceTable(peimage
, fsizel
, &pData
);
330 /* ico file or NE exe/dll*/
331 if (sig
==IMAGE_OS2_SIGNATURE
|| sig
==1) /* .ICO file */
334 NE_TYPEINFO
*pTInfo
= (NE_TYPEINFO
*)(pData
+ 2);
335 NE_NAMEINFO
*pIconStorage
= NULL
;
336 NE_NAMEINFO
*pIconDir
= NULL
;
337 LPicoICONDIR lpiID
= NULL
;
340 TRACE("-- OS2/icon Signature (0x%08x)\n", sig
);
342 if (pData
== (BYTE
*)-1)
344 pCIDir
= ICO_GetIconDirectory(peimage
, &lpiID
, &uSize
); /* check for .ICO file */
347 iconDirCount
= 1; iconCount
= lpiID
->idCount
;
348 TRACE("-- icon found %p 0x%08x 0x%08x 0x%08x\n", pCIDir
, uSize
, iconDirCount
, iconCount
);
351 else while (pTInfo
->type_id
&& !(pIconStorage
&& pIconDir
))
353 if (pTInfo
->type_id
== NE_RSCTYPE_GROUP_ICON
) /* find icon directory and icon repository */
355 iconDirCount
= pTInfo
->count
;
356 pIconDir
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
357 TRACE("\tfound directory - %i icon families\n", iconDirCount
);
359 if (pTInfo
->type_id
== NE_RSCTYPE_ICON
)
361 iconCount
= pTInfo
->count
;
362 pIconStorage
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
363 TRACE("\ttotal icons - %i\n", iconCount
);
365 pTInfo
= (NE_TYPEINFO
*)((char*)(pTInfo
+1)+pTInfo
->count
*sizeof(NE_NAMEINFO
));
368 if ((pIconStorage
&& pIconDir
) || lpiID
) /* load resources and create icons */
373 if (lpiID
) /* *.ico file, deallocate heap pointer*/
374 HeapFree(GetProcessHeap(), 0, pCIDir
);
376 else if (nIconIndex
< iconDirCount
)
379 if (nIcons
> iconDirCount
- nIconIndex
)
380 nIcons
= iconDirCount
- nIconIndex
;
382 for (i
= 0; i
< nIcons
; i
++)
384 /* .ICO files have only one icon directory */
385 if (lpiID
== NULL
) /* not *.ico */
386 pCIDir
= USER32_LoadResource(peimage
, pIconDir
+ i
+ nIconIndex
, *(WORD
*)pData
, &uSize
);
387 pIconId
[i
] = LookupIconIdFromDirectoryEx(pCIDir
, TRUE
, cx1
, cy1
, flags
);
388 if (cx2
&& cy2
) pIconId
[++i
] = LookupIconIdFromDirectoryEx(pCIDir
, TRUE
, cx2
, cy2
, flags
);
390 if (lpiID
) /* *.ico file, deallocate heap pointer*/
391 HeapFree(GetProcessHeap(), 0, pCIDir
);
393 for (icon
= 0; icon
< nIcons
; icon
++)
397 pCIDir
= ICO_LoadIcon(peimage
, lpiID
->idEntries
+ (int)pIconId
[icon
], &uSize
);
399 for (i
= 0; i
< iconCount
; i
++)
400 if (pIconStorage
[i
].id
== ((int)pIconId
[icon
] | 0x8000) )
401 pCIDir
= USER32_LoadResource(peimage
, pIconStorage
+ i
, *(WORD
*)pData
, &uSize
);
405 RetPtr
[icon
] = CreateIconFromResourceEx(pCIDir
, uSize
, TRUE
, 0x00030000,
408 RetPtr
[++icon
] = CreateIconFromResourceEx(pCIDir
, uSize
, TRUE
, 0x00030000,
414 ret
= icon
; /* return number of retrieved icons */
421 else if( sig
== IMAGE_NT_SIGNATURE
)
423 BYTE
*idata
, *igdata
;
424 const IMAGE_RESOURCE_DIRECTORY
*rootresdir
, *iconresdir
, *icongroupresdir
;
425 const IMAGE_RESOURCE_DATA_ENTRY
*idataent
, *igdataent
;
426 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*xresent
;
430 rootresdir
= RtlImageDirectoryEntryToData((HMODULE
)peimage
, FALSE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
433 WARN("haven't found section for resource directory.\n");
437 /* search for the group icon directory */
438 if (!(icongroupresdir
= find_entry_by_id(rootresdir
, LOWORD(RT_GROUP_ICON
), rootresdir
)))
440 WARN("No Icongroupresourcedirectory!\n");
441 goto end
; /* failure */
443 iconDirCount
= icongroupresdir
->NumberOfNamedEntries
+ icongroupresdir
->NumberOfIdEntries
;
445 /* only number of icons requested */
449 goto end
; /* success */
454 /* search resource id */
456 int iId
= abs(nIconIndex
);
457 const IMAGE_RESOURCE_DIRECTORY_ENTRY
* xprdeTmp
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(icongroupresdir
+1);
459 while(n
<iconDirCount
&& xprdeTmp
)
461 if(xprdeTmp
->u
.Id
== iId
)
471 WARN("resource id %d not found\n", iId
);
472 goto end
; /* failure */
477 /* check nIconIndex to be in range */
478 if (nIconIndex
>= iconDirCount
)
480 WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex
,iconDirCount
);
481 goto end
; /* failure */
485 /* assure we don't get too much */
486 if( nIcons
> iconDirCount
- nIconIndex
)
487 nIcons
= iconDirCount
- nIconIndex
;
489 /* starting from specified index */
490 xresent
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(icongroupresdir
+1) + nIconIndex
;
492 for (i
=0; i
< nIcons
; i
++,xresent
++)
494 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
496 /* go down this resource entry, name */
497 resdir
= (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)rootresdir
+ xresent
->u2
.s2
.OffsetToDirectory
);
499 /* default language (0) */
500 resdir
= find_entry_default(resdir
,rootresdir
);
501 igdataent
= (const IMAGE_RESOURCE_DATA_ENTRY
*)resdir
;
503 /* lookup address in mapped image for virtual address */
504 igdata
= RtlImageRvaToVa(RtlImageNtHeader((HMODULE
)peimage
), (HMODULE
)peimage
, igdataent
->OffsetToData
, NULL
);
507 FIXME("no matching real address for icongroup!\n");
508 goto end
; /* failure */
510 pIconId
[i
] = LookupIconIdFromDirectoryEx(igdata
, TRUE
, cx1
, cy1
, flags
);
511 if (cx2
&& cy2
) pIconId
[++i
] = LookupIconIdFromDirectoryEx(igdata
, TRUE
, cx2
, cy2
, flags
);
514 if (!(iconresdir
=find_entry_by_id(rootresdir
,LOWORD(RT_ICON
),rootresdir
)))
516 WARN("No Iconresourcedirectory!\n");
517 goto end
; /* failure */
520 for (i
=0; i
<nIcons
; i
++)
522 const IMAGE_RESOURCE_DIRECTORY
*xresdir
;
523 xresdir
= find_entry_by_id(iconresdir
, LOWORD(pIconId
[i
]), rootresdir
);
526 WARN("icon entry %d not found\n", LOWORD(pIconId
[i
]));
530 xresdir
= find_entry_default(xresdir
, rootresdir
);
531 idataent
= (const IMAGE_RESOURCE_DATA_ENTRY
*)xresdir
;
533 idata
= RtlImageRvaToVa(RtlImageNtHeader((HMODULE
)peimage
), (HMODULE
)peimage
, idataent
->OffsetToData
, NULL
);
536 WARN("no matching real address found for icondata!\n");
540 RetPtr
[i
] = CreateIconFromResourceEx(idata
, idataent
->Size
, TRUE
, 0x00030000, cx1
, cy1
, flags
);
542 RetPtr
[++i
] = CreateIconFromResourceEx(idata
, idataent
->Size
, TRUE
, 0x00030000, cx2
, cy2
, flags
);
544 ret
= i
; /* return number of retrieved icons */
545 } /* if(sig == IMAGE_NT_SIGNATURE) */
548 UnmapViewOfFile(peimage
); /* success */
552 /***********************************************************************
553 * PrivateExtractIconsW [USER32.@]
556 * If HIWORD(sizeX) && HIWORD(sizeY) 2 * ((nIcons + 1) MOD 2) icons are
557 * returned, with the LOWORD size icon first and the HIWORD size icon
559 * Also the Windows equivalent does extract icons in a strange way if
560 * nIndex is negative. Our implementation treats a negative nIndex as
561 * looking for that resource identifier for the first icon to retrieve.
564 * should also support 16 bit EXE + DLLs, cursor and animated cursor as
565 * well as bitmap files.
568 UINT WINAPI
PrivateExtractIconsW (
573 HICON
* phicon
, /* [out] pointer to array of nIcons HICON handles */
574 UINT
* pIconId
, /* [out] pointer to array of nIcons icon identifiers or NULL */
575 UINT nIcons
, /* [in] number of icons to retrieve */
576 UINT flags
) /* [in] LR_* flags used by LoadImage */
578 TRACE("%s %d %dx%d %p %p %d 0x%08x\n",
579 debugstr_w(lpwstrFile
), nIndex
, sizeX
, sizeY
, phicon
, pIconId
, nIcons
, flags
);
581 if ((nIcons
& 1) && HIWORD(sizeX
) && HIWORD(sizeY
))
583 WARN("Uneven number %d of icons requested for small and large icons!\n", nIcons
);
585 return ICO_ExtractIconExW(lpwstrFile
, phicon
, nIndex
, nIcons
, sizeX
, sizeY
, pIconId
, flags
);
588 /***********************************************************************
589 * PrivateExtractIconsA [USER32.@]
592 UINT WINAPI
PrivateExtractIconsA (
597 HICON
* phicon
, /* [out] pointer to array of nIcons HICON handles */
598 UINT
* piconid
, /* [out] pointer to array of nIcons icon identifiers or NULL */
599 UINT nIcons
, /* [in] number of icons to retrieve */
600 UINT flags
) /* [in] LR_* flags used by LoadImage */
603 INT len
= MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, NULL
, 0);
604 LPWSTR lpwstrFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
606 MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, lpwstrFile
, len
);
607 ret
= PrivateExtractIconsW(lpwstrFile
, nIndex
, sizeX
, sizeY
, phicon
, piconid
, nIcons
, flags
);
609 HeapFree(GetProcessHeap(), 0, lpwstrFile
);
613 /***********************************************************************
614 * PrivateExtractIconExW [USER32.@]
616 * if nIndex == -1 it returns the number of icons in any case !!!
618 UINT WINAPI
PrivateExtractIconExW (
625 DWORD cyicon
, cysmicon
, cxicon
, cxsmicon
;
628 TRACE("%s %d %p %p %d\n",
629 debugstr_w(lpwstrFile
),nIndex
,phIconLarge
, phIconSmall
, nIcons
);
632 /* get the number of icons */
633 return ICO_ExtractIconExW(lpwstrFile
, NULL
, 0, 0, 0, 0, NULL
, LR_DEFAULTCOLOR
);
635 if (nIcons
== 1 && phIconSmall
&& phIconLarge
)
638 cxicon
= GetSystemMetrics(SM_CXICON
);
639 cyicon
= GetSystemMetrics(SM_CYICON
);
640 cxsmicon
= GetSystemMetrics(SM_CXSMICON
);
641 cysmicon
= GetSystemMetrics(SM_CYSMICON
);
643 ret
= ICO_ExtractIconExW(lpwstrFile
, hIcon
, nIndex
, 2, cxicon
| (cxsmicon
<<16),
644 cyicon
| (cysmicon
<<16), NULL
, LR_DEFAULTCOLOR
);
645 *phIconLarge
= hIcon
[0];
646 *phIconSmall
= hIcon
[1];
652 /* extract n small icons */
653 cxsmicon
= GetSystemMetrics(SM_CXSMICON
);
654 cysmicon
= GetSystemMetrics(SM_CYSMICON
);
655 ret
= ICO_ExtractIconExW(lpwstrFile
, phIconSmall
, nIndex
, nIcons
, cxsmicon
,
656 cysmicon
, NULL
, LR_DEFAULTCOLOR
);
660 /* extract n large icons */
661 cxicon
= GetSystemMetrics(SM_CXICON
);
662 cyicon
= GetSystemMetrics(SM_CYICON
);
663 ret
= ICO_ExtractIconExW(lpwstrFile
, phIconLarge
, nIndex
, nIcons
, cxicon
,
664 cyicon
, NULL
, LR_DEFAULTCOLOR
);
669 /***********************************************************************
670 * PrivateExtractIconExA [USER32.@]
672 UINT WINAPI
PrivateExtractIconExA (
680 INT len
= MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, NULL
, 0);
681 LPWSTR lpwstrFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
683 TRACE("%s %d %p %p %d\n", lpstrFile
, nIndex
, phIconLarge
, phIconSmall
, nIcons
);
685 MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, lpwstrFile
, len
);
686 ret
= PrivateExtractIconExW(lpwstrFile
, nIndex
, phIconLarge
, phIconSmall
, nIcons
);
687 HeapFree(GetProcessHeap(), 0, lpwstrFile
);