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 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(resource
);
44 /**********************************************************************
47 * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
49 inline static int is_data_file_module( HMODULE hmod
)
51 return (ULONG_PTR
)hmod
& 1;
55 /**********************************************************************
58 * Get the resource directory of a PE module
60 static const IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
64 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
65 else if (!HIWORD(hmod
))
67 FIXME("Enumeration of 16-bit resources is not supported\n");
68 SetLastError(ERROR_INVALID_HANDLE
);
71 return RtlImageDirectoryEntryToData( hmod
, TRUE
, IMAGE_DIRECTORY_ENTRY_RESOURCE
, &size
);
75 /**********************************************************************
78 * Find an entry by id in a resource directory
80 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY
*dir
,
81 WORD id
, const void *root
)
83 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
86 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
87 min
= dir
->NumberOfNamedEntries
;
88 max
= min
+ dir
->NumberOfIdEntries
- 1;
91 pos
= (min
+ max
) / 2;
92 if (entry
[pos
].u1
.s2
.Id
== id
)
93 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
94 if (entry
[pos
].u1
.s2
.Id
> id
) max
= pos
- 1;
101 /**********************************************************************
102 * find_entry_by_nameW
104 * Find an entry by name in a resource directory
106 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY
*dir
,
107 LPCWSTR name
, const void *root
)
109 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
110 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
111 int min
, max
, res
, pos
, namelen
;
113 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
117 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
119 return find_entry_by_id( dir
, atoi(buf
), root
);
122 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
123 namelen
= strlenW(name
);
125 max
= dir
->NumberOfNamedEntries
- 1;
128 pos
= (min
+ max
) / 2;
129 str
= (IMAGE_RESOURCE_DIR_STRING_U
*)((char *)root
+ entry
[pos
].u1
.s1
.NameOffset
);
130 res
= strncmpiW( name
, str
->NameString
, str
->Length
);
131 if (!res
&& namelen
== str
->Length
)
132 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
[pos
].u2
.s3
.OffsetToDirectory
);
133 if (res
< 0) max
= pos
- 1;
140 /**********************************************************************
141 * find_entry_by_nameA
143 * Find an entry by name in a resource directory
145 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY
*dir
,
146 LPCSTR name
, const void *root
)
148 const IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
152 if (!HIWORD(name
)) return find_entry_by_id( dir
, LOWORD(name
), root
);
155 return find_entry_by_id( dir
, atoi(name
+1), root
);
158 len
= MultiByteToWideChar( CP_ACP
, 0, name
, -1, NULL
, 0 );
159 if ((nameW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
161 MultiByteToWideChar( CP_ACP
, 0, name
, -1, nameW
, len
);
162 ret
= find_entry_by_nameW( dir
, nameW
, root
);
163 HeapFree( GetProcessHeap(), 0, nameW
);
169 /**********************************************************************
172 * Find a default entry in a resource directory
174 static const IMAGE_RESOURCE_DIRECTORY
*find_entry_default( const IMAGE_RESOURCE_DIRECTORY
*dir
,
177 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
;
179 entry
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(dir
+ 1);
180 return (IMAGE_RESOURCE_DIRECTORY
*)((char *)root
+ entry
->u2
.s3
.OffsetToDirectory
);
184 /**********************************************************************
187 * FindResourceExA/W does search in the following order:
188 * 1. Exact specified language
189 * 2. Language with neutral sublanguage
190 * 3. Neutral language with neutral sublanguage
191 * 4. Neutral language with default sublanguage
193 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
195 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
199 if (!resdirptr
) return 0;
202 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
203 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
205 /* 1. Exact specified language */
206 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
208 /* 2. Language with neutral sublanguage */
209 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
210 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
212 /* 3. Neutral language with neutral sublanguage */
213 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
214 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
216 /* 4. Neutral language with default sublanguage */
217 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
218 result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
);
224 /**********************************************************************
227 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
228 * FindResourceA/W does search in the following order:
229 * 1. Neutral language with neutral sublanguage
230 * 2. Neutral language with default sublanguage
231 * 3. Current locale lang id
232 * 4. Current locale lang id with neutral sublanguage
233 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
234 * 6. Return first in the list
236 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
238 const IMAGE_RESOURCE_DIRECTORY
*resdirptr
= get_resdir(hmod
);
243 if (!resdirptr
) return 0;
246 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, type
, root
))) return 0;
247 if (!(resdirptr
= find_entry_by_nameW(resdirptr
, name
, root
))) return 0;
249 /* 1. Neutral language with neutral sublanguage */
250 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
251 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
253 /* 2. Neutral language with default sublanguage */
254 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
255 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
257 /* 3. Current locale lang id */
258 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
259 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
261 /* 4. Current locale lang id with neutral sublanguage */
262 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
263 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
265 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
266 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
267 if ((result
= (HRSRC
)find_entry_by_id( resdirptr
, lang
, root
))) goto found
;
269 /* 6. Return first in the list */
270 result
= (HRSRC
)find_entry_default( resdirptr
, root
);
277 /**********************************************************************
280 HGLOBAL
PE_LoadResource( HMODULE hmod
, HRSRC hRsrc
)
284 if (!hRsrc
) return 0;
285 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
287 offset
= ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
;
289 if (is_data_file_module(hmod
))
291 hmod
= (HMODULE
)((ULONG_PTR
)hmod
& ~1);
292 return (HGLOBAL
)RtlImageRvaToVa( RtlImageNtHeader(hmod
), hmod
, offset
, NULL
);
295 return (HGLOBAL
)((char *)hmod
+ offset
);
299 /**********************************************************************
302 DWORD
PE_SizeofResource( HRSRC hRsrc
)
304 if (!hRsrc
) return 0;
305 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
309 /**********************************************************************
310 * EnumResourceTypesA (KERNEL32.@)
312 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
315 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
316 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
319 if (!resdir
) return FALSE
;
321 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
323 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
326 if (et
[i
].u1
.s1
.NameIsString
)
328 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
329 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
330 NULL
, 0, NULL
, NULL
);
331 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
333 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
334 type
, len
, NULL
, NULL
);
336 ret
= lpfun(hmod
,type
,lparam
);
337 HeapFree(GetProcessHeap(), 0, type
);
341 type
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
342 ret
= lpfun(hmod
,type
,lparam
);
351 /**********************************************************************
352 * EnumResourceTypesW (KERNEL32.@)
354 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
357 const IMAGE_RESOURCE_DIRECTORY
*resdir
= get_resdir(hmod
);
358 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
361 if (!resdir
) return FALSE
;
363 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
365 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
368 if (et
[i
].u1
.s1
.NameIsString
)
370 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s1
.NameOffset
);
371 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
373 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
374 type
[pResString
->Length
] = '\0';
375 ret
= lpfun(hmod
,type
,lparam
);
376 HeapFree(GetProcessHeap(), 0, type
);
380 type
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
381 ret
= lpfun(hmod
,type
,lparam
);
390 /**********************************************************************
391 * EnumResourceNamesA (KERNEL32.@)
393 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
396 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
397 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
398 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
401 if (!basedir
) return FALSE
;
403 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
405 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
407 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
410 if (et
[i
].u1
.s1
.NameIsString
)
412 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
413 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
414 NULL
, 0, NULL
, NULL
);
415 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
417 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
418 name
, len
, NULL
, NULL
);
420 ret
= lpfun(hmod
,type
,name
,lparam
);
421 HeapFree( GetProcessHeap(), 0, name
);
425 name
= (LPSTR
)(int)et
[i
].u1
.s2
.Id
;
426 ret
= lpfun(hmod
,type
,name
,lparam
);
435 /**********************************************************************
436 * EnumResourceNamesW (KERNEL32.@)
438 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
441 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
442 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
443 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
446 if (!basedir
) return FALSE
;
448 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
450 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
452 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
455 if (et
[i
].u1
.s1
.NameIsString
)
457 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s1
.NameOffset
);
458 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
460 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
461 name
[pResString
->Length
] = '\0';
462 ret
= lpfun(hmod
,type
,name
,lparam
);
463 HeapFree(GetProcessHeap(), 0, name
);
467 name
= (LPWSTR
)(int)et
[i
].u1
.s2
.Id
;
468 ret
= lpfun(hmod
,type
,name
,lparam
);
477 /**********************************************************************
478 * EnumResourceLanguagesA (KERNEL32.@)
480 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
481 ENUMRESLANGPROCA lpfun
, LONG lparam
)
484 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
485 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
486 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
489 if (!basedir
) return FALSE
;
490 if (!(resdir
= find_entry_by_nameA( basedir
, type
, basedir
))) return FALSE
;
491 if (!(resdir
= find_entry_by_nameA( resdir
, name
, basedir
))) return FALSE
;
493 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
495 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
496 /* languages are just ids... I hope */
497 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);
505 /**********************************************************************
506 * EnumResourceLanguagesW (KERNEL32.@)
508 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
509 ENUMRESLANGPROCW lpfun
, LONG lparam
)
512 const IMAGE_RESOURCE_DIRECTORY
*basedir
= get_resdir(hmod
);
513 const IMAGE_RESOURCE_DIRECTORY
*resdir
;
514 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
517 if (!basedir
) return FALSE
;
519 if (!(resdir
= find_entry_by_nameW( basedir
, type
, basedir
))) return FALSE
;
520 if (!(resdir
= find_entry_by_nameW( resdir
, name
, basedir
))) return FALSE
;
522 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
524 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
525 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.s2
.Id
,lparam
);