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
17 #include "cursoricon.h"
20 #include "debugtools.h"
22 DEFAULT_DEBUG_CHANNEL(icon
)
28 BYTE bWidth
; /* Width, in pixels, of the image */
29 BYTE bHeight
; /* Height, in pixels, of the image */
30 BYTE bColorCount
; /* Number of colors in image (0 if >=8bpp) */
31 BYTE bReserved
; /* Reserved ( must be 0) */
32 WORD wPlanes
; /* Color Planes */
33 WORD wBitCount
; /* Bits per pixel */
34 DWORD dwBytesInRes
; /* How many bytes in this resource? */
35 DWORD dwImageOffset
; /* Where in the file is this image? */
36 } icoICONDIRENTRY
, *LPicoICONDIRENTRY
;
40 WORD idReserved
; /* Reserved (must be 0) */
41 WORD idType
; /* Resource Type (RES_ICON or RES_CURSOR) */
42 WORD idCount
; /* How many images */
43 icoICONDIRENTRY idEntries
[1]; /* An entry for each image (idCount of 'em) */
44 } icoICONDIR
, *LPicoICONDIR
;
49 static void dumpIcoDirEnty ( LPicoICONDIRENTRY entry
)
51 TRACE("width = 0x%08x height = 0x%08x\n", entry
->bWidth
, entry
->bHeight
);
52 TRACE("colors = 0x%08x planes = 0x%08x\n", entry
->bColorCount
, entry
->wPlanes
);
53 TRACE("bitcount = 0x%08x bytesinres = 0x%08lx offset = 0x%08lx\n",
54 entry
->wBitCount
, entry
->dwBytesInRes
, entry
->dwImageOffset
);
56 static void dumpIcoDir ( LPicoICONDIR entry
)
58 TRACE("type = 0x%08x count = 0x%08x\n", entry
->idType
, entry
->idCount
);
61 /*************************************************************************
62 * USER32_GetResourceTable
64 static DWORD
USER32_GetResourceTable(LPBYTE peimage
, LPBYTE
*retptr
)
66 IMAGE_DOS_HEADER
* mz_header
;
68 TRACE("%p %p\n", peimage
, retptr
);
72 mz_header
= (IMAGE_DOS_HEADER
*) peimage
;
74 if (mz_header
->e_magic
!= IMAGE_DOS_SIGNATURE
)
76 if (mz_header
->e_cblp
== 1) /* .ICO file ? */
78 *retptr
= (LPBYTE
)-1; /* ICONHEADER.idType, must be 1 */
82 return 0; /* failed */
85 if (*((DWORD
*)(peimage
+ mz_header
->e_lfanew
)) == IMAGE_NT_SIGNATURE
)
86 return IMAGE_NT_SIGNATURE
;
88 if (*((WORD
*)(peimage
+ mz_header
->e_lfanew
)) == IMAGE_OS2_SIGNATURE
)
90 IMAGE_OS2_HEADER
* ne_header
;
92 ne_header
= (IMAGE_OS2_HEADER
*)(peimage
+ mz_header
->e_lfanew
);
94 if (ne_header
->ne_magic
!= IMAGE_OS2_SIGNATURE
)
97 if( (ne_header
->ne_restab
- ne_header
->ne_rsrctab
) <= sizeof(NE_TYPEINFO
) )
100 *retptr
= peimage
+ mz_header
->e_lfanew
+ ne_header
->ne_rsrctab
;
102 return IMAGE_OS2_SIGNATURE
;
104 return 0; /* failed */
106 /*************************************************************************
107 * USER32_LoadResource
109 static BYTE
* USER32_LoadResource( LPBYTE peimage
, NE_NAMEINFO
* pNInfo
, WORD sizeShift
, ULONG
*uSize
)
111 TRACE("%p %p 0x%08x\n", peimage
, pNInfo
, sizeShift
);
113 *uSize
= (DWORD
)pNInfo
->length
<< sizeShift
;
114 return peimage
+ ((DWORD
)pNInfo
->offset
<< sizeShift
);
117 /*************************************************************************
120 static BYTE
* ICO_LoadIcon( LPBYTE peimage
, LPicoICONDIRENTRY lpiIDE
, ULONG
*uSize
)
122 TRACE("%p %p\n", peimage
, lpiIDE
);
124 *uSize
= lpiIDE
->dwBytesInRes
;
125 return peimage
+ lpiIDE
->dwImageOffset
;
128 /*************************************************************************
129 * ICO_GetIconDirectory
131 * Reads .ico file and build phony ICONDIR struct
132 * see http://www.microsoft.com/win32dev/ui/icons.htm
134 #define HEADER_SIZE (sizeof(CURSORICONDIR) - sizeof (CURSORICONDIRENTRY))
135 #define HEADER_SIZE_FILE (sizeof(icoICONDIR) - sizeof (icoICONDIRENTRY))
137 static BYTE
* ICO_GetIconDirectory( LPBYTE peimage
, LPicoICONDIR
* lplpiID
, ULONG
*uSize
)
139 CURSORICONDIR
* lpcid
; /* icon resource in resource-dir format */
140 CURSORICONDIR
* lpID
; /* icon resource in resource format */
143 TRACE("%p %p\n", peimage
, lplpiID
);
145 lpcid
= (CURSORICONDIR
*)peimage
;
147 if( lpcid
->idReserved
|| (lpcid
->idType
!= 1) || (!lpcid
->idCount
) )
150 /* allocate the phony ICONDIR structure */
151 *uSize
= lpcid
->idCount
* sizeof(CURSORICONDIRENTRY
) + HEADER_SIZE
;
152 if( (lpID
= (CURSORICONDIR
*)HeapAlloc(GetProcessHeap(),0, *uSize
) ))
154 /* copy the header */
155 lpID
->idReserved
= lpcid
->idReserved
;
156 lpID
->idType
= lpcid
->idType
;
157 lpID
->idCount
= lpcid
->idCount
;
159 /* copy the entrys */
160 for( i
=0; i
< lpcid
->idCount
; i
++ )
162 memcpy((void*)&(lpID
->idEntries
[i
]),(void*)&(lpcid
->idEntries
[i
]), sizeof(CURSORICONDIRENTRY
) - 2);
163 lpID
->idEntries
[i
].wResId
= i
;
166 *lplpiID
= (LPicoICONDIR
)peimage
;
172 /*************************************************************************
173 * ICO_ExtractIconExW [internal]
176 * nIcons = 0: returns number of Icons in file
179 * failure:0; success: icon handle or nr of icons (nIconIndex-1)
181 static HRESULT WINAPI
ICO_ExtractIconExW(
182 LPCWSTR lpszExeFileName
,
189 HGLOBAL hRet
= E_FAIL
;
193 UINT16 iconDirCount
= 0,iconCount
= 0;
198 TRACE("(file %s,start %d,extract %d\n", debugstr_w(lpszExeFileName
), nIconIndex
, nIcons
);
200 hFile
= CreateFileW( lpszExeFileName
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, -1 );
201 if (hFile
== INVALID_HANDLE_VALUE
) return hRet
;
204 fmapping
= CreateFileMappingA( hFile
, NULL
, PAGE_READONLY
| SEC_COMMIT
, 0, 0, NULL
);
207 WARN("CreateFileMapping error %ld\n", GetLastError() );
211 if ( !(peimage
= MapViewOfFile(fmapping
,FILE_MAP_READ
,0,0,0)))
213 WARN("MapViewOfFile error %ld\n", GetLastError() );
218 sig
= USER32_GetResourceTable(peimage
,&pData
);
221 if( sig
==IMAGE_OS2_SIGNATURE
|| sig
==1 ) /* .ICO file */
224 NE_TYPEINFO
*pTInfo
= (NE_TYPEINFO
*)(pData
+ 2);
225 NE_NAMEINFO
*pIconStorage
= NULL
;
226 NE_NAMEINFO
*pIconDir
= NULL
;
227 LPicoICONDIR lpiID
= NULL
;
229 TRACE("-- OS2/icon Signature (0x%08lx)\n", sig
);
231 if( pData
== (BYTE
*)-1 )
233 /* FIXME: pCIDir is allocated on the heap - memory leak */
234 pCIDir
= ICO_GetIconDirectory(peimage
, &lpiID
, &uSize
); /* check for .ICO file */
237 iconDirCount
= 1; iconCount
= lpiID
->idCount
;
238 TRACE("-- icon found %p 0x%08lx 0x%08x 0x%08x\n", pCIDir
, uSize
, iconDirCount
, iconCount
);
241 else while( pTInfo
->type_id
&& !(pIconStorage
&& pIconDir
) )
243 if( pTInfo
->type_id
== NE_RSCTYPE_GROUP_ICON
) /* find icon directory and icon repository */
245 iconDirCount
= pTInfo
->count
;
246 pIconDir
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
247 TRACE("\tfound directory - %i icon families\n", iconDirCount
);
249 if( pTInfo
->type_id
== NE_RSCTYPE_ICON
)
251 iconCount
= pTInfo
->count
;
252 pIconStorage
= ((NE_NAMEINFO
*)(pTInfo
+ 1));
253 TRACE("\ttotal icons - %i\n", iconCount
);
255 pTInfo
= (NE_TYPEINFO
*)((char*)(pTInfo
+1)+pTInfo
->count
*sizeof(NE_NAMEINFO
));
258 if( (pIconStorage
&& pIconDir
) || lpiID
) /* load resources and create icons */
264 else if( nIconIndex
< iconDirCount
)
267 if( nIcons
> iconDirCount
- nIconIndex
)
268 nIcons
= iconDirCount
- nIconIndex
;
270 for( i
= nIconIndex
; i
< nIconIndex
+ nIcons
; i
++ )
272 /* .ICO files have only one icon directory */
273 if( lpiID
== NULL
) /* *.ico */
274 pCIDir
= USER32_LoadResource( peimage
, pIconDir
+ i
, *(WORD
*)pData
, &uSize
);
275 RetPtr
[i
-nIconIndex
] = LookupIconIdFromDirectoryEx( pCIDir
, TRUE
, cxDesired
, cyDesired
, 0);
278 for( icon
= nIconIndex
; icon
< nIconIndex
+ nIcons
; icon
++ )
282 pCIDir
= ICO_LoadIcon( peimage
, lpiID
->idEntries
+ RetPtr
[icon
-nIconIndex
], &uSize
);
284 for( i
= 0; i
< iconCount
; i
++ )
285 if( pIconStorage
[i
].id
== (RetPtr
[icon
-nIconIndex
] | 0x8000) )
286 pCIDir
= USER32_LoadResource( peimage
, pIconStorage
+ i
,*(WORD
*)pData
, &uSize
);
289 RetPtr
[icon
-nIconIndex
] = (HICON
) CreateIconFromResourceEx(pCIDir
,uSize
,TRUE
,0x00030000, cxDesired
, cyDesired
, LR_DEFAULTCOLOR
);
291 RetPtr
[icon
-nIconIndex
] = 0;
300 else if( sig
== IMAGE_NT_SIGNATURE
)
303 PIMAGE_DOS_HEADER dheader
;
304 PIMAGE_NT_HEADERS pe_header
;
305 PIMAGE_SECTION_HEADER pe_sections
;
306 PIMAGE_RESOURCE_DIRECTORY rootresdir
,iconresdir
,icongroupresdir
;
307 PIMAGE_RESOURCE_DATA_ENTRY idataent
,igdataent
;
308 PIMAGE_RESOURCE_DIRECTORY_ENTRY xresent
;
311 dheader
= (PIMAGE_DOS_HEADER
)peimage
;
312 pe_header
= (PIMAGE_NT_HEADERS
)(peimage
+dheader
->e_lfanew
); /* it is a pe header, USER32_GetResourceTable checked that */
313 pe_sections
= (PIMAGE_SECTION_HEADER
)(((char*)pe_header
)+sizeof(*pe_header
)); /* probably makes problems with short PE headers...*/
316 /* search for the root resource directory */
317 for (i
=0;i
<pe_header
->FileHeader
.NumberOfSections
;i
++)
319 if (pe_sections
[i
].Characteristics
& IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
321 /* FIXME: doesn't work when the resources are not in a seperate section */
322 if (pe_sections
[i
].VirtualAddress
== pe_header
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
)
324 rootresdir
= (PIMAGE_RESOURCE_DIRECTORY
)(peimage
+pe_sections
[i
].PointerToRawData
);
331 WARN("haven't found section for resource directory.\n");
332 goto end_3
; /* failure */
335 /* search for the group icon directory */
336 if (!(icongroupresdir
= GetResDirEntryW(rootresdir
, RT_GROUP_ICONW
, (DWORD
)rootresdir
, FALSE
)))
338 WARN("No Icongroupresourcedirectory!\n");
339 goto end_3
; /* failure */
341 iconDirCount
= icongroupresdir
->NumberOfNamedEntries
+ icongroupresdir
->NumberOfIdEntries
;
343 /* only number of icons requested */
347 goto end_3
; /* success */
352 /* search resource id */
354 int iId
= abs(nIconIndex
);
355 PIMAGE_RESOURCE_DIRECTORY_ENTRY xprdeTmp
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(icongroupresdir
+1);
357 while(n
<iconDirCount
&& xprdeTmp
)
359 if(xprdeTmp
->u1
.Id
== iId
)
369 WARN("resource id %d not found\n", iId
);
370 goto end_3
; /* failure */
375 /* check nIconIndex to be in range */
376 if (nIconIndex
>= iconDirCount
)
378 WARN("nIconIndex %d is larger than iconDirCount %d\n",nIconIndex
,iconDirCount
);
379 goto end_3
; /* failure */
383 /* assure we don't get too much */
384 if( nIcons
> iconDirCount
- nIconIndex
)
385 nIcons
= iconDirCount
- nIconIndex
;
387 /* starting from specified index */
388 xresent
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(icongroupresdir
+1) + nIconIndex
;
390 for (i
=0; i
< nIcons
; i
++,xresent
++)
392 PIMAGE_RESOURCE_DIRECTORY resdir
;
394 /* go down this resource entry, name */
395 resdir
= (PIMAGE_RESOURCE_DIRECTORY
)((DWORD
)rootresdir
+(xresent
->u2
.s
.OffsetToDirectory
));
397 /* default language (0) */
398 resdir
= GetResDirEntryW(resdir
,(LPWSTR
)0,(DWORD
)rootresdir
,TRUE
);
399 igdataent
= (PIMAGE_RESOURCE_DATA_ENTRY
)resdir
;
401 /* lookup address in mapped image for virtual address */
404 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
406 if (igdataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
408 if (igdataent
->OffsetToData
+igdataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
410 igdata
= peimage
+(igdataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
415 WARN("no matching real address for icongroup!\n");
416 goto end_3
; /* failure */
418 RetPtr
[i
] = (HICON
)LookupIconIdFromDirectoryEx(igdata
, TRUE
, cxDesired
, cyDesired
, LR_DEFAULTCOLOR
);
421 if (!(iconresdir
=GetResDirEntryW(rootresdir
,RT_ICONW
,(DWORD
)rootresdir
,FALSE
)))
423 WARN("No Iconresourcedirectory!\n");
424 goto end_3
; /* failure */
427 for (i
=0; i
<nIcons
; i
++)
429 PIMAGE_RESOURCE_DIRECTORY xresdir
;
430 xresdir
= GetResDirEntryW(iconresdir
,(LPWSTR
)(DWORD
)RetPtr
[i
],(DWORD
)rootresdir
,FALSE
);
431 xresdir
= GetResDirEntryW(xresdir
,(LPWSTR
)0,(DWORD
)rootresdir
,TRUE
);
432 idataent
= (PIMAGE_RESOURCE_DATA_ENTRY
)xresdir
;
435 /* map virtual to address in image */
436 for (j
=0;j
<pe_header
->FileHeader
.NumberOfSections
;j
++)
438 if (idataent
->OffsetToData
< pe_sections
[j
].VirtualAddress
)
440 if (idataent
->OffsetToData
+idataent
->Size
> pe_sections
[j
].VirtualAddress
+pe_sections
[j
].SizeOfRawData
)
442 idata
= peimage
+(idataent
->OffsetToData
-pe_sections
[j
].VirtualAddress
+pe_sections
[j
].PointerToRawData
);
446 WARN("no matching real address found for icondata!\n");
450 RetPtr
[i
] = (HICON
) CreateIconFromResourceEx(idata
,idataent
->Size
,TRUE
,0x00030000, cxDesired
, cyDesired
, LR_DEFAULTCOLOR
);
452 hRet
= S_OK
; /* return first icon */
453 goto end_3
; /* sucess */
454 } /* if(sig == IMAGE_NT_SIGNATURE) */
456 end_3
: UnmapViewOfFile(peimage
); /* success */
457 end_2
: CloseHandle(fmapping
);
458 end_1
: _lclose( hFile
);
462 /***********************************************************************
463 * PrivateExtractIconsW [USER32.@]
466 * nIndex = 1: a small and a large icon are extracted.
467 * the higher word of sizeXY contains the size of the small icon, the lower
468 * word the size of the big icon. phicon points to HICON[2].
471 * nIcons > 0: HRESULT
472 * nIcons = 0: the number of icons
475 HRESULT WINAPI
PrivateExtractIconsW (
480 HICON
* phicon
, /* HICON* */
483 DWORD y
) /* 0x80 maybe LR_* constant */
486 TRACE("%s 0x%08x 0x%08lx 0x%08lx %p 0x%08lx 0x%08x 0x%08lx stub\n",
487 debugstr_w(lpwstrFile
),nIndex
, sizeX
,sizeY
,phicon
,w
,nIcons
,y
);
490 if ((nIcons
== 2) && HIWORD(sizeX
) && HIWORD(sizeY
))
492 ret
= ICO_ExtractIconExW(lpwstrFile
, phicon
, nIndex
, 1, sizeX
& 0xffff, sizeY
& 0xffff );
493 if (!SUCCEEDED(ret
)) return ret
;
494 ret
= ICO_ExtractIconExW(lpwstrFile
, phicon
+1, nIndex
, 1, (sizeX
>>16) & 0xffff, (sizeY
>>16) & 0xffff );
498 ret
= ICO_ExtractIconExW(lpwstrFile
, phicon
, nIndex
, nIcons
, sizeX
& 0xffff, sizeY
& 0xffff );
501 FIXME_(icon
)("hicon=%08x ret=0x%08lx\n", *phicon
, ret
);
506 /***********************************************************************
507 * PrivateExtractIconsA [USER32.@]
510 HRESULT WINAPI
PrivateExtractIconsA (
521 LPWSTR lpwstrFile
= HEAP_strdupAtoW(GetProcessHeap(), 0, lpstrFile
);
523 FIXME_(icon
)("%s 0x%08lx 0x%08lx 0x%08lx %p 0x%08lx 0x%08x 0x%08lx stub\n",
524 lpstrFile
, nIndex
, sizeX
, sizeY
, phicon
, w
, nIcons
, y
);
526 ret
= PrivateExtractIconsW(lpwstrFile
, nIndex
, sizeX
, sizeY
, phicon
, w
, nIcons
, y
);
528 FIXME_(icon
)("hicon=%08x ret=0x%08lx\n", *phicon
, ret
);
530 HeapFree(GetProcessHeap(), 0, lpwstrFile
);
534 /***********************************************************************
535 * PrivateExtractIconExW [USER32.443]
537 * if nIcons = -1 it returns the number of icons in any case !!!
539 HRESULT WINAPI
PrivateExtractIconExW (
546 DWORD cyicon
, cysmicon
, cxicon
, cxsmicon
;
549 TRACE("%s 0x%08lx %p %p 0x%08x\n",
550 debugstr_w(lpwstrFile
),nIndex
,phIconLarge
, phIconSmall
, nIcons
);
552 if (nIndex
== 1 && phIconSmall
&& phIconLarge
)
555 cxicon
= GetSystemMetrics(SM_CXICON
);
556 cyicon
= GetSystemMetrics(SM_CYICON
);
557 cxsmicon
= GetSystemMetrics(SM_CXSMICON
);
558 cysmicon
= GetSystemMetrics(SM_CYSMICON
);
560 ret
= PrivateExtractIconsW ( lpwstrFile
, nIndex
, cxicon
| (cxsmicon
<<16), cyicon
| (cysmicon
<<16),
561 (HICON
*) &hIcon
, 0, 2, 0 );
562 *phIconLarge
= hIcon
[0];
563 *phIconSmall
= hIcon
[1];
571 /* extract n small icons */
572 cxsmicon
= GetSystemMetrics(SM_CXSMICON
);
573 cysmicon
= GetSystemMetrics(SM_CYSMICON
);
574 ret
= PrivateExtractIconsW ( lpwstrFile
, nIndex
, cxsmicon
, cysmicon
, phIconSmall
, 0, nIcons
, 0 );
578 /* extract n large icons */
579 cxicon
= GetSystemMetrics(SM_CXICON
);
580 cyicon
= GetSystemMetrics(SM_CYICON
);
581 ret
= PrivateExtractIconsW ( lpwstrFile
, nIndex
, cxicon
, cyicon
, phIconLarge
, 0, nIcons
, 0 );
586 /* get the number of icons */
587 return PrivateExtractIconsW ( lpwstrFile
, 0, 0, 0, 0, 0, 0, 0 );
590 /***********************************************************************
591 * PrivateExtractIconExA [USER32.442]
593 HRESULT WINAPI
PrivateExtractIconExA (
601 LPWSTR lpwstrFile
= HEAP_strdupAtoW(GetProcessHeap(), 0, lpstrFile
);
603 TRACE("%s 0x%08lx %p %p 0x%08x\n",
604 lpstrFile
, nIndex
, phIconLarge
, phIconSmall
, nIcons
);
606 ret
= PrivateExtractIconExW(lpwstrFile
,nIndex
,phIconLarge
, phIconSmall
, nIcons
);
608 HeapFree(GetProcessHeap(), 0, lpwstrFile
);