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