[8049] | 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 |
|
---|
| 9 | #include "config.h"
|
---|
| 10 |
|
---|
| 11 | #include <string.h>
|
---|
| 12 | #include <stdlib.h> /* abs() */
|
---|
| 13 | #include <sys/types.h>
|
---|
| 14 | #include <unistd.h>
|
---|
| 15 |
|
---|
| 16 |
|
---|
| 17 | #include "winbase.h"
|
---|
| 18 | #include "windef.h"
|
---|
| 19 | #include "winerror.h"
|
---|
| 20 | #include "wingdi.h"
|
---|
| 21 | #include "winuser.h"
|
---|
| 22 | #include "wine/winbase16.h"
|
---|
| 23 | #include "cursoricon.h"
|
---|
| 24 | #ifdef __WIN32OS2__
|
---|
| 25 | #include <odin.h>
|
---|
| 26 | #include "module.h"
|
---|
| 27 | #include "winnls.h"
|
---|
| 28 | #define s2 s
|
---|
| 29 | #define s3 s
|
---|
| 30 | #endif
|
---|
| 31 | #include "debugtools.h"
|
---|
| 32 |
|
---|
| 33 | 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 | #include "poppack.h"
|
---|
| 58 |
|
---|
| 59 | #if 0
|
---|
| 60 | static void dumpIcoDirEnty ( LPicoICONDIRENTRY entry )
|
---|
| 61 | {
|
---|
| 62 | TRACE("width = 0x%08x height = 0x%08x\n", entry->bWidth, entry->bHeight);
|
---|
| 63 | TRACE("colors = 0x%08x planes = 0x%08x\n", entry->bColorCount, entry->wPlanes);
|
---|
| 64 | TRACE("bitcount = 0x%08x bytesinres = 0x%08lx offset = 0x%08lx\n",
|
---|
| 65 | entry->wBitCount, entry->dwBytesInRes, entry->dwImageOffset);
|
---|
| 66 | }
|
---|
| 67 | static void dumpIcoDir ( LPicoICONDIR entry )
|
---|
| 68 | {
|
---|
| 69 | TRACE("type = 0x%08x count = 0x%08x\n", entry->idType, entry->idCount);
|
---|
| 70 | }
|
---|
| 71 | #endif
|
---|
| 72 |
|
---|
| 73 | /**********************************************************************
|
---|
| 74 | * find_entry_by_id
|
---|
| 75 | *
|
---|
| 76 | * Find an entry by id in a resource directory
|
---|
| 77 | * Copied from loader/pe_resource.c (FIXME: should use exported resource functions)
|
---|
| 78 | */
|
---|
| 79 | static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
|
---|
| 80 | WORD id, const void *root )
|
---|
| 81 | {
|
---|
| 82 | const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
|
---|
| 83 | int min, max, pos;
|
---|
| 84 |
|
---|
| 85 | entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
|
---|
| 86 | min = dir->NumberOfNamedEntries;
|
---|
| 87 | max = min + dir->NumberOfIdEntries - 1;
|
---|
| 88 | while (min <= max)
|
---|
| 89 | {
|
---|
| 90 | pos = (min + max) / 2;
|
---|
| 91 | if (entry[pos].u1.Id == id)
|
---|
| 92 | return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
|
---|
| 93 | if (entry[pos].u1.Id > id) max = pos - 1;
|
---|
| 94 | else min = pos + 1;
|
---|
| 95 | }
|
---|
| 96 | return NULL;
|
---|
| 97 | }
|
---|
| 98 |
|
---|
| 99 | /**********************************************************************
|
---|
| 100 | * find_entry_default
|
---|
| 101 | *
|
---|
| 102 | * Find a default entry 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_default( const IMAGE_RESOURCE_DIRECTORY *dir,
|
---|
| 106 | const void *root )
|
---|
| 107 | {
|
---|
| 108 | const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
|
---|
| 109 | entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
|
---|
| 110 | return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
|
---|
| 111 | }
|
---|
| 112 |
|
---|
| 113 | /*************************************************************************
|
---|
| 114 | * USER32_GetResourceTable
|
---|
| 115 | */
|
---|
| 116 | static DWORD USER32_GetResourceTable(LPBYTE peimage,DWORD pesize,LPBYTE *retptr)
|
---|
| 117 | {
|
---|
| 118 | IMAGE_DOS_HEADER * mz_header;
|
---|
| 119 |
|
---|
| 120 | TRACE("%p %p\n", peimage, retptr);
|
---|
| 121 |
|
---|
| 122 | *retptr = NULL;
|
---|
| 123 |
|
---|
| 124 | mz_header = (IMAGE_DOS_HEADER*) peimage;
|
---|
| 125 |
|
---|
| 126 | if (mz_header->e_magic != IMAGE_DOS_SIGNATURE)
|
---|
| 127 | {
|
---|
| 128 | if (mz_header->e_cblp == 1) /* .ICO file ? */
|
---|
| 129 | {
|
---|
| 130 | *retptr = (LPBYTE)-1; /* ICONHEADER.idType, must be 1 */
|
---|
| 131 | return 1;
|
---|
| 132 | }
|
---|
| 133 | else
|
---|
| 134 | return 0; /* failed */
|
---|
| 135 | }
|
---|
| 136 | if (mz_header->e_lfanew >= pesize) {
|
---|
| 137 | return 0; /* failed, happens with PKZIP DOS Exes for instance. */
|
---|
| 138 | }
|
---|
| 139 | if (*((DWORD*)(peimage + mz_header->e_lfanew)) == IMAGE_NT_SIGNATURE )
|
---|
| 140 | return IMAGE_NT_SIGNATURE;
|
---|
| 141 |
|
---|
| 142 | if (*((WORD*)(peimage + mz_header->e_lfanew)) == IMAGE_OS2_SIGNATURE )
|
---|
| 143 | {
|
---|
| 144 | IMAGE_OS2_HEADER * ne_header;
|
---|
| 145 |
|
---|
| 146 | ne_header = (IMAGE_OS2_HEADER*)(peimage + mz_header->e_lfanew);
|
---|
| 147 |
|
---|
| 148 | if (ne_header->ne_magic != IMAGE_OS2_SIGNATURE)
|
---|
| 149 | return 0;
|
---|
| 150 |
|
---|
| 151 | if( (ne_header->ne_restab - ne_header->ne_rsrctab) <= sizeof(NE_TYPEINFO) )
|
---|
| 152 | *retptr = (LPBYTE)-1;
|
---|
| 153 | else
|
---|
| 154 | *retptr = peimage + mz_header->e_lfanew + ne_header->ne_rsrctab;
|
---|
| 155 |
|
---|
| 156 | return IMAGE_OS2_SIGNATURE;
|
---|
| 157 | }
|
---|
| 158 | return 0; /* failed */
|
---|
| 159 | }
|
---|
| 160 | /*************************************************************************
|
---|
| 161 | * USER32_LoadResource
|
---|
| 162 | */
|
---|
| 163 | static BYTE * USER32_LoadResource( LPBYTE peimage, NE_NAMEINFO* pNInfo, WORD sizeShift, ULONG *uSize)
|
---|
| 164 | {
|
---|
| 165 | TRACE("%p %p 0x%08x\n", peimage, pNInfo, sizeShift);
|
---|
| 166 |
|
---|
| 167 | *uSize = (DWORD)pNInfo->length << sizeShift;
|
---|
| 168 | return peimage + ((DWORD)pNInfo->offset << sizeShift);
|
---|
| 169 | }
|
---|
| 170 |
|
---|
| 171 | /*************************************************************************
|
---|
| 172 | * ICO_LoadIcon
|
---|
| 173 | */
|
---|
| 174 | static BYTE * ICO_LoadIcon( LPBYTE peimage, LPicoICONDIRENTRY lpiIDE, ULONG *uSize)
|
---|
| 175 | {
|
---|
| 176 | TRACE("%p %p\n", peimage, lpiIDE);
|
---|
| 177 |
|
---|
| 178 | *uSize = lpiIDE->dwBytesInRes;
|
---|
| 179 | return peimage + lpiIDE->dwImageOffset;
|
---|
| 180 | }
|
---|
| 181 |
|
---|
| 182 | /*************************************************************************
|
---|
| 183 | * ICO_GetIconDirectory
|
---|
| 184 | *
|
---|
| 185 | * Reads .ico file and build phony ICONDIR struct
|
---|
| 186 | * see http://www.microsoft.com/win32dev/ui/icons.htm
|
---|
| 187 | */
|
---|
| 188 | #define HEADER_SIZE (sizeof(CURSORICONDIR) - sizeof (CURSORICONDIRENTRY))
|
---|
| 189 | #define HEADER_SIZE_FILE (sizeof(icoICONDIR) - sizeof (icoICONDIRENTRY))
|
---|
| 190 |
|
---|
| 191 | static BYTE * ICO_GetIconDirectory( LPBYTE peimage, LPicoICONDIR* lplpiID, ULONG *uSize )
|
---|
| 192 | {
|
---|
| 193 | CURSORICONDIR * lpcid; /* icon resource in resource-dir format */
|
---|
| 194 | CURSORICONDIR * lpID; /* icon resource in resource format */
|
---|
| 195 | int i;
|
---|
| 196 |
|
---|
| 197 | TRACE("%p %p\n", peimage, lplpiID);
|
---|
| 198 |
|
---|
| 199 | lpcid = (CURSORICONDIR*)peimage;
|
---|
| 200 |
|
---|
| 201 | if( lpcid->idReserved || (lpcid->idType != 1) || (!lpcid->idCount) )
|
---|
| 202 | return 0;
|
---|
| 203 |
|
---|
| 204 | /* allocate the phony ICONDIR structure */
|
---|
| 205 | *uSize = lpcid->idCount * sizeof(CURSORICONDIRENTRY) + HEADER_SIZE;
|
---|
[21356] | 206 | if( (lpID = (CURSORICONDIR*)HeapAlloc(GetProcessHeap(),0, *uSize) ) != NULL)
|
---|
[8049] | 207 | {
|
---|
| 208 | /* copy the header */
|
---|
| 209 | lpID->idReserved = lpcid->idReserved;
|
---|
| 210 | lpID->idType = lpcid->idType;
|
---|
| 211 | lpID->idCount = lpcid->idCount;
|
---|
| 212 |
|
---|
| 213 | /* copy the entries */
|
---|
| 214 | for( i=0; i < lpcid->idCount; i++ )
|
---|
| 215 | {
|
---|
| 216 | memcpy((void*)&(lpID->idEntries[i]),(void*)&(lpcid->idEntries[i]), sizeof(CURSORICONDIRENTRY) - 2);
|
---|
| 217 | lpID->idEntries[i].wResId = i;
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 | *lplpiID = (LPicoICONDIR)peimage;
|
---|
| 221 | return (BYTE *)lpID;
|
---|
| 222 | }
|
---|
| 223 | return 0;
|
---|
| 224 | }
|
---|
| 225 |
|
---|
| 226 | /*************************************************************************
|
---|
| 227 | * ICO_ExtractIconExW [internal]
|
---|
| 228 | *
|
---|
| 229 | * NOTES
|
---|
| 230 | * nIcons = 0: returns number of Icons in file
|
---|
| 231 | *
|
---|
| 232 | * returns
|
---|
| 233 | * failure:0; success: icon handle or nr of icons (nIconIndex-1)
|
---|
| 234 | */
|
---|
| 235 | static HRESULT ICO_ExtractIconExW(
|
---|
| 236 | LPCWSTR lpszExeFileName,
|
---|
| 237 | HICON * RetPtr,
|
---|
| 238 | INT nIconIndex,
|
---|
| 239 | UINT nIcons,
|
---|
| 240 | UINT cxDesired,
|
---|
| 241 | UINT cyDesired )
|
---|
| 242 | {
|
---|
| 243 | HGLOBAL hRet = E_FAIL;
|
---|
| 244 | LPBYTE pData;
|
---|
| 245 | DWORD sig;
|
---|
| 246 | HFILE hFile;
|
---|
| 247 | UINT16 iconDirCount = 0,iconCount = 0;
|
---|
| 248 | LPBYTE peimage;
|
---|
| 249 | HANDLE fmapping;
|
---|
| 250 | ULONG uSize;
|
---|
| 251 | DWORD fsizeh,fsizel;
|
---|
| 252 |
|
---|
| 253 | TRACE("(file %s,start %d,extract %d\n", debugstr_w(lpszExeFileName), nIconIndex, nIcons);
|
---|
| 254 |
|
---|
| 255 | hFile = CreateFileW( lpszExeFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
|
---|
| 256 | if (hFile == INVALID_HANDLE_VALUE) return hRet;
|
---|
| 257 | fsizel = GetFileSize(hFile,&fsizeh);
|
---|
| 258 |
|
---|
| 259 | /* Map the file */
|
---|
| 260 | fmapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL );
|
---|
| 261 | CloseHandle( hFile );
|
---|
| 262 | if (!fmapping)
|
---|
| 263 | {
|
---|
| 264 | WARN("CreateFileMapping error %ld\n", GetLastError() );
|
---|
| 265 | return hRet;
|
---|
| 266 | }
|
---|
| 267 |
|
---|
| 268 | if ( !(peimage = MapViewOfFile(fmapping,FILE_MAP_READ,0,0,0)))
|
---|
| 269 | {
|
---|
| 270 | WARN("MapViewOfFile error %ld\n", GetLastError() );
|
---|
| 271 | CloseHandle( fmapping );
|
---|
| 272 | return hRet;
|
---|
| 273 | }
|
---|
| 274 | CloseHandle( fmapping );
|
---|
| 275 |
|
---|
| 276 | sig = USER32_GetResourceTable(peimage,fsizel,&pData);
|
---|
| 277 |
|
---|
| 278 | /* ico file */
|
---|
| 279 | if( sig==IMAGE_OS2_SIGNATURE || sig==1 ) /* .ICO file */
|
---|
| 280 | {
|
---|
| 281 | BYTE *pCIDir = 0;
|
---|
| 282 | NE_TYPEINFO *pTInfo = (NE_TYPEINFO*)(pData + 2);
|
---|
| 283 | NE_NAMEINFO *pIconStorage = NULL;
|
---|
| 284 | NE_NAMEINFO *pIconDir = NULL;
|
---|
| 285 | LPicoICONDIR lpiID = NULL;
|
---|
| 286 |
|
---|
| 287 | TRACE("-- OS2/icon Signature (0x%08lx)\n", sig);
|
---|
| 288 |
|
---|
| 289 | if( pData == (BYTE*)-1 )
|
---|
| 290 | {
|
---|
| 291 | /* FIXME: pCIDir is allocated on the heap - memory leak */
|
---|
| 292 | pCIDir = ICO_GetIconDirectory(peimage, &lpiID, &uSize); /* check for .ICO file */
|
---|
| 293 | if( pCIDir )
|
---|
| 294 | {
|
---|
| 295 | iconDirCount = 1; iconCount = lpiID->idCount;
|
---|
| 296 | TRACE("-- icon found %p 0x%08lx 0x%08x 0x%08x\n", pCIDir, uSize, iconDirCount, iconCount);
|
---|
| 297 | }
|
---|
| 298 | }
|
---|
| 299 | else while( pTInfo->type_id && !(pIconStorage && pIconDir) )
|
---|
| 300 | {
|
---|
| 301 | if( pTInfo->type_id == NE_RSCTYPE_GROUP_ICON ) /* find icon directory and icon repository */
|
---|
| 302 | {
|
---|
| 303 | iconDirCount = pTInfo->count;
|
---|
| 304 | pIconDir = ((NE_NAMEINFO*)(pTInfo + 1));
|
---|
| 305 | TRACE("\tfound directory - %i icon families\n", iconDirCount);
|
---|
| 306 | }
|
---|
| 307 | if( pTInfo->type_id == NE_RSCTYPE_ICON )
|
---|
| 308 | {
|
---|
| 309 | iconCount = pTInfo->count;
|
---|
| 310 | pIconStorage = ((NE_NAMEINFO*)(pTInfo + 1));
|
---|
| 311 | TRACE("\ttotal icons - %i\n", iconCount);
|
---|
| 312 | }
|
---|
| 313 | pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1)+pTInfo->count*sizeof(NE_NAMEINFO));
|
---|
| 314 | }
|
---|
| 315 |
|
---|
| 316 | if( (pIconStorage && pIconDir) || lpiID ) /* load resources and create icons */
|
---|
| 317 | {
|
---|
| 318 | if( nIcons == 0 )
|
---|
| 319 | {
|
---|
| 320 | hRet = iconDirCount;
|
---|
| 321 | }
|
---|
| 322 | else if( nIconIndex < iconDirCount )
|
---|
| 323 | {
|
---|
| 324 | UINT16 i, icon;
|
---|
| 325 | if( nIcons > iconDirCount - nIconIndex )
|
---|
| 326 | nIcons = iconDirCount - nIconIndex;
|
---|
| 327 |
|
---|
| 328 | for( i = nIconIndex; i < nIconIndex + nIcons; i++ )
|
---|
| 329 | {
|
---|
| 330 | /* .ICO files have only one icon directory */
|
---|
| 331 | if( lpiID == NULL ) /* *.ico */
|
---|
| 332 | pCIDir = USER32_LoadResource( peimage, pIconDir + i, *(WORD*)pData, &uSize );
|
---|
| 333 | RetPtr[i-nIconIndex] = LookupIconIdFromDirectoryEx( pCIDir, TRUE, cxDesired, cyDesired, 0);
|
---|
| 334 | }
|
---|
| 335 |
|
---|
| 336 | for( icon = nIconIndex; icon < nIconIndex + nIcons; icon++ )
|
---|
| 337 | {
|
---|
| 338 | pCIDir = NULL;
|
---|
| 339 | if( lpiID )
|
---|
| 340 | pCIDir = ICO_LoadIcon( peimage, lpiID->idEntries + RetPtr[icon-nIconIndex], &uSize);
|
---|
| 341 | else
|
---|
| 342 | for( i = 0; i < iconCount; i++ )
|
---|
| 343 | if( pIconStorage[i].id == (RetPtr[icon-nIconIndex] | 0x8000) )
|
---|
| 344 | pCIDir = USER32_LoadResource( peimage, pIconStorage + i,*(WORD*)pData, &uSize );
|
---|
| 345 |
|
---|
| 346 | if( pCIDir )
|
---|
| 347 | RetPtr[icon-nIconIndex] = (HICON) CreateIconFromResourceEx(pCIDir,uSize,TRUE,0x00030000, cxDesired, cyDesired, LR_DEFAULTCOLOR);
|
---|
| 348 | else
|
---|
| 349 | RetPtr[icon-nIconIndex] = 0;
|
---|
| 350 | }
|
---|
| 351 | hRet = S_OK;
|
---|
| 352 | }
|
---|
| 353 | }
|
---|
| 354 | }
|
---|
| 355 | /* end ico file */
|
---|
| 356 |
|
---|
| 357 | /* exe/dll */
|
---|
| 358 | else if( sig == IMAGE_NT_SIGNATURE )
|
---|
| 359 | {
|
---|
| 360 | LPBYTE idata,igdata;
|
---|
| 361 | PIMAGE_DOS_HEADER dheader;
|
---|
| 362 | PIMAGE_NT_HEADERS pe_header;
|
---|
| 363 | PIMAGE_SECTION_HEADER pe_sections;
|
---|
| 364 | const IMAGE_RESOURCE_DIRECTORY *rootresdir,*iconresdir,*icongroupresdir;
|
---|
| 365 | const IMAGE_RESOURCE_DATA_ENTRY *idataent,*igdataent;
|
---|
| 366 | const IMAGE_RESOURCE_DIRECTORY_ENTRY *xresent;
|
---|
| 367 | int i,j;
|
---|
| 368 |
|
---|
| 369 | dheader = (PIMAGE_DOS_HEADER)peimage;
|
---|
| 370 | pe_header = (PIMAGE_NT_HEADERS)(peimage+dheader->e_lfanew); /* it is a pe header, USER32_GetResourceTable checked that */
|
---|
| 371 | pe_sections = (PIMAGE_SECTION_HEADER)(((char*)pe_header)+sizeof(*pe_header)); /* probably makes problems with short PE headers...*/
|
---|
| 372 | rootresdir = NULL;
|
---|
| 373 |
|
---|
| 374 | /* search for the root resource directory */
|
---|
| 375 | for (i=0;i<pe_header->FileHeader.NumberOfSections;i++)
|
---|
| 376 | {
|
---|
| 377 | if (pe_sections[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA)
|
---|
| 378 | continue;
|
---|
| 379 | if (fsizel < pe_sections[i].PointerToRawData+pe_sections[i].SizeOfRawData) {
|
---|
| 380 | FIXME("File %s too short (section is at %ld bytes, real size is %ld)\n",
|
---|
| 381 | debugstr_w(lpszExeFileName),
|
---|
| 382 | pe_sections[i].PointerToRawData+pe_sections[i].SizeOfRawData,
|
---|
| 383 | fsizel
|
---|
| 384 | );
|
---|
| 385 | goto end;
|
---|
| 386 | }
|
---|
| 387 | /* FIXME: doesn't work when the resources are not in a separate section */
|
---|
| 388 | if (pe_sections[i].VirtualAddress == pe_header->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress)
|
---|
| 389 | {
|
---|
| 390 | rootresdir = (PIMAGE_RESOURCE_DIRECTORY)(peimage+pe_sections[i].PointerToRawData);
|
---|
| 391 | break;
|
---|
| 392 | }
|
---|
| 393 | }
|
---|
| 394 |
|
---|
| 395 | if (!rootresdir)
|
---|
| 396 | {
|
---|
| 397 | WARN("haven't found section for resource directory.\n");
|
---|
| 398 | goto end; /* failure */
|
---|
| 399 | }
|
---|
| 400 |
|
---|
| 401 | /* search for the group icon directory */
|
---|
| 402 | if (!(icongroupresdir = find_entry_by_id(rootresdir, LOWORD(RT_GROUP_ICONW), rootresdir)))
|
---|
| 403 | {
|
---|
| 404 | WARN("No Icongroupresourcedirectory!\n");
|
---|
| 405 | goto end; /* failure */
|
---|
| 406 | }
|
---|
| 407 | iconDirCount = icongroupresdir->NumberOfNamedEntries + icongroupresdir->NumberOfIdEntries;
|
---|
| 408 |
|
---|
| 409 | /* only number of icons requested */
|
---|
| 410 | if( nIcons == 0 )
|
---|
| 411 | {
|
---|
| 412 | hRet = iconDirCount;
|
---|
| 413 | goto end; /* success */
|
---|
| 414 | }
|
---|
| 415 |
|
---|
| 416 | if( nIconIndex < 0 )
|
---|
| 417 | {
|
---|
| 418 | /* search resource id */
|
---|
| 419 | int n = 0;
|
---|
| 420 | int iId = abs(nIconIndex);
|
---|
| 421 | PIMAGE_RESOURCE_DIRECTORY_ENTRY xprdeTmp = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1);
|
---|
| 422 |
|
---|
| 423 | while(n<iconDirCount && xprdeTmp)
|
---|
| 424 | {
|
---|
| 425 | if(xprdeTmp->u1.Id == iId)
|
---|
| 426 | {
|
---|
| 427 | nIconIndex = n;
|
---|
| 428 | break;
|
---|
| 429 | }
|
---|
| 430 | n++;
|
---|
| 431 | xprdeTmp++;
|
---|
| 432 | }
|
---|
| 433 | if (nIconIndex < 0)
|
---|
| 434 | {
|
---|
| 435 | WARN("resource id %d not found\n", iId);
|
---|
| 436 | goto end; /* failure */
|
---|
| 437 | }
|
---|
| 438 | }
|
---|
| 439 | else
|
---|
| 440 | {
|
---|
| 441 | /* check nIconIndex to be in range */
|
---|
| 442 | if (nIconIndex >= iconDirCount)
|
---|
| 443 | {
|
---|
| 444 | WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex,iconDirCount);
|
---|
| 445 | goto end; /* failure */
|
---|
| 446 | }
|
---|
| 447 | }
|
---|
| 448 |
|
---|
| 449 | /* assure we don't get too much */
|
---|
| 450 | if( nIcons > iconDirCount - nIconIndex )
|
---|
| 451 | nIcons = iconDirCount - nIconIndex;
|
---|
| 452 |
|
---|
| 453 | /* starting from specified index */
|
---|
| 454 | xresent = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(icongroupresdir+1) + nIconIndex;
|
---|
| 455 |
|
---|
| 456 | for (i=0; i < nIcons; i++,xresent++)
|
---|
| 457 | {
|
---|
| 458 | const IMAGE_RESOURCE_DIRECTORY *resdir;
|
---|
| 459 |
|
---|
| 460 | /* go down this resource entry, name */
|
---|
| 461 | resdir = (PIMAGE_RESOURCE_DIRECTORY)((DWORD)rootresdir+(xresent->u2.s3.OffsetToDirectory));
|
---|
| 462 |
|
---|
| 463 | /* default language (0) */
|
---|
| 464 | resdir = find_entry_default(resdir,rootresdir);
|
---|
| 465 | igdataent = (PIMAGE_RESOURCE_DATA_ENTRY)resdir;
|
---|
| 466 |
|
---|
| 467 | /* lookup address in mapped image for virtual address */
|
---|
| 468 | igdata = NULL;
|
---|
| 469 |
|
---|
| 470 | for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
|
---|
| 471 | {
|
---|
| 472 | if (igdataent->OffsetToData < pe_sections[j].VirtualAddress)
|
---|
| 473 | continue;
|
---|
| 474 | if (igdataent->OffsetToData+igdataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
|
---|
| 475 | continue;
|
---|
| 476 |
|
---|
| 477 | if (igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData+igdataent->Size > fsizel) {
|
---|
| 478 | FIXME("overflow in PE lookup (%s has len %ld, have offset %ld), short file?\n",debugstr_w(lpszExeFileName),fsizel,igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData+igdataent->Size);
|
---|
| 479 | goto end; /* failure */
|
---|
| 480 | }
|
---|
| 481 | igdata = peimage+(igdataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
|
---|
| 482 | }
|
---|
| 483 |
|
---|
| 484 | if (!igdata)
|
---|
| 485 | {
|
---|
| 486 | FIXME("no matching real address for icongroup!\n");
|
---|
| 487 | goto end; /* failure */
|
---|
| 488 | }
|
---|
| 489 | RetPtr[i] = (HICON)LookupIconIdFromDirectoryEx(igdata, TRUE, cxDesired, cyDesired, LR_DEFAULTCOLOR);
|
---|
| 490 | }
|
---|
| 491 |
|
---|
| 492 | if (!(iconresdir=find_entry_by_id(rootresdir,LOWORD(RT_ICONW),rootresdir)))
|
---|
| 493 | {
|
---|
| 494 | WARN("No Iconresourcedirectory!\n");
|
---|
| 495 | goto end; /* failure */
|
---|
| 496 | }
|
---|
| 497 |
|
---|
| 498 | for (i=0; i<nIcons; i++)
|
---|
| 499 | {
|
---|
| 500 | const IMAGE_RESOURCE_DIRECTORY *xresdir;
|
---|
| 501 | xresdir = find_entry_by_id(iconresdir,RetPtr[i],rootresdir);
|
---|
| 502 | xresdir = find_entry_default(xresdir,rootresdir);
|
---|
| 503 | idataent = (PIMAGE_RESOURCE_DATA_ENTRY)xresdir;
|
---|
| 504 | idata = NULL;
|
---|
| 505 |
|
---|
| 506 | /* map virtual to address in image */
|
---|
| 507 | for (j=0;j<pe_header->FileHeader.NumberOfSections;j++)
|
---|
| 508 | {
|
---|
| 509 | if (idataent->OffsetToData < pe_sections[j].VirtualAddress)
|
---|
| 510 | continue;
|
---|
| 511 | if (idataent->OffsetToData+idataent->Size > pe_sections[j].VirtualAddress+pe_sections[j].SizeOfRawData)
|
---|
| 512 | continue;
|
---|
| 513 | idata = peimage+(idataent->OffsetToData-pe_sections[j].VirtualAddress+pe_sections[j].PointerToRawData);
|
---|
| 514 | }
|
---|
| 515 | if (!idata)
|
---|
| 516 | {
|
---|
| 517 | WARN("no matching real address found for icondata!\n");
|
---|
| 518 | RetPtr[i]=0;
|
---|
| 519 | continue;
|
---|
| 520 | }
|
---|
| 521 | RetPtr[i] = (HICON) CreateIconFromResourceEx(idata,idataent->Size,TRUE,0x00030000, cxDesired, cyDesired, LR_DEFAULTCOLOR);
|
---|
| 522 | }
|
---|
| 523 | hRet = S_OK; /* return first icon */
|
---|
| 524 | } /* if(sig == IMAGE_NT_SIGNATURE) */
|
---|
| 525 |
|
---|
| 526 | end: UnmapViewOfFile(peimage); /* success */
|
---|
| 527 | return hRet;
|
---|
| 528 | }
|
---|
| 529 |
|
---|
| 530 | /***********************************************************************
|
---|
| 531 | * PrivateExtractIconsW [USER32.@]
|
---|
| 532 | *
|
---|
| 533 | * NOTES
|
---|
| 534 | * nIndex = 1: a small and a large icon are extracted.
|
---|
| 535 | * the higher word of sizeXY contains the size of the small icon, the lower
|
---|
| 536 | * word the size of the big icon. phicon points to HICON[2].
|
---|
| 537 | *
|
---|
| 538 | * RETURNS
|
---|
| 539 | * nIcons > 0: HRESULT
|
---|
| 540 | * nIcons = 0: the number of icons
|
---|
| 541 | */
|
---|
| 542 |
|
---|
| 543 | HRESULT WINAPI PrivateExtractIconsW (
|
---|
| 544 | LPCWSTR lpwstrFile,
|
---|
| 545 | int nIndex,
|
---|
| 546 | DWORD sizeX,
|
---|
| 547 | DWORD sizeY,
|
---|
| 548 | HICON * phicon, /* [???] NOTE: HICON* */
|
---|
| 549 | DWORD w, /* [in] NOTE: 0 */
|
---|
| 550 | UINT nIcons,
|
---|
| 551 | DWORD y ) /* [in] NOTE: 0x80 maybe LR_* constant */
|
---|
| 552 | {
|
---|
| 553 | DWORD ret;
|
---|
| 554 | TRACE("%s 0x%08x 0x%08lx 0x%08lx %p 0x%08lx 0x%08x 0x%08lx\n",
|
---|
| 555 | debugstr_w(lpwstrFile),nIndex, sizeX ,sizeY ,phicon,w,nIcons,y );
|
---|
| 556 |
|
---|
| 557 | if ((nIcons == 2) && HIWORD(sizeX) && HIWORD(sizeY))
|
---|
| 558 | {
|
---|
| 559 | ret = ICO_ExtractIconExW(lpwstrFile, phicon, nIndex, 1, sizeX & 0xffff, sizeY & 0xffff );
|
---|
| 560 | if (!SUCCEEDED(ret)) return ret;
|
---|
| 561 | ret = ICO_ExtractIconExW(lpwstrFile, phicon+1, nIndex, 1, (sizeX>>16) & 0xffff, (sizeY>>16) & 0xffff );
|
---|
| 562 | } else
|
---|
| 563 | ret = ICO_ExtractIconExW(lpwstrFile, phicon, nIndex, nIcons, sizeX & 0xffff, sizeY & 0xffff );
|
---|
| 564 | return ret;
|
---|
| 565 | }
|
---|
| 566 |
|
---|
| 567 | /***********************************************************************
|
---|
| 568 | * PrivateExtractIconsA [USER32.@]
|
---|
| 569 | */
|
---|
| 570 |
|
---|
| 571 | HRESULT WINAPI PrivateExtractIconsA (
|
---|
| 572 | LPCSTR lpstrFile,
|
---|
| 573 | INT nIndex,
|
---|
| 574 | DWORD sizeX,
|
---|
| 575 | DWORD sizeY,
|
---|
| 576 | HICON * phicon,
|
---|
| 577 | DWORD w, /* [in] NOTE: 0 */
|
---|
| 578 | UINT nIcons,
|
---|
| 579 | DWORD y ) /* [in] NOTE: 0x80 */
|
---|
| 580 | {
|
---|
| 581 | DWORD ret;
|
---|
| 582 | INT len = MultiByteToWideChar( CP_ACP, 0, lpstrFile, -1, NULL, 0 );
|
---|
| 583 | LPWSTR lpwstrFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
|
---|
| 584 |
|
---|
| 585 | MultiByteToWideChar( CP_ACP, 0, lpstrFile, -1, lpwstrFile, len );
|
---|
| 586 | ret = PrivateExtractIconsW(
|
---|
| 587 | lpwstrFile, nIndex, sizeX, sizeY, phicon, w, nIcons, y
|
---|
| 588 | );
|
---|
| 589 |
|
---|
| 590 | HeapFree(GetProcessHeap(), 0, lpwstrFile);
|
---|
| 591 | return ret;
|
---|
| 592 | }
|
---|
| 593 |
|
---|
| 594 | /***********************************************************************
|
---|
| 595 | * PrivateExtractIconExW [USER32.@]
|
---|
| 596 | * NOTES
|
---|
| 597 | * if nIcons = -1 it returns the number of icons in any case !!!
|
---|
| 598 | */
|
---|
| 599 | HRESULT WINAPI PrivateExtractIconExW (
|
---|
| 600 | LPCWSTR lpwstrFile,
|
---|
| 601 | DWORD nIndex,
|
---|
| 602 | HICON * phIconLarge,
|
---|
| 603 | HICON * phIconSmall,
|
---|
| 604 | UINT nIcons )
|
---|
| 605 | {
|
---|
| 606 | DWORD cyicon, cysmicon, cxicon, cxsmicon;
|
---|
| 607 | HRESULT ret = 0;
|
---|
| 608 |
|
---|
| 609 | TRACE("%s 0x%08lx %p %p 0x%08x\n",
|
---|
| 610 | debugstr_w(lpwstrFile),nIndex,phIconLarge, phIconSmall, nIcons);
|
---|
| 611 |
|
---|
| 612 | if (nIndex == 1 && phIconSmall && phIconLarge)
|
---|
| 613 | {
|
---|
| 614 | HICON hIcon[2];
|
---|
| 615 | cxicon = GetSystemMetrics(SM_CXICON);
|
---|
| 616 | cyicon = GetSystemMetrics(SM_CYICON);
|
---|
| 617 | cxsmicon = GetSystemMetrics(SM_CXSMICON);
|
---|
| 618 | cysmicon = GetSystemMetrics(SM_CYSMICON);
|
---|
| 619 |
|
---|
| 620 | ret = PrivateExtractIconsW ( lpwstrFile, nIndex, cxicon | (cxsmicon<<16), cyicon | (cysmicon<<16),
|
---|
| 621 | (HICON*) &hIcon, 0, 2, 0 );
|
---|
| 622 | *phIconLarge = hIcon[0];
|
---|
| 623 | *phIconSmall = hIcon[1];
|
---|
| 624 | return ret;
|
---|
| 625 | }
|
---|
| 626 |
|
---|
| 627 | if (nIndex != -1)
|
---|
| 628 | {
|
---|
| 629 | if (phIconSmall)
|
---|
| 630 | {
|
---|
| 631 | /* extract n small icons */
|
---|
| 632 | cxsmicon = GetSystemMetrics(SM_CXSMICON);
|
---|
| 633 | cysmicon = GetSystemMetrics(SM_CYSMICON);
|
---|
| 634 | ret = PrivateExtractIconsW ( lpwstrFile, nIndex, cxsmicon, cysmicon, phIconSmall, 0, nIcons, 0 );
|
---|
| 635 | }
|
---|
| 636 | if (phIconLarge )
|
---|
| 637 | {
|
---|
| 638 | /* extract n large icons */
|
---|
| 639 | cxicon = GetSystemMetrics(SM_CXICON);
|
---|
| 640 | cyicon = GetSystemMetrics(SM_CYICON);
|
---|
| 641 | ret = PrivateExtractIconsW ( lpwstrFile, nIndex, cxicon, cyicon, phIconLarge, 0, nIcons, 0 );
|
---|
| 642 | }
|
---|
| 643 | return ret;
|
---|
| 644 | }
|
---|
| 645 |
|
---|
| 646 | /* get the number of icons */
|
---|
| 647 | return PrivateExtractIconsW ( lpwstrFile, 0, 0, 0, 0, 0, 0, 0 );
|
---|
| 648 | }
|
---|
| 649 |
|
---|
| 650 | /***********************************************************************
|
---|
| 651 | * PrivateExtractIconExA [USER32.@]
|
---|
| 652 | */
|
---|
| 653 | HRESULT WINAPI PrivateExtractIconExA (
|
---|
| 654 | LPCSTR lpstrFile,
|
---|
| 655 | DWORD nIndex,
|
---|
| 656 | HICON * phIconLarge,
|
---|
| 657 | HICON * phIconSmall,
|
---|
| 658 | UINT nIcons )
|
---|
| 659 | {
|
---|
| 660 | DWORD ret;
|
---|
| 661 | INT len = MultiByteToWideChar( CP_ACP, 0, lpstrFile, -1, NULL, 0 );
|
---|
| 662 | LPWSTR lpwstrFile = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
|
---|
| 663 |
|
---|
| 664 | TRACE("%s 0x%08lx %p %p 0x%08x\n", lpstrFile, nIndex, phIconLarge, phIconSmall, nIcons);
|
---|
| 665 |
|
---|
| 666 | MultiByteToWideChar( CP_ACP, 0, lpstrFile, -1, lpwstrFile, len );
|
---|
| 667 | ret = PrivateExtractIconExW(lpwstrFile,nIndex,phIconLarge, phIconSmall, nIcons);
|
---|
| 668 | HeapFree(GetProcessHeap(), 0, lpwstrFile);
|
---|
| 669 | return ret;
|
---|
| 670 | }
|
---|
| 671 |
|
---|