Fixed loader - broken search for already loaded modules.
[wine] / loader / pe_resource.c
1 /*
2  * PE (Portable Execute) File Resources
3  *
4  * Copyright 1995 Thomas Sandford
5  * Copyright 1996 Martin von Loewis
6  *
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
11  */
12
13 #include <stdlib.h>
14 #include <sys/types.h>
15 #include "wine/winestring.h"
16 #include "wine/unicode.h"
17 #include "windef.h"
18 #include "winnls.h"
19 #include "module.h"
20 #include "heap.h"
21 #include "task.h"
22 #include "process.h"
23 #include "stackframe.h"
24 #include "neexe.h"
25 #include "debugtools.h"
26
27 /**********************************************************************
28  *  get_resdir
29  *
30  * Get the resource directory of a PE module
31  */
32 static IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
33 {
34     IMAGE_DATA_DIRECTORY *dir;
35     IMAGE_RESOURCE_DIRECTORY *ret = NULL;
36
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);
41     return ret;
42 }
43
44
45 /**********************************************************************
46  *          GetResDirEntryW
47  *
48  *      Helper function - goes down one level of PE resource tree
49  *
50  */
51 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr,
52                                            LPCWSTR name,DWORD root,
53                                            BOOL allowdefault)
54 {
55     int entrynum;
56     PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable;
57     int namelen;
58
59     if (HIWORD(name)) {
60         if (name[0]=='#') {
61                 char    buf[10];
62                 if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
63                     return NULL;
64                 return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault);
65         }
66         entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdirptr + 1);
67         namelen = strlenW(name);
68         for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++)
69         {
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)
74                         continue;
75                 if(strncmpiW(name,str->NameString,str->Length)==0)
76                         return (PIMAGE_RESOURCE_DIRECTORY) (
77                                 root +
78                                 entryTable[entrynum].u2.s.OffsetToDirectory);
79         }
80         return NULL;
81     } else {
82         entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
83                         (BYTE *) resdirptr + 
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) (
89                         root +
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) (
94                         root +
95                         entryTable[0].u2.s.OffsetToDirectory);
96         return NULL;
97     }
98 }
99
100 /**********************************************************************
101  *          GetResDirEntryA
102  */
103 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr,
104                                            LPCSTR name, DWORD root,
105                                            BOOL allowdefault )
106 {
107     PIMAGE_RESOURCE_DIRECTORY retv;
108     LPWSTR nameW = HIWORD(name)? HEAP_strdupAtoW( GetProcessHeap(), 0, name ) 
109                                : (LPWSTR)name;
110
111     retv = GetResDirEntryW( resdirptr, nameW, root, allowdefault );
112
113     if ( HIWORD(name) ) HeapFree( GetProcessHeap(), 0, nameW );
114
115     return retv;
116 }
117
118 /**********************************************************************
119  *          PE_FindResourceExW
120  *
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
126  */
127 HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
128 {
129     PIMAGE_RESOURCE_DIRECTORY resdirptr = get_resdir(hmod);
130     DWORD root;
131     HRSRC result;
132
133     if (!resdirptr) return 0;
134
135     root = (DWORD) resdirptr;
136     if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
137         return 0;
138     if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
139         return 0;
140
141     /* 1. Exact specified language */
142     result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
143
144     if (!result)
145     {
146         /* 2. Language with neutral sublanguage */
147         lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
148         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
149     }
150
151     if (!result)
152     {
153         /* 3. Neutral language with neutral sublanguage */
154         lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
155         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
156     }
157
158     if (!result)
159     {
160         /* 4. Neutral language with default sublanguage */
161         lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
162         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
163     }
164
165     return result;
166 }
167
168 /**********************************************************************
169  *          PE_FindResourceW
170  *
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
179  */
180 HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
181 {
182     PIMAGE_RESOURCE_DIRECTORY resdirptr = get_resdir(hmod);
183     DWORD root;
184     HRSRC result;
185     WORD lang;
186
187     if (!resdirptr) return 0;
188
189     root = (DWORD) resdirptr;
190     if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
191         return 0;
192     if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
193         return 0;
194
195     /* 1. Neutral language with neutral sublanguage */
196     lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
197     result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
198
199     if (!result)
200     {
201         /* 2. Neutral language with default sublanguage */
202         lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
203         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
204     }
205
206     if (!result)
207     {
208         /* 3. Current locale lang id */
209         lang = LANGIDFROMLCID(GetUserDefaultLCID());
210         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
211     }
212
213     if (!result)
214     {
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);
218     }
219
220     if (!result)
221     {
222         /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
223         lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
224         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
225     }
226
227     if (!result)
228     {
229         /* 6. Return first in the list */
230         result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)0, root, TRUE);
231     }
232
233     return result;
234 }
235
236
237 /**********************************************************************
238  *          PE_LoadResource
239  */
240 HANDLE PE_LoadResource( HMODULE hmod, HANDLE hRsrc )
241 {
242     if (!hRsrc) return 0;
243     return (HANDLE)(hmod + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
244 }
245
246
247 /**********************************************************************
248  *          PE_SizeofResource
249  */
250 DWORD PE_SizeofResource( HANDLE hRsrc )
251 {
252     if (!hRsrc) return 0;
253     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
254 }
255
256
257 /**********************************************************************
258  *      EnumResourceTypesA      (KERNEL32.90)
259  */
260 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
261 {
262     int         i;
263     PIMAGE_RESOURCE_DIRECTORY resdir = get_resdir(hmod);
264     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
265     BOOL        ret;
266
267     if (!resdir) return FALSE;
268
269     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
270     ret = FALSE;
271     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
272         LPSTR type;
273
274         if (et[i].u1.s.NameIsString)
275         {
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)))
280                 return FALSE;
281             WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
282                                  type, len, NULL, NULL);
283             type[len] = '\0';
284             ret = lpfun(hmod,type,lparam);
285             HeapFree(GetProcessHeap(), 0, type);
286         }
287         else
288         {
289             type = (LPSTR)(int)et[i].u1.Id;
290             ret = lpfun(hmod,type,lparam);
291         }
292         if (!ret)
293                 break;
294     }
295     return ret;
296 }
297
298
299 /**********************************************************************
300  *      EnumResourceTypesW      (KERNEL32.91)
301  */
302 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
303 {
304     int         i;
305     PIMAGE_RESOURCE_DIRECTORY           resdir = get_resdir(hmod);
306     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
307     BOOL        ret;
308
309     if (!resdir) return FALSE;
310
311     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
312     ret = FALSE;
313     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
314         LPWSTR  type;
315
316         if (et[i].u1.s.NameIsString)
317         {
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))))
320                 return FALSE;
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);
325         }
326         else
327         {
328             type = (LPWSTR)(int)et[i].u1.Id;
329             ret = lpfun(hmod,type,lparam);
330         }
331         if (!ret)
332                 break;
333     }
334     return ret;
335 }
336
337
338 /**********************************************************************
339  *      EnumResourceNamesA      (KERNEL32.88)
340  */
341 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
342 {
343     int         i;
344     PIMAGE_RESOURCE_DIRECTORY           basedir = get_resdir(hmod);
345     PIMAGE_RESOURCE_DIRECTORY           resdir;
346     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
347     BOOL        ret;
348
349     if (!basedir) return FALSE;
350
351     if (!(resdir = GetResDirEntryA(basedir,type,(DWORD)basedir,FALSE))) return FALSE;
352
353     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
354     ret = FALSE;
355     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
356         LPSTR name;
357
358         if (et[i].u1.s.NameIsString)
359         {
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 )))
364                 return FALSE;
365             WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
366                                  name, len, NULL, NULL );
367             name[len] = '\0';
368             ret = lpfun(hmod,type,name,lparam);
369             HeapFree( GetProcessHeap(), 0, name );
370         }
371         else
372         {
373             name = (LPSTR)(int)et[i].u1.Id;
374             ret = lpfun(hmod,type,name,lparam);
375         }
376         if (!ret)
377                 break;
378     }
379     return ret;
380 }
381
382
383 /**********************************************************************
384  *      EnumResourceNamesW      (KERNEL32.89)
385  */
386 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
387 {
388     int         i;
389     PIMAGE_RESOURCE_DIRECTORY           basedir = get_resdir(hmod);
390     PIMAGE_RESOURCE_DIRECTORY           resdir;
391     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
392     BOOL        ret;
393
394     if (!basedir) return FALSE;
395
396     resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE);
397     if (!resdir)
398         return FALSE;
399     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
400     ret = FALSE;
401     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
402         LPWSTR name;
403
404         if (et[i].u1.s.NameIsString)
405         {
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))))
408                 return FALSE;
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);
413         }
414         else
415         {
416             name = (LPWSTR)(int)et[i].u1.Id;
417             ret = lpfun(hmod,type,name,lparam);
418         }
419         if (!ret)
420                 break;
421     }
422     return ret;
423 }
424
425
426 /**********************************************************************
427  *      EnumResourceLanguagesA  (KERNEL32.86)
428  */
429 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
430                                     ENUMRESLANGPROCA lpfun, LONG lparam )
431 {
432     int         i;
433     PIMAGE_RESOURCE_DIRECTORY           basedir = get_resdir(hmod);
434     PIMAGE_RESOURCE_DIRECTORY           resdir;
435     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
436     BOOL        ret;
437
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;
441
442     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
443     ret = FALSE;
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);
447         if (!ret)
448                 break;
449     }
450     return ret;
451 }
452
453
454 /**********************************************************************
455  *      EnumResourceLanguagesW  (KERNEL32.87)
456  */
457 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
458                                     ENUMRESLANGPROCW lpfun, LONG lparam )
459 {
460     int         i;
461     PIMAGE_RESOURCE_DIRECTORY           basedir = get_resdir(hmod);
462     PIMAGE_RESOURCE_DIRECTORY           resdir;
463     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
464     BOOL        ret;
465
466     if (!basedir) return FALSE;
467
468     resdir = GetResDirEntryW(basedir,type,(DWORD)basedir,FALSE);
469     if (!resdir)
470         return FALSE;
471     resdir = GetResDirEntryW(resdir,name,(DWORD)basedir,FALSE);
472     if (!resdir)
473         return FALSE;
474     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
475     ret = FALSE;
476     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
477         ret = lpfun(hmod,type,name,et[i].u1.Id,lparam);
478         if (!ret)
479                 break;
480     }
481     return ret;
482 }