Delay import of user32 to allow debugging crashes in user init code.
[wine/multimedia.git] / loader / pe_resource.c
blob976e8ba606be58a0748904cbf3086e66e1710006
1 /*
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
13 #include <stdlib.h>
14 #include <sys/types.h>
16 #include "config.h"
18 #include "wine/unicode.h"
19 #include "windef.h"
20 #include "winnls.h"
21 #include "winerror.h"
22 #include "module.h"
23 #include "heap.h"
24 #include "stackframe.h"
25 #include "debugtools.h"
27 DEFAULT_DEBUG_CHANNEL(resource);
29 /**********************************************************************
30 * get_resdir
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);
44 return NULL;
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);
49 return ret;
53 /**********************************************************************
54 * find_entry_by_id
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;
62 int min, max, pos;
64 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
65 min = dir->NumberOfNamedEntries;
66 max = min + dir->NumberOfIdEntries - 1;
67 while (min <= max)
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;
73 else min = pos + 1;
75 return NULL;
79 /**********************************************************************
80 * find_entry_by_nameW
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 );
92 if (name[0] == '#')
94 char buf[16];
95 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
96 return NULL;
97 return find_entry_by_id( dir, atoi(buf), root );
100 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
101 namelen = strlenW(name);
102 min = 0;
103 max = dir->NumberOfNamedEntries - 1;
104 while (min <= max)
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;
112 else min = pos + 1;
114 return NULL;
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;
127 LPWSTR nameW;
129 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
130 if (name[0] == '#')
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 );
140 return ret;
144 /**********************************************************************
145 * find_entry_default
147 * Find a default entry in a resource directory
149 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
150 const void *root )
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 /**********************************************************************
160 * PE_FindResourceExW
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);
171 const void *root;
172 HRSRC result;
174 if (!resdirptr) return 0;
176 root = resdirptr;
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 );
195 found:
196 return result;
199 /**********************************************************************
200 * PE_FindResourceW
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);
214 const void *root;
215 HRSRC result;
216 WORD lang;
218 if (!resdirptr) return 0;
220 root = resdirptr;
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 );
247 found:
248 return result;
252 /**********************************************************************
253 * PE_LoadResource
255 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
257 if (!hRsrc) return 0;
258 return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
262 /**********************************************************************
263 * PE_SizeofResource
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)
277 int i;
278 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
279 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
280 BOOL ret;
282 if (!resdir) return FALSE;
284 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
285 ret = FALSE;
286 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
287 LPSTR type;
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)))
295 return FALSE;
296 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
297 type, len, NULL, NULL);
298 type[len] = '\0';
299 ret = lpfun(hmod,type,lparam);
300 HeapFree(GetProcessHeap(), 0, type);
302 else
304 type = (LPSTR)(int)et[i].u1.s2.Id;
305 ret = lpfun(hmod,type,lparam);
307 if (!ret)
308 break;
310 return ret;
314 /**********************************************************************
315 * EnumResourceTypesW (KERNEL32.91)
317 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
319 int i;
320 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
321 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
322 BOOL ret;
324 if (!resdir) return FALSE;
326 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
327 ret = FALSE;
328 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
329 LPWSTR type;
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))))
335 return FALSE;
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);
341 else
343 type = (LPWSTR)(int)et[i].u1.s2.Id;
344 ret = lpfun(hmod,type,lparam);
346 if (!ret)
347 break;
349 return ret;
353 /**********************************************************************
354 * EnumResourceNamesA (KERNEL32.88)
356 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
358 int i;
359 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
360 const IMAGE_RESOURCE_DIRECTORY *resdir;
361 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
362 BOOL ret;
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);
369 ret = FALSE;
370 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
371 LPSTR name;
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 )))
379 return FALSE;
380 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
381 name, len, NULL, NULL );
382 name[len] = '\0';
383 ret = lpfun(hmod,type,name,lparam);
384 HeapFree( GetProcessHeap(), 0, name );
386 else
388 name = (LPSTR)(int)et[i].u1.s2.Id;
389 ret = lpfun(hmod,type,name,lparam);
391 if (!ret)
392 break;
394 return ret;
398 /**********************************************************************
399 * EnumResourceNamesW (KERNEL32.89)
401 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
403 int i;
404 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
405 const IMAGE_RESOURCE_DIRECTORY *resdir;
406 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
407 BOOL ret;
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);
414 ret = FALSE;
415 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
416 LPWSTR name;
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))))
422 return FALSE;
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);
428 else
430 name = (LPWSTR)(int)et[i].u1.s2.Id;
431 ret = lpfun(hmod,type,name,lparam);
433 if (!ret)
434 break;
436 return ret;
440 /**********************************************************************
441 * EnumResourceLanguagesA (KERNEL32.86)
443 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
444 ENUMRESLANGPROCA lpfun, LONG lparam )
446 int i;
447 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
448 const IMAGE_RESOURCE_DIRECTORY *resdir;
449 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
450 BOOL ret;
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);
457 ret = FALSE;
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);
461 if (!ret)
462 break;
464 return ret;
468 /**********************************************************************
469 * EnumResourceLanguagesW (KERNEL32.87)
471 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
472 ENUMRESLANGPROCW lpfun, LONG lparam )
474 int i;
475 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
476 const IMAGE_RESOURCE_DIRECTORY *resdir;
477 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
478 BOOL ret;
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);
486 ret = FALSE;
487 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
488 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
489 if (!ret)
490 break;
492 return ret;