Built-in dlls now have resources attached via the PE-header like
[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 "windef.h"
17 #include "pe_image.h"
18 #include "module.h"
19 #include "heap.h"
20 #include "task.h"
21 #include "process.h"
22 #include "libres.h"
23 #include "stackframe.h"
24 #include "neexe.h"
25 #include "debug.h"
26
27 /**********************************************************************
28  *  HMODULE32toPE_MODREF 
29  *
30  * small helper function to get a PE_MODREF from a passed HMODULE32
31  */
32 static PE_MODREF*
33 HMODULE32toPE_MODREF(HMODULE hmod) {
34         WINE_MODREF     *wm;
35
36         wm = MODULE32_LookupHMODULE( hmod );
37         if (!wm || wm->type!=MODULE32_PE)
38                 return NULL;
39         return &(wm->binfmt.pe);
40 }
41
42 /**********************************************************************
43  *          GetResDirEntryW
44  *
45  *      Helper function - goes down one level of PE resource tree
46  *
47  */
48 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr,
49                                            LPCWSTR name,DWORD root,
50                                            BOOL allowdefault)
51 {
52     int entrynum;
53     PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable;
54     int namelen;
55
56     if (HIWORD(name)) {
57         if (name[0]=='#') {
58                 char    buf[10];
59
60                 lstrcpynWtoA(buf,name+1,10);
61                 return GetResDirEntryW(resdirptr,(LPCWSTR)atoi(buf),root,allowdefault);
62         }
63         entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
64                         (BYTE *) resdirptr + 
65                         sizeof(IMAGE_RESOURCE_DIRECTORY));
66         namelen = lstrlenW(name);
67         for (entrynum = 0; entrynum < resdirptr->NumberOfNamedEntries; entrynum++)
68         {
69                 PIMAGE_RESOURCE_DIR_STRING_U str =
70                 (PIMAGE_RESOURCE_DIR_STRING_U) (root + 
71                         entryTable[entrynum].u1.s.NameOffset);
72                 if(namelen != str->Length)
73                         continue;
74                 if(lstrncmpiW(name,str->NameString,str->Length)==0)
75                         return (PIMAGE_RESOURCE_DIRECTORY) (
76                                 root +
77                                 entryTable[entrynum].u2.s.OffsetToDirectory);
78         }
79         return NULL;
80     } else {
81         entryTable = (PIMAGE_RESOURCE_DIRECTORY_ENTRY) (
82                         (BYTE *) resdirptr + 
83                         sizeof(IMAGE_RESOURCE_DIRECTORY) +
84                         resdirptr->NumberOfNamedEntries * sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY));
85         for (entrynum = 0; entrynum < resdirptr->NumberOfIdEntries; entrynum++)
86             if ((DWORD)entryTable[entrynum].u1.Name == (DWORD)name)
87                 return (PIMAGE_RESOURCE_DIRECTORY) (
88                         root +
89                         entryTable[entrynum].u2.s.OffsetToDirectory);
90         /* just use first entry if no default can be found */
91         if (allowdefault && !name && resdirptr->NumberOfIdEntries)
92                 return (PIMAGE_RESOURCE_DIRECTORY) (
93                         root +
94                         entryTable[0].u2.s.OffsetToDirectory);
95         return NULL;
96     }
97 }
98
99 /**********************************************************************
100  *          GetResDirEntryA
101  */
102 PIMAGE_RESOURCE_DIRECTORY GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr,
103                                            LPCSTR name, DWORD root,
104                                            BOOL allowdefault )
105 {
106     PIMAGE_RESOURCE_DIRECTORY retv;
107     LPWSTR nameW = HIWORD(name)? HEAP_strdupAtoW( GetProcessHeap(), 0, name ) 
108                                : (LPWSTR)name;
109
110     retv = GetResDirEntryW( resdirptr, nameW, root, allowdefault );
111
112     if ( HIWORD(name) ) HeapFree( GetProcessHeap(), 0, nameW );
113
114     return retv;
115 }
116
117 /**********************************************************************
118  *          PE_FindResourceEx32W
119  */
120 HANDLE PE_FindResourceExW(
121         WINE_MODREF *wm,LPCWSTR name,LPCWSTR type,WORD lang
122 ) {
123     PIMAGE_RESOURCE_DIRECTORY resdirptr;
124     DWORD root;
125     HANDLE result;
126     PE_MODREF   *pem = &(wm->binfmt.pe);
127
128     if (!pem || !pem->pe_resource)
129         return 0;
130
131     resdirptr = pem->pe_resource;
132     root = (DWORD) resdirptr;
133     if ((resdirptr = GetResDirEntryW(resdirptr, type, root, FALSE)) == NULL)
134         return 0;
135     if ((resdirptr = GetResDirEntryW(resdirptr, name, root, FALSE)) == NULL)
136         return 0;
137     result = (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)(UINT)lang, root, FALSE);
138         /* Try LANG_NEUTRAL, too */
139     if(!result)
140         return (HANDLE)GetResDirEntryW(resdirptr, (LPCWSTR)0, root, TRUE);
141     return result;
142 }
143
144
145 /**********************************************************************
146  *          PE_LoadResource32
147  */
148 HANDLE PE_LoadResource( WINE_MODREF *wm, HANDLE hRsrc )
149 {
150     if (!hRsrc || !wm || wm->type!=MODULE32_PE)
151         return 0;
152     return (HANDLE) (wm->module + ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData);
153 }
154
155
156 /**********************************************************************
157  *          PE_SizeofResource32
158  */
159 DWORD PE_SizeofResource( HINSTANCE hModule, HANDLE hRsrc )
160 {
161     /* we don't need hModule */
162     if (!hRsrc)
163          return 0;
164     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
165 }
166
167 /**********************************************************************
168  *          PE_EnumResourceTypes32A
169  */
170 BOOL
171 PE_EnumResourceTypesA(HMODULE hmod,ENUMRESTYPEPROCA lpfun,LONG lparam) {
172     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
173     int         i;
174     PIMAGE_RESOURCE_DIRECTORY           resdir;
175     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
176     BOOL        ret;
177     HANDLE      heap = GetProcessHeap();        
178
179     if (!pem || !pem->pe_resource)
180         return FALSE;
181
182     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
183     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
184     ret = FALSE;
185     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
186         LPSTR   name;
187
188         if (HIWORD(et[i].u1.Name))
189                 name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.Name));
190         else
191                 name = (LPSTR)et[i].u1.Name;
192         ret = lpfun(hmod,name,lparam);
193         if (HIWORD(name))
194                 HeapFree(heap,0,name);
195         if (!ret)
196                 break;
197     }
198     return ret;
199 }
200
201 /**********************************************************************
202  *          PE_EnumResourceTypes32W
203  */
204 BOOL
205 PE_EnumResourceTypesW(HMODULE hmod,ENUMRESTYPEPROCW lpfun,LONG lparam) {
206     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
207     int         i;
208     PIMAGE_RESOURCE_DIRECTORY           resdir;
209     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
210     BOOL        ret;
211
212     if (!pem || !pem->pe_resource)
213         return FALSE;
214
215     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
216     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
217     ret = FALSE;
218     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
219         LPWSTR  type;
220         if (HIWORD(et[i].u1.Name))
221                 type = (LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.Name);
222         else
223                 type = (LPWSTR)et[i].u1.Name;
224
225         ret = lpfun(hmod,type,lparam);
226         if (!ret)
227                 break;
228     }
229     return ret;
230 }
231
232 /**********************************************************************
233  *          PE_EnumResourceNames32A
234  */
235 BOOL
236 PE_EnumResourceNamesA(
237         HMODULE hmod,LPCSTR type,ENUMRESNAMEPROCA lpfun,LONG lparam
238 ) {
239     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
240     int         i;
241     PIMAGE_RESOURCE_DIRECTORY           resdir;
242     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
243     BOOL        ret;
244     HANDLE      heap = GetProcessHeap();        
245     LPWSTR      typeW;
246
247     if (!pem || !pem->pe_resource)
248         return FALSE;
249     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
250     if (HIWORD(type))
251         typeW = HEAP_strdupAtoW(heap,0,type);
252     else
253         typeW = (LPWSTR)type;
254     resdir = GetResDirEntryW(resdir,typeW,(DWORD)pem->pe_resource,FALSE);
255     if (HIWORD(typeW))
256         HeapFree(heap,0,typeW);
257     if (!resdir)
258         return FALSE;
259     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
260     ret = FALSE;
261     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
262         LPSTR   name;
263
264         if (HIWORD(et[i].u1.Name))
265             name = HEAP_strdupWtoA(heap,0,(LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.Name));
266         else
267             name = (LPSTR)et[i].u1.Name;
268         ret = lpfun(hmod,type,name,lparam);
269         if (HIWORD(name)) HeapFree(heap,0,name);
270         if (!ret)
271                 break;
272     }
273     return ret;
274 }
275
276 /**********************************************************************
277  *          PE_EnumResourceNames32W
278  */
279 BOOL
280 PE_EnumResourceNamesW(
281         HMODULE hmod,LPCWSTR type,ENUMRESNAMEPROCW lpfun,LONG lparam
282 ) {
283     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
284     int         i;
285     PIMAGE_RESOURCE_DIRECTORY           resdir;
286     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
287     BOOL        ret;
288
289     if (!pem || !pem->pe_resource)
290         return FALSE;
291
292     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
293     resdir = GetResDirEntryW(resdir,type,(DWORD)pem->pe_resource,FALSE);
294     if (!resdir)
295         return FALSE;
296     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
297     ret = FALSE;
298     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
299         LPWSTR  name;
300         if (HIWORD(et[i].u1.Name))
301                 name = (LPWSTR)((LPBYTE)pem->pe_resource+et[i].u1.Name);
302         else
303                 name = (LPWSTR)et[i].u1.Name;
304         ret = lpfun(hmod,type,name,lparam);
305         if (!ret)
306                 break;
307     }
308     return ret;
309 }
310
311 /**********************************************************************
312  *          PE_EnumResourceNames32A
313  */
314 BOOL
315 PE_EnumResourceLanguagesA(
316         HMODULE hmod,LPCSTR name,LPCSTR type,ENUMRESLANGPROCA lpfun,
317         LONG lparam
318 ) {
319     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
320     int         i;
321     PIMAGE_RESOURCE_DIRECTORY           resdir;
322     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
323     BOOL        ret;
324     HANDLE      heap = GetProcessHeap();        
325     LPWSTR      nameW,typeW;
326
327     if (!pem || !pem->pe_resource)
328         return FALSE;
329
330     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
331     if (HIWORD(name))
332         nameW = HEAP_strdupAtoW(heap,0,name);
333     else
334         nameW = (LPWSTR)name;
335     resdir = GetResDirEntryW(resdir,nameW,(DWORD)pem->pe_resource,FALSE);
336     if (HIWORD(nameW))
337         HeapFree(heap,0,nameW);
338     if (!resdir)
339         return FALSE;
340     if (HIWORD(type))
341         typeW = HEAP_strdupAtoW(heap,0,type);
342     else
343         typeW = (LPWSTR)type;
344     resdir = GetResDirEntryW(resdir,typeW,(DWORD)pem->pe_resource,FALSE);
345     if (HIWORD(typeW))
346         HeapFree(heap,0,typeW);
347     if (!resdir)
348         return FALSE;
349     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
350     ret = FALSE;
351     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
352         /* languages are just ids... I hopem */
353         ret = lpfun(hmod,name,type,et[i].u1.Id,lparam);
354         if (!ret)
355                 break;
356     }
357     return ret;
358 }
359
360 /**********************************************************************
361  *          PE_EnumResourceLanguages32W
362  */
363 BOOL
364 PE_EnumResourceLanguagesW(
365         HMODULE hmod,LPCWSTR name,LPCWSTR type,ENUMRESLANGPROCW lpfun,
366         LONG lparam
367 ) {
368     PE_MODREF   *pem = HMODULE32toPE_MODREF(hmod);
369     int         i;
370     PIMAGE_RESOURCE_DIRECTORY           resdir;
371     PIMAGE_RESOURCE_DIRECTORY_ENTRY     et;
372     BOOL        ret;
373
374     if (!pem || !pem->pe_resource)
375         return FALSE;
376
377     resdir = (PIMAGE_RESOURCE_DIRECTORY)pem->pe_resource;
378     resdir = GetResDirEntryW(resdir,name,(DWORD)pem->pe_resource,FALSE);
379     if (!resdir)
380         return FALSE;
381     resdir = GetResDirEntryW(resdir,type,(DWORD)pem->pe_resource,FALSE);
382     if (!resdir)
383         return FALSE;
384     et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)((LPBYTE)resdir+sizeof(IMAGE_RESOURCE_DIRECTORY));
385     ret = FALSE;
386     for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
387         ret = lpfun(hmod,name,type,et[i].u1.Id,lparam);
388         if (!ret)
389                 break;
390     }
391     return ret;
392 }