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>
18 #include "wine/unicode.h"
25 #include "stackframe.h"
26 #include "debugtools.h"
28 DEFAULT_DEBUG_CHANNEL(resource
);
30 /**********************************************************************
33 * Get the resource directory of a PE module
35 static const IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
37 const IMAGE_DATA_DIRECTORY
*dir
;
38 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
40 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
41 else if (!HIWORD(hmod
))
43 FIXME("Enumeration of 16-bit resources is not supported\n");
44 SetLastError(ERROR_INVALID_HANDLE
);
47 dir
= &PE_HEADER(hmod
)->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
];
48 if (dir
->Size
&& dir
->VirtualAddress
)
49 ret
= (IMAGE_RESOURCE_DIRECTORY
*)((char *)hmod
+ dir
->VirtualAddress
);
54 /**********************************************************************
57 * Find an entry by id in a resource directory
59 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
60 WORD id
, const void *root
)
62 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
65 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
66 min
= dir
->NumberOfNamedEntries
;
67 max
= min
+ dir
->NumberOfIdEntries
- 1;
70 pos
= (min
+ max
) / 2;
71 if (entry
[pos
].u1
.s2
.Id
== id
)
72 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
73 if (entry
[pos
].u1
.s2
.Id
> id
) max
= pos
- 1;
80 /**********************************************************************
83 * Find an entry by name in a resource directory
85 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY
*dir
,
86 LPCWSTR name
, const void *root
)
88 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
89 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
90 int min
, max
, res
, pos
, namelen
;
92 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
96 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
98 return find_entry_by_id( dir
, atoi(buf
), root
);
101 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
102 namelen
= strlenW(name
);
104 max
= dir
->NumberOfNamedEntries
- 1;
107 pos
= (min
+ max
) / 2;
108 str
= (IMAGE_RESOURCE_DIR_STRING_U
*)((char *)root
+ entry
[pos
].u1
.s1
.NameOffset
);
109 res
= strncmpiW( name
, str
->NameString
, str
->Length
);
110 if (!res
&& namelen
== str
->Length
)
111 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
112 if (res
< 0) max
= pos
- 1;
119 /**********************************************************************
120 * find_entry_by_nameA
122 * Find an entry by name in a resource directory
124 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY
*dir
,
125 LPCSTR name
, const void *root
)
127 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
130 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
133 return find_entry_by_id( dir
, atoi(name
+1), root
);
136 if ((nameW
= HEAP_strdupAtoW( GetProcessHeap(), 0, name
)))
138 ret
= find_entry_by_nameW( dir
, nameW
, root
);
139 HeapFree( GetProcessHeap(), 0, nameW
);
145 /**********************************************************************
148 * Find a default entry in a resource directory
150 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
153 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
155 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
156 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
->u2
.s3
.OffsetToDirectory
);
160 /**********************************************************************
163 * FindResourceExA/W does search in the following order:
164 * 1. Exact specified language
165 * 2. Language with neutral sublanguage
166 * 3. Neutral language with neutral sublanguage
167 * 4. Neutral language with default sublanguage
169 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
171 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
175 if (!resdirptr
) return 0;
178 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
179 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
181 /* 1. Exact specified language */
182 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
184 /* 2. Language with neutral sublanguage */
185 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
186 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
188 /* 3. Neutral language with neutral sublanguage */
189 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
190 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
192 /* 4. Neutral language with default sublanguage */
193 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
194 result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
);
200 /**********************************************************************
203 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
204 * FindResourceA/W does search in the following order:
205 * 1. Neutral language with neutral sublanguage
206 * 2. Neutral language with default sublanguage
207 * 3. Current locale lang id
208 * 4. Current locale lang id with neutral sublanguage
209 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
210 * 6. Return first in the list
212 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
214 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
219 if (!resdirptr
) return 0;
222 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
223 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
225 /* 1. Neutral language with neutral sublanguage */
226 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
227 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
229 /* 2. Neutral language with default sublanguage */
230 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
231 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
233 /* 3. Current locale lang id */
234 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
235 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
237 /* 4. Current locale lang id with neutral sublanguage */
238 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
239 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
241 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
242 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
243 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
245 /* 6. Return first in the list */
246 result
= (HRSRC
)find_entry_default( resdirptr
, root
);
253 /**********************************************************************
256 HGLOBAL
PE_LoadResource( HMODULE hmod
, HRSRC hRsrc
)
258 if (!hRsrc
) return 0;
259 return (HANDLE
)(hmod
+ ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
);
263 /**********************************************************************
266 DWORD
PE_SizeofResource( HRSRC hRsrc
)
268 if (!hRsrc
) return 0;
269 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
273 /**********************************************************************
274 * EnumResourceTypesA (KERNEL32.90)
276 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
279 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
280 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
283 if (!resdir
) return FALSE
;
285 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
287 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
290 if (et
[i
].u1
.s1
.NameIsString
)
292 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
293 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
294 NULL
, 0, NULL
, NULL
);
295 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
297 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
298 type
, len
, NULL
, NULL
);
300 ret
= lpfun(hmod
,type
,lparam
);
301 HeapFree(GetProcessHeap(), 0, type
);
305 type
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
306 ret
= lpfun(hmod
,type
,lparam
);
315 /**********************************************************************
316 * EnumResourceTypesW (KERNEL32.91)
318 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
321 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
322 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
325 if (!resdir
) return FALSE
;
327 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
329 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
332 if (et
[i
].u1
.s1
.NameIsString
)
334 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
335 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
337 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
338 type
[pResString
->Length
] = '\0';
339 ret
= lpfun(hmod
,type
,lparam
);
340 HeapFree(GetProcessHeap(), 0, type
);
344 type
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
345 ret
= lpfun(hmod
,type
,lparam
);
354 /**********************************************************************
355 * EnumResourceNamesA (KERNEL32.88)
357 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
360 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
361 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
362 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
365 if (!basedir
) return FALSE
;
367 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
369 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
371 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
374 if (et
[i
].u1
.s1
.NameIsString
)
376 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
377 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
378 NULL
, 0, NULL
, NULL
);
379 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
381 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
382 name
, len
, NULL
, NULL
);
384 ret
= lpfun(hmod
,type
,name
,lparam
);
385 HeapFree( GetProcessHeap(), 0, name
);
389 name
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
390 ret
= lpfun(hmod
,type
,name
,lparam
);
399 /**********************************************************************
400 * EnumResourceNamesW (KERNEL32.89)
402 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
405 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
406 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
407 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
410 if (!basedir
) return FALSE
;
412 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
414 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
416 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
419 if (et
[i
].u1
.s1
.NameIsString
)
421 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
422 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
424 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
425 name
[pResString
->Length
] = '\0';
426 ret
= lpfun(hmod
,type
,name
,lparam
);
427 HeapFree(GetProcessHeap(), 0, name
);
431 name
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
432 ret
= lpfun(hmod
,type
,name
,lparam
);
441 /**********************************************************************
442 * EnumResourceLanguagesA (KERNEL32.86)
444 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
445 ENUMRESLANGPROCA lpfun
, LONG lparam
)
448 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
449 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
450 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
453 if (!basedir
) return FALSE
;
454 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
455 if (!(resdir
= find_entry_by_nameA( resdir
, name
, basedir
))) return FALSE
;
457 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
459 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
460 /* languages are just ids... I hope */
461 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);
469 /**********************************************************************
470 * EnumResourceLanguagesW (KERNEL32.87)
472 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
473 ENUMRESLANGPROCW lpfun
, LONG lparam
)
476 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
477 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
478 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
481 if (!basedir
) return FALSE
;
483 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
484 if (!(resdir
= find_entry_by_nameW( resdir
, name
, basedir
))) return FALSE
;
486 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
488 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
489 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);