kernel32: Skip the VirtualAllocEx test under Win9x.
[wine] / dlls / kernel32 / resource.c
1 /*
2  * Resources
3  *
4  * Copyright 1993 Robert J. Amstadt
5  * Copyright 1995, 2003 Alexandre Julliard
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <stdarg.h>
26
27 #define NONAMELESSUNION
28 #define NONAMELESSSTRUCT
29 #include "ntstatus.h"
30 #define WIN32_NO_STATUS
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winternl.h"
34 #include "wownt32.h"
35 #include "wine/winbase16.h"
36 #include "wine/debug.h"
37 #include "excpt.h"
38 #include "wine/exception.h"
39 #include "wine/unicode.h"
40 #include "wine/list.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(resource);
43
44 /* handle conversions */
45 #define HRSRC_32(h16)   ((HRSRC)(ULONG_PTR)(h16))
46 #define HRSRC_16(h32)   (LOWORD(h32))
47 #define HGLOBAL_32(h16) ((HGLOBAL)(ULONG_PTR)(h16))
48 #define HGLOBAL_16(h32) (LOWORD(h32))
49 #define HMODULE_16(h32) (LOWORD(h32))
50
51 /* retrieve the resource name to pass to the ntdll functions */
52 static NTSTATUS get_res_nameA( LPCSTR name, UNICODE_STRING *str )
53 {
54     if (!HIWORD(name))
55     {
56         str->Buffer = (LPWSTR)name;
57         return STATUS_SUCCESS;
58     }
59     if (name[0] == '#')
60     {
61         ULONG value;
62         if (RtlCharToInteger( name + 1, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
63             return STATUS_INVALID_PARAMETER;
64         str->Buffer = (LPWSTR)value;
65         return STATUS_SUCCESS;
66     }
67     RtlCreateUnicodeStringFromAsciiz( str, name );
68     RtlUpcaseUnicodeString( str, str, FALSE );
69     return STATUS_SUCCESS;
70 }
71
72 /* retrieve the resource name to pass to the ntdll functions */
73 static NTSTATUS get_res_nameW( LPCWSTR name, UNICODE_STRING *str )
74 {
75     if (!HIWORD(name))
76     {
77         str->Buffer = (LPWSTR)name;
78         return STATUS_SUCCESS;
79     }
80     if (name[0] == '#')
81     {
82         ULONG value;
83         RtlInitUnicodeString( str, name + 1 );
84         if (RtlUnicodeStringToInteger( str, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
85             return STATUS_INVALID_PARAMETER;
86         str->Buffer = (LPWSTR)value;
87         return STATUS_SUCCESS;
88     }
89     RtlCreateUnicodeString( str, name );
90     RtlUpcaseUnicodeString( str, str, FALSE );
91     return STATUS_SUCCESS;
92 }
93
94 /* retrieve the resource names for the 16-bit FindResource function */
95 static BOOL get_res_name_type_WtoA( LPCWSTR name, LPCWSTR type, LPSTR *nameA, LPSTR *typeA )
96 {
97     *nameA = *typeA = NULL;
98
99     __TRY
100     {
101         if (HIWORD(name))
102         {
103             DWORD len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL );
104             *nameA = HeapAlloc( GetProcessHeap(), 0, len );
105             if (*nameA) WideCharToMultiByte( CP_ACP, 0, name, -1, *nameA, len, NULL, NULL );
106         }
107         else *nameA = (LPSTR)name;
108
109         if (HIWORD(type))
110         {
111             DWORD len = WideCharToMultiByte( CP_ACP, 0, type, -1, NULL, 0, NULL, NULL );
112             *typeA = HeapAlloc( GetProcessHeap(), 0, len );
113             if (*typeA) WideCharToMultiByte( CP_ACP, 0, type, -1, *typeA, len, NULL, NULL );
114         }
115         else *typeA = (LPSTR)type;
116     }
117     __EXCEPT_PAGE_FAULT
118     {
119         if (HIWORD(*nameA)) HeapFree( GetProcessHeap(), 0, *nameA );
120         if (HIWORD(*typeA)) HeapFree( GetProcessHeap(), 0, *typeA );
121         SetLastError( ERROR_INVALID_PARAMETER );
122         return FALSE;
123     }
124     __ENDTRY
125     return TRUE;
126 }
127
128 /* implementation of FindResourceExA */
129 static HRSRC find_resourceA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
130 {
131     NTSTATUS status;
132     UNICODE_STRING nameW, typeW;
133     LDR_RESOURCE_INFO info;
134     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
135
136     __TRY
137     {
138         if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS) goto done;
139         if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS) goto done;
140         info.Type = (ULONG_PTR)typeW.Buffer;
141         info.Name = (ULONG_PTR)nameW.Buffer;
142         info.Language = lang;
143         status = LdrFindResource_U( hModule, &info, 3, &entry );
144     done:
145         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
146     }
147     __EXCEPT_PAGE_FAULT
148     {
149         SetLastError( ERROR_INVALID_PARAMETER );
150     }
151     __ENDTRY
152
153     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
154     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
155     return (HRSRC)entry;
156 }
157
158
159 /* implementation of FindResourceExW */
160 static HRSRC find_resourceW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
161 {
162     NTSTATUS status;
163     UNICODE_STRING nameW, typeW;
164     LDR_RESOURCE_INFO info;
165     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
166
167     nameW.Buffer = typeW.Buffer = NULL;
168
169     __TRY
170     {
171         if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS) goto done;
172         if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS) goto done;
173         info.Type = (ULONG_PTR)typeW.Buffer;
174         info.Name = (ULONG_PTR)nameW.Buffer;
175         info.Language = lang;
176         status = LdrFindResource_U( hModule, &info, 3, &entry );
177     done:
178         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
179     }
180     __EXCEPT_PAGE_FAULT
181     {
182         SetLastError( ERROR_INVALID_PARAMETER );
183     }
184     __ENDTRY
185
186     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
187     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
188     return (HRSRC)entry;
189 }
190
191 /**********************************************************************
192  *          FindResourceExA  (KERNEL32.@)
193  */
194 HRSRC WINAPI FindResourceExA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
195 {
196     TRACE( "%p %s %s %04x\n", hModule, debugstr_a(type), debugstr_a(name), lang );
197
198     if (!hModule) hModule = GetModuleHandleW(0);
199     else if (!HIWORD(hModule))
200     {
201         return HRSRC_32( FindResource16( HMODULE_16(hModule), name, type ) );
202     }
203     return find_resourceA( hModule, type, name, lang );
204 }
205
206
207 /**********************************************************************
208  *          FindResourceA    (KERNEL32.@)
209  */
210 HRSRC WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
211 {
212     return FindResourceExA( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
213 }
214
215
216 /**********************************************************************
217  *          FindResourceExW  (KERNEL32.@)
218  */
219 HRSRC WINAPI FindResourceExW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
220 {
221     TRACE( "%p %s %s %04x\n", hModule, debugstr_w(type), debugstr_w(name), lang );
222
223     if (!hModule) hModule = GetModuleHandleW(0);
224     else if (!HIWORD(hModule))
225     {
226         LPSTR nameA, typeA;
227         HRSRC16 ret;
228
229         if (!get_res_name_type_WtoA( name, type, &nameA, &typeA )) return NULL;
230
231         ret = FindResource16( HMODULE_16(hModule), nameA, typeA );
232         if (HIWORD(nameA)) HeapFree( GetProcessHeap(), 0, nameA );
233         if (HIWORD(typeA)) HeapFree( GetProcessHeap(), 0, typeA );
234         return HRSRC_32(ret);
235     }
236
237     return find_resourceW( hModule, type, name, lang );
238 }
239
240
241 /**********************************************************************
242  *          FindResourceW    (KERNEL32.@)
243  */
244 HRSRC WINAPI FindResourceW( HINSTANCE hModule, LPCWSTR name, LPCWSTR type )
245 {
246     return FindResourceExW( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
247 }
248
249
250 /**********************************************************************
251  *      EnumResourceTypesA      (KERNEL32.@)
252  */
253 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG_PTR lparam )
254 {
255     int i;
256     BOOL ret = FALSE;
257     LPSTR type = NULL;
258     DWORD len = 0, newlen;
259     NTSTATUS status;
260     const IMAGE_RESOURCE_DIRECTORY *resdir;
261     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
262     const IMAGE_RESOURCE_DIR_STRING_U *str;
263
264     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
265
266     if (!hmod) hmod = GetModuleHandleA( NULL );
267
268     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
269     {
270         SetLastError( RtlNtStatusToDosError(status) );
271         return FALSE;
272     }
273     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
274     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
275     {
276         if (et[i].u1.s1.NameIsString)
277         {
278             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
279             newlen = WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
280             if (newlen + 1 > len)
281             {
282                 len = newlen + 1;
283                 HeapFree( GetProcessHeap(), 0, type );
284                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
285             }
286             WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, type, len, NULL, NULL);
287             type[newlen] = 0;
288             ret = lpfun(hmod,type,lparam);
289         }
290         else
291         {
292             ret = lpfun( hmod, (LPSTR)(int)et[i].u1.s2.Id, lparam );
293         }
294         if (!ret) break;
295     }
296     HeapFree( GetProcessHeap(), 0, type );
297     return ret;
298 }
299
300
301 /**********************************************************************
302  *      EnumResourceTypesW      (KERNEL32.@)
303  */
304 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG_PTR lparam )
305 {
306     int i, len = 0;
307     BOOL ret = FALSE;
308     LPWSTR type = NULL;
309     NTSTATUS status;
310     const IMAGE_RESOURCE_DIRECTORY *resdir;
311     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
312     const IMAGE_RESOURCE_DIR_STRING_U *str;
313
314     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
315
316     if (!hmod) hmod = GetModuleHandleW( NULL );
317
318     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
319     {
320         SetLastError( RtlNtStatusToDosError(status) );
321         return FALSE;
322     }
323     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
324     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
325     {
326         if (et[i].u1.s1.NameIsString)
327         {
328             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
329             if (str->Length + 1 > len)
330             {
331                 len = str->Length + 1;
332                 HeapFree( GetProcessHeap(), 0, type );
333                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
334             }
335             memcpy(type, str->NameString, str->Length * sizeof (WCHAR));
336             type[str->Length] = 0;
337             ret = lpfun(hmod,type,lparam);
338         }
339         else
340         {
341             ret = lpfun( hmod, (LPWSTR)(int)et[i].u1.s2.Id, lparam );
342         }
343         if (!ret) break;
344     }
345     HeapFree( GetProcessHeap(), 0, type );
346     return ret;
347 }
348
349
350 /**********************************************************************
351  *      EnumResourceNamesA      (KERNEL32.@)
352  */
353 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG_PTR lparam )
354 {
355     int i;
356     BOOL ret = FALSE;
357     DWORD len = 0, newlen;
358     LPSTR name = NULL;
359     NTSTATUS status;
360     UNICODE_STRING typeW;
361     LDR_RESOURCE_INFO info;
362     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
363     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
364     const IMAGE_RESOURCE_DIR_STRING_U *str;
365
366     TRACE( "%p %s %p %lx\n", hmod, debugstr_a(type), lpfun, lparam );
367
368     if (!hmod) hmod = GetModuleHandleA( NULL );
369     typeW.Buffer = NULL;
370     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
371         goto done;
372     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
373         goto done;
374     info.Type = (ULONG)typeW.Buffer;
375     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
376         goto done;
377
378     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
379     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
380     {
381         if (et[i].u1.s1.NameIsString)
382         {
383             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
384             newlen = WideCharToMultiByte(CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
385             if (newlen + 1 > len)
386             {
387                 len = newlen + 1;
388                 HeapFree( GetProcessHeap(), 0, name );
389                 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
390                 {
391                     ret = FALSE;
392                     break;
393                 }
394             }
395             WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, name, len, NULL, NULL );
396             name[newlen] = 0;
397             ret = lpfun(hmod,type,name,lparam);
398         }
399         else
400         {
401             ret = lpfun( hmod, type, (LPSTR)(int)et[i].u1.s2.Id, lparam );
402         }
403         if (!ret) break;
404     }
405 done:
406     HeapFree( GetProcessHeap(), 0, name );
407     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
408     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
409     return ret;
410 }
411
412
413 /**********************************************************************
414  *      EnumResourceNamesW      (KERNEL32.@)
415  */
416 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG_PTR lparam )
417 {
418     int i, len = 0;
419     BOOL ret = FALSE;
420     LPWSTR name = NULL;
421     NTSTATUS status;
422     UNICODE_STRING typeW;
423     LDR_RESOURCE_INFO info;
424     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
425     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
426     const IMAGE_RESOURCE_DIR_STRING_U *str;
427
428     TRACE( "%p %s %p %lx\n", hmod, debugstr_w(type), lpfun, lparam );
429
430     if (!hmod) hmod = GetModuleHandleW( NULL );
431     typeW.Buffer = NULL;
432     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
433         goto done;
434     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
435         goto done;
436     info.Type = (ULONG)typeW.Buffer;
437     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
438         goto done;
439
440     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
441     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
442     {
443         if (et[i].u1.s1.NameIsString)
444         {
445             str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
446             if (str->Length + 1 > len)
447             {
448                 len = str->Length + 1;
449                 HeapFree( GetProcessHeap(), 0, name );
450                 if (!(name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
451                 {
452                     ret = FALSE;
453                     break;
454                 }
455             }
456             memcpy(name, str->NameString, str->Length * sizeof (WCHAR));
457             name[str->Length] = 0;
458             ret = lpfun(hmod,type,name,lparam);
459         }
460         else
461         {
462             ret = lpfun( hmod, type, (LPWSTR)(int)et[i].u1.s2.Id, lparam );
463         }
464         if (!ret) break;
465     }
466 done:
467     HeapFree( GetProcessHeap(), 0, name );
468     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
469     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
470     return ret;
471 }
472
473
474 /**********************************************************************
475  *      EnumResourceLanguagesA  (KERNEL32.@)
476  */
477 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
478                                     ENUMRESLANGPROCA lpfun, LONG_PTR lparam )
479 {
480     int i;
481     BOOL ret = FALSE;
482     NTSTATUS status;
483     UNICODE_STRING typeW, nameW;
484     LDR_RESOURCE_INFO info;
485     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
486     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
487
488     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_a(type), debugstr_a(name), lpfun, lparam );
489
490     if (!hmod) hmod = GetModuleHandleA( NULL );
491     typeW.Buffer = nameW.Buffer = NULL;
492     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
493         goto done;
494     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
495         goto done;
496     if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS)
497         goto done;
498     info.Type = (ULONG_PTR)typeW.Buffer;
499     info.Name = (ULONG_PTR)nameW.Buffer;
500     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
501         goto done;
502
503     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
504     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
505     {
506         ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
507         if (!ret) break;
508     }
509 done:
510     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
511     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
512     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
513     return ret;
514 }
515
516
517 /**********************************************************************
518  *      EnumResourceLanguagesW  (KERNEL32.@)
519  */
520 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
521                                     ENUMRESLANGPROCW lpfun, LONG_PTR lparam )
522 {
523     int i;
524     BOOL ret = FALSE;
525     NTSTATUS status;
526     UNICODE_STRING typeW, nameW;
527     LDR_RESOURCE_INFO info;
528     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
529     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
530
531     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_w(type), debugstr_w(name), lpfun, lparam );
532
533     if (!hmod) hmod = GetModuleHandleW( NULL );
534     typeW.Buffer = nameW.Buffer = NULL;
535     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
536         goto done;
537     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
538         goto done;
539     if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS)
540         goto done;
541     info.Type = (ULONG_PTR)typeW.Buffer;
542     info.Name = (ULONG_PTR)nameW.Buffer;
543     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
544         goto done;
545
546     et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
547     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
548     {
549         ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
550         if (!ret) break;
551     }
552 done:
553     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
554     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
555     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
556     return ret;
557 }
558
559
560 /**********************************************************************
561  *          LoadResource     (KERNEL32.@)
562  */
563 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
564 {
565     NTSTATUS status;
566     void *ret = NULL;
567
568     TRACE( "%p %p\n", hModule, hRsrc );
569
570     if (hModule && !HIWORD(hModule))
571         /* FIXME: should convert return to 32-bit resource */
572         return HGLOBAL_32( LoadResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) ) );
573
574     if (!hRsrc) return 0;
575     if (!hModule) hModule = GetModuleHandleA( NULL );
576     status = LdrAccessResource( hModule, (IMAGE_RESOURCE_DATA_ENTRY *)hRsrc, &ret, NULL );
577     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
578     return ret;
579 }
580
581
582 /**********************************************************************
583  *          LockResource     (KERNEL32.@)
584  */
585 LPVOID WINAPI LockResource( HGLOBAL handle )
586 {
587     TRACE("(%p)\n", handle );
588
589     if (HIWORD( handle ))  /* 32-bit memory handle */
590         return (LPVOID)handle;
591
592     /* 16-bit memory handle */
593     return LockResource16( HGLOBAL_16(handle) );
594 }
595
596
597 /**********************************************************************
598  *          FreeResource     (KERNEL32.@)
599  */
600 BOOL WINAPI FreeResource( HGLOBAL handle )
601 {
602     if (HIWORD(handle)) return 0; /* 32-bit memory handle: nothing to do */
603     return FreeResource16( HGLOBAL_16(handle) );
604 }
605
606
607 /**********************************************************************
608  *          SizeofResource   (KERNEL32.@)
609  */
610 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
611 {
612     if (hModule && !HIWORD(hModule))
613         return SizeofResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) );
614
615     if (!hRsrc) return 0;
616     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
617 }
618
619 /*
620  *  Data structure for updating resources.
621  *  Type/Name/Language is a keyset for accessing resource data.
622  *
623  *  QUEUEDUPDATES (root) ->
624  *    list of struct resouce_dir_entry    (Type) ->
625  *      list of struct resouce_dir_entry  (Name)   ->
626  *         list of struct resouce_data    Language + Data
627  */
628
629 typedef struct
630 {
631     LPWSTR pFileName;
632     struct list root;
633 } QUEUEDUPDATES;
634
635 /* this structure is shared for types and names */
636 struct resource_dir_entry {
637     struct list entry;
638     LPWSTR id;
639     struct list children;
640 };
641
642 /* this structure is the leaf */
643 struct resource_data {
644     struct list entry;
645     LANGID lang;
646     DWORD codepage;
647     DWORD cbData;
648     BYTE data[1];
649 };
650
651 int resource_strcmp( LPCWSTR a, LPCWSTR b )
652 {
653     if ( a == b )
654         return 0;
655     if (HIWORD( a ) && HIWORD( b ) )
656         return lstrcmpW( a, b );
657     /* strings come before ids */
658     if (HIWORD( a ) && !HIWORD( b ))
659         return -1;
660     if (HIWORD( b ) && !HIWORD( a ))
661         return 1;
662     return ( a < b ) ? -1 : 1;
663 }
664
665 struct resource_dir_entry *find_resource_dir_entry( struct list *dir, LPCWSTR id )
666 {
667     struct resource_dir_entry *ent;
668
669     /* match either IDs or strings */
670     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
671         if (!resource_strcmp( id, ent->id ))
672             return ent;
673
674     return NULL;
675 }
676
677 struct resource_data *find_resource_data( struct list *dir, LANGID lang )
678 {
679     struct resource_data *res_data;
680
681     /* match only languages here */
682     LIST_FOR_EACH_ENTRY( res_data, dir, struct resource_data, entry )
683         if ( lang == res_data->lang )
684              return res_data;
685
686     return NULL;
687 }
688
689 void add_resource_dir_entry( struct list *dir, struct resource_dir_entry *resdir )
690 {
691     struct resource_dir_entry *ent;
692
693     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
694     {
695         if (0>resource_strcmp( ent->id, resdir->id ))
696             continue;
697
698         list_add_before( &ent->entry, &resdir->entry );
699         return;
700     }
701     list_add_tail( dir, &resdir->entry );
702 }
703
704 void add_resource_data_entry( struct list *dir, struct resource_data *resdata )
705 {
706     struct resource_data *ent;
707
708     LIST_FOR_EACH_ENTRY( ent, dir, struct resource_data, entry )
709     {
710         if (ent->lang < resdata->lang)
711             continue;
712
713         list_add_before( &ent->entry, &resdata->entry );
714         return;
715     }
716     list_add_tail( dir, &resdata->entry );
717 }
718
719 LPWSTR res_strdupW( LPCWSTR str )
720 {
721     LPWSTR ret;
722     UINT len;
723
724     if (HIWORD(str) == 0)
725         return (LPWSTR) (UINT_PTR) LOWORD(str);
726     len = (lstrlenW( str ) + 1) * sizeof (WCHAR);
727     ret = HeapAlloc( GetProcessHeap(), 0, len );
728     memcpy( ret, str, len );
729     return ret;
730 }
731
732 void res_free_str( LPWSTR str )
733 {
734     if (HIWORD(str))
735         HeapFree( GetProcessHeap(), 0, str );
736 }
737
738 BOOL update_add_resource( QUEUEDUPDATES *updates, LPCWSTR Type, LPCWSTR Name,
739                           WORD Language, DWORD codepage, LPCVOID lpData, DWORD cbData )
740 {
741     struct resource_dir_entry *restype, *resname;
742     struct resource_data *resdata;
743
744     TRACE("%p %s %s %04x %04x %p %d bytes\n", updates, debugstr_w(Type), debugstr_w(Name), Language, codepage, lpData, cbData);
745
746     if (!lpData || !cbData)
747         return FALSE;
748
749     restype = find_resource_dir_entry( &updates->root, Type );
750     if (!restype)
751     {
752         restype = HeapAlloc( GetProcessHeap(), 0, sizeof *restype );
753         restype->id = res_strdupW( Type );
754         list_init( &restype->children );
755         add_resource_dir_entry( &updates->root, restype );
756     }
757
758     resname = find_resource_dir_entry( &restype->children, Name );
759     if (!resname)
760     {
761         resname = HeapAlloc( GetProcessHeap(), 0, sizeof *resname );
762         resname->id = res_strdupW( Name );
763         list_init( &resname->children );
764         add_resource_dir_entry( &restype->children, resname );
765     }
766
767     /*
768      * If there's an existing resource entry with matching (Type,Name,Language)
769      *  it needs to be removed before adding the new data.
770      */
771     resdata = find_resource_data( &resname->children, Language );
772     if (resdata)
773     {
774         list_remove( &resdata->entry );
775         HeapFree( GetProcessHeap(), 0, resdata );
776     }
777
778     resdata = HeapAlloc( GetProcessHeap(), 0, sizeof *resdata + cbData );
779     resdata->lang = Language;
780     resdata->codepage = codepage;
781     resdata->cbData = cbData;
782     memcpy( resdata->data, lpData, cbData );
783
784     add_resource_data_entry( &resname->children, resdata );
785
786     return TRUE;
787 }
788
789 void free_resource_directory( struct list *head, int level )
790 {
791     struct list *ptr = NULL;
792
793     while ((ptr = list_head( head )))
794     {
795         list_remove( ptr );
796         if (level)
797         {
798             struct resource_dir_entry *ent;
799
800             ent = LIST_ENTRY( ptr, struct resource_dir_entry, entry );
801             res_free_str( ent->id );
802             free_resource_directory( &ent->children, level - 1 );
803             HeapFree(GetProcessHeap(), 0, ent);
804         }
805         else
806         {
807             struct resource_data *data;
808
809             data = LIST_ENTRY( ptr, struct resource_data, entry );
810             HeapFree( GetProcessHeap(), 0, data );
811         }
812     }
813 }
814
815 IMAGE_NT_HEADERS *get_nt_header( void *base, DWORD mapping_size )
816 {
817     IMAGE_NT_HEADERS *nt;
818     IMAGE_DOS_HEADER *dos;
819
820     if (mapping_size<sizeof (*dos))
821         return NULL;
822
823     dos = base;
824     if (dos->e_magic != IMAGE_DOS_SIGNATURE)
825         return NULL;
826
827     if ((dos->e_lfanew + sizeof (*nt)) > mapping_size)
828         return NULL;
829
830     nt = (void*) ((BYTE*)base + dos->e_lfanew);
831
832     if (nt->Signature != IMAGE_NT_SIGNATURE)
833         return NULL;
834
835     return nt;
836 }
837
838 IMAGE_SECTION_HEADER *get_section_header( void *base, DWORD mapping_size, DWORD *num_sections )
839 {
840     IMAGE_NT_HEADERS *nt;
841     IMAGE_SECTION_HEADER *sec;
842     DWORD section_ofs;
843
844     nt = get_nt_header( base, mapping_size );
845     if (!nt)
846         return NULL;
847
848     /* check that we don't go over the end of the file accessing the sections */
849     section_ofs = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + nt->FileHeader.SizeOfOptionalHeader;
850     if ((nt->FileHeader.NumberOfSections * sizeof (*sec) + section_ofs) > mapping_size)
851         return NULL;
852
853     if (num_sections)
854         *num_sections = nt->FileHeader.NumberOfSections;
855
856     /* from here we have a valid PE exe to update */
857     return (void*) ((BYTE*)nt + section_ofs);
858 }
859
860 static BOOL load_raw_resources( HANDLE file, QUEUEDUPDATES *updates )
861 {
862     const IMAGE_NT_HEADERS *nt;
863     const IMAGE_SECTION_HEADER *sec;
864     BOOL ret = FALSE;
865     HANDLE mapping;
866     DWORD mapping_size, num_sections = 0;
867     void *base = NULL;
868
869     mapping_size = GetFileSize( file, NULL );
870
871     mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
872     if (!mapping)
873         goto done;
874
875     base = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, mapping_size );
876     if (!base)
877         goto done;
878
879     nt = get_nt_header( base, mapping_size );
880     if (!nt)
881         goto done;
882
883     TRACE("resources: %08x %08x\n",
884           nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
885           nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
886
887     sec = get_section_header( base, mapping_size, &num_sections );
888     if (!sec)
889         goto done;
890
891     ret = TRUE;
892
893     FIXME("not implemented\n");
894
895 done:
896     if (base)
897         UnmapViewOfFile( base );
898     if (mapping)
899         CloseHandle( mapping );
900
901     return ret;
902 }
903
904 BOOL write_raw_resources( QUEUEDUPDATES *updates )
905 {
906     FIXME("not implemented\n");
907     return FALSE;
908 }
909
910 /***********************************************************************
911  *          BeginUpdateResourceW                 (KERNEL32.@)
912  */
913 HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources )
914 {
915     QUEUEDUPDATES *updates = NULL;
916     HANDLE hUpdate, file, ret = NULL;
917
918     TRACE("%s, %d\n", debugstr_w(pFileName), bDeleteExistingResources);
919
920     hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES));
921     if (!hUpdate)
922         return ret;
923
924     updates = GlobalLock(hUpdate);
925     if (updates)
926     {
927         list_init( &updates->root );
928         updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
929         if (updates->pFileName)
930         {
931             lstrcpyW(updates->pFileName, pFileName);
932
933             file = CreateFileW( pFileName, GENERIC_READ | GENERIC_WRITE,
934                                 0, NULL, OPEN_EXISTING, 0, 0 );
935
936             /* if resources are deleted, only the file's presence is checked */
937             if (file != INVALID_HANDLE_VALUE &&
938                 (bDeleteExistingResources || load_raw_resources( file, updates )))
939                 ret = hUpdate;
940             else
941                 HeapFree( GetProcessHeap(), 0, updates->pFileName );
942
943             CloseHandle( file );
944         }
945         GlobalUnlock(hUpdate);
946     }
947
948     if (!ret)
949         GlobalFree(hUpdate);
950
951     return ret;
952 }
953
954
955 /***********************************************************************
956  *          BeginUpdateResourceA                 (KERNEL32.@)
957  */
958 HANDLE WINAPI BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources )
959 {
960     UNICODE_STRING FileNameW;
961     HANDLE ret;
962     RtlCreateUnicodeStringFromAsciiz(&FileNameW, pFileName);
963     ret = BeginUpdateResourceW(FileNameW.Buffer, bDeleteExistingResources);
964     RtlFreeUnicodeString(&FileNameW);
965     return ret;
966 }
967
968
969 /***********************************************************************
970  *          EndUpdateResourceW                 (KERNEL32.@)
971  */
972 BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
973 {
974     QUEUEDUPDATES *updates;
975     BOOL ret;
976
977     TRACE("%p %d\n", hUpdate, fDiscard);
978
979     updates = GlobalLock(hUpdate);
980     if (!updates)
981         return FALSE;
982
983     ret = fDiscard || write_raw_resources( updates );
984
985     free_resource_directory( &updates->root, 2 );
986
987     HeapFree( GetProcessHeap(), 0, updates->pFileName );
988     GlobalUnlock( hUpdate );
989     GlobalFree( hUpdate );
990
991     return ret;
992 }
993
994
995 /***********************************************************************
996  *          EndUpdateResourceA                 (KERNEL32.@)
997  */
998 BOOL WINAPI EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard )
999 {
1000     return EndUpdateResourceW(hUpdate, fDiscard);
1001 }
1002
1003
1004 /***********************************************************************
1005  *           UpdateResourceW                 (KERNEL32.@)
1006  */
1007 BOOL WINAPI UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
1008                              WORD wLanguage, LPVOID lpData, DWORD cbData)
1009 {
1010     QUEUEDUPDATES *updates;
1011     BOOL ret = FALSE;
1012
1013     TRACE("%p %s %s %08x %p %d\n", hUpdate,
1014           debugstr_w(lpType), debugstr_w(lpName), wLanguage, lpData, cbData);
1015
1016     updates = GlobalLock(hUpdate);
1017     if (updates)
1018     {
1019         ret = update_add_resource( updates, lpType, lpName,
1020                                    wLanguage, GetACP(), lpData, cbData );
1021         GlobalUnlock(hUpdate);
1022     }
1023     return ret;
1024 }
1025
1026
1027 /***********************************************************************
1028  *           UpdateResourceA                 (KERNEL32.@)
1029  */
1030 BOOL WINAPI UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
1031                              WORD wLanguage, LPVOID lpData, DWORD cbData)
1032 {
1033     BOOL ret;
1034     UNICODE_STRING TypeW;
1035     UNICODE_STRING NameW;
1036     if(!HIWORD(lpType))
1037         TypeW.Buffer = (LPWSTR)lpType;
1038     else
1039         RtlCreateUnicodeStringFromAsciiz(&TypeW, lpType);
1040     if(!HIWORD(lpName))
1041         NameW.Buffer = (LPWSTR)lpName;
1042     else
1043         RtlCreateUnicodeStringFromAsciiz(&NameW, lpName);
1044     ret = UpdateResourceW(hUpdate, TypeW.Buffer, NameW.Buffer, wLanguage, lpData, cbData);
1045     if(HIWORD(lpType)) RtlFreeUnicodeString(&TypeW);
1046     if(HIWORD(lpName)) RtlFreeUnicodeString(&NameW);
1047     return ret;
1048 }