Fixed typo in SetGraphicsMode.
[wine/multimedia.git] / loader / pe_resource.c
blobaec210817ed3112ad9ecc6ef4cc5b6c37578521b
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
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
27 #include "config.h"
29 #include <stdlib.h>
30 #include <sys/types.h>
32 #define NONAMELESSUNION
33 #define NONAMELESSSTRUCT
34 #include "wine/unicode.h"
35 #include "windef.h"
36 #include "winnls.h"
37 #include "winternl.h"
38 #include "winerror.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(resource);
44 /**********************************************************************
45 * is_data_file_module
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 /**********************************************************************
56 * get_resdir
58 * Get the resource directory of a PE module
60 static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
62 DWORD size;
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);
69 return NULL;
71 return RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
75 /**********************************************************************
76 * find_entry_by_id
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;
84 int min, max, pos;
86 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
87 min = dir->NumberOfNamedEntries;
88 max = min + dir->NumberOfIdEntries - 1;
89 while (min <= max)
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;
95 else min = pos + 1;
97 return NULL;
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 );
114 if (name[0] == '#')
116 char buf[16];
117 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
118 return NULL;
119 return find_entry_by_id( dir, atoi(buf), root );
122 entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
123 namelen = strlenW(name);
124 min = 0;
125 max = dir->NumberOfNamedEntries - 1;
126 while (min <= max)
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;
134 else min = pos + 1;
136 return NULL;
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;
149 LPWSTR nameW;
150 INT len;
152 if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
153 if (name[0] == '#')
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 );
165 return ret;
169 /**********************************************************************
170 * find_entry_default
172 * Find a default entry in a resource directory
174 static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
175 const void *root )
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 /**********************************************************************
185 * PE_FindResourceExW
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);
196 const void *root;
197 HRSRC result;
199 if (!resdirptr) return 0;
201 root = resdirptr;
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 );
220 found:
221 return result;
224 /**********************************************************************
225 * PE_FindResourceW
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);
239 const void *root;
240 HRSRC result;
241 WORD lang;
243 if (!resdirptr) return 0;
245 root = resdirptr;
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 );
272 found:
273 return result;
277 /**********************************************************************
278 * PE_LoadResource
280 HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
282 DWORD offset;
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 );
294 else
295 return (HGLOBAL)((char *)hmod + offset);
299 /**********************************************************************
300 * PE_SizeofResource
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)
314 int i;
315 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
316 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
317 BOOL ret;
319 if (!resdir) return FALSE;
321 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
322 ret = FALSE;
323 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
324 LPSTR type;
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)))
332 return FALSE;
333 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
334 type, len, NULL, NULL);
335 type[len] = '\0';
336 ret = lpfun(hmod,type,lparam);
337 HeapFree(GetProcessHeap(), 0, type);
339 else
341 type = (LPSTR)(int)et[i].u1.s2.Id;
342 ret = lpfun(hmod,type,lparam);
344 if (!ret)
345 break;
347 return ret;
351 /**********************************************************************
352 * EnumResourceTypesW (KERNEL32.@)
354 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
356 int i;
357 const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
358 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
359 BOOL ret;
361 if (!resdir) return FALSE;
363 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
364 ret = FALSE;
365 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
366 LPWSTR type;
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))))
372 return FALSE;
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);
378 else
380 type = (LPWSTR)(int)et[i].u1.s2.Id;
381 ret = lpfun(hmod,type,lparam);
383 if (!ret)
384 break;
386 return ret;
390 /**********************************************************************
391 * EnumResourceNamesA (KERNEL32.@)
393 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
395 int i;
396 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
397 const IMAGE_RESOURCE_DIRECTORY *resdir;
398 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
399 BOOL ret;
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);
406 ret = FALSE;
407 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
408 LPSTR name;
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 )))
416 return FALSE;
417 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
418 name, len, NULL, NULL );
419 name[len] = '\0';
420 ret = lpfun(hmod,type,name,lparam);
421 HeapFree( GetProcessHeap(), 0, name );
423 else
425 name = (LPSTR)(int)et[i].u1.s2.Id;
426 ret = lpfun(hmod,type,name,lparam);
428 if (!ret)
429 break;
431 return ret;
435 /**********************************************************************
436 * EnumResourceNamesW (KERNEL32.@)
438 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
440 int i;
441 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
442 const IMAGE_RESOURCE_DIRECTORY *resdir;
443 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
444 BOOL ret;
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);
451 ret = FALSE;
452 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
453 LPWSTR name;
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))))
459 return FALSE;
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);
465 else
467 name = (LPWSTR)(int)et[i].u1.s2.Id;
468 ret = lpfun(hmod,type,name,lparam);
470 if (!ret)
471 break;
473 return ret;
477 /**********************************************************************
478 * EnumResourceLanguagesA (KERNEL32.@)
480 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
481 ENUMRESLANGPROCA lpfun, LONG lparam )
483 int i;
484 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
485 const IMAGE_RESOURCE_DIRECTORY *resdir;
486 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
487 BOOL ret;
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);
494 ret = FALSE;
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);
498 if (!ret)
499 break;
501 return ret;
505 /**********************************************************************
506 * EnumResourceLanguagesW (KERNEL32.@)
508 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
509 ENUMRESLANGPROCW lpfun, LONG lparam )
511 int i;
512 const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
513 const IMAGE_RESOURCE_DIRECTORY *resdir;
514 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
515 BOOL ret;
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);
523 ret = FALSE;
524 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
525 ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
526 if (!ret)
527 break;
529 return ret;