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
40 #include "wine/winbase16.h"
41 #include "user_private.h"
42 #include "wine/debug.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(icon
);
50 BYTE bWidth
; /* Width, in pixels, of the image */
51 BYTE bHeight
; /* Height, in pixels, of the image */
52 BYTE bColorCount
; /* Number of colors in image (0 if >=8bpp) */
53 BYTE bReserved
; /* Reserved ( must be 0) */
54 WORD wPlanes
; /* Color Planes */
55 WORD wBitCount
; /* Bits per pixel */
56 DWORD dwBytesInRes
; /* How many bytes in this resource? */
57 DWORD dwImageOffset
; /* Where in the file is this image? */
58 } icoICONDIRENTRY
, *LPicoICONDIRENTRY
;
62 WORD idReserved
; /* Reserved (must be 0) */
63 WORD idType
; /* Resource Type (RES_ICON or RES_CURSOR) */
64 WORD idCount
; /* How many images */
65 icoICONDIRENTRY idEntries
[1]; /* An entry for each image (idCount of 'em) */
66 } icoICONDIR
, *LPicoICONDIR
;
71 static void dumpIcoDirEnty ( LPicoICONDIRENTRY entry
)
73 TRACE("width = 0x%08x height = 0x%08x\n", entry
->bWidth
, entry
->bHeight
);
74 TRACE("colors = 0x%08x planes = 0x%08x\n", entry
->bColorCount
, entry
->wPlanes
);
75 TRACE("bitcount = 0x%08x bytesinres = 0x%08lx offset = 0x%08lx\n",
76 entry
->wBitCount
, entry
->dwBytesInRes
, entry
->dwImageOffset
);
78 static void dumpIcoDir ( LPicoICONDIR entry
)
80 TRACE("type = 0x%08x count = 0x%08x\n", entry
->idType
, entry
->idCount
);
84 /**********************************************************************
87 * Find an entry by id in a resource directory
88 * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
90 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
91 WORD id
, const void *root
)
93 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
96 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
97 min
= dir
->NumberOfNamedEntries
;
98 max
= min
+ dir
->NumberOfIdEntries
- 1;
101 pos
= (min
+ max
) / 2;
102 if (entry
[pos
].u1
.s2
.Id
== id
)
103 return (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
104 if (entry
[pos
].u1
.s2
.Id
> id
) max
= pos
- 1;
110 /**********************************************************************
113 * Find a default entry in a resource directory
114 * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
116 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
119 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
120 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
121 return (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ entry
->u2
.s3
.OffsetToDirectory
);
124 /*************************************************************************
125 * USER32_GetResourceTable
127 static DWORD
USER32_GetResourceTable(LPBYTE peimage
,DWORD pesize
,LPBYTE
*retptr
)
129 IMAGE_DOS_HEADER
* mz_header
;
131 TRACE("%p %p\n", peimage
, retptr
);
135 mz_header
= (IMAGE_DOS_HEADER
*) peimage
;
137 if (mz_header
->e_magic
!= IMAGE_DOS_SIGNATURE
)
139 if (mz_header
->e_cblp
== 1) /* .ICO file ? */
141 *retptr
= (LPBYTE
)-1; /* ICONHEADER.idType, must be 1 */
145 return 0; /* failed */
147 if (mz_header
->e_lfanew
>= pesize
) {
148 return 0; /* failed, happens with PKZIP DOS Exes for instance. */
150 if (*((DWORD
*)(peimage
+ mz_header
->e_lfanew
)) == IMAGE_NT_SIGNATURE
)
151 return IMAGE_NT_SIGNATURE
;
153 if (*((WORD
*)(peimage
+ mz_header
->e_lfanew
)) == IMAGE_OS2_SIGNATURE
)
155 IMAGE_OS2_HEADER
* ne_header
;
157 ne_header
= (IMAGE_OS2_HEADER
*)(peimage
+ mz_header
->e_lfanew
);
159 if (ne_header
->ne_magic
!= IMAGE_OS2_SIGNATURE
)
162 if( (ne_header
->ne_restab
- ne_header
->ne_rsrctab
) <= sizeof(NE_TYPEINFO
) )
163 *retptr
= (LPBYTE
)-1;
165 *retptr
= peimage
+ mz_header
->e_lfanew
+ ne_header
->ne_rsrctab
;
167 return IMAGE_OS2_SIGNATURE
;
169 return 0; /* failed */
171 /*************************************************************************
172 * USER32_LoadResource
174 static BYTE
* USER32_LoadResource( LPBYTE peimage
, NE_NAMEINFO
* pNInfo
, WORD sizeShift
, ULONG
*uSize
)
176 TRACE("%p %p 0x%08x\n", peimage
, pNInfo
, sizeShift
);
178 *uSize
= (DWORD
)pNInfo
->length
<< sizeShift
;
179 return peimage
+ ((DWORD
)pNInfo
->offset
<< sizeShift
);
182 /*************************************************************************
185 static BYTE
* ICO_LoadIcon( LPBYTE peimage
, LPicoICONDIRENTRY lpiIDE
, ULONG
*uSize
)
187 TRACE("%p %p\n", peimage
, lpiIDE
);
189 *uSize
= lpiIDE
->dwBytesInRes
;
190 return peimage
+ lpiIDE
->dwImageOffset
;
193 /*************************************************************************
194 * ICO_GetIconDirectory
196 * Reads .ico file and build phony ICONDIR struct
198 #define HEADER_SIZE (sizeof(CURSORICONDIR) - sizeof (CURSORICONDIRENTRY))
199 #define HEADER_SIZE_FILE (sizeof(icoICONDIR) - sizeof (icoICONDIRENTRY))
201 static BYTE
* ICO_GetIconDirectory( LPBYTE peimage
, LPicoICONDIR
* lplpiID
, ULONG
*uSize
)
203 CURSORICONDIR
* lpcid
; /* icon resource in resource-dir format */
204 CURSORICONDIR
* lpID
; /* icon resource in resource format */
207 TRACE("%p %p\n", peimage
, lplpiID
);
209 lpcid
= (CURSORICONDIR
*)peimage
;
211 if( lpcid
->idReserved
|| (lpcid
->idType
!= 1) || (!lpcid
->idCount
) )
214 /* allocate the phony ICONDIR structure */
215 *uSize
= lpcid
->idCount
* sizeof(CURSORICONDIRENTRY
) + HEADER_SIZE
;
216 if( (lpID
= HeapAlloc(GetProcessHeap(),0, *uSize
) ))
218 /* copy the header */
219 lpID
->idReserved
= lpcid
->idReserved
;
220 lpID
->idType
= lpcid
->idType
;
221 lpID
->idCount
= lpcid
->idCount
;
223 /* copy the entries */
224 for( i
=0; i
< lpcid
->idCount
; i
++ )
226 memcpy((void*)&(lpID
->idEntries
[i
]),(void*)&(lpcid
->idEntries
[i
]), sizeof(CURSORICONDIRENTRY
) - 2);
227 lpID
->idEntries
[i
].wResId
= i
;
230 *lplpiID
= (LPicoICONDIR
)peimage
;
236 /******************************************************************************
237 * struct extract_icons_state [internal]
239 * Used to carry params and state through the iterations of EnumResourceNames in ICO_ExtractIconExW
241 struct extract_icons_state
{
242 INT nBaseIndex
; /* Zero based index or negated integer id of the first icon to extract. */
243 UINT nIcons
; /* Number of icons to extract. */
244 UINT cxDesired
; /* Desired horizontal size in pixels (Might be two sizes in HI/LOWORD). */
245 UINT cyDesired
; /* Desired vertical size in pixels (Might be two sizes in HI/LOWORD). */
246 UINT fuLoad
; /* Flags passed to LoadImage. */
247 INT cIter
; /* Iteration counter. */
248 HICON
*pahIcon
; /* Pointer to an array where the icon handles will be stored. */
249 UINT
*paIconId
; /* Pointer to an array where the icon identifiers will be stored. */
252 /******************************************************************************
253 * extract_icons_callback [internal]
255 * Callback function of type ENUMRESNAMEPROC for EnumResourceNames. Used in
256 * ICO_ExtractIconsExW.
258 static BOOL CALLBACK
extract_icons_callback(HMODULE hModule
, LPCWSTR pwszType
, LPWSTR pwszName
,
261 struct extract_icons_state
*pState
= (struct extract_icons_state
*)lParam
;
262 INT idCurrent
= LOWORD(pwszName
);
264 /* If the handle array pointer is NULL, we just count the number of icons in the module. */
265 if (!pState
->pahIcon
) {
270 /* If we didn't already start extracting icons (cIter == 0), we look if the current
271 * icon is the one we should start with. That's the case if nBaseIndex is negative and
272 * it's absolute value matches the current icon's identifier. Or if nBaseIndex is positive
273 * and we already omitted the first nBaseIndex icons. */
274 if (pState
->cIter
== 0) {
275 if (pState
->nBaseIndex
< 0) {
276 if (!IS_INTRESOURCE(pwszName
) || idCurrent
!= -pState
->nBaseIndex
) {
279 } else if (pState
->nBaseIndex
> 0) {
280 pState
->nBaseIndex
--;
285 if (pState
->cIter
< pState
->nIcons
) {
286 /* Load the current icon with the size given in the LOWORD of cx/cyDesired */
287 pState
->pahIcon
[pState
->cIter
] =
288 LoadImageW(hModule
, pwszName
, IMAGE_ICON
, LOWORD(pState
->cxDesired
),
289 LOWORD(pState
->cyDesired
), pState
->fuLoad
);
290 /* FIXME: The resource's identifier (that is not idCurrent, which is the
291 * identifier of the icon directory) should be stored in paIconId, but I don't
292 * know how to query for it. */
293 if (pState
->paIconId
) pState
->paIconId
[pState
->cIter
] = 0;
296 /* If there is a second desired size given in the HIWORDs of cx/cyDesired, load too.
297 * There seems to be an off-by-one error here, since pState->cIter might now be equal
298 * to pState->nIcons, but this is in fact how it works on windows. */
299 if (HIWORD(pState
->cxDesired
) && HIWORD(pState
->cyDesired
)) {
300 pState
->pahIcon
[pState
->cIter
] =
301 LoadImageW(hModule
, pwszName
, IMAGE_ICON
, HIWORD(pState
->cxDesired
),
302 HIWORD(pState
->cyDesired
), pState
->fuLoad
);
303 if (pState
->paIconId
) pState
->paIconId
[pState
->cIter
] = 0;
308 return pState
->cIter
< pState
->nIcons
;
311 /*************************************************************************
312 * ICO_ExtractIconExW [internal]
315 * nIcons = 0: returns number of Icons in file
320 * success: number of icons in file (nIcons = 0) or nr of icons retrieved
322 static UINT
ICO_ExtractIconExW(
323 LPCWSTR lpszExeFileName
,
333 UINT cx1
, cx2
, cy1
, cy2
;
337 UINT16 iconDirCount
= 0,iconCount
= 0;
341 WCHAR szExePath
[MAX_PATH
];
342 DWORD dwSearchReturn
;
344 TRACE("%s, %d, %d %p 0x%08x\n", debugstr_w(lpszExeFileName
), nIconIndex
, nIcons
, pIconId
, flags
);
346 dwSearchReturn
= SearchPathW(NULL
, lpszExeFileName
, NULL
, sizeof(szExePath
) / sizeof(szExePath
[0]), szExePath
, NULL
);
347 if ((dwSearchReturn
== 0) || (dwSearchReturn
> sizeof(szExePath
) / sizeof(szExePath
[0])))
349 /* This is very wine specific: If the user tries to extract icons from system dlls,
350 * wine's builtin *.dll.so's will not be found (Even if they would be found it wouldn't
351 * work, since they are not in PE-format). Thus, if the SearchPath call fails, we try
352 * to load the file with LoadLibrary and extract the icons with LoadImage (via
353 * EnumResourceNames).
355 struct extract_icons_state state
;
356 HMODULE hDllSo
= LoadLibraryW(lpszExeFileName
);
359 WARN("File %s not found or path too long\n", debugstr_w(lpszExeFileName
));
363 state
.nBaseIndex
= nIconIndex
;
364 state
.nIcons
= nIcons
;
365 state
.cxDesired
= cxDesired
;
366 state
.cyDesired
= cyDesired
;
367 state
.fuLoad
= flags
;
369 state
.pahIcon
= RetPtr
;
370 state
.paIconId
= pIconId
;
372 EnumResourceNamesW(hDllSo
, MAKEINTRESOURCEW(RT_GROUP_ICON
), extract_icons_callback
,
379 hFile
= CreateFileW(szExePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
380 if (hFile
== INVALID_HANDLE_VALUE
) return ret
;
381 fsizel
= GetFileSize(hFile
,&fsizeh
);
384 fmapping
= CreateFileMappingW(hFile
, NULL
, PAGE_READONLY
| SEC_COMMIT
, 0, 0, NULL
);
388 WARN("CreateFileMapping error %d\n", GetLastError() );
392 if (!(peimage
= MapViewOfFile(fmapping
, FILE_MAP_READ
, 0, 0, 0)))
394 WARN("MapViewOfFile error %d\n", GetLastError() );
395 CloseHandle(fmapping
);
398 CloseHandle(fmapping
);
400 cx1
= LOWORD(cxDesired
);
401 cx2
= HIWORD(cxDesired
);
402 cy1
= LOWORD(cyDesired
);
403 cy2
= HIWORD(cyDesired
);
405 if (pIconId
) /* Invalidate first icon identifier */
406 *pIconId
= 0xFFFFFFFF;
408 if (!pIconId
) /* if no icon identifier array present use the icon handle array as intermediate storage */
409 pIconId
= (UINT
*)RetPtr
;
411 sig
= USER32_GetResourceTable(peimage
, fsizel
, &pData
);
413 /* ico file or NE exe/dll*/
414 if (sig
==IMAGE_OS2_SIGNATURE
|| sig
==1) /* .ICO file */
417 NE_TYPEINFO
*pTInfo
= (NE_TYPEINFO
*)(pData
+ 2);
418 NE_NAMEINFO
*pIconStorage
= NULL
;
419 NE_NAMEINFO
*pIconDir
= NULL
;
420 LPicoICONDIR lpiID
= NULL
;
423 TRACE("-- OS2/icon Signature (0x%08x)\n", sig
);
425 if (pData
== (BYTE
*)-1)
427 pCIDir
= ICO_GetIconDirectory(peimage
, &lpiID
, &uSize
); /* check for .ICO file */
430 iconDirCount
= 1; iconCount
= lpiID
->idCount
;
431 TRACE("-- icon found %p 0x%08x 0x%08x 0x%08x\n", pCIDir
, uSize
, iconDirCount
, iconCount
);
434 else while (pTInfo
->type_id
&& !(pIconStorage
&& pIconDir
))
436 if (pTInfo
->type_id
== NE_RSCTYPE_GROUP_ICON
) /* find icon directory and icon repository */
438 iconDirCount
= pTInfo
->count
;
439 pIconDir
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
440 TRACE("\tfound directory - %i icon families\n", iconDirCount
);
442 if (pTInfo
->type_id
== NE_RSCTYPE_ICON
)
444 iconCount
= pTInfo
->count
;
445 pIconStorage
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
446 TRACE("\ttotal icons - %i\n", iconCount
);
448 pTInfo
= (NE_TYPEINFO
*)((char*)(pTInfo
+1)+pTInfo
->count
*sizeof(NE_NAMEINFO
));
451 if ((pIconStorage
&& pIconDir
) || lpiID
) /* load resources and create icons */
456 if (lpiID
) /* *.ico file, deallocate heap pointer*/
457 HeapFree(GetProcessHeap(), 0, pCIDir
);
459 else if (nIconIndex
< iconDirCount
)
462 if (nIcons
> iconDirCount
- nIconIndex
)
463 nIcons
= iconDirCount
- nIconIndex
;
465 for (i
= 0; i
< nIcons
; i
++)
467 /* .ICO files have only one icon directory */
468 if (lpiID
== NULL
) /* not *.ico */
469 pCIDir
= USER32_LoadResource(peimage
, pIconDir
+ i
+ nIconIndex
, *(WORD
*)pData
, &uSize
);
470 pIconId
[i
] = LookupIconIdFromDirectoryEx(pCIDir
, TRUE
, cx1
, cy1
, flags
);
471 if (cx2
&& cy2
) pIconId
[++i
] = LookupIconIdFromDirectoryEx(pCIDir
, TRUE
, cx2
, cy2
, flags
);
473 if (lpiID
) /* *.ico file, deallocate heap pointer*/
474 HeapFree(GetProcessHeap(), 0, pCIDir
);
476 for (icon
= 0; icon
< nIcons
; icon
++)
480 pCIDir
= ICO_LoadIcon(peimage
, lpiID
->idEntries
+ (int)pIconId
[icon
], &uSize
);
482 for (i
= 0; i
< iconCount
; i
++)
483 if (pIconStorage
[i
].id
== ((int)pIconId
[icon
] | 0x8000) )
484 pCIDir
= USER32_LoadResource(peimage
, pIconStorage
+ i
, *(WORD
*)pData
, &uSize
);
488 RetPtr
[icon
] = CreateIconFromResourceEx(pCIDir
, uSize
, TRUE
, 0x00030000,
491 RetPtr
[++icon
] = CreateIconFromResourceEx(pCIDir
, uSize
, TRUE
, 0x00030000,
497 ret
= icon
; /* return number of retrieved icons */
504 else if( sig
== IMAGE_NT_SIGNATURE
)
507 PIMAGE_DOS_HEADER dheader
;
508 PIMAGE_NT_HEADERS pe_header
;
509 PIMAGE_SECTION_HEADER pe_sections
;
510 const IMAGE_RESOURCE_DIRECTORY
*rootresdir
,*iconresdir
,*icongroupresdir
;
511 const IMAGE_RESOURCE_DATA_ENTRY
*idataent
,*igdataent
;
512 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*xresent
;
515 dheader
= (PIMAGE_DOS_HEADER
)peimage
;
516 pe_header
= (PIMAGE_NT_HEADERS
)(peimage
+dheader
->e_lfanew
); /* it is a pe header, USER32_GetResourceTable checked that */
517 pe_sections
= (PIMAGE_SECTION_HEADER
)(((char*)pe_header
) + sizeof(DWORD
) + sizeof(IMAGE_FILE_HEADER
)
518 + pe_header
->FileHeader
.SizeOfOptionalHeader
);
521 /* search for the root resource directory */
522 for (i
=0;i
<pe_header
->FileHeader
.NumberOfSections
;i
++)
524 if (pe_sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
526 if (fsizel
< pe_sections
[i
].PointerToRawData
+pe_sections
[i
].SizeOfRawData
) {
527 FIXME("File %s too short (section is at %d bytes, real size is %d)\n",
528 debugstr_w(lpszExeFileName
),
529 pe_sections
[i
].PointerToRawData
+pe_sections
[i
].SizeOfRawData
,
534 /* FIXME: doesn't work when the resources are not in a separate section */
535 if (pe_sections
[i
].VirtualAddress
== pe_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
)
537 rootresdir
= (PIMAGE_RESOURCE_DIRECTORY
)(peimage
+pe_sections
[i
].PointerToRawData
);
544 WARN("haven't found section for resource directory.\n");
545 goto end
; /* failure */
548 /* search for the group icon directory */
549 if (!(icongroupresdir
= find_entry_by_id(rootresdir
, LOWORD(RT_GROUP_ICON
), rootresdir
)))
551 WARN("No Icongroupresourcedirectory!\n");
552 goto end
; /* failure */
554 iconDirCount
= icongroupresdir
->NumberOfNamedEntries
+ icongroupresdir
->NumberOfIdEntries
;
556 /* only number of icons requested */
560 goto end
; /* success */
565 /* search resource id */
567 int iId
= abs(nIconIndex
);
568 const IMAGE_RESOURCE_DIRECTORY_ENTRY
* xprdeTmp
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(icongroupresdir
+1);
570 while(n
<iconDirCount
&& xprdeTmp
)
572 if(xprdeTmp
->u1
.s2
.Id
== iId
)
582 WARN("resource id %d not found\n", iId
);
583 goto end
; /* failure */
588 /* check nIconIndex to be in range */
589 if (nIconIndex
>= iconDirCount
)
591 WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex
,iconDirCount
);
592 goto end
; /* failure */
596 /* assure we don't get too much */
597 if( nIcons
> iconDirCount
- nIconIndex
)
598 nIcons
= iconDirCount
- nIconIndex
;
600 /* starting from specified index */
601 xresent
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(icongroupresdir
+1) + nIconIndex
;
603 for (i
=0; i
< nIcons
; i
++,xresent
++)
605 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
607 /* go down this resource entry, name */
608 resdir
= (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)rootresdir
+ xresent
->u2
.s3
.OffsetToDirectory
);
610 /* default language (0) */
611 resdir
= find_entry_default(resdir
,rootresdir
);
612 igdataent
= (const IMAGE_RESOURCE_DATA_ENTRY
*)resdir
;
614 /* lookup address in mapped image for virtual address */
617 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
619 if (igdataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
621 if (igdataent
->OffsetToData
+igdataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
624 if (igdataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
+igdataent
->Size
> fsizel
) {
625 FIXME("overflow in PE lookup (%s has len %d, have offset %d), short file?\n", debugstr_w(lpszExeFileName
), fsizel
,
626 igdataent
->OffsetToData
- pe_sections
[j
].VirtualAddress
+ pe_sections
[j
].PointerToRawData
+ igdataent
->Size
);
627 goto end
; /* failure */
629 igdata
= peimage
+(igdataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
634 FIXME("no matching real address for icongroup!\n");
635 goto end
; /* failure */
637 pIconId
[i
] = LookupIconIdFromDirectoryEx(igdata
, TRUE
, cx1
, cy1
, flags
);
638 if (cx2
&& cy2
) pIconId
[++i
] = LookupIconIdFromDirectoryEx(igdata
, TRUE
, cx2
, cy2
, flags
);
641 if (!(iconresdir
=find_entry_by_id(rootresdir
,LOWORD(RT_ICON
),rootresdir
)))
643 WARN("No Iconresourcedirectory!\n");
644 goto end
; /* failure */
647 for (i
=0; i
<nIcons
; i
++)
649 const IMAGE_RESOURCE_DIRECTORY
*xresdir
;
650 xresdir
= find_entry_by_id(iconresdir
, LOWORD(pIconId
[i
]), rootresdir
);
653 WARN("icon entry %d not found\n", LOWORD(pIconId
[i
]));
657 xresdir
= find_entry_default(xresdir
, rootresdir
);
658 idataent
= (const IMAGE_RESOURCE_DATA_ENTRY
*)xresdir
;
661 /* map virtual to address in image */
662 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
664 if (idataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
666 if (idataent
->OffsetToData
+idataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
668 idata
= peimage
+(idataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
672 WARN("no matching real address found for icondata!\n");
676 RetPtr
[i
] = CreateIconFromResourceEx(idata
, idataent
->Size
, TRUE
, 0x00030000, cx1
, cy1
, flags
);
678 RetPtr
[++i
] = CreateIconFromResourceEx(idata
, idataent
->Size
, TRUE
, 0x00030000, cx2
, cy2
, flags
);
680 ret
= i
; /* return number of retrieved icons */
681 } /* if(sig == IMAGE_NT_SIGNATURE) */
684 UnmapViewOfFile(peimage
); /* success */
688 /***********************************************************************
689 * PrivateExtractIconsW [USER32.@]
692 * If HIWORD(sizeX) && HIWORD(sizeY) 2 * ((nIcons + 1) MOD 2) icons are
693 * returned, with the LOWORD size icon first and the HIWORD size icon
695 * Also the Windows equivalent does extract icons in a strange way if
696 * nIndex is negative. Our implementation treats a negative nIndex as
697 * looking for that resource identifier for the first icon to retrieve.
700 * should also support 16 bit EXE + DLLs, cursor and animated cursor as
701 * well as bitmap files.
704 UINT WINAPI
PrivateExtractIconsW (
709 HICON
* phicon
, /* [out] pointer to array of nIcons HICON handles */
710 UINT
* pIconId
, /* [out] pointer to array of nIcons icon identifiers or NULL */
711 UINT nIcons
, /* [in] number of icons to retrieve */
712 UINT flags
) /* [in] LR_* flags used by LoadImage */
714 TRACE("%s %d %dx%d %p %p %d 0x%08x\n",
715 debugstr_w(lpwstrFile
), nIndex
, sizeX
, sizeY
, phicon
, pIconId
, nIcons
, flags
);
717 if ((nIcons
& 1) && HIWORD(sizeX
) && HIWORD(sizeY
))
719 WARN("Uneven number %d of icons requested for small and large icons!\n", nIcons
);
721 return ICO_ExtractIconExW(lpwstrFile
, phicon
, nIndex
, nIcons
, sizeX
, sizeY
, pIconId
, flags
);
724 /***********************************************************************
725 * PrivateExtractIconsA [USER32.@]
728 UINT WINAPI
PrivateExtractIconsA (
733 HICON
* phicon
, /* [out] pointer to array of nIcons HICON handles */
734 UINT
* piconid
, /* [out] pointer to array of nIcons icon identifiers or NULL */
735 UINT nIcons
, /* [in] number of icons to retrieve */
736 UINT flags
) /* [in] LR_* flags used by LoadImage */
739 INT len
= MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, NULL
, 0);
740 LPWSTR lpwstrFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
742 MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, lpwstrFile
, len
);
743 ret
= PrivateExtractIconsW(lpwstrFile
, nIndex
, sizeX
, sizeY
, phicon
, piconid
, nIcons
, flags
);
745 HeapFree(GetProcessHeap(), 0, lpwstrFile
);
749 /***********************************************************************
750 * PrivateExtractIconExW [USER32.@]
752 * if nIndex == -1 it returns the number of icons in any case !!!
754 UINT WINAPI
PrivateExtractIconExW (
761 DWORD cyicon
, cysmicon
, cxicon
, cxsmicon
;
764 TRACE("%s %d %p %p %d\n",
765 debugstr_w(lpwstrFile
),nIndex
,phIconLarge
, phIconSmall
, nIcons
);
768 /* get the number of icons */
769 return ICO_ExtractIconExW(lpwstrFile
, NULL
, 0, 0, 0, 0, NULL
, LR_DEFAULTCOLOR
);
771 if (nIcons
== 1 && phIconSmall
&& phIconLarge
)
774 cxicon
= GetSystemMetrics(SM_CXICON
);
775 cyicon
= GetSystemMetrics(SM_CYICON
);
776 cxsmicon
= GetSystemMetrics(SM_CXSMICON
);
777 cysmicon
= GetSystemMetrics(SM_CYSMICON
);
779 ret
= ICO_ExtractIconExW(lpwstrFile
, (HICON
*) &hIcon
, nIndex
, 2, cxicon
| (cxsmicon
<<16),
780 cyicon
| (cysmicon
<<16), NULL
, LR_DEFAULTCOLOR
);
781 *phIconLarge
= hIcon
[0];
782 *phIconSmall
= hIcon
[1];
788 /* extract n small icons */
789 cxsmicon
= GetSystemMetrics(SM_CXSMICON
);
790 cysmicon
= GetSystemMetrics(SM_CYSMICON
);
791 ret
= ICO_ExtractIconExW(lpwstrFile
, phIconSmall
, nIndex
, nIcons
, cxsmicon
,
792 cysmicon
, NULL
, LR_DEFAULTCOLOR
);
796 /* extract n large icons */
797 cxicon
= GetSystemMetrics(SM_CXICON
);
798 cyicon
= GetSystemMetrics(SM_CYICON
);
799 ret
= ICO_ExtractIconExW(lpwstrFile
, phIconLarge
, nIndex
, nIcons
, cxicon
,
800 cyicon
, NULL
, LR_DEFAULTCOLOR
);
805 /***********************************************************************
806 * PrivateExtractIconExA [USER32.@]
808 UINT WINAPI
PrivateExtractIconExA (
816 INT len
= MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, NULL
, 0);
817 LPWSTR lpwstrFile
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
819 TRACE("%s %d %p %p %d\n", lpstrFile
, nIndex
, phIconLarge
, phIconSmall
, nIcons
);
821 MultiByteToWideChar(CP_ACP
, 0, lpstrFile
, -1, lpwstrFile
, len
);
822 ret
= PrivateExtractIconExW(lpwstrFile
, nIndex
, phIconLarge
, phIconSmall
, nIcons
);
823 HeapFree(GetProcessHeap(), 0, lpwstrFile
);