xref: /reactos/win32ss/user/user32/misc/exticon.c (revision 07608028)
1 /*
2  *	icon extracting
3  *
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
7  *
8  * Copyright 2000 Juergen Schmied
9  *
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.
14  *
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.
19  *
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
23  */
24 
25 #include <user32.h>
26 
27 #ifndef ARRAY_SIZE
28 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
29 #endif
30 
31 /* Start of Hack section */
32 
33 WINE_DEFAULT_DEBUG_CHANNEL(icon);
34 
35 #include <pshpack1.h>
36 
37 typedef struct
38 {
39     BYTE        bWidth;          /* Width, in pixels, of the image	*/
40     BYTE        bHeight;         /* Height, in pixels, of the image	*/
41     BYTE        bColorCount;     /* Number of colors in image (0 if >=8bpp) */
42     BYTE        bReserved;       /* Reserved ( must be 0)		*/
43     WORD        wPlanes;         /* Color Planes			*/
44     WORD        wBitCount;       /* Bits per pixel			*/
45     DWORD       dwBytesInRes;    /* How many bytes in this resource?	*/
46     DWORD       dwImageOffset;   /* Where in the file is this image?	*/
47 } icoICONDIRENTRY, *LPicoICONDIRENTRY;
48 
49 typedef struct
50 {
51     WORD            idReserved;   /* Reserved (must be 0) */
52     WORD            idType;       /* Resource Type (RES_ICON or RES_CURSOR) */
53     WORD            idCount;      /* How many images */
54     icoICONDIRENTRY idEntries[1]; /* An entry for each image (idCount of 'em) */
55 } icoICONDIR, *LPicoICONDIR;
56 
57 typedef struct
58 {
59     WORD offset;
60     WORD length;
61     WORD flags;
62     WORD id;
63     WORD handle;
64     WORD usage;
65 } NE_NAMEINFO;
66 
67 typedef struct
68 {
69     WORD  type_id;
70     WORD  count;
71     DWORD resloader;
72 } NE_TYPEINFO;
73 
74 #define NE_RSCTYPE_ICON        0x8003
75 #define NE_RSCTYPE_GROUP_ICON  0x800e
76 
77 #include <poppack.h>
78 
79 #if 0
80 static void dumpIcoDirEnty ( LPicoICONDIRENTRY entry )
81 {
82 	TRACE("width = 0x%08x height = 0x%08x\n", entry->bWidth, entry->bHeight);
83 	TRACE("colors = 0x%08x planes = 0x%08x\n", entry->bColorCount, entry->wPlanes);
84 	TRACE("bitcount = 0x%08x bytesinres = 0x%08lx offset = 0x%08lx\n",
85 	entry->wBitCount, entry->dwBytesInRes, entry->dwImageOffset);
86 }
87 static void dumpIcoDir ( LPicoICONDIR entry )
88 {
89 	TRACE("type = 0x%08x count = 0x%08x\n", entry->idType, entry->idCount);
90 }
91 #endif
92 
93 #ifndef WINE
94 DWORD get_best_icon_file_offset(const LPBYTE dir,
95                                 DWORD dwFileSize,
96                                 int cxDesired,
97                                 int cyDesired,
98                                 BOOL bIcon,
99                                 DWORD fuLoad,
100                                 POINT *ptHotSpot);
101 #endif
102 
103 /**********************************************************************
104  *  find_entry_by_id
105  *
106  * Find an entry by id in a resource directory
107  * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
108  */
109 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
110                                                          WORD id, const void *root )
111 {
112     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
113     int min, max, pos;
114 
115     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
116     min = dir->NumberOfNamedEntries;
117     max = min + dir->NumberOfIdEntries - 1;
118     while (min <= max)
119     {
120         pos = (min + max) / 2;
121         if (entry[pos].Id == id)
122             return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry[pos].OffsetToDirectory);
123         if (entry[pos].Id > id) max = pos - 1;
124         else min = pos + 1;
125     }
126     return NULL;
127 }
128 
129 /**********************************************************************
130  *  find_entry_default
131  *
132  * Find a default entry in a resource directory
133  * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
134  */
135 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
136                                                            const void *root )
137 {
138     const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
139     entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
140     return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry->OffsetToDirectory);
141 }
142 
143 /*************************************************************************
144  *				USER32_GetResourceTable
145  */
146 static DWORD USER32_GetResourceTable(LPBYTE peimage,DWORD pesize,LPBYTE *retptr)
147 {
148 	IMAGE_DOS_HEADER	* mz_header;
149 
150 	TRACE("%p %p\n", peimage, retptr);
151 
152 	*retptr = NULL;
153 
154 	mz_header = (IMAGE_DOS_HEADER*) peimage;
155 
156 	if (mz_header->e_magic != IMAGE_DOS_SIGNATURE)
157 	{
158 	  if (mz_header->e_cblp == 1 || mz_header->e_cblp == 2)	/* .ICO or .CUR file ? */
159 	  {
160 	    *retptr = (LPBYTE)-1;	/* ICONHEADER.idType, must be 1 */
161 	    return mz_header->e_cblp;
162 	  }
163 	  else
164 	    return 0; /* failed */
165 	}
166 	if (mz_header->e_lfanew >= pesize) {
167 	    return 0; /* failed, happens with PKZIP DOS Exes for instance. */
168 	}
169 	if (*((DWORD*)(peimage + mz_header->e_lfanew)) == IMAGE_NT_SIGNATURE )
170 	  return IMAGE_NT_SIGNATURE;
171 
172 	if (*((WORD*)(peimage + mz_header->e_lfanew)) == IMAGE_OS2_SIGNATURE )
173 	{
174 	  IMAGE_OS2_HEADER	* ne_header;
175 
176 	  ne_header = (IMAGE_OS2_HEADER*)(peimage + mz_header->e_lfanew);
177 
178 	  if (ne_header->ne_magic != IMAGE_OS2_SIGNATURE)
179 	    return 0;
180 
181 	  if( (ne_header->ne_restab - ne_header->ne_rsrctab) <= sizeof(NE_TYPEINFO) )
182 	    *retptr = (LPBYTE)-1;
183 	  else
184 	    *retptr = peimage + mz_header->e_lfanew + ne_header->ne_rsrctab;
185 
186 	  return IMAGE_OS2_SIGNATURE;
187 	}
188 	return 0; /* failed */
189 }
190 /*************************************************************************
191  *			USER32_LoadResource
192  */
193 static BYTE * USER32_LoadResource( LPBYTE peimage, NE_NAMEINFO* pNInfo, WORD sizeShift, ULONG *uSize)
194 {
195 	TRACE("%p %p 0x%08x\n", peimage, pNInfo, sizeShift);
196 
197 	*uSize = (DWORD)pNInfo->length << sizeShift;
198 	return peimage + ((DWORD)pNInfo->offset << sizeShift);
199 }
200 
201 /*************************************************************************
202  *                      ICO_LoadIcon
203  */
204 static BYTE * ICO_LoadIcon( LPBYTE peimage, LPicoICONDIRENTRY lpiIDE, ULONG *uSize)
205 {
206 	TRACE("%p %p\n", peimage, lpiIDE);
207 
208 	*uSize = lpiIDE->dwBytesInRes;
209 	return peimage + lpiIDE->dwImageOffset;
210 }
211 
212 /*************************************************************************
213  *                      ICO_GetIconDirectory
214  *
215  * Reads .ico file and build phony ICONDIR struct
216  */
217 static BYTE * ICO_GetIconDirectory( LPBYTE peimage, LPicoICONDIR* lplpiID, ULONG *uSize )
218 {
219 	CURSORICONDIR	* lpcid;	/* icon resource in resource-dir format */
220 	CURSORICONDIR	* lpID;		/* icon resource in resource format */
221 	int		i;
222 
223 	TRACE("%p %p\n", peimage, lplpiID);
224 
225 	lpcid = (CURSORICONDIR*)peimage;
226 
227 	if( lpcid->idReserved || (lpcid->idType != 1) || (!lpcid->idCount) )
228 	  return 0;
229 
230 	/* allocate the phony ICONDIR structure */
231         *uSize = FIELD_OFFSET(CURSORICONDIR, idEntries[lpcid->idCount]);
232 	if( (lpID = HeapAlloc(GetProcessHeap(),0, *uSize) ))
233 	{
234 	  /* copy the header */
235 	  lpID->idReserved = lpcid->idReserved;
236 	  lpID->idType = lpcid->idType;
237 	  lpID->idCount = lpcid->idCount;
238 
239 	  /* copy the entries */
240 	  for( i=0; i < lpcid->idCount; i++ )
241 	  {
242             memcpy(&lpID->idEntries[i], &lpcid->idEntries[i], sizeof(CURSORICONDIRENTRY) - 2);
243 	    lpID->idEntries[i].wResId = i;
244 	  }
245 
246 	  *lplpiID = (LPicoICONDIR)peimage;
247 	  return (BYTE *)lpID;
248 	}
249 	return 0;
250 }
251 
252 /*************************************************************************
253  *	ICO_ExtractIconExW		[internal]
254  *
255  * NOTES
256  *  nIcons = 0: returns number of Icons in file
257  *
258  * returns
259  *  invalid file: -1
260  *  failure:0;
261  *  success: number of icons in file (nIcons = 0) or nr of icons retrieved
262  */
263 static UINT ICO_ExtractIconExW(
264 	LPCWSTR lpszExeFileName,
265 	HICON * RetPtr,
266 	INT nIconIndex,
267 	UINT nIcons,
268 	UINT cxDesired,
269 	UINT cyDesired,
270 	UINT *pIconId,
271 	UINT flags)
272 {
273 	UINT		ret = 0;
274 	UINT		cx1, cx2, cy1, cy2;
275 	LPBYTE		pData;
276 	DWORD		sig;
277 	HANDLE		hFile;
278 	UINT16		iconDirCount = 0,iconCount = 0;
279 	LPBYTE		peimage;
280 	HANDLE		fmapping;
281 	DWORD		fsizeh,fsizel;
282 #ifdef __REACTOS__
283     WCHAR		szExpandedExePath[MAX_PATH];
284 #endif
285         WCHAR		szExePath[MAX_PATH];
286         DWORD		dwSearchReturn;
287 
288 	TRACE("%s, %d, %d %p 0x%08x\n", debugstr_w(lpszExeFileName), nIconIndex, nIcons, pIconId, flags);
289 
290 #ifdef __REACTOS__
291     if (RetPtr)
292         *RetPtr = NULL;
293 
294     if (ExpandEnvironmentStringsW(lpszExeFileName, szExpandedExePath, ARRAY_SIZE(szExpandedExePath)))
295         lpszExeFileName = szExpandedExePath;
296 #endif
297 
298         dwSearchReturn = SearchPathW(NULL, lpszExeFileName, NULL, ARRAY_SIZE(szExePath), szExePath, NULL);
299         if ((dwSearchReturn == 0) || (dwSearchReturn > ARRAY_SIZE(szExePath)))
300         {
301             WARN("File %s not found or path too long\n", debugstr_w(lpszExeFileName));
302             return -1;
303         }
304 
305 	hFile = CreateFileW(szExePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
306 	if (hFile == INVALID_HANDLE_VALUE) return ret;
307 	fsizel = GetFileSize(hFile,&fsizeh);
308 
309 	/* Map the file */
310 	fmapping = CreateFileMappingW(hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL);
311 	CloseHandle(hFile);
312 	if (!fmapping)
313 	{
314           WARN("CreateFileMapping error %ld\n", GetLastError() );
315 	  return 0xFFFFFFFF;
316 	}
317 
318 	if (!(peimage = MapViewOfFile(fmapping, FILE_MAP_READ, 0, 0, 0)))
319 	{
320           WARN("MapViewOfFile error %ld\n", GetLastError() );
321 	  CloseHandle(fmapping);
322 	  return 0xFFFFFFFF;
323 	}
324 	CloseHandle(fmapping);
325 
326 	cx1 = LOWORD(cxDesired);
327 	cx2 = HIWORD(cxDesired);
328 	cy1 = LOWORD(cyDesired);
329 	cy2 = HIWORD(cyDesired);
330 
331 	if (pIconId) /* Invalidate first icon identifier */
332 		*pIconId = 0xFFFFFFFF;
333 
334 	if (!pIconId) /* if no icon identifier array present use the icon handle array as intermediate storage */
335 	  pIconId = (UINT*)RetPtr;
336 
337 	sig = USER32_GetResourceTable(peimage, fsizel, &pData);
338 
339 /* NE exe/dll */
340 	if (sig==IMAGE_OS2_SIGNATURE)
341 	{
342 	  BYTE		*pCIDir = 0;
343 	  NE_TYPEINFO	*pTInfo = (NE_TYPEINFO*)(pData + 2);
344 	  NE_NAMEINFO	*pIconStorage = NULL;
345 	  NE_NAMEINFO	*pIconDir = NULL;
346 	  LPicoICONDIR	lpiID = NULL;
347 	  ULONG		uSize = 0;
348 
349           TRACE("-- OS2/icon Signature (0x%08x)\n", sig);
350 
351 	  if (pData == (BYTE*)-1)
352 	  {
353 	    pCIDir = ICO_GetIconDirectory(peimage, &lpiID, &uSize);	/* check for .ICO file */
354 	    if (pCIDir)
355 	    {
356 	      iconDirCount = 1; iconCount = lpiID->idCount;
357               TRACE("-- icon found %p 0x%08x 0x%08x 0x%08x\n", pCIDir, uSize, iconDirCount, iconCount);
358 	    }
359 	  }
360 	  else while (pTInfo->type_id && !(pIconStorage && pIconDir))
361 	  {
362 	    if (pTInfo->type_id == NE_RSCTYPE_GROUP_ICON)	/* find icon directory and icon repository */
363 	    {
364 	      iconDirCount = pTInfo->count;
365 	      pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
366 	      TRACE("\tfound directory - %i icon families\n", iconDirCount);
367 	    }
368 	    if (pTInfo->type_id == NE_RSCTYPE_ICON)
369 	    {
370 	      iconCount = pTInfo->count;
371 	      pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
372 	      TRACE("\ttotal icons - %i\n", iconCount);
373 	    }
374 	    pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
375 	  }
376 
377 	  if ((pIconStorage && pIconDir) || lpiID)	  /* load resources and create icons */
378 	  {
379 	    if (nIcons == 0)
380 	    {
381 	      ret = iconDirCount;
382               if (lpiID)	/* *.ico file, deallocate heap pointer*/
383 	        HeapFree(GetProcessHeap(), 0, pCIDir);
384 	    }
385 	    else if (nIconIndex < iconDirCount)
386 	    {
387 	      UINT16   i, icon;
388 	      if (nIcons > iconDirCount - nIconIndex)
389 	        nIcons = iconDirCount - nIconIndex;
390 
391 	      for (i = 0; i < nIcons; i++)
392 	      {
393 	        /* .ICO files have only one icon directory */
394 	        if (lpiID == NULL)	/* not *.ico */
395 	          pCIDir = USER32_LoadResource(peimage, pIconDir + i + nIconIndex, *(WORD*)pData, &uSize);
396 	        pIconId[i] = LookupIconIdFromDirectoryEx(pCIDir, TRUE, cx1, cy1, flags);
397                 if (cx2 && cy2) pIconId[++i] = LookupIconIdFromDirectoryEx(pCIDir, TRUE,  cx2, cy2, flags);
398 	      }
399               if (lpiID)	/* *.ico file, deallocate heap pointer*/
400 	        HeapFree(GetProcessHeap(), 0, pCIDir);
401 
402 	      for (icon = 0; icon < nIcons; icon++)
403 	      {
404 	        pCIDir = NULL;
405 	        if (lpiID)
406 	          pCIDir = ICO_LoadIcon(peimage, lpiID->idEntries + (int)pIconId[icon], &uSize);
407 	        else
408 	          for (i = 0; i < iconCount; i++)
409 	            if (pIconStorage[i].id == ((int)pIconId[icon] | 0x8000) )
410 	              pCIDir = USER32_LoadResource(peimage, pIconStorage + i, *(WORD*)pData, &uSize);
411 
412 	        if (pCIDir)
413                 {
414 	          RetPtr[icon] = CreateIconFromResourceEx(pCIDir, uSize, TRUE, 0x00030000,
415                                                                  cx1, cy1, flags);
416                   if (cx2 && cy2)
417                       RetPtr[++icon] = CreateIconFromResourceEx(pCIDir, uSize, TRUE, 0x00030000,
418                                                                        cx2, cy2, flags);
419                 }
420 	        else
421 	          RetPtr[icon] = 0;
422 	      }
423 	      ret = icon;	/* return number of retrieved icons */
424 	    }
425 	  }
426 	}
427     else
428     if (sig == 1 || sig == 2) /* .ICO or .CUR file */
429     {
430         TRACE("-- icon Signature (0x%08x)\n", sig);
431 
432         if (pData == (BYTE*)-1)
433         {
434             INT cx[2] = {cx1, cx2}, cy[2] = {cy1, cy2};
435             INT index;
436 
437             for(index = 0; index < (cx2 || cy2 ? 2 : 1); index++)
438             {
439                 DWORD dataOffset;
440                 LPBYTE imageData;
441                 POINT hotSpot;
442                 LPICONIMAGE entry;
443 
444                 dataOffset = get_best_icon_file_offset(peimage, fsizel, cx[index], cy[index], sig == 1, flags, sig == 1 ? NULL : &hotSpot);
445 
446                 if (dataOffset)
447                 {
448                     HICON icon;
449                     WORD *cursorData = NULL;
450 
451                     imageData = peimage + dataOffset;
452                     entry = (LPICONIMAGE)(imageData);
453 
454                     if(sig == 2)
455                     {
456                         /* we need to prepend the bitmap data with hot spots for CreateIconFromResourceEx */
457                         cursorData = HeapAlloc(GetProcessHeap(), 0, entry->icHeader.biSizeImage + 2 * sizeof(WORD));
458 
459                         if(!cursorData)
460                             continue;
461 
462                         cursorData[0] = hotSpot.x;
463                         cursorData[1] = hotSpot.y;
464 
465                         memcpy(cursorData + 2, imageData, entry->icHeader.biSizeImage);
466 
467                         imageData = (LPBYTE)cursorData;
468                     }
469 
470                     icon = CreateIconFromResourceEx(imageData, entry->icHeader.biSizeImage, sig == 1, 0x00030000, cx[index], cy[index], flags);
471 
472                     if (icon)
473                     {
474                         RetPtr[index] = icon;
475                         iconCount = 1;
476                     }
477 
478                     if(cursorData != NULL)
479                         HeapFree(GetProcessHeap(), 0, cursorData);
480                 }
481             }
482 
483         }
484         ret = iconCount;	/* return number of retrieved icons */
485     }
486 /* end ico file */
487 
488 /* exe/dll */
489 	else if( sig == IMAGE_NT_SIGNATURE )
490 	{
491         BYTE *idata, *igdata;
492         const IMAGE_RESOURCE_DIRECTORY *rootresdir, *iconresdir, *icongroupresdir;
493         const IMAGE_RESOURCE_DATA_ENTRY *idataent, *igdataent;
494         const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent;
495         ULONG size;
496         UINT i;
497 
498         rootresdir = RtlImageDirectoryEntryToData((HMODULE)peimage, FALSE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size);
499         if (!rootresdir)
500         {
501             WARN("haven't found section for resource directory.\n");
502             goto end;
503         }
504 
505 	  /* search for the group icon directory */
506 	  if (!(icongroupresdir = find_entry_by_id(rootresdir, LOWORD(RT_GROUP_ICON), rootresdir)))
507 	  {
508 	    WARN("No Icongroupresourcedirectory!\n");
509 	    goto end;		/* failure */
510 	  }
511 	  iconDirCount = icongroupresdir->NumberOfNamedEntries + icongroupresdir->NumberOfIdEntries;
512 
513 	  /* only number of icons requested */
514 	  if( !pIconId )
515 	  {
516 	    ret = iconDirCount;
517 	    goto end;		/* success */
518 	  }
519 
520 	  if( nIconIndex < 0 )
521 	  {
522 	    /* search resource id */
523 	    int n = 0;
524 	    int iId = abs(nIconIndex);
525 	    const IMAGE_RESOURCE_DIRECTORY_ENTRY* xprdeTmp = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1);
526 
527 	    while(n<iconDirCount && xprdeTmp)
528 	    {
529               if(xprdeTmp->Id ==  iId)
530               {
531                   nIconIndex = n;
532                   break;
533               }
534               n++;
535               xprdeTmp++;
536 	    }
537 	    if (nIconIndex < 0)
538 	    {
539 	      WARN("resource id %d not found\n", iId);
540 	      goto end;		/* failure */
541 	    }
542 	  }
543 	  else
544 	  {
545 	    /* check nIconIndex to be in range */
546 	    if (nIconIndex >= iconDirCount)
547 	    {
548 	      WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount);
549 	      goto end;		/* failure */
550 	    }
551 	  }
552 
553 	  /* assure we don't get too much */
554 	  if( nIcons > iconDirCount - nIconIndex )
555 	    nIcons = iconDirCount - nIconIndex;
556 
557 	  /* starting from specified index */
558 	  xresent = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1) + nIconIndex;
559 
560 	  for (i=0; i < nIcons; i++,xresent++)
561 	  {
562 	    const IMAGE_RESOURCE_DIRECTORY *resdir;
563 
564 	    /* go down this resource entry, name */
565             resdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)rootresdir + xresent->OffsetToDirectory);
566 
567 	    /* default language (0) */
568 	    resdir = find_entry_default(resdir,rootresdir);
569 	    igdataent = (const IMAGE_RESOURCE_DATA_ENTRY*)resdir;
570 
571 	    /* lookup address in mapped image for virtual address */
572         igdata = RtlImageRvaToVa(RtlImageNtHeader((HMODULE)peimage), (HMODULE)peimage, igdataent->OffsetToData, NULL);
573         if (!igdata)
574 	    {
575 	      FIXME("no matching real address for icongroup!\n");
576 	      goto end;	/* failure */
577 	    }
578 	    pIconId[i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx1, cy1, flags);
579             if (cx2 && cy2) pIconId[++i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx2, cy2, flags);
580 	  }
581 
582 	  if (!(iconresdir=find_entry_by_id(rootresdir,LOWORD(RT_ICON),rootresdir)))
583 	  {
584 	    WARN("No Iconresourcedirectory!\n");
585 	    goto end;		/* failure */
586 	  }
587 
588 	  for (i=0; i<nIcons; i++)
589 	  {
590 	    const IMAGE_RESOURCE_DIRECTORY *xresdir;
591 	    xresdir = find_entry_by_id(iconresdir, LOWORD(pIconId[i]), rootresdir);
592             if( !xresdir )
593             {
594               WARN("icon entry %d not found\n", LOWORD(pIconId[i]));
595 	      RetPtr[i]=0;
596 	      continue;
597             }
598 	    xresdir = find_entry_default(xresdir, rootresdir);
599 	    idataent = (const IMAGE_RESOURCE_DATA_ENTRY*)xresdir;
600 
601         idata = RtlImageRvaToVa(RtlImageNtHeader((HMODULE)peimage), (HMODULE)peimage, idataent->OffsetToData, NULL);
602         if (!idata)
603 	    {
604 	      WARN("no matching real address found for icondata!\n");
605 	      RetPtr[i]=0;
606 	      continue;
607 	    }
608 	    RetPtr[i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx1, cy1, flags);
609             if (cx2 && cy2)
610                 RetPtr[++i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx2, cy2, flags);
611 	  }
612 	  ret = i;	/* return number of retrieved icons */
613 	}			/* if(sig == IMAGE_NT_SIGNATURE) */
614 
615 end:
616 	UnmapViewOfFile(peimage);	/* success */
617 	return ret;
618 }
619 
620 /***********************************************************************
621  *           PrivateExtractIconsW			[USER32.@]
622  *
623  * NOTES
624  *  If HIWORD(sizeX) && HIWORD(sizeY) 2 * ((nIcons + 1) MOD 2) icons are
625  *  returned, with the LOWORD size icon first and the HIWORD size icon
626  *  second.
627  *  Also the Windows equivalent does extract icons in a strange way if
628  *  nIndex is negative. Our implementation treats a negative nIndex as
629  *  looking for that resource identifier for the first icon to retrieve.
630  *
631  * FIXME:
632  *  should also support 16 bit EXE + DLLs, cursor and animated cursor as
633  *  well as bitmap files.
634  */
635 
636 UINT WINAPI PrivateExtractIconsW (
637 	LPCWSTR lpwstrFile,
638 	int nIndex,
639 	int sizeX,
640 	int sizeY,
641 	HICON * phicon, /* [out] pointer to array of nIcons HICON handles */
642 	UINT* pIconId,  /* [out] pointer to array of nIcons icon identifiers or NULL */
643 	UINT nIcons,    /* [in] number of icons to retrieve */
644 	UINT flags )    /* [in] LR_* flags used by LoadImage */
645 {
646 	TRACE("%s %d %dx%d %p %p %d 0x%08x\n",
647 	      debugstr_w(lpwstrFile), nIndex, sizeX, sizeY, phicon, pIconId, nIcons, flags);
648 
649 	if ((nIcons & 1) && HIWORD(sizeX) && HIWORD(sizeY))
650 	{
651 	  WARN("Uneven number %d of icons requested for small and large icons!\n", nIcons);
652 	}
653 	return ICO_ExtractIconExW(lpwstrFile, phicon, nIndex, nIcons, sizeX, sizeY, pIconId, flags);
654 }
655 
656 /***********************************************************************
657  *           PrivateExtractIconsA			[USER32.@]
658  */
659 
660 UINT WINAPI PrivateExtractIconsA (
661 	LPCSTR lpstrFile,
662 	int nIndex,
663 	int sizeX,
664 	int sizeY,
665 	HICON * phicon, /* [out] pointer to array of nIcons HICON handles */
666 	UINT* piconid,  /* [out] pointer to array of nIcons icon identifiers or NULL */
667 	UINT nIcons,    /* [in] number of icons to retrieve */
668 	UINT flags )    /* [in] LR_* flags used by LoadImage */
669 {
670     UINT ret;
671     INT len = MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, NULL, 0);
672     LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
673 #ifdef __REACTOS__
674     if (lpwstrFile == NULL)
675         return 0;
676 #endif
677 
678     MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, lpwstrFile, len);
679     ret = PrivateExtractIconsW(lpwstrFile, nIndex, sizeX, sizeY, phicon, piconid, nIcons, flags);
680 
681     HeapFree(GetProcessHeap(), 0, lpwstrFile);
682     return ret;
683 }
684 
685 /***********************************************************************
686  *           PrivateExtractIconExW			[USER32.@]
687  * NOTES
688  *  if nIndex == -1 it returns the number of icons in any case !!!
689  */
690 UINT WINAPI PrivateExtractIconExW (
691 	LPCWSTR lpwstrFile,
692 	int nIndex,
693 	HICON * phIconLarge,
694 	HICON * phIconSmall,
695 	UINT nIcons )
696 {
697 	DWORD cyicon, cysmicon, cxicon, cxsmicon;
698 	UINT ret = 0;
699 
700 	TRACE("%s %d %p %p %d\n",
701 	debugstr_w(lpwstrFile),nIndex,phIconLarge, phIconSmall, nIcons);
702 
703 	if (nIndex == -1)
704 	  /* get the number of icons */
705 	  return ICO_ExtractIconExW(lpwstrFile, NULL, 0, 0, 0, 0, NULL, LR_DEFAULTCOLOR);
706 
707 	if (nIcons == 1 && phIconSmall && phIconLarge)
708 	{
709 	  HICON hIcon[2];
710 	  cxicon = GetSystemMetrics(SM_CXICON);
711 	  cyicon = GetSystemMetrics(SM_CYICON);
712 	  cxsmicon = GetSystemMetrics(SM_CXSMICON);
713 	  cysmicon = GetSystemMetrics(SM_CYSMICON);
714 
715           ret = ICO_ExtractIconExW(lpwstrFile, hIcon, nIndex, 2, cxicon | (cxsmicon<<16),
716 	                           cyicon | (cysmicon<<16), NULL, LR_DEFAULTCOLOR);
717 	  *phIconLarge = hIcon[0];
718 	  *phIconSmall = hIcon[1];
719  	  return ret;
720 	}
721 
722 	if (phIconSmall)
723 	{
724 	  /* extract n small icons */
725 	  cxsmicon = GetSystemMetrics(SM_CXSMICON);
726 	  cysmicon = GetSystemMetrics(SM_CYSMICON);
727 	  ret = ICO_ExtractIconExW(lpwstrFile, phIconSmall, nIndex, nIcons, cxsmicon,
728 	                           cysmicon, NULL, LR_DEFAULTCOLOR);
729 	}
730        if (phIconLarge)
731 	{
732 	  /* extract n large icons */
733 	  cxicon = GetSystemMetrics(SM_CXICON);
734 	  cyicon = GetSystemMetrics(SM_CYICON);
735          ret = ICO_ExtractIconExW(lpwstrFile, phIconLarge, nIndex, nIcons, cxicon,
736 	                           cyicon, NULL, LR_DEFAULTCOLOR);
737 	}
738 	return ret;
739 }
740 
741 /***********************************************************************
742  *           PrivateExtractIconExA			[USER32.@]
743  */
744 UINT WINAPI PrivateExtractIconExA (
745 	LPCSTR lpstrFile,
746 	int nIndex,
747 	HICON * phIconLarge,
748 	HICON * phIconSmall,
749 	UINT nIcons )
750 {
751 	UINT ret;
752 	INT len = MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, NULL, 0);
753 	LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
754 #ifdef __REACTOS__
755     if (lpwstrFile == NULL)
756         return 0;
757 #endif
758 
759 	TRACE("%s %d %p %p %d\n", lpstrFile, nIndex, phIconLarge, phIconSmall, nIcons);
760 
761 	MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, lpwstrFile, len);
762 	ret = PrivateExtractIconExW(lpwstrFile, nIndex, phIconLarge, phIconSmall, nIcons);
763 	HeapFree(GetProcessHeap(), 0, lpwstrFile);
764 	return ret;
765 }
766