Better handling of 16-bit native dlls when a 32-bit builtin with the
[wine] / dlls / kernel / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 #include "windef.h"
31 #include "winbase.h"
32 #include "winreg.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 static WINE_EXCEPTION_FILTER(page_fault)
52 {
53     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
54         GetExceptionCode() == EXCEPTION_PRIV_INSTRUCTION)
55         return EXCEPTION_EXECUTE_HANDLER;
56     return EXCEPTION_CONTINUE_SEARCH;
57 }
58
59 /* retrieve the resource name to pass to the ntdll functions */
60 static NTSTATUS get_res_nameA( LPCSTR name, UNICODE_STRING *str )
61 {
62     if (!HIWORD(name))
63     {
64         str->Buffer = (LPWSTR)name;
65         return STATUS_SUCCESS;
66     }
67     if (name[0] == '#')
68     {
69         ULONG value;
70         if (RtlCharToInteger( name + 1, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
71             return STATUS_INVALID_PARAMETER;
72         str->Buffer = (LPWSTR)value;
73         return STATUS_SUCCESS;
74     }
75     RtlCreateUnicodeStringFromAsciiz( str, name );
76     RtlUpcaseUnicodeString( str, str, FALSE );
77     return STATUS_SUCCESS;
78 }
79
80 /* retrieve the resource name to pass to the ntdll functions */
81 static NTSTATUS get_res_nameW( LPCWSTR name, UNICODE_STRING *str )
82 {
83     if (!HIWORD(name))
84     {
85         str->Buffer = (LPWSTR)name;
86         return STATUS_SUCCESS;
87     }
88     if (name[0] == '#')
89     {
90         ULONG value;
91         RtlInitUnicodeString( str, name + 1 );
92         if (RtlUnicodeStringToInteger( str, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
93             return STATUS_INVALID_PARAMETER;
94         str->Buffer = (LPWSTR)value;
95         return STATUS_SUCCESS;
96     }
97     RtlCreateUnicodeString( str, name );
98     RtlUpcaseUnicodeString( str, str, FALSE );
99     return STATUS_SUCCESS;
100 }
101
102 /* retrieve the resource names for the 16-bit FindResource function */
103 static BOOL get_res_name_type_WtoA( LPCWSTR name, LPCWSTR type, LPSTR *nameA, LPSTR *typeA )
104 {
105     *nameA = *typeA = NULL;
106
107     __TRY
108     {
109         if (HIWORD(name))
110         {
111             DWORD len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL );
112             *nameA = HeapAlloc( GetProcessHeap(), 0, len );
113             if (*nameA) WideCharToMultiByte( CP_ACP, 0, name, -1, *nameA, len, NULL, NULL );
114         }
115         else *nameA = (LPSTR)name;
116
117         if (HIWORD(type))
118         {
119             DWORD len = WideCharToMultiByte( CP_ACP, 0, type, -1, NULL, 0, NULL, NULL );
120             *typeA = HeapAlloc( GetProcessHeap(), 0, len );
121             if (*typeA) WideCharToMultiByte( CP_ACP, 0, type, -1, *typeA, len, NULL, NULL );
122         }
123         else *typeA = (LPSTR)type;
124     }
125     __EXCEPT(page_fault)
126     {
127         if (HIWORD(*nameA)) HeapFree( GetProcessHeap(), 0, *nameA );
128         if (HIWORD(*typeA)) HeapFree( GetProcessHeap(), 0, *typeA );
129         SetLastError( ERROR_INVALID_PARAMETER );
130         return FALSE;
131     }
132     __ENDTRY
133     return TRUE;
134 }
135
136 /* implementation of FindResourceExA */
137 static HRSRC find_resourceA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
138 {
139     NTSTATUS status;
140     UNICODE_STRING nameW, typeW;
141     LDR_RESOURCE_INFO info;
142     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
143
144     __TRY
145     {
146         if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS) goto done;
147         if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS) goto done;
148         info.Type = (ULONG)typeW.Buffer;
149         info.Name = (ULONG)nameW.Buffer;
150         info.Language = lang;
151         status = LdrFindResource_U( hModule, &info, 3, &entry );
152     done:
153         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
154     }
155     __EXCEPT(page_fault)
156     {
157         SetLastError( ERROR_INVALID_PARAMETER );
158     }
159     __ENDTRY
160
161     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
162     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
163     return (HRSRC)entry;
164 }
165
166
167 /* implementation of FindResourceExW */
168 static HRSRC find_resourceW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
169 {
170     NTSTATUS status;
171     UNICODE_STRING nameW, typeW;
172     LDR_RESOURCE_INFO info;
173     const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
174
175     nameW.Buffer = typeW.Buffer = NULL;
176
177     __TRY
178     {
179         if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS) goto done;
180         if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS) goto done;
181         info.Type = (ULONG)typeW.Buffer;
182         info.Name = (ULONG)nameW.Buffer;
183         info.Language = lang;
184         status = LdrFindResource_U( hModule, &info, 3, &entry );
185     done:
186         if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
187     }
188     __EXCEPT(page_fault)
189     {
190         SetLastError( ERROR_INVALID_PARAMETER );
191     }
192     __ENDTRY
193
194     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
195     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
196     return (HRSRC)entry;
197 }
198
199 /**********************************************************************
200  *          FindResourceExA  (KERNEL32.@)
201  */
202 HRSRC WINAPI FindResourceExA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
203 {
204     TRACE( "%p %s %s %04x\n", hModule, debugstr_a(type), debugstr_a(name), lang );
205
206     if (!hModule) hModule = GetModuleHandleW(0);
207     else if (!HIWORD(hModule))
208     {
209         return HRSRC_32( FindResource16( HMODULE_16(hModule), name, type ) );
210     }
211     return find_resourceA( hModule, type, name, lang );
212 }
213
214
215 /**********************************************************************
216  *          FindResourceA    (KERNEL32.@)
217  */
218 HRSRC WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
219 {
220     return FindResourceExA( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
221 }
222
223
224 /**********************************************************************
225  *          FindResourceExW  (KERNEL32.@)
226  */
227 HRSRC WINAPI FindResourceExW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
228 {
229     TRACE( "%p %s %s %04x\n", hModule, debugstr_w(type), debugstr_w(name), lang );
230
231     if (!hModule) hModule = GetModuleHandleW(0);
232     else if (!HIWORD(hModule))
233     {
234         LPSTR nameA, typeA;
235         HRSRC16 ret;
236
237         if (!get_res_name_type_WtoA( name, type, &nameA, &typeA )) return NULL;
238
239         ret = FindResource16( HMODULE_16(hModule), nameA, typeA );
240         if (HIWORD(nameA)) HeapFree( GetProcessHeap(), 0, nameA );
241         if (HIWORD(typeA)) HeapFree( GetProcessHeap(), 0, typeA );
242         return HRSRC_32(ret);
243     }
244
245     return find_resourceW( hModule, type, name, lang );
246 }
247
248
249 /**********************************************************************
250  *          FindResourceW    (KERNEL32.@)
251  */
252 HRSRC WINAPI FindResourceW( HINSTANCE hModule, LPCWSTR name, LPCWSTR type )
253 {
254     return FindResourceExW( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
255 }
256
257
258 /**********************************************************************
259  *      EnumResourceTypesA      (KERNEL32.@)
260  */
261 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG_PTR lparam )
262 {
263     int i;
264     BOOL ret = FALSE;
265     LPSTR type = NULL;
266     DWORD len = 0, newlen;
267     NTSTATUS status;
268     const IMAGE_RESOURCE_DIRECTORY *resdir;
269     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
270     const IMAGE_RESOURCE_DIR_STRING_U *str;
271
272     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
273
274     if (!hmod) hmod = GetModuleHandleA( NULL );
275
276     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
277     {
278         SetLastError( RtlNtStatusToDosError(status) );
279         return FALSE;
280     }
281     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
282     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
283     {
284         if (et[i].u1.s1.NameIsString)
285         {
286             str = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
287             newlen = WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
288             if (newlen + 1 > len)
289             {
290                 len = newlen + 1;
291                 HeapFree( GetProcessHeap(), 0, type );
292                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
293             }
294             WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, type, len, NULL, NULL);
295             type[newlen] = 0;
296             ret = lpfun(hmod,type,lparam);
297         }
298         else
299         {
300             ret = lpfun( hmod, (LPSTR)(int)et[i].u1.s2.Id, lparam );
301         }
302         if (!ret) break;
303     }
304     HeapFree( GetProcessHeap(), 0, type );
305     return ret;
306 }
307
308
309 /**********************************************************************
310  *      EnumResourceTypesW      (KERNEL32.@)
311  */
312 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG_PTR lparam )
313 {
314     int i, len = 0;
315     BOOL ret = FALSE;
316     LPWSTR type = NULL;
317     NTSTATUS status;
318     const IMAGE_RESOURCE_DIRECTORY *resdir;
319     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
320     const IMAGE_RESOURCE_DIR_STRING_U *str;
321
322     TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
323
324     if (!hmod) hmod = GetModuleHandleW( NULL );
325
326     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
327     {
328         SetLastError( RtlNtStatusToDosError(status) );
329         return FALSE;
330     }
331     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
332     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
333     {
334         if (et[i].u1.s1.NameIsString)
335         {
336             str = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
337             if (str->Length + 1 > len)
338             {
339                 len = str->Length + 1;
340                 HeapFree( GetProcessHeap(), 0, type );
341                 if (!(type = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
342             }
343             memcpy(type, str->NameString, str->Length * sizeof (WCHAR));
344             type[str->Length] = 0;
345             ret = lpfun(hmod,type,lparam);
346         }
347         else
348         {
349             ret = lpfun( hmod, (LPWSTR)(int)et[i].u1.s2.Id, lparam );
350         }
351         if (!ret) break;
352     }
353     HeapFree( GetProcessHeap(), 0, type );
354     return ret;
355 }
356
357
358 /**********************************************************************
359  *      EnumResourceNamesA      (KERNEL32.@)
360  */
361 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG_PTR lparam )
362 {
363     int i;
364     BOOL ret = FALSE;
365     DWORD len = 0, newlen;
366     LPSTR name = NULL;
367     NTSTATUS status;
368     UNICODE_STRING typeW;
369     LDR_RESOURCE_INFO info;
370     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
371     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
372     const IMAGE_RESOURCE_DIR_STRING_U *str;
373
374     TRACE( "%p %s %p %lx\n", hmod, debugstr_a(type), lpfun, lparam );
375
376     if (!hmod) hmod = GetModuleHandleA( NULL );
377     typeW.Buffer = NULL;
378     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
379         goto done;
380     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
381         goto done;
382     info.Type = (ULONG)typeW.Buffer;
383     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
384         goto done;
385
386     et = (IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
387     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
388     {
389         if (et[i].u1.s1.NameIsString)
390         {
391             str = (IMAGE_RESOURCE_DIR_STRING_U *) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
392             newlen = WideCharToMultiByte(CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
393             if (newlen + 1 > len)
394             {
395                 len = newlen + 1;
396                 HeapFree( GetProcessHeap(), 0, name );
397                 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
398                 {
399                     ret = FALSE;
400                     break;
401                 }
402             }
403             WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, name, len, NULL, NULL );
404             name[newlen] = 0;
405             ret = lpfun(hmod,type,name,lparam);
406         }
407         else
408         {
409             ret = lpfun( hmod, type, (LPSTR)(int)et[i].u1.s2.Id, lparam );
410         }
411         if (!ret) break;
412     }
413 done:
414     HeapFree( GetProcessHeap(), 0, name );
415     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
416     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
417     return ret;
418 }
419
420
421 /**********************************************************************
422  *      EnumResourceNamesW      (KERNEL32.@)
423  */
424 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG_PTR lparam )
425 {
426     int i, len = 0;
427     BOOL ret = FALSE;
428     LPWSTR name = NULL;
429     NTSTATUS status;
430     UNICODE_STRING typeW;
431     LDR_RESOURCE_INFO info;
432     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
433     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
434     const IMAGE_RESOURCE_DIR_STRING_U *str;
435
436     TRACE( "%p %s %p %lx\n", hmod, debugstr_w(type), lpfun, lparam );
437
438     if (!hmod) hmod = GetModuleHandleW( NULL );
439     typeW.Buffer = NULL;
440     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
441         goto done;
442     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
443         goto done;
444     info.Type = (ULONG)typeW.Buffer;
445     if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
446         goto done;
447
448     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
449     for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
450     {
451         if (et[i].u1.s1.NameIsString)
452         {
453             str = (IMAGE_RESOURCE_DIR_STRING_U *) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
454             if (str->Length + 1 > len)
455             {
456                 len = str->Length + 1;
457                 HeapFree( GetProcessHeap(), 0, name );
458                 if (!(name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
459                 {
460                     ret = FALSE;
461                     break;
462                 }
463             }
464             memcpy(name, str->NameString, str->Length * sizeof (WCHAR));
465             name[str->Length] = 0;
466             ret = lpfun(hmod,type,name,lparam);
467         }
468         else
469         {
470             ret = lpfun( hmod, type, (LPWSTR)(int)et[i].u1.s2.Id, lparam );
471         }
472         if (!ret) break;
473     }
474 done:
475     HeapFree( GetProcessHeap(), 0, name );
476     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
477     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
478     return ret;
479 }
480
481
482 /**********************************************************************
483  *      EnumResourceLanguagesA  (KERNEL32.@)
484  */
485 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
486                                     ENUMRESLANGPROCA lpfun, LONG_PTR lparam )
487 {
488     int i;
489     BOOL ret = FALSE;
490     NTSTATUS status;
491     UNICODE_STRING typeW, nameW;
492     LDR_RESOURCE_INFO info;
493     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
494     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
495
496     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_a(type), debugstr_a(name), lpfun, lparam );
497
498     if (!hmod) hmod = GetModuleHandleA( NULL );
499     typeW.Buffer = nameW.Buffer = NULL;
500     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
501         goto done;
502     if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
503         goto done;
504     if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS)
505         goto done;
506     info.Type = (ULONG)typeW.Buffer;
507     info.Name = (ULONG)nameW.Buffer;
508     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
509         goto done;
510
511     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
512     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
513     {
514         ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
515         if (!ret) break;
516     }
517 done:
518     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
519     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
520     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
521     return ret;
522 }
523
524
525 /**********************************************************************
526  *      EnumResourceLanguagesW  (KERNEL32.@)
527  */
528 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
529                                     ENUMRESLANGPROCW lpfun, LONG_PTR lparam )
530 {
531     int i;
532     BOOL ret = FALSE;
533     NTSTATUS status;
534     UNICODE_STRING typeW, nameW;
535     LDR_RESOURCE_INFO info;
536     const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
537     const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
538
539     TRACE( "%p %s %s %p %lx\n", hmod, debugstr_w(type), debugstr_w(name), lpfun, lparam );
540
541     if (!hmod) hmod = GetModuleHandleW( NULL );
542     typeW.Buffer = nameW.Buffer = NULL;
543     if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
544         goto done;
545     if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
546         goto done;
547     if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS)
548         goto done;
549     info.Type = (ULONG)typeW.Buffer;
550     info.Name = (ULONG)nameW.Buffer;
551     if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
552         goto done;
553
554     et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
555     for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
556     {
557         ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
558         if (!ret) break;
559     }
560 done:
561     if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
562     if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
563     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
564     return ret;
565 }
566
567
568 /**********************************************************************
569  *          LoadResource     (KERNEL32.@)
570  */
571 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
572 {
573     NTSTATUS status;
574     void *ret = NULL;
575
576     TRACE( "%p %p\n", hModule, hRsrc );
577
578     if (hModule && !HIWORD(hModule))
579         /* FIXME: should convert return to 32-bit resource */
580         return HGLOBAL_32( LoadResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) ) );
581
582     if (!hRsrc) return 0;
583     if (!hModule) hModule = GetModuleHandleA( NULL );
584     status = LdrAccessResource( hModule, (IMAGE_RESOURCE_DATA_ENTRY *)hRsrc, &ret, NULL );
585     if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
586     return ret;
587 }
588
589
590 /**********************************************************************
591  *          LockResource     (KERNEL32.@)
592  */
593 LPVOID WINAPI LockResource( HGLOBAL handle )
594 {
595     TRACE("(%p)\n", handle );
596
597     if (HIWORD( handle ))  /* 32-bit memory handle */
598         return (LPVOID)handle;
599
600     /* 16-bit memory handle */
601     return LockResource16( HGLOBAL_16(handle) );
602 }
603
604
605 /**********************************************************************
606  *          FreeResource     (KERNEL32.@)
607  */
608 BOOL WINAPI FreeResource( HGLOBAL handle )
609 {
610     if (HIWORD(handle)) return 0; /* 32-bit memory handle: nothing to do */
611     return FreeResource16( HGLOBAL_16(handle) );
612 }
613
614
615 /**********************************************************************
616  *          SizeofResource   (KERNEL32.@)
617  */
618 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
619 {
620     if (hModule && !HIWORD(hModule))
621         return SizeofResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) );
622
623     if (!hRsrc) return 0;
624     return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
625 }
626
627
628 typedef struct
629 {
630     LPWSTR pFileName;
631     struct list resources_list;
632 } QUEUEDUPDATES;
633
634 typedef struct
635 {
636     struct list entry;
637     LPWSTR lpType;
638     LPWSTR lpName;
639     WORD wLanguage;
640     LPVOID lpData;
641     DWORD cbData;
642 } QUEUEDRESOURCE;
643
644 static BOOL CALLBACK enum_resources_languages_delete_all(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLang, LONG_PTR lParam)
645 {
646     return UpdateResourceW((HANDLE)lParam, lpType, lpName, wLang, NULL, 0);
647 }
648
649 static BOOL CALLBACK enum_resources_names_delete_all(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
650 {
651     return EnumResourceLanguagesW(hModule, lpType, lpName, enum_resources_languages_delete_all, lParam);
652 }
653
654 static BOOL CALLBACK enum_resources_types_delete_all(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam)
655 {
656     return EnumResourceNamesW(hModule, lpType, enum_resources_names_delete_all, lParam);
657 }
658
659 static BOOL CALLBACK enum_resources_languages_add_all(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLang, LONG_PTR lParam)
660 {
661     DWORD size;
662     HRSRC hResource = FindResourceExW(hModule, lpType, lpName, wLang);
663     HGLOBAL hGlobal;
664     LPVOID lpData;
665
666     if(hResource == NULL) return FALSE;
667     if(!(hGlobal = LoadResource(hModule, hResource))) return FALSE;
668     if(!(lpData = LockResource(hGlobal))) return FALSE;
669     if(!(size = SizeofResource(hModule, hResource))) return FALSE;
670     return UpdateResourceW((HANDLE)lParam, lpType, lpName, wLang, lpData, size);
671 }
672
673 static BOOL CALLBACK enum_resources_names_add_all(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
674 {
675     return EnumResourceLanguagesW(hModule, lpType, lpName, enum_resources_languages_add_all, lParam);
676 }
677
678 static BOOL CALLBACK enum_resources_types_add_all(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam)
679 {
680     return EnumResourceNamesW(hModule, lpType, enum_resources_names_add_all, lParam);
681 }
682
683 /***********************************************************************
684  *          BeginUpdateResourceW                 (KERNEL32.@)
685  */
686 HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources )
687 {
688     HANDLE hFile = NULL;
689     WIN32_FIND_DATAW fd;
690     HANDLE hModule = NULL;
691     HANDLE hUpdate = NULL;
692     QUEUEDUPDATES *current_updates = NULL;
693     HANDLE ret = NULL;
694
695     TRACE("%s, %d\n",debugstr_w(pFileName),bDeleteExistingResources);
696
697     hFile = FindFirstFileW(pFileName, &fd);
698     if(hFile == INVALID_HANDLE_VALUE)
699     {
700         hFile = NULL;
701         SetLastError(ERROR_FILE_NOT_FOUND);
702         goto done;
703     }
704     if(fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
705     {
706         SetLastError(ERROR_FILE_READ_ONLY);
707         goto done;
708     }
709
710     hModule = LoadLibraryW(pFileName);
711     if(hModule == NULL)
712     {
713         SetLastError(ERROR_INVALID_PARAMETER);
714         goto done;
715     }
716
717     if(!(hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES))))
718     {
719         SetLastError(ERROR_OUTOFMEMORY);
720         goto done;
721     }
722     if(!(current_updates = GlobalLock(hUpdate)))
723     {
724         SetLastError(ERROR_INVALID_HANDLE);
725         goto done;
726     }
727     if(!(current_updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (strlenW(pFileName)+1)*sizeof(WCHAR))))
728     {
729         SetLastError(ERROR_OUTOFMEMORY);
730         goto done;
731     }
732     strcpyW(current_updates->pFileName, pFileName);
733     list_init(&current_updates->resources_list);
734
735     if(bDeleteExistingResources)
736     {
737         if(!EnumResourceTypesW(hModule, enum_resources_types_delete_all, (LONG_PTR)hUpdate))
738             goto done;
739     }
740     else
741     {
742         if(!EnumResourceTypesW(hModule, enum_resources_types_add_all, (LONG_PTR)hUpdate))
743             goto done;
744     }
745     ret = hUpdate;
746
747 done:
748     if(!ret && current_updates)
749     {
750         HeapFree(GetProcessHeap(), 0, current_updates->pFileName);
751         GlobalUnlock(hUpdate);
752         GlobalFree(hUpdate);
753         hUpdate = NULL;
754     }
755     if(hUpdate) GlobalUnlock(hUpdate);
756     if(hModule) FreeLibrary(hModule);
757     if(hFile) FindClose(hFile);
758     return ret;
759 }
760
761
762 /***********************************************************************
763  *          BeginUpdateResourceA                 (KERNEL32.@)
764  */
765 HANDLE WINAPI BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources )
766 {
767     UNICODE_STRING FileNameW;
768     HANDLE ret;
769     RtlCreateUnicodeStringFromAsciiz(&FileNameW, pFileName);
770     ret = BeginUpdateResourceW(FileNameW.Buffer, bDeleteExistingResources);
771     RtlFreeUnicodeString(&FileNameW);
772     return ret;
773 }
774
775
776 /***********************************************************************
777  *          EndUpdateResourceW                 (KERNEL32.@)
778  */
779 BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
780 {
781     QUEUEDUPDATES *current_updates = NULL;
782     BOOL found = TRUE;
783     BOOL ret = FALSE;
784     struct list *ptr = NULL;
785     QUEUEDRESOURCE *current_resource = NULL;
786
787     FIXME("(%p,%d): stub\n",hUpdate,fDiscard);
788
789     if(!(current_updates = GlobalLock(hUpdate)))
790     {
791         SetLastError(ERROR_INVALID_HANDLE);
792         found = FALSE;
793         goto done;
794     }
795
796     if(fDiscard)
797         ret = TRUE;
798     else
799     {
800         /* FIXME: This is the only missing part, an actual implementation */
801         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
802         ret = FALSE;
803     }
804
805 done:
806     if(found)
807     {
808         while ((ptr = list_head(&current_updates->resources_list)) != NULL)
809         {
810             current_resource = LIST_ENTRY(ptr, QUEUEDRESOURCE, entry);
811             list_remove(&current_resource->entry);
812             if(HIWORD(current_resource->lpType)) HeapFree(GetProcessHeap(), 0, current_resource->lpType);
813             if(HIWORD(current_resource->lpName)) HeapFree(GetProcessHeap(), 0, current_resource->lpName);
814             HeapFree(GetProcessHeap(), 0, current_resource->lpData);
815             HeapFree(GetProcessHeap(), 0, current_resource);
816         }
817         HeapFree(GetProcessHeap(), 0, current_updates->pFileName);
818         GlobalUnlock(hUpdate);
819         GlobalFree(hUpdate);
820     }
821     return ret;
822 }
823
824
825 /***********************************************************************
826  *          EndUpdateResourceA                 (KERNEL32.@)
827  */
828 BOOL WINAPI EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard )
829 {
830     return EndUpdateResourceW(hUpdate, fDiscard);
831 }
832
833
834 /***********************************************************************
835  *           UpdateResourceW                 (KERNEL32.@)
836  */
837 BOOL WINAPI UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
838                              WORD wLanguage, LPVOID lpData, DWORD cbData)
839 {
840     QUEUEDUPDATES *current_updates = NULL;
841     BOOL found = TRUE;
842     QUEUEDRESOURCE *current_resource = NULL;
843     BOOL ret = FALSE;
844
845     TRACE("%p %s %s %08x %p %ld\n",hUpdate,debugstr_w(lpType),debugstr_w(lpName),wLanguage,lpData,cbData);
846
847     if(!(current_updates = GlobalLock(hUpdate)))
848     {
849         SetLastError(ERROR_INVALID_HANDLE);
850         found = FALSE;
851         goto done;
852     }
853
854     if(!(current_resource = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUEDRESOURCE))))
855     {
856         SetLastError(ERROR_OUTOFMEMORY);
857         goto done;
858     }
859     if(!HIWORD(lpType))
860         current_resource->lpType = (LPWSTR)lpType;
861     else if((current_resource->lpType = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpType)+1)*sizeof(WCHAR))))
862         strcpyW(current_resource->lpType, lpType);
863     else
864     {
865         SetLastError(ERROR_OUTOFMEMORY);
866         goto done;
867     }
868     if(!HIWORD(lpName))
869         current_resource->lpName = (LPWSTR)lpName;
870     else if((current_resource->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpName)+1)*sizeof(WCHAR))))
871         strcpyW(current_resource->lpName, lpName);
872     else
873     {
874         SetLastError(ERROR_OUTOFMEMORY);
875         goto done;
876     }
877     if(!(current_resource->lpData = HeapAlloc(GetProcessHeap(), 0, cbData)))
878     {
879         SetLastError(ERROR_OUTOFMEMORY);
880         goto done;
881     }
882     current_resource->wLanguage = wLanguage;
883     memcpy(current_resource->lpData, lpData, cbData);
884     current_resource->cbData = cbData;
885     list_add_tail(&current_updates->resources_list, &current_resource->entry);
886     ret = TRUE;
887
888 done:
889     if(!ret && current_resource)
890     {
891         if(HIWORD(current_resource->lpType)) HeapFree(GetProcessHeap(), 0, current_resource->lpType);
892         if(HIWORD(current_resource->lpName)) HeapFree(GetProcessHeap(), 0, current_resource->lpName);
893         HeapFree(GetProcessHeap(), 0, current_resource->lpData);
894         HeapFree(GetProcessHeap(), 0, current_resource);
895     }
896     if(found) GlobalUnlock(hUpdate);
897     return ret;
898 }
899
900
901 /***********************************************************************
902  *           UpdateResourceA                 (KERNEL32.@)
903  */
904 BOOL WINAPI UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
905                              WORD wLanguage, LPVOID lpData, DWORD cbData)
906 {
907     BOOL ret;
908     UNICODE_STRING TypeW;
909     UNICODE_STRING NameW;
910     if(!HIWORD(lpType))
911         TypeW.Buffer = (LPWSTR)lpType;
912     else
913         RtlCreateUnicodeStringFromAsciiz(&TypeW, lpType);
914     if(!HIWORD(lpName))
915         NameW.Buffer = (LPWSTR)lpName;
916     else
917         RtlCreateUnicodeStringFromAsciiz(&NameW, lpName);
918     ret = UpdateResourceW(hUpdate, TypeW.Buffer, NameW.Buffer, wLanguage, lpData, cbData);
919     if(HIWORD(lpType)) RtlFreeUnicodeString(&TypeW);
920     if(HIWORD(lpName)) RtlFreeUnicodeString(&NameW);
921     return ret;
922 }