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"
24 #include "stackframe.h"
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(resource
);
29 /**********************************************************************
32 * Get the resource directory of a PE module
34 static const IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
36 const IMAGE_DATA_DIRECTORY
*dir
;
37 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
39 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
40 else if (!HIWORD(hmod
))
42 FIXME("Enumeration of 16-bit resources is not supported\n");
43 SetLastError(ERROR_INVALID_HANDLE
);
46 dir
= &PE_HEADER(hmod
)->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
];
47 if (dir
->Size
&& dir
->VirtualAddress
)
48 ret
= (IMAGE_RESOURCE_DIRECTORY
*)((char *)hmod
+ dir
->VirtualAddress
);
53 /**********************************************************************
56 * Find an entry by id in a resource directory
58 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
59 WORD id
, const void *root
)
61 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
64 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
65 min
= dir
->NumberOfNamedEntries
;
66 max
= min
+ dir
->NumberOfIdEntries
- 1;
69 pos
= (min
+ max
) / 2;
70 if (entry
[pos
].u1
.s2
.Id
== id
)
71 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
72 if (entry
[pos
].u1
.s2
.Id
> id
) max
= pos
- 1;
79 /**********************************************************************
82 * Find an entry by name in a resource directory
84 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY
*dir
,
85 LPCWSTR name
, const void *root
)
87 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
88 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
89 int min
, max
, res
, pos
, namelen
;
91 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
95 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
97 return find_entry_by_id( dir
, atoi(buf
), root
);
100 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
101 namelen
= strlenW(name
);
103 max
= dir
->NumberOfNamedEntries
- 1;
106 pos
= (min
+ max
) / 2;
107 str
= (IMAGE_RESOURCE_DIR_STRING_U
*)((char *)root
+ entry
[pos
].u1
.s1
.NameOffset
);
108 res
= strncmpiW( name
, str
->NameString
, str
->Length
);
109 if (!res
&& namelen
== str
->Length
)
110 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
111 if (res
< 0) max
= pos
- 1;
118 /**********************************************************************
119 * find_entry_by_nameA
121 * Find an entry by name in a resource directory
123 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY
*dir
,
124 LPCSTR name
, const void *root
)
126 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
129 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
132 return find_entry_by_id( dir
, atoi(name
+1), root
);
135 if ((nameW
= HEAP_strdupAtoW( GetProcessHeap(), 0, name
)))
137 ret
= find_entry_by_nameW( dir
, nameW
, root
);
138 HeapFree( GetProcessHeap(), 0, nameW
);
144 /**********************************************************************
147 * Find a default entry in a resource directory
149 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
152 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
154 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
155 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
->u2
.s3
.OffsetToDirectory
);
159 /**********************************************************************
162 * FindResourceExA/W does search in the following order:
163 * 1. Exact specified language
164 * 2. Language with neutral sublanguage
165 * 3. Neutral language with neutral sublanguage
166 * 4. Neutral language with default sublanguage
168 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
170 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
174 if (!resdirptr
) return 0;
177 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
178 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
180 /* 1. Exact specified language */
181 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
183 /* 2. Language with neutral sublanguage */
184 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
185 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
187 /* 3. Neutral language with neutral sublanguage */
188 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
189 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
191 /* 4. Neutral language with default sublanguage */
192 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
193 result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
);
199 /**********************************************************************
202 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
203 * FindResourceA/W does search in the following order:
204 * 1. Neutral language with neutral sublanguage
205 * 2. Neutral language with default sublanguage
206 * 3. Current locale lang id
207 * 4. Current locale lang id with neutral sublanguage
208 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
209 * 6. Return first in the list
211 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
213 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
218 if (!resdirptr
) return 0;
221 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
222 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
224 /* 1. Neutral language with neutral sublanguage */
225 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
226 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
228 /* 2. Neutral language with default sublanguage */
229 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
230 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
232 /* 3. Current locale lang id */
233 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
234 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
236 /* 4. Current locale lang id with neutral sublanguage */
237 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
238 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
240 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
241 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
242 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
244 /* 6. Return first in the list */
245 result
= (HRSRC
)find_entry_default( resdirptr
, root
);
252 /**********************************************************************
255 HGLOBAL
PE_LoadResource( HMODULE hmod
, HRSRC hRsrc
)
257 if (!hRsrc
) return 0;
258 return (HANDLE
)(hmod
+ ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
);
262 /**********************************************************************
265 DWORD
PE_SizeofResource( HRSRC hRsrc
)
267 if (!hRsrc
) return 0;
268 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
272 /**********************************************************************
273 * EnumResourceTypesA (KERNEL32.90)
275 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
278 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
279 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
282 if (!resdir
) return FALSE
;
284 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
286 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
289 if (et
[i
].u1
.s1
.NameIsString
)
291 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
292 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
293 NULL
, 0, NULL
, NULL
);
294 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
296 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
297 type
, len
, NULL
, NULL
);
299 ret
= lpfun(hmod
,type
,lparam
);
300 HeapFree(GetProcessHeap(), 0, type
);
304 type
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
305 ret
= lpfun(hmod
,type
,lparam
);
314 /**********************************************************************
315 * EnumResourceTypesW (KERNEL32.91)
317 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
320 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
321 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
324 if (!resdir
) return FALSE
;
326 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
328 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
331 if (et
[i
].u1
.s1
.NameIsString
)
333 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
334 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
336 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
337 type
[pResString
->Length
] = '\0';
338 ret
= lpfun(hmod
,type
,lparam
);
339 HeapFree(GetProcessHeap(), 0, type
);
343 type
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
344 ret
= lpfun(hmod
,type
,lparam
);
353 /**********************************************************************
354 * EnumResourceNamesA (KERNEL32.88)
356 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
359 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
360 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
361 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
364 if (!basedir
) return FALSE
;
366 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
368 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
370 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
373 if (et
[i
].u1
.s1
.NameIsString
)
375 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
376 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
377 NULL
, 0, NULL
, NULL
);
378 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
380 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
381 name
, len
, NULL
, NULL
);
383 ret
= lpfun(hmod
,type
,name
,lparam
);
384 HeapFree( GetProcessHeap(), 0, name
);
388 name
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
389 ret
= lpfun(hmod
,type
,name
,lparam
);
398 /**********************************************************************
399 * EnumResourceNamesW (KERNEL32.89)
401 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
404 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
405 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
406 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
409 if (!basedir
) return FALSE
;
411 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
413 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
415 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
418 if (et
[i
].u1
.s1
.NameIsString
)
420 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
421 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
423 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
424 name
[pResString
->Length
] = '\0';
425 ret
= lpfun(hmod
,type
,name
,lparam
);
426 HeapFree(GetProcessHeap(), 0, name
);
430 name
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
431 ret
= lpfun(hmod
,type
,name
,lparam
);
440 /**********************************************************************
441 * EnumResourceLanguagesA (KERNEL32.86)
443 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
444 ENUMRESLANGPROCA lpfun
, LONG lparam
)
447 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
448 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
449 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
452 if (!basedir
) return FALSE
;
453 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
454 if (!(resdir
= find_entry_by_nameA( resdir
, name
, basedir
))) return FALSE
;
456 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
458 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
459 /* languages are just ids... I hope */
460 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);
468 /**********************************************************************
469 * EnumResourceLanguagesW (KERNEL32.87)
471 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
472 ENUMRESLANGPROCW lpfun
, LONG lparam
)
475 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
476 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
477 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
480 if (!basedir
) return FALSE
;
482 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
483 if (!(resdir
= find_entry_by_nameW( resdir
, name
, basedir
))) return FALSE
;
485 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
487 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
488 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);