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