Fixed some difficulties with the font on vertical tabs. Also plugged a
[wine.git] / loader / pe_resource.c
blobf30ca6536c25d5756f15215789ae1902b0558e0f
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 "wine/unicode.h"
17 #include "windef.h"
18 #include "winnls.h"
19 #include "winerror.h"
20 #include "module.h"
21 #include "heap.h"
22 #include "task.h"
23 #include "stackframe.h"
24 #include "debugtools.h"
26 DEFAULT_DEBUG_CHANNEL(resource);
28 /**********************************************************************
29 * get_resdir
31 * Get the resource directory of a PE module
33 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
35 const IMAGE_DATA_DIRECTORY *dir;
36 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
38 if (!hmod) hmod = GetModuleHandleA( NULL );
39 else if (!HIWORD(hmod))
41 FIXME("Enumeration of 16-bit resources is not supported\n");
42 SetLastError(ERROR_INVALID_HANDLE);
43 return NULL;
45 dir = &PE_HEADER(hmod)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
46 if (dir->Size && dir->VirtualAddress)
47 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)hmod + dir->VirtualAddress);
48 return ret;
52 /**********************************************************************
53 * find_entry_by_id
55 * Find an entry by id in a resource directory
57 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
58 WORD id, const void *root )
60 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
61 int min, max, pos;
63 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
64 min = dir->NumberOfNamedEntries;
65 max = min + dir->NumberOfIdEntries - 1;
66 while (min <= max)
68 pos = (min + max) / 2;
69 if (entry[pos].u1.Id == id)
70 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s2.OffsetToDirectory);
71 if (entry[pos].u1.Id > id) max = pos - 1;
72 else min = pos + 1;
74 return NULL;
78 /**********************************************************************
79 * find_entry_by_nameW
81 * Find an entry by name in a resource directory
83 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
84 LPCWSTR name, const void *root )
86 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
87 const IMAGE_RESOURCE_DIR_STRING_U *str;
88 int min, max, res, pos, namelen;
90 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
91 if (name[0] == '#')
93 char buf[16];
94 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
95 return NULL;
96 return find_entry_by_id( dir, atoi(buf), root );
99 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
100 namelen = strlenW(name);
101 min = 0;
102 max = dir->NumberOfNamedEntries - 1;
103 while (min <= max)
105 pos = (min + max) / 2;
106 str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
107 res = strncmpiW( name, str->NameString, str->Length );
108 if (!res && namelen == str->Length)
109 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s2.OffsetToDirectory);
110 if (res < 0) max = pos - 1;
111 else min = pos + 1;
113 return NULL;
117 /**********************************************************************
118 * find_entry_by_nameA
120 * Find an entry by name in a resource directory
122 static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
123 LPCSTR name, const void *root )
125 const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
126 LPWSTR nameW;
128 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
129 if (name[0] == '#')
131 return find_entry_by_id( dir, atoi(name+1), root );
134 if ((nameW = HEAP_strdupAtoW( GetProcessHeap(), 0, name )))
136 ret = find_entry_by_nameW( dir, nameW, root );
137 HeapFree( GetProcessHeap(), 0, nameW );
139 return ret;
143 /**********************************************************************
144 * find_entry_default
146 * Find a default entry in a resource directory
148 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
149 const void *root )
151 const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
153 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
154 return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s2.OffsetToDirectory);
158 /**********************************************************************
159 * PE_FindResourceExW
161 * FindResourceExA/W does search in the following order:
162 * 1. Exact specified language
163 * 2. Language with neutral sublanguage
164 * 3. Neutral language with neutral sublanguage
165 * 4. Neutral language with default sublanguage
167 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
169 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
170 const void *root;
171 HRSRC result;
173 if (!resdirptr) return 0;
175 root = resdirptr;
176 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
177 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
179 /* 1. Exact specified language */
180 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
182 /* 2. Language with neutral sublanguage */
183 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
184 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
186 /* 3. Neutral language with neutral sublanguage */
187 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
188 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
190 /* 4. Neutral language with default sublanguage */
191 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
192 result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
194 found:
195 return result;
198 /**********************************************************************
199 * PE_FindResourceW
201 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
202 * FindResourceA/W does search in the following order:
203 * 1. Neutral language with neutral sublanguage
204 * 2. Neutral language with default sublanguage
205 * 3. Current locale lang id
206 * 4. Current locale lang id with neutral sublanguage
207 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
208 * 6. Return first in the list
210 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
212 const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
213 const void *root;
214 HRSRC result;
215 WORD lang;
217 if (!resdirptr) return 0;
219 root = resdirptr;
220 if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
221 if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
223 /* 1. Neutral language with neutral sublanguage */
224 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
225 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
227 /* 2. Neutral language with default sublanguage */
228 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
229 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
231 /* 3. Current locale lang id */
232 lang = LANGIDFROMLCID(GetUserDefaultLCID());
233 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
235 /* 4. Current locale lang id with neutral sublanguage */
236 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
237 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
239 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
240 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
241 if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
243 /* 6. Return first in the list */
244 result = (HRSRC)find_entry_default( resdirptr, root );
246 found:
247 return result;
251 /**********************************************************************
252 * PE_LoadResource
254 HANDLE PE_LoadResource( HMODULE hmod, HANDLE hRsrc )
256 if (!hRsrc) return 0;
257 return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
261 /**********************************************************************
262 * PE_SizeofResource
264 DWORD PE_SizeofResource( HANDLE hRsrc )
266 if (!hRsrc) return 0;
267 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
271 /**********************************************************************
272 * EnumResourceTypesA (KERNEL32.90)
274 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
276 int i;
277 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
278 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
279 BOOL ret;
281 if (!resdir) return FALSE;
283 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
284 ret = FALSE;
285 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
286 LPSTR type;
288 if (et[i].u1.s1.NameIsString)
290 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
291 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
292 NULL, 0, NULL, NULL);
293 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
294 return FALSE;
295 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
296 type, len, NULL, NULL);
297 type[len] = '\0';
298 ret = lpfun(hmod,type,lparam);
299 HeapFree(GetProcessHeap(), 0, type);
301 else
303 type = (LPSTR)(int)et[i].u1.Id;
304 ret = lpfun(hmod,type,lparam);
306 if (!ret)
307 break;
309 return ret;
313 /**********************************************************************
314 * EnumResourceTypesW (KERNEL32.91)
316 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
318 int i;
319 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
320 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
321 BOOL ret;
323 if (!resdir) return FALSE;
325 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
326 ret = FALSE;
327 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
328 LPWSTR type;
330 if (et[i].u1.s1.NameIsString)
332 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
333 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
334 return FALSE;
335 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
336 type[pResString->Length] = '\0';
337 ret = lpfun(hmod,type,lparam);
338 HeapFree(GetProcessHeap(), 0, type);
340 else
342 type = (LPWSTR)(int)et[i].u1.Id;
343 ret = lpfun(hmod,type,lparam);
345 if (!ret)
346 break;
348 return ret;
352 /**********************************************************************
353 * EnumResourceNamesA (KERNEL32.88)
355 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
357 int i;
358 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
359 const IMAGE_RESOURCE_DIRECTORY *resdir;
360 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
361 BOOL ret;
363 if (!basedir) return FALSE;
365 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
367 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
368 ret = FALSE;
369 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
370 LPSTR name;
372 if (et[i].u1.s1.NameIsString)
374 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
375 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
376 NULL, 0, NULL, NULL);
377 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
378 return FALSE;
379 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
380 name, len, NULL, NULL );
381 name[len] = '\0';
382 ret = lpfun(hmod,type,name,lparam);
383 HeapFree( GetProcessHeap(), 0, name );
385 else
387 name = (LPSTR)(int)et[i].u1.Id;
388 ret = lpfun(hmod,type,name,lparam);
390 if (!ret)
391 break;
393 return ret;
397 /**********************************************************************
398 * EnumResourceNamesW (KERNEL32.89)
400 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
402 int i;
403 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
404 const IMAGE_RESOURCE_DIRECTORY *resdir;
405 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
406 BOOL ret;
408 if (!basedir) return FALSE;
410 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
412 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
413 ret = FALSE;
414 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
415 LPWSTR name;
417 if (et[i].u1.s1.NameIsString)
419 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
420 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
421 return FALSE;
422 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
423 name[pResString->Length] = '\0';
424 ret = lpfun(hmod,type,name,lparam);
425 HeapFree(GetProcessHeap(), 0, name);
427 else
429 name = (LPWSTR)(int)et[i].u1.Id;
430 ret = lpfun(hmod,type,name,lparam);
432 if (!ret)
433 break;
435 return ret;
439 /**********************************************************************
440 * EnumResourceLanguagesA (KERNEL32.86)
442 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
443 ENUMRESLANGPROCA lpfun, LONG lparam )
445 int i;
446 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
447 const IMAGE_RESOURCE_DIRECTORY *resdir;
448 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
449 BOOL ret;
451 if (!basedir) return FALSE;
452 if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
453 if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
455 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
456 ret = FALSE;
457 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
458 /* languages are just ids... I hope */
459 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
460 if (!ret)
461 break;
463 return ret;
467 /**********************************************************************
468 * EnumResourceLanguagesW (KERNEL32.87)
470 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
471 ENUMRESLANGPROCW lpfun, LONG lparam )
473 int i;
474 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
475 const IMAGE_RESOURCE_DIRECTORY *resdir;
476 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
477 BOOL ret;
479 if (!basedir) return FALSE;
481 if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
482 if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;
484 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
485 ret = FALSE;
486 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
487 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
488 if (!ret)
489 break;
491 return ret;