| 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; | 
|---|
| 206 | if( (lpID = (CURSORICONDIR*)HeapAlloc(GetProcessHeap(),0, *uSize) ) != NULL) | 
|---|
| 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 |  | 
|---|