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
14 #include <sys/types.h>
15 #include "wine/winestring.h"
16 #include "wine/unicode.h"
23 #include "stackframe.h"
25 #include "debugtools.h"
27 /**********************************************************************
30 * Get the resource directory of a PE module
32 static IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
34 IMAGE_DATA_DIRECTORY *dir;
35 IMAGE_RESOURCE_DIRECTORY *ret = NULL;
37 if (!hmod) hmod = GetModuleHandleA( NULL );
38 dir = &PE_HEADER(hmod)->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE];
39 if (dir->Size && dir->VirtualAddress)
40 ret = (IMAGE_RESOURCE_DIRECTORY *)((char *)hmod + dir->VirtualAddress);
45 /**********************************************************************
48 * Helper function - goes down one level of PE resource tree
51 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr,
52 LPCWSTR name,DWORD root,
56 PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable;
62 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
64 return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault);
66 entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdirptr + 1);
67 namelen = strlenW(name);
68 for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++)
70 PIMAGE_RESOURCE_DIR_STRING_U str =
71 (PIMAGE_RESOURCE_DIR_STRING_U) (root +
72 entryTable[entrynum].u1.s.NameOffset);
73 if(namelen != str->Length)
75 if(strncmpiW(name,str->NameString,str->Length)==0)
76 return (PIMAGE_RESOURCE_DIRECTORY) (
78 entryTable[entrynum].u2.s.OffsetToDirectory);
82 entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
84 sizeof(IMAGE_RESOURCE_DIRECTORY) +
85 resdirptr->NumberOfNamedEntries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
86 for (entrynum = 0; entrynum < resdirptr->NumberOfIdEntries; entrynum++)
87 if ((DWORD)entryTable[entrynum].u1.Name == (DWORD)name)
88 return (PIMAGE_RESOURCE_DIRECTORY) (
90 entryTable[entrynum].u2.s.OffsetToDirectory);
91 /* just use first entry if no default can be found */
92 if (allowdefault && !name && resdirptr->NumberOfIdEntries)
93 return (PIMAGE_RESOURCE_DIRECTORY) (
95 entryTable[0].u2.s.OffsetToDirectory);
100 /**********************************************************************
103 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr,
104 LPCSTR name, DWORD root,
107 PIMAGE_RESOURCE_DIRECTORY retv;
108 LPWSTR nameW = HIWORD(name)? HEAP_strdupAtoW( GetProcessHeap(), 0, name )
111 retv = GetResDirEntryW( resdirptr, nameW, root, allowdefault );
113 if ( HIWORD(name) ) HeapFree( GetProcessHeap(), 0, nameW );
118 /**********************************************************************
121 * FindResourceExA/W does search in the following order:
122 * 1. Exact specified language
123 * 2. Language with neutral sublanguage
124 * 3. Neutral language with neutral sublanguage
125 * 4. Neutral language with default sublanguage
127 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
129 PIMAGE_RESOURCE_DIRECTORY resdirptr = get_resdir(hmod);
133 if (!resdirptr) return 0;
135 root = (DWORD) resdirptr;
136 if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
138 if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
141 /* 1. Exact specified language */
142 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
146 /* 2. Language with neutral sublanguage */
147 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
148 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
153 /* 3. Neutral language with neutral sublanguage */
154 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
155 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
160 /* 4. Neutral language with default sublanguage */
161 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
162 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
168 /**********************************************************************
171 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
172 * FindResourceA/W does search in the following order:
173 * 1. Neutral language with neutral sublanguage
174 * 2. Neutral language with default sublanguage
175 * 3. Current locale lang id
176 * 4. Current locale lang id with neutral sublanguage
177 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
178 * 6. Return first in the list
180 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
182 PIMAGE_RESOURCE_DIRECTORY resdirptr = get_resdir(hmod);
187 if (!resdirptr) return 0;
189 root = (DWORD) resdirptr;
190 if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
192 if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
195 /* 1. Neutral language with neutral sublanguage */
196 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
197 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
201 /* 2. Neutral language with default sublanguage */
202 lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
203 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
208 /* 3. Current locale lang id */
209 lang = LANGIDFROMLCID(GetUserDefaultLCID());
210 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
215 /* 4. Current locale lang id with neutral sublanguage */
216 lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
217 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
222 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
223 lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
224 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
229 /* 6. Return first in the list */
230 result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)0, root, TRUE);
237 /**********************************************************************
240 HANDLE PE_LoadResource( HMODULE hmod, HANDLE hRsrc )
242 if (!hRsrc) return 0;
243 return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
247 /**********************************************************************
250 DWORD PE_SizeofResource( HANDLE hRsrc )
252 if (!hRsrc) return 0;
253 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
257 /**********************************************************************
258 * EnumResourceTypesA (KERNEL32.90)
260 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
263 PIMAGE_RESOURCE_DIRECTORY resdir = get_resdir(hmod);
264 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
267 if (!resdir) return FALSE;
269 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
271 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
274 if (et[i].u1.s.NameIsString)
276 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s.NameOffset);
277 DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
278 NULL, 0, NULL, NULL);
279 if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
281 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
282 type, len, NULL, NULL);
284 ret = lpfun(hmod,type,lparam);
285 HeapFree(GetProcessHeap(), 0, type);
289 type = (LPSTR)(int)et[i].u1.Id;
290 ret = lpfun(hmod,type,lparam);
299 /**********************************************************************
300 * EnumResourceTypesW (KERNEL32.91)
302 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
305 PIMAGE_RESOURCE_DIRECTORY resdir = get_resdir(hmod);
306 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
309 if (!resdir) return FALSE;
311 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
313 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
316 if (et[i].u1.s.NameIsString)
318 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s.NameOffset);
319 if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
321 memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
322 type[pResString->Length] = '\0';
323 ret = lpfun(hmod,type,lparam);
324 HeapFree(GetProcessHeap(), 0, type);
328 type = (LPWSTR)(int)et[i].u1.Id;
329 ret = lpfun(hmod,type,lparam);
338 /**********************************************************************
339 * EnumResourceNamesA (KERNEL32.88)
341 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
344 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
345 PIMAGE_RESOURCE_DIRECTORY resdir;
346 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
349 if (!basedir) return FALSE;
351 if (!(resdir = GetResDirEntryA(basedir,type,(DWORD)basedir,FALSE))) return FALSE;
353 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
355 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
358 if (et[i].u1.s.NameIsString)
360 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s.NameOffset);
361 DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
362 NULL, 0, NULL, NULL);
363 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
365 WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
366 name, len, NULL, NULL );
368 ret = lpfun(hmod,type,name,lparam);
369 HeapFree( GetProcessHeap(), 0, name );
373 name = (LPSTR)(int)et[i].u1.Id;
374 ret = lpfun(hmod,type,name,lparam);
383 /**********************************************************************
384 * EnumResourceNamesW (KERNEL32.89)
386 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
389 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
390 PIMAGE_RESOURCE_DIRECTORY resdir;
391 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
394 if (!basedir) return FALSE;
396 resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE);
399 et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
401 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
404 if (et[i].u1.s.NameIsString)
406 PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s.NameOffset);
407 if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
409 memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
410 name[pResString->Length] = '\0';
411 ret = lpfun(hmod,type,name,lparam);
412 HeapFree(GetProcessHeap(), 0, name);
416 name = (LPWSTR)(int)et[i].u1.Id;
417 ret = lpfun(hmod,type,name,lparam);
426 /**********************************************************************
427 * EnumResourceLanguagesA (KERNEL32.86)
429 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
430 ENUMRESLANGPROCA lpfun, LONG lparam )
433 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
434 PIMAGE_RESOURCE_DIRECTORY resdir;
435 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
438 if (!basedir) return FALSE;
439 if (!(resdir = GetResDirEntryA(basedir,type,(DWORD)basedir,FALSE))) return FALSE;
440 if (!(resdir = GetResDirEntryA(resdir,name,(DWORD)basedir,FALSE))) return FALSE;
442 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
444 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
445 /* languages are just ids... I hope */
446 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
454 /**********************************************************************
455 * EnumResourceLanguagesW (KERNEL32.87)
457 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
458 ENUMRESLANGPROCW lpfun, LONG lparam )
461 PIMAGE_RESOURCE_DIRECTORY basedir = get_resdir(hmod);
462 PIMAGE_RESOURCE_DIRECTORY resdir;
463 PIMAGE_RESOURCE_DIRECTORY_ENTRY et;
466 if (!basedir) return FALSE;
468 resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE);
471 resdir = GetResDirEntryW(resdir,name,(DWORD)basedir,FALSE);
474 et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
476 for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
477 ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);