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 HeapFree(GetProcessHeap(), 0, cursorData); 473 474 if (icon) 475 { 476 if (RetPtr) 477 RetPtr[index] = icon; 478 else 479 DestroyIcon(icon); 480 481 iconCount = 1; 482 break; 483 } 484 } 485 } 486 } 487 ret = iconCount; /* return number of retrieved icons */ 488 } 489 /* end ico file */ 490 491 /* exe/dll */ 492 else if( sig == IMAGE_NT_SIGNATURE ) 493 { 494 BYTE *idata, *igdata; 495 const IMAGE_RESOURCE_DIRECTORY *rootresdir, *iconresdir, *icongroupresdir; 496 const IMAGE_RESOURCE_DATA_ENTRY *idataent, *igdataent; 497 const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent; 498 ULONG size; 499 UINT i; 500 501 rootresdir = RtlImageDirectoryEntryToData((HMODULE)peimage, FALSE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size); 502 if (!rootresdir) 503 { 504 WARN("haven't found section for resource directory.\n"); 505 goto end; 506 } 507 508 /* search for the group icon directory */ 509 if (!(icongroupresdir = find_entry_by_id(rootresdir, LOWORD(RT_GROUP_ICON), rootresdir))) 510 { 511 WARN("No Icongroupresourcedirectory!\n"); 512 goto end; /* failure */ 513 } 514 iconDirCount = icongroupresdir->NumberOfNamedEntries + icongroupresdir->NumberOfIdEntries; 515 516 /* only number of icons requested */ 517 if( !pIconId ) 518 { 519 ret = iconDirCount; 520 goto end; /* success */ 521 } 522 523 if( nIconIndex < 0 ) 524 { 525 /* search resource id */ 526 int n = 0; 527 int iId = abs(nIconIndex); 528 const IMAGE_RESOURCE_DIRECTORY_ENTRY* xprdeTmp = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1); 529 530 while(n<iconDirCount && xprdeTmp) 531 { 532 if(xprdeTmp->Id == iId) 533 { 534 nIconIndex = n; 535 break; 536 } 537 n++; 538 xprdeTmp++; 539 } 540 if (nIconIndex < 0) 541 { 542 WARN("resource id %d not found\n", iId); 543 goto end; /* failure */ 544 } 545 } 546 else 547 { 548 /* check nIconIndex to be in range */ 549 if (nIconIndex >= iconDirCount) 550 { 551 WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount); 552 goto end; /* failure */ 553 } 554 } 555 556 /* assure we don't get too much */ 557 if( nIcons > iconDirCount - nIconIndex ) 558 nIcons = iconDirCount - nIconIndex; 559 560 /* starting from specified index */ 561 xresent = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(icongroupresdir+1) + nIconIndex; 562 563 for (i=0; i < nIcons; i++,xresent++) 564 { 565 const IMAGE_RESOURCE_DIRECTORY *resdir; 566 567 /* go down this resource entry, name */ 568 resdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)rootresdir + xresent->OffsetToDirectory); 569 570 /* default language (0) */ 571 resdir = find_entry_default(resdir,rootresdir); 572 igdataent = (const IMAGE_RESOURCE_DATA_ENTRY*)resdir; 573 574 /* lookup address in mapped image for virtual address */ 575 igdata = RtlImageRvaToVa(RtlImageNtHeader((HMODULE)peimage), (HMODULE)peimage, igdataent->OffsetToData, NULL); 576 if (!igdata) 577 { 578 FIXME("no matching real address for icongroup!\n"); 579 goto end; /* failure */ 580 } 581 pIconId[i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx1, cy1, flags); 582 if (cx2 && cy2) pIconId[++i] = LookupIconIdFromDirectoryEx(igdata, TRUE, cx2, cy2, flags); 583 } 584 585 if (!(iconresdir=find_entry_by_id(rootresdir,LOWORD(RT_ICON),rootresdir))) 586 { 587 WARN("No Iconresourcedirectory!\n"); 588 goto end; /* failure */ 589 } 590 591 for (i=0; i<nIcons; i++) 592 { 593 const IMAGE_RESOURCE_DIRECTORY *xresdir; 594 xresdir = find_entry_by_id(iconresdir, LOWORD(pIconId[i]), rootresdir); 595 if( !xresdir ) 596 { 597 WARN("icon entry %d not found\n", LOWORD(pIconId[i])); 598 RetPtr[i]=0; 599 continue; 600 } 601 xresdir = find_entry_default(xresdir, rootresdir); 602 idataent = (const IMAGE_RESOURCE_DATA_ENTRY*)xresdir; 603 604 idata = RtlImageRvaToVa(RtlImageNtHeader((HMODULE)peimage), (HMODULE)peimage, idataent->OffsetToData, NULL); 605 if (!idata) 606 { 607 WARN("no matching real address found for icondata!\n"); 608 RetPtr[i]=0; 609 continue; 610 } 611 RetPtr[i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx1, cy1, flags); 612 if (cx2 && cy2) 613 RetPtr[++i] = CreateIconFromResourceEx(idata, idataent->Size, TRUE, 0x00030000, cx2, cy2, flags); 614 } 615 ret = i; /* return number of retrieved icons */ 616 } /* if(sig == IMAGE_NT_SIGNATURE) */ 617 618 end: 619 UnmapViewOfFile(peimage); /* success */ 620 return ret; 621 } 622 623 /*********************************************************************** 624 * PrivateExtractIconsW [USER32.@] 625 * 626 * NOTES 627 * If HIWORD(sizeX) && HIWORD(sizeY) 2 * ((nIcons + 1) MOD 2) icons are 628 * returned, with the LOWORD size icon first and the HIWORD size icon 629 * second. 630 * Also the Windows equivalent does extract icons in a strange way if 631 * nIndex is negative. Our implementation treats a negative nIndex as 632 * looking for that resource identifier for the first icon to retrieve. 633 * 634 * FIXME: 635 * should also support 16 bit EXE + DLLs, cursor and animated cursor as 636 * well as bitmap files. 637 */ 638 639 UINT WINAPI PrivateExtractIconsW ( 640 LPCWSTR lpwstrFile, 641 int nIndex, 642 int sizeX, 643 int sizeY, 644 HICON * phicon, /* [out] pointer to array of nIcons HICON handles */ 645 UINT* pIconId, /* [out] pointer to array of nIcons icon identifiers or NULL */ 646 UINT nIcons, /* [in] number of icons to retrieve */ 647 UINT flags ) /* [in] LR_* flags used by LoadImage */ 648 { 649 TRACE("%s %d %dx%d %p %p %d 0x%08x\n", 650 debugstr_w(lpwstrFile), nIndex, sizeX, sizeY, phicon, pIconId, nIcons, flags); 651 652 if ((nIcons & 1) && HIWORD(sizeX) && HIWORD(sizeY)) 653 { 654 WARN("Uneven number %d of icons requested for small and large icons!\n", nIcons); 655 } 656 return ICO_ExtractIconExW(lpwstrFile, phicon, nIndex, nIcons, sizeX, sizeY, pIconId, flags); 657 } 658 659 /*********************************************************************** 660 * PrivateExtractIconsA [USER32.@] 661 */ 662 663 UINT WINAPI PrivateExtractIconsA ( 664 LPCSTR lpstrFile, 665 int nIndex, 666 int sizeX, 667 int sizeY, 668 HICON * phicon, /* [out] pointer to array of nIcons HICON handles */ 669 UINT* piconid, /* [out] pointer to array of nIcons icon identifiers or NULL */ 670 UINT nIcons, /* [in] number of icons to retrieve */ 671 UINT flags ) /* [in] LR_* flags used by LoadImage */ 672 { 673 UINT ret; 674 INT len = MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, NULL, 0); 675 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 676 #ifdef __REACTOS__ 677 if (lpwstrFile == NULL) 678 return 0; 679 #endif 680 681 MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, lpwstrFile, len); 682 ret = PrivateExtractIconsW(lpwstrFile, nIndex, sizeX, sizeY, phicon, piconid, nIcons, flags); 683 684 HeapFree(GetProcessHeap(), 0, lpwstrFile); 685 return ret; 686 } 687 688 /*********************************************************************** 689 * PrivateExtractIconExW [USER32.@] 690 * NOTES 691 * if nIndex == -1 it returns the number of icons in any case !!! 692 */ 693 UINT WINAPI PrivateExtractIconExW ( 694 LPCWSTR lpwstrFile, 695 int nIndex, 696 HICON * phIconLarge, 697 HICON * phIconSmall, 698 UINT nIcons ) 699 { 700 DWORD cyicon, cysmicon, cxicon, cxsmicon; 701 UINT ret = 0; 702 703 TRACE("%s %d %p %p %d\n", 704 debugstr_w(lpwstrFile),nIndex,phIconLarge, phIconSmall, nIcons); 705 706 if (nIndex == -1) 707 /* get the number of icons */ 708 return ICO_ExtractIconExW(lpwstrFile, NULL, 0, 0, 0, 0, NULL, LR_DEFAULTCOLOR); 709 710 if (nIcons == 1 && phIconSmall && phIconLarge) 711 { 712 HICON hIcon[2]; 713 cxicon = GetSystemMetrics(SM_CXICON); 714 cyicon = GetSystemMetrics(SM_CYICON); 715 cxsmicon = GetSystemMetrics(SM_CXSMICON); 716 cysmicon = GetSystemMetrics(SM_CYSMICON); 717 718 ret = ICO_ExtractIconExW(lpwstrFile, hIcon, nIndex, 2, cxicon | (cxsmicon<<16), 719 cyicon | (cysmicon<<16), NULL, LR_DEFAULTCOLOR); 720 *phIconLarge = hIcon[0]; 721 *phIconSmall = hIcon[1]; 722 return ret; 723 } 724 725 if (phIconSmall) 726 { 727 /* extract n small icons */ 728 cxsmicon = GetSystemMetrics(SM_CXSMICON); 729 cysmicon = GetSystemMetrics(SM_CYSMICON); 730 ret = ICO_ExtractIconExW(lpwstrFile, phIconSmall, nIndex, nIcons, cxsmicon, 731 cysmicon, NULL, LR_DEFAULTCOLOR); 732 } 733 if (phIconLarge) 734 { 735 /* extract n large icons */ 736 cxicon = GetSystemMetrics(SM_CXICON); 737 cyicon = GetSystemMetrics(SM_CYICON); 738 ret = ICO_ExtractIconExW(lpwstrFile, phIconLarge, nIndex, nIcons, cxicon, 739 cyicon, NULL, LR_DEFAULTCOLOR); 740 } 741 return ret; 742 } 743 744 /*********************************************************************** 745 * PrivateExtractIconExA [USER32.@] 746 */ 747 UINT WINAPI PrivateExtractIconExA ( 748 LPCSTR lpstrFile, 749 int nIndex, 750 HICON * phIconLarge, 751 HICON * phIconSmall, 752 UINT nIcons ) 753 { 754 UINT ret; 755 INT len = MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, NULL, 0); 756 LPWSTR lpwstrFile = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR)); 757 #ifdef __REACTOS__ 758 if (lpwstrFile == NULL) 759 return 0; 760 #endif 761 762 TRACE("%s %d %p %p %d\n", lpstrFile, nIndex, phIconLarge, phIconSmall, nIcons); 763 764 MultiByteToWideChar(CP_ACP, 0, lpstrFile, -1, lpwstrFile, len); 765 ret = PrivateExtractIconExW(lpwstrFile, nIndex, phIconLarge, phIconSmall, nIcons); 766 HeapFree(GetProcessHeap(), 0, lpwstrFile); 767 return ret; 768 } 769