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
14 #include <sys/types.h>
16 #include "wine/unicode.h"
23 #include "stackframe.h"
24 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(resource
);
28 /**********************************************************************
31 * Get the resource directory of a PE module
33 static const IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
35 const IMAGE_DATA_DIRECTORY
*dir
;
36 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
38 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
39 else if (!HIWORD(hmod
))
41 FIXME("Enumeration of 16-bit resources is not supported\n");
42 SetLastError(ERROR_INVALID_HANDLE
);
45 dir
= &PE_HEADER(hmod
)->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
];
46 if (dir
->Size
&& dir
->VirtualAddress
)
47 ret
= (IMAGE_RESOURCE_DIRECTORY
*)((char *)hmod
+ dir
->VirtualAddress
);
52 /**********************************************************************
55 * Find an entry by id in a resource directory
57 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
58 WORD id
, const void *root
)
60 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
63 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
64 min
= dir
->NumberOfNamedEntries
;
65 max
= min
+ dir
->NumberOfIdEntries
- 1;
68 pos
= (min
+ max
) / 2;
69 if (entry
[pos
].u1
.Id
== id
)
70 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s2
.OffsetToDirectory
);
71 if (entry
[pos
].u1
.Id
> id
) max
= pos
- 1;
78 /**********************************************************************
81 * Find an entry by name in a resource directory
83 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY
*dir
,
84 LPCWSTR name
, const void *root
)
86 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
87 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
88 int min
, max
, res
, pos
, namelen
;
90 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
94 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
96 return find_entry_by_id( dir
, atoi(buf
), root
);
99 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
100 namelen
= strlenW(name
);
102 max
= dir
->NumberOfNamedEntries
- 1;
105 pos
= (min
+ max
) / 2;
106 str
= (IMAGE_RESOURCE_DIR_STRING_U
*)((char *)root
+ entry
[pos
].u1
.s1
.NameOffset
);
107 res
= strncmpiW( name
, str
->NameString
, str
->Length
);
108 if (!res
&& namelen
== str
->Length
)
109 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s2
.OffsetToDirectory
);
110 if (res
< 0) max
= pos
- 1;
117 /**********************************************************************
118 * find_entry_by_nameA
120 * Find an entry by name in a resource directory
122 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY
*dir
,
123 LPCSTR name
, const void *root
)
125 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
128 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
131 return find_entry_by_id( dir
, atoi(name
+1), root
);
134 if ((nameW
= HEAP_strdupAtoW( GetProcessHeap(), 0, name
)))
136 ret
= find_entry_by_nameW( dir
, nameW
, root
);
137 HeapFree( GetProcessHeap(), 0, nameW
);
143 /**********************************************************************
146 * Find a default entry in a resource directory
148 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
151 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
153 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
154 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
->u2
.s2
.OffsetToDirectory
);
158 /**********************************************************************
161 * FindResourceExA/W does search in the following order:
162 * 1. Exact specified language
163 * 2. Language with neutral sublanguage
164 * 3. Neutral language with neutral sublanguage
165 * 4. Neutral language with default sublanguage
167 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
169 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
173 if (!resdirptr
) return 0;
176 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
177 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
179 /* 1. Exact specified language */
180 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
182 /* 2. Language with neutral sublanguage */
183 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
184 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
186 /* 3. Neutral language with neutral sublanguage */
187 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
188 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
190 /* 4. Neutral language with default sublanguage */
191 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
192 result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
);
198 /**********************************************************************
201 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
202 * FindResourceA/W does search in the following order:
203 * 1. Neutral language with neutral sublanguage
204 * 2. Neutral language with default sublanguage
205 * 3. Current locale lang id
206 * 4. Current locale lang id with neutral sublanguage
207 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
208 * 6. Return first in the list
210 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
212 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
217 if (!resdirptr
) return 0;
220 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
221 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
223 /* 1. Neutral language with neutral sublanguage */
224 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
225 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
227 /* 2. Neutral language with default sublanguage */
228 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
229 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
231 /* 3. Current locale lang id */
232 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
233 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
235 /* 4. Current locale lang id with neutral sublanguage */
236 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
237 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
239 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
240 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
241 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
243 /* 6. Return first in the list */
244 result
= (HRSRC
)find_entry_default( resdirptr
, root
);
251 /**********************************************************************
254 HANDLE
PE_LoadResource( HMODULE hmod
, HANDLE hRsrc
)
256 if (!hRsrc
) return 0;
257 return (HANDLE
)(hmod
+ ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
);
261 /**********************************************************************
264 DWORD
PE_SizeofResource( HANDLE hRsrc
)
266 if (!hRsrc
) return 0;
267 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
271 /**********************************************************************
272 * EnumResourceTypesA (KERNEL32.90)
274 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
277 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
278 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
281 if (!resdir
) return FALSE
;
283 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
285 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
288 if (et
[i
].u1
.s1
.NameIsString
)
290 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
291 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
292 NULL
, 0, NULL
, NULL
);
293 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
295 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
296 type
, len
, NULL
, NULL
);
298 ret
= lpfun(hmod
,type
,lparam
);
299 HeapFree(GetProcessHeap(), 0, type
);
303 type
= (LPSTR
)(int)et
[i
].u1
.Id
;
304 ret
= lpfun(hmod
,type
,lparam
);
313 /**********************************************************************
314 * EnumResourceTypesW (KERNEL32.91)
316 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
319 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
320 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
323 if (!resdir
) return FALSE
;
325 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
327 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
330 if (et
[i
].u1
.s1
.NameIsString
)
332 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
333 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
335 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
336 type
[pResString
->Length
] = '\0';
337 ret
= lpfun(hmod
,type
,lparam
);
338 HeapFree(GetProcessHeap(), 0, type
);
342 type
= (LPWSTR
)(int)et
[i
].u1
.Id
;
343 ret
= lpfun(hmod
,type
,lparam
);
352 /**********************************************************************
353 * EnumResourceNamesA (KERNEL32.88)
355 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
358 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
359 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
360 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
363 if (!basedir
) return FALSE
;
365 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
367 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
369 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
372 if (et
[i
].u1
.s1
.NameIsString
)
374 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
375 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
376 NULL
, 0, NULL
, NULL
);
377 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
379 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
380 name
, len
, NULL
, NULL
);
382 ret
= lpfun(hmod
,type
,name
,lparam
);
383 HeapFree( GetProcessHeap(), 0, name
);
387 name
= (LPSTR
)(int)et
[i
].u1
.Id
;
388 ret
= lpfun(hmod
,type
,name
,lparam
);
397 /**********************************************************************
398 * EnumResourceNamesW (KERNEL32.89)
400 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
403 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
404 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
405 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
408 if (!basedir
) return FALSE
;
410 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
412 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
414 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
417 if (et
[i
].u1
.s1
.NameIsString
)
419 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
420 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
422 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
423 name
[pResString
->Length
] = '\0';
424 ret
= lpfun(hmod
,type
,name
,lparam
);
425 HeapFree(GetProcessHeap(), 0, name
);
429 name
= (LPWSTR
)(int)et
[i
].u1
.Id
;
430 ret
= lpfun(hmod
,type
,name
,lparam
);
439 /**********************************************************************
440 * EnumResourceLanguagesA (KERNEL32.86)
442 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
443 ENUMRESLANGPROCA lpfun
, LONG lparam
)
446 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
447 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
448 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
451 if (!basedir
) return FALSE
;
452 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
453 if (!(resdir
= find_entry_by_nameA( resdir
, name
, basedir
))) return FALSE
;
455 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
457 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
458 /* languages are just ids... I hope */
459 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.Id
,lparam
);
467 /**********************************************************************
468 * EnumResourceLanguagesW (KERNEL32.87)
470 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
471 ENUMRESLANGPROCW lpfun
, LONG lparam
)
474 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
475 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
476 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
479 if (!basedir
) return FALSE
;
481 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
482 if (!(resdir
= find_entry_by_nameW( resdir
, name
, basedir
))) return FALSE
;
484 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
486 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
487 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.Id
,lparam
);