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