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
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <sys/types.h>
32 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(resource
);
42 /**********************************************************************
45 * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
47 inline static int is_data_file_module( HMODULE hmod
)
49 return (ULONG_PTR
)hmod
& 1;
53 /**********************************************************************
56 * Get the resource directory of a PE module
58 static const IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
62 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
63 else if (!HIWORD(hmod
))
65 FIXME("Enumeration of 16-bit resources is not supported\n");
66 SetLastError(ERROR_INVALID_HANDLE
);
69 return RtlImageDirectoryEntryToData( hmod
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
73 /**********************************************************************
76 * Find an entry by id in a resource directory
78 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
79 WORD id
, const void *root
)
81 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
84 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
85 min
= dir
->NumberOfNamedEntries
;
86 max
= min
+ dir
->NumberOfIdEntries
- 1;
89 pos
= (min
+ max
) / 2;
90 if (entry
[pos
].u1
.s2
.Id
== id
)
91 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
92 if (entry
[pos
].u1
.s2
.Id
> id
) max
= pos
- 1;
99 /**********************************************************************
100 * find_entry_by_nameW
102 * Find an entry by name in a resource directory
104 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY
*dir
,
105 LPCWSTR name
, const void *root
)
107 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
108 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
109 int min
, max
, res
, pos
, namelen
;
111 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
115 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
117 return find_entry_by_id( dir
, atoi(buf
), root
);
120 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
121 namelen
= strlenW(name
);
123 max
= dir
->NumberOfNamedEntries
- 1;
126 pos
= (min
+ max
) / 2;
127 str
= (IMAGE_RESOURCE_DIR_STRING_U
*)((char *)root
+ entry
[pos
].u1
.s1
.NameOffset
);
128 res
= strncmpiW( name
, str
->NameString
, str
->Length
);
129 if (!res
&& namelen
== str
->Length
)
130 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
131 if (res
< 0) max
= pos
- 1;
138 /**********************************************************************
139 * find_entry_by_nameA
141 * Find an entry by name in a resource directory
143 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY
*dir
,
144 LPCSTR name
, const void *root
)
146 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
150 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
153 return find_entry_by_id( dir
, atoi(name
+1), root
);
156 len
= MultiByteToWideChar( CP_ACP
, 0, name
, -1, NULL
, 0 );
157 if ((nameW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
159 MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, len
);
160 ret
= find_entry_by_nameW( dir
, nameW
, root
);
161 HeapFree( GetProcessHeap(), 0, nameW
);
167 /**********************************************************************
170 * Find a default entry in a resource directory
172 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
175 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
177 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
178 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
->u2
.s3
.OffsetToDirectory
);
182 /**********************************************************************
185 * FindResourceExA/W does search in the following order:
186 * 1. Exact specified language
187 * 2. Language with neutral sublanguage
188 * 3. Neutral language with neutral sublanguage
189 * 4. Neutral language with default sublanguage
191 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
193 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
197 if (!resdirptr
) return 0;
200 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
201 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
203 /* 1. Exact specified language */
204 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
206 /* 2. Language with neutral sublanguage */
207 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
208 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
210 /* 3. Neutral language with neutral sublanguage */
211 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
212 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
214 /* 4. Neutral language with default sublanguage */
215 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
216 result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
);
222 /**********************************************************************
225 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
226 * FindResourceA/W does search in the following order:
227 * 1. Neutral language with neutral sublanguage
228 * 2. Neutral language with default sublanguage
229 * 3. Current locale lang id
230 * 4. Current locale lang id with neutral sublanguage
231 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
232 * 6. Return first in the list
234 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
236 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
241 if (!resdirptr
) return 0;
244 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
245 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
247 /* 1. Neutral language with neutral sublanguage */
248 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
249 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
251 /* 2. Neutral language with default sublanguage */
252 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
253 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
255 /* 3. Current locale lang id */
256 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
257 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
259 /* 4. Current locale lang id with neutral sublanguage */
260 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
261 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
263 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
264 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
265 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
267 /* 6. Return first in the list */
268 result
= (HRSRC
)find_entry_default( resdirptr
, root
);
275 /**********************************************************************
278 HGLOBAL
PE_LoadResource( HMODULE hmod
, HRSRC hRsrc
)
282 if (!hRsrc
) return 0;
283 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
285 offset
= ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
;
287 if (is_data_file_module(hmod
))
289 hmod
= (HMODULE
)((ULONG_PTR
)hmod
& ~1);
290 return (HGLOBAL
)RtlImageRvaToVa( RtlImageNtHeader(hmod
), hmod
, offset
, NULL
);
293 return (HGLOBAL
)((char *)hmod
+ offset
);
297 /**********************************************************************
300 DWORD
PE_SizeofResource( HRSRC hRsrc
)
302 if (!hRsrc
) return 0;
303 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
307 /**********************************************************************
308 * EnumResourceTypesA (KERNEL32.@)
310 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
313 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
314 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
317 if (!resdir
) return FALSE
;
319 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
321 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
324 if (et
[i
].u1
.s1
.NameIsString
)
326 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
327 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
328 NULL
, 0, NULL
, NULL
);
329 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
331 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
332 type
, len
, NULL
, NULL
);
334 ret
= lpfun(hmod
,type
,lparam
);
335 HeapFree(GetProcessHeap(), 0, type
);
339 type
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
340 ret
= lpfun(hmod
,type
,lparam
);
349 /**********************************************************************
350 * EnumResourceTypesW (KERNEL32.@)
352 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
355 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
356 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
359 if (!resdir
) return FALSE
;
361 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
363 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
366 if (et
[i
].u1
.s1
.NameIsString
)
368 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
369 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
371 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
372 type
[pResString
->Length
] = '\0';
373 ret
= lpfun(hmod
,type
,lparam
);
374 HeapFree(GetProcessHeap(), 0, type
);
378 type
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
379 ret
= lpfun(hmod
,type
,lparam
);
388 /**********************************************************************
389 * EnumResourceNamesA (KERNEL32.@)
391 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
394 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
395 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
396 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
399 if (!basedir
) return FALSE
;
401 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
403 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
405 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
408 if (et
[i
].u1
.s1
.NameIsString
)
410 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
411 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
412 NULL
, 0, NULL
, NULL
);
413 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
415 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
416 name
, len
, NULL
, NULL
);
418 ret
= lpfun(hmod
,type
,name
,lparam
);
419 HeapFree( GetProcessHeap(), 0, name
);
423 name
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
424 ret
= lpfun(hmod
,type
,name
,lparam
);
433 /**********************************************************************
434 * EnumResourceNamesW (KERNEL32.@)
436 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
439 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
440 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
441 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
444 if (!basedir
) return FALSE
;
446 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
448 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
450 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
453 if (et
[i
].u1
.s1
.NameIsString
)
455 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
456 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
458 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
459 name
[pResString
->Length
] = '\0';
460 ret
= lpfun(hmod
,type
,name
,lparam
);
461 HeapFree(GetProcessHeap(), 0, name
);
465 name
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
466 ret
= lpfun(hmod
,type
,name
,lparam
);
475 /**********************************************************************
476 * EnumResourceLanguagesA (KERNEL32.@)
478 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
479 ENUMRESLANGPROCA lpfun
, LONG lparam
)
482 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
483 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
484 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
487 if (!basedir
) return FALSE
;
488 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
489 if (!(resdir
= find_entry_by_nameA( resdir
, name
, basedir
))) return FALSE
;
491 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
493 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
494 /* languages are just ids... I hope */
495 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);
503 /**********************************************************************
504 * EnumResourceLanguagesW (KERNEL32.@)
506 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
507 ENUMRESLANGPROCW lpfun
, LONG lparam
)
510 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
511 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
512 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
515 if (!basedir
) return FALSE
;
517 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
518 if (!(resdir
= find_entry_by_nameW( resdir
, name
, basedir
))) return FALSE
;
520 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
522 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
523 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);