2 * PE (Portable Execute) File Resources
4 * Copyright 1995 Thomas Sandford
5 * Copyright 1996 Martin von Loewis
7 * Based on the Win16 resource handling code in loader/resource.c
8 * Copyright 1993 Robert J. Amstadt
9 * Copyright 1995 Alexandre Julliard
10 * Copyright 1997 Marcus Meissner
16 #include <sys/types.h>
18 #include "wine/unicode.h"
24 #include "stackframe.h"
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(resource
);
30 /**********************************************************************
33 * Get the base address of a module
35 static const void *get_module_base( HMODULE hmod
)
37 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
38 else if (!HIWORD(hmod
))
40 FIXME("Enumeration of 16-bit resources is not supported\n");
41 SetLastError(ERROR_INVALID_HANDLE
);
45 /* clear low order bit in case of LOAD_LIBRARY_AS_DATAFILE module */
46 return (void *)((ULONG_PTR
)hmod
& ~1);
50 /**********************************************************************
53 * Get the resource directory of a PE module
55 static const IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
57 const IMAGE_DATA_DIRECTORY
*dir
;
58 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
59 const void *base
= get_module_base( hmod
);
63 dir
= &PE_HEADER(base
)->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
];
64 if (dir
->Size
&& dir
->VirtualAddress
)
65 ret
= (IMAGE_RESOURCE_DIRECTORY
*)((char *)base
+ dir
->VirtualAddress
);
71 /**********************************************************************
74 * Find an entry by id in a resource directory
76 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
77 WORD id
, const void *root
)
79 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
82 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
83 min
= dir
->NumberOfNamedEntries
;
84 max
= min
+ dir
->NumberOfIdEntries
- 1;
87 pos
= (min
+ max
) / 2;
88 if (entry
[pos
].u1
.s2
.Id
== id
)
89 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
90 if (entry
[pos
].u1
.s2
.Id
> id
) max
= pos
- 1;
97 /**********************************************************************
100 * Find an entry by name in a resource directory
102 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY
*dir
,
103 LPCWSTR name
, const void *root
)
105 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
106 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
107 int min
, max
, res
, pos
, namelen
;
109 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
113 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
115 return find_entry_by_id( dir
, atoi(buf
), root
);
118 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
119 namelen
= strlenW(name
);
121 max
= dir
->NumberOfNamedEntries
- 1;
124 pos
= (min
+ max
) / 2;
125 str
= (IMAGE_RESOURCE_DIR_STRING_U
*)((char *)root
+ entry
[pos
].u1
.s1
.NameOffset
);
126 res
= strncmpiW( name
, str
->NameString
, str
->Length
);
127 if (!res
&& namelen
== str
->Length
)
128 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
129 if (res
< 0) max
= pos
- 1;
136 /**********************************************************************
137 * find_entry_by_nameA
139 * Find an entry by name in a resource directory
141 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY
*dir
,
142 LPCSTR name
, const void *root
)
144 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
147 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
150 return find_entry_by_id( dir
, atoi(name
+1), root
);
153 if ((nameW
= HEAP_strdupAtoW( GetProcessHeap(), 0, name
)))
155 ret
= find_entry_by_nameW( dir
, nameW
, root
);
156 HeapFree( GetProcessHeap(), 0, nameW
);
162 /**********************************************************************
165 * Find a default entry in a resource directory
167 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
170 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
172 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
173 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
->u2
.s3
.OffsetToDirectory
);
177 /**********************************************************************
180 * FindResourceExA/W does search in the following order:
181 * 1. Exact specified language
182 * 2. Language with neutral sublanguage
183 * 3. Neutral language with neutral sublanguage
184 * 4. Neutral language with default sublanguage
186 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
188 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
192 if (!resdirptr
) return 0;
195 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
196 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
198 /* 1. Exact specified language */
199 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
201 /* 2. Language with neutral sublanguage */
202 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
203 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
205 /* 3. Neutral language with neutral sublanguage */
206 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
207 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
209 /* 4. Neutral language with default sublanguage */
210 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
211 result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
);
217 /**********************************************************************
220 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
221 * FindResourceA/W does search in the following order:
222 * 1. Neutral language with neutral sublanguage
223 * 2. Neutral language with default sublanguage
224 * 3. Current locale lang id
225 * 4. Current locale lang id with neutral sublanguage
226 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
227 * 6. Return first in the list
229 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
231 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
236 if (!resdirptr
) return 0;
239 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
240 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
242 /* 1. Neutral language with neutral sublanguage */
243 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
244 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
246 /* 2. Neutral language with default sublanguage */
247 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
248 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
250 /* 3. Current locale lang id */
251 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
252 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
254 /* 4. Current locale lang id with neutral sublanguage */
255 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
256 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
258 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
259 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
260 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
262 /* 6. Return first in the list */
263 result
= (HRSRC
)find_entry_default( resdirptr
, root
);
270 /**********************************************************************
273 HGLOBAL
PE_LoadResource( HMODULE hmod
, HRSRC hRsrc
)
275 const void *base
= get_module_base( hmod
);
276 if (!hRsrc
) return 0;
277 return (HANDLE
)((char *)base
+ ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
);
281 /**********************************************************************
284 DWORD
PE_SizeofResource( HRSRC hRsrc
)
286 if (!hRsrc
) return 0;
287 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
291 /**********************************************************************
292 * EnumResourceTypesA (KERNEL32.@)
294 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
297 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
298 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
301 if (!resdir
) return FALSE
;
303 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
305 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
308 if (et
[i
].u1
.s1
.NameIsString
)
310 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
311 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
312 NULL
, 0, NULL
, NULL
);
313 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
315 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
316 type
, len
, NULL
, NULL
);
318 ret
= lpfun(hmod
,type
,lparam
);
319 HeapFree(GetProcessHeap(), 0, type
);
323 type
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
324 ret
= lpfun(hmod
,type
,lparam
);
333 /**********************************************************************
334 * EnumResourceTypesW (KERNEL32.@)
336 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
339 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
340 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
343 if (!resdir
) return FALSE
;
345 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
347 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
350 if (et
[i
].u1
.s1
.NameIsString
)
352 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
353 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
355 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
356 type
[pResString
->Length
] = '\0';
357 ret
= lpfun(hmod
,type
,lparam
);
358 HeapFree(GetProcessHeap(), 0, type
);
362 type
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
363 ret
= lpfun(hmod
,type
,lparam
);
372 /**********************************************************************
373 * EnumResourceNamesA (KERNEL32.@)
375 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
378 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
379 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
380 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
383 if (!basedir
) return FALSE
;
385 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
387 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
389 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
392 if (et
[i
].u1
.s1
.NameIsString
)
394 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
395 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
396 NULL
, 0, NULL
, NULL
);
397 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
399 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
400 name
, len
, NULL
, NULL
);
402 ret
= lpfun(hmod
,type
,name
,lparam
);
403 HeapFree( GetProcessHeap(), 0, name
);
407 name
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
408 ret
= lpfun(hmod
,type
,name
,lparam
);
417 /**********************************************************************
418 * EnumResourceNamesW (KERNEL32.@)
420 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
423 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
424 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
425 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
428 if (!basedir
) return FALSE
;
430 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
432 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
434 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
437 if (et
[i
].u1
.s1
.NameIsString
)
439 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
440 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
442 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
443 name
[pResString
->Length
] = '\0';
444 ret
= lpfun(hmod
,type
,name
,lparam
);
445 HeapFree(GetProcessHeap(), 0, name
);
449 name
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
450 ret
= lpfun(hmod
,type
,name
,lparam
);
459 /**********************************************************************
460 * EnumResourceLanguagesA (KERNEL32.@)
462 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
463 ENUMRESLANGPROCA lpfun
, LONG lparam
)
466 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
467 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
468 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
471 if (!basedir
) return FALSE
;
472 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
473 if (!(resdir
= find_entry_by_nameA( resdir
, name
, basedir
))) return FALSE
;
475 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
477 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
478 /* languages are just ids... I hope */
479 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);
487 /**********************************************************************
488 * EnumResourceLanguagesW (KERNEL32.@)
490 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
491 ENUMRESLANGPROCW lpfun
, LONG lparam
)
494 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
495 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
496 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
499 if (!basedir
) return FALSE
;
501 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
502 if (!(resdir
= find_entry_by_nameW( resdir
, name
, basedir
))) return FALSE
;
504 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
506 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
507 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);