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/winestring.h"
17 #include "wine/unicode.h"
25 #include "stackframe.h"
27 #include "debugtools.h"
29 DEFAULT_DEBUG_CHANNEL(resource
);
31 /**********************************************************************
34 * Get the resource directory of a PE module
36 static const IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
38 const IMAGE_DATA_DIRECTORY
*dir
;
39 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
41 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
42 else if (!HIWORD(hmod
))
44 FIXME("Enumeration of 16-bit resources is not supported\n");
45 SetLastError(ERROR_INVALID_HANDLE
);
48 dir
= &PE_HEADER(hmod
)->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
];
49 if (dir
->Size
&& dir
->VirtualAddress
)
50 ret
= (IMAGE_RESOURCE_DIRECTORY
*)((char *)hmod
+ dir
->VirtualAddress
);
55 /**********************************************************************
58 * Find an entry by id in a resource directory
60 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
61 WORD id
, const void *root
)
63 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
66 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
67 min
= dir
->NumberOfNamedEntries
;
68 max
= min
+ dir
->NumberOfIdEntries
- 1;
71 pos
= (min
+ max
) / 2;
72 if (entry
[pos
].u1
.Id
== id
)
73 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s
.OffsetToDirectory
);
74 if (entry
[pos
].u1
.Id
> id
) max
= pos
- 1;
81 /**********************************************************************
84 * Find an entry by name in a resource directory
86 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY
*dir
,
87 LPCWSTR name
, const void *root
)
89 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
90 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
91 int min
, max
, res
, pos
, namelen
;
93 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
97 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
99 return find_entry_by_id( dir
, atoi(buf
), root
);
102 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
103 namelen
= strlenW(name
);
105 max
= dir
->NumberOfNamedEntries
- 1;
108 pos
= (min
+ max
) / 2;
109 str
= (IMAGE_RESOURCE_DIR_STRING_U
*)((char *)root
+ entry
[pos
].u1
.s
.NameOffset
);
110 res
= strncmpiW( name
, str
->NameString
, str
->Length
);
111 if (!res
&& namelen
== str
->Length
)
112 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s
.OffsetToDirectory
);
113 if (res
< 0) max
= pos
- 1;
120 /**********************************************************************
121 * find_entry_by_nameA
123 * Find an entry by name in a resource directory
125 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY
*dir
,
126 LPCSTR name
, const void *root
)
128 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
131 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
134 return find_entry_by_id( dir
, atoi(name
+1), root
);
137 if ((nameW
= HEAP_strdupAtoW( GetProcessHeap(), 0, name
)))
139 ret
= find_entry_by_nameW( dir
, nameW
, root
);
140 HeapFree( GetProcessHeap(), 0, nameW
);
146 /**********************************************************************
149 * Find a default entry in a resource directory
151 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
154 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
156 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
157 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
->u2
.s
.OffsetToDirectory
);
161 /**********************************************************************
164 * FindResourceExA/W does search in the following order:
165 * 1. Exact specified language
166 * 2. Language with neutral sublanguage
167 * 3. Neutral language with neutral sublanguage
168 * 4. Neutral language with default sublanguage
170 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
172 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
176 if (!resdirptr
) return 0;
179 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
180 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
182 /* 1. Exact specified language */
183 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
185 /* 2. Language with neutral sublanguage */
186 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
187 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
189 /* 3. Neutral language with neutral sublanguage */
190 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
191 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
193 /* 4. Neutral language with default sublanguage */
194 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
195 result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
);
201 /**********************************************************************
204 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
205 * FindResourceA/W does search in the following order:
206 * 1. Neutral language with neutral sublanguage
207 * 2. Neutral language with default sublanguage
208 * 3. Current locale lang id
209 * 4. Current locale lang id with neutral sublanguage
210 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
211 * 6. Return first in the list
213 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
215 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
220 if (!resdirptr
) return 0;
223 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
224 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
226 /* 1. Neutral language with neutral sublanguage */
227 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
228 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
230 /* 2. Neutral language with default sublanguage */
231 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
232 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
234 /* 3. Current locale lang id */
235 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
236 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
238 /* 4. Current locale lang id with neutral sublanguage */
239 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
240 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
242 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
243 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
244 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
246 /* 6. Return first in the list */
247 result
= (HRSRC
)find_entry_default( resdirptr
, root
);
254 /**********************************************************************
257 HANDLE
PE_LoadResource( HMODULE hmod
, HANDLE hRsrc
)
259 if (!hRsrc
) return 0;
260 return (HANDLE
)(hmod
+ ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
);
264 /**********************************************************************
267 DWORD
PE_SizeofResource( HANDLE hRsrc
)
269 if (!hRsrc
) return 0;
270 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
274 /**********************************************************************
275 * EnumResourceTypesA (KERNEL32.90)
277 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
280 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
281 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
284 if (!resdir
) return FALSE
;
286 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
288 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
291 if (et
[i
].u1
.s
.NameIsString
)
293 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s
.NameOffset
);
294 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
295 NULL
, 0, NULL
, NULL
);
296 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
298 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
299 type
, len
, NULL
, NULL
);
301 ret
= lpfun(hmod
,type
,lparam
);
302 HeapFree(GetProcessHeap(), 0, type
);
306 type
= (LPSTR
)(int)et
[i
].u1
.Id
;
307 ret
= lpfun(hmod
,type
,lparam
);
316 /**********************************************************************
317 * EnumResourceTypesW (KERNEL32.91)
319 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
322 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
323 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
326 if (!resdir
) return FALSE
;
328 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
330 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
333 if (et
[i
].u1
.s
.NameIsString
)
335 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s
.NameOffset
);
336 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
338 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
339 type
[pResString
->Length
] = '\0';
340 ret
= lpfun(hmod
,type
,lparam
);
341 HeapFree(GetProcessHeap(), 0, type
);
345 type
= (LPWSTR
)(int)et
[i
].u1
.Id
;
346 ret
= lpfun(hmod
,type
,lparam
);
355 /**********************************************************************
356 * EnumResourceNamesA (KERNEL32.88)
358 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
361 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
362 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
363 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
366 if (!basedir
) return FALSE
;
368 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
370 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
372 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
375 if (et
[i
].u1
.s
.NameIsString
)
377 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s
.NameOffset
);
378 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
379 NULL
, 0, NULL
, NULL
);
380 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
382 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
383 name
, len
, NULL
, NULL
);
385 ret
= lpfun(hmod
,type
,name
,lparam
);
386 HeapFree( GetProcessHeap(), 0, name
);
390 name
= (LPSTR
)(int)et
[i
].u1
.Id
;
391 ret
= lpfun(hmod
,type
,name
,lparam
);
400 /**********************************************************************
401 * EnumResourceNamesW (KERNEL32.89)
403 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
406 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
407 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
408 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
411 if (!basedir
) return FALSE
;
413 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
415 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
417 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
420 if (et
[i
].u1
.s
.NameIsString
)
422 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s
.NameOffset
);
423 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
425 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
426 name
[pResString
->Length
] = '\0';
427 ret
= lpfun(hmod
,type
,name
,lparam
);
428 HeapFree(GetProcessHeap(), 0, name
);
432 name
= (LPWSTR
)(int)et
[i
].u1
.Id
;
433 ret
= lpfun(hmod
,type
,name
,lparam
);
442 /**********************************************************************
443 * EnumResourceLanguagesA (KERNEL32.86)
445 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
446 ENUMRESLANGPROCA lpfun
, LONG lparam
)
449 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
450 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
451 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
454 if (!basedir
) return FALSE
;
455 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
456 if (!(resdir
= find_entry_by_nameA( resdir
, name
, basedir
))) return FALSE
;
458 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
460 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
461 /* languages are just ids... I hope */
462 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.Id
,lparam
);
470 /**********************************************************************
471 * EnumResourceLanguagesW (KERNEL32.87)
473 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
474 ENUMRESLANGPROCW lpfun
, LONG lparam
)
477 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
478 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
479 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
482 if (!basedir
) return FALSE
;
484 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
485 if (!(resdir
= find_entry_by_nameW( resdir
, name
, basedir
))) return FALSE
;
487 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
489 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
490 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.Id
,lparam
);