rpcrt4: Add a FIXME for unsupported client protocol sequences.
[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 typedef struct
621 {
622     LPWSTR pFileName;
623     struct list resources_list;
624 } QUEUEDUPDATES;
625
626 typedef struct
627 {
628     struct list entry;
629     LPWSTR lpType;
630     LPWSTR lpName;
631     WORD wLanguage;
632     LPVOID lpData;
633     DWORD cbData;
634 } QUEUEDRESOURCE;
635
636 static BOOL CALLBACK enum_resources_languages_delete_all(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLang, LONG_PTR lParam)
637 {
638     return UpdateResourceW((HANDLE)lParam, lpType, lpName, wLang, NULL, 0);
639 }
640
641 static BOOL CALLBACK enum_resources_names_delete_all(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
642 {
643     return EnumResourceLanguagesW(hModule, lpType, lpName, enum_resources_languages_delete_all, lParam);
644 }
645
646 static BOOL CALLBACK enum_resources_types_delete_all(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam)
647 {
648     return EnumResourceNamesW(hModule, lpType, enum_resources_names_delete_all, lParam);
649 }
650
651 static BOOL CALLBACK enum_resources_languages_add_all(HMODULE hModule, LPCWSTR lpType, LPCWSTR lpName, WORD wLang, LONG_PTR lParam)
652 {
653     DWORD size;
654     HRSRC hResource = FindResourceExW(hModule, lpType, lpName, wLang);
655     HGLOBAL hGlobal;
656     LPVOID lpData;
657
658     if(hResource == NULL) return FALSE;
659     if(!(hGlobal = LoadResource(hModule, hResource))) return FALSE;
660     if(!(lpData = LockResource(hGlobal))) return FALSE;
661     if(!(size = SizeofResource(hModule, hResource))) return FALSE;
662     return UpdateResourceW((HANDLE)lParam, lpType, lpName, wLang, lpData, size);
663 }
664
665 static BOOL CALLBACK enum_resources_names_add_all(HMODULE hModule, LPCWSTR lpType, LPWSTR lpName, LONG_PTR lParam)
666 {
667     return EnumResourceLanguagesW(hModule, lpType, lpName, enum_resources_languages_add_all, lParam);
668 }
669
670 static BOOL CALLBACK enum_resources_types_add_all(HMODULE hModule, LPWSTR lpType, LONG_PTR lParam)
671 {
672     return EnumResourceNamesW(hModule, lpType, enum_resources_names_add_all, lParam);
673 }
674
675 /***********************************************************************
676  *          BeginUpdateResourceW                 (KERNEL32.@)
677  */
678 HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources )
679 {
680     HANDLE hFile = NULL;
681     WIN32_FIND_DATAW fd;
682     HANDLE hModule = NULL;
683     HANDLE hUpdate = NULL;
684     QUEUEDUPDATES *current_updates = NULL;
685     HANDLE ret = NULL;
686
687     TRACE("%s, %d\n",debugstr_w(pFileName),bDeleteExistingResources);
688
689     hFile = FindFirstFileW(pFileName, &fd);
690     if(hFile == INVALID_HANDLE_VALUE)
691     {
692         hFile = NULL;
693         SetLastError(ERROR_FILE_NOT_FOUND);
694         goto done;
695     }
696     if(fd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
697     {
698         SetLastError(ERROR_FILE_READ_ONLY);
699         goto done;
700     }
701
702     hModule = LoadLibraryW(pFileName);
703     if(hModule == NULL)
704     {
705         SetLastError(ERROR_INVALID_PARAMETER);
706         goto done;
707     }
708
709     if(!(hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES))))
710     {
711         SetLastError(ERROR_OUTOFMEMORY);
712         goto done;
713     }
714     if(!(current_updates = GlobalLock(hUpdate)))
715     {
716         SetLastError(ERROR_INVALID_HANDLE);
717         goto done;
718     }
719     if(!(current_updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (strlenW(pFileName)+1)*sizeof(WCHAR))))
720     {
721         SetLastError(ERROR_OUTOFMEMORY);
722         goto done;
723     }
724     strcpyW(current_updates->pFileName, pFileName);
725     list_init(&current_updates->resources_list);
726
727     if(bDeleteExistingResources)
728     {
729         if(!EnumResourceTypesW(hModule, enum_resources_types_delete_all, (LONG_PTR)hUpdate))
730             goto done;
731     }
732     else
733     {
734         if(!EnumResourceTypesW(hModule, enum_resources_types_add_all, (LONG_PTR)hUpdate))
735             goto done;
736     }
737     ret = hUpdate;
738
739 done:
740     if(!ret && current_updates)
741     {
742         HeapFree(GetProcessHeap(), 0, current_updates->pFileName);
743         GlobalUnlock(hUpdate);
744         GlobalFree(hUpdate);
745         hUpdate = NULL;
746     }
747     if(hUpdate) GlobalUnlock(hUpdate);
748     if(hModule) FreeLibrary(hModule);
749     if(hFile) FindClose(hFile);
750     return ret;
751 }
752
753
754 /***********************************************************************
755  *          BeginUpdateResourceA                 (KERNEL32.@)
756  */
757 HANDLE WINAPI BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources )
758 {
759     UNICODE_STRING FileNameW;
760     HANDLE ret;
761     RtlCreateUnicodeStringFromAsciiz(&FileNameW, pFileName);
762     ret = BeginUpdateResourceW(FileNameW.Buffer, bDeleteExistingResources);
763     RtlFreeUnicodeString(&FileNameW);
764     return ret;
765 }
766
767
768 /***********************************************************************
769  *          EndUpdateResourceW                 (KERNEL32.@)
770  */
771 BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
772 {
773     QUEUEDUPDATES *current_updates = NULL;
774     BOOL found = TRUE;
775     BOOL ret = FALSE;
776     struct list *ptr = NULL;
777     QUEUEDRESOURCE *current_resource = NULL;
778
779     FIXME("(%p,%d): stub\n",hUpdate,fDiscard);
780
781     if(!(current_updates = GlobalLock(hUpdate)))
782     {
783         SetLastError(ERROR_INVALID_HANDLE);
784         found = FALSE;
785         goto done;
786     }
787
788     if(fDiscard)
789         ret = TRUE;
790     else
791     {
792         /* FIXME: This is the only missing part, an actual implementation */
793         SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
794         ret = FALSE;
795     }
796
797 done:
798     if(found)
799     {
800         while ((ptr = list_head(&current_updates->resources_list)) != NULL)
801         {
802             current_resource = LIST_ENTRY(ptr, QUEUEDRESOURCE, entry);
803             list_remove(&current_resource->entry);
804             if(HIWORD(current_resource->lpType)) HeapFree(GetProcessHeap(), 0, current_resource->lpType);
805             if(HIWORD(current_resource->lpName)) HeapFree(GetProcessHeap(), 0, current_resource->lpName);
806             HeapFree(GetProcessHeap(), 0, current_resource->lpData);
807             HeapFree(GetProcessHeap(), 0, current_resource);
808         }
809         HeapFree(GetProcessHeap(), 0, current_updates->pFileName);
810         GlobalUnlock(hUpdate);
811         GlobalFree(hUpdate);
812     }
813     return ret;
814 }
815
816
817 /***********************************************************************
818  *          EndUpdateResourceA                 (KERNEL32.@)
819  */
820 BOOL WINAPI EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard )
821 {
822     return EndUpdateResourceW(hUpdate, fDiscard);
823 }
824
825
826 /***********************************************************************
827  *           UpdateResourceW                 (KERNEL32.@)
828  */
829 BOOL WINAPI UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
830                              WORD wLanguage, LPVOID lpData, DWORD cbData)
831 {
832     QUEUEDUPDATES *current_updates = NULL;
833     BOOL found = TRUE;
834     QUEUEDRESOURCE *current_resource = NULL;
835     BOOL ret = FALSE;
836
837     TRACE("%p %s %s %08x %p %d\n",hUpdate,debugstr_w(lpType),debugstr_w(lpName),wLanguage,lpData,cbData);
838
839     if(!(current_updates = GlobalLock(hUpdate)))
840     {
841         SetLastError(ERROR_INVALID_HANDLE);
842         found = FALSE;
843         goto done;
844     }
845
846     if(!(current_resource = HeapAlloc(GetProcessHeap(), 0, sizeof(QUEUEDRESOURCE))))
847     {
848         SetLastError(ERROR_OUTOFMEMORY);
849         goto done;
850     }
851     if(!HIWORD(lpType))
852         current_resource->lpType = (LPWSTR)lpType;
853     else if((current_resource->lpType = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpType)+1)*sizeof(WCHAR))))
854         strcpyW(current_resource->lpType, lpType);
855     else
856     {
857         SetLastError(ERROR_OUTOFMEMORY);
858         goto done;
859     }
860     if(!HIWORD(lpName))
861         current_resource->lpName = (LPWSTR)lpName;
862     else if((current_resource->lpName = HeapAlloc(GetProcessHeap(), 0, (strlenW(lpName)+1)*sizeof(WCHAR))))
863         strcpyW(current_resource->lpName, lpName);
864     else
865     {
866         SetLastError(ERROR_OUTOFMEMORY);
867         goto done;
868     }
869     if(!(current_resource->lpData = HeapAlloc(GetProcessHeap(), 0, cbData)))
870     {
871         SetLastError(ERROR_OUTOFMEMORY);
872         goto done;
873     }
874     current_resource->wLanguage = wLanguage;
875     memcpy(current_resource->lpData, lpData, cbData);
876     current_resource->cbData = cbData;
877     list_add_tail(&current_updates->resources_list, &current_resource->entry);
878     ret = TRUE;
879
880 done:
881     if(!ret && current_resource)
882     {
883         if(HIWORD(current_resource->lpType)) HeapFree(GetProcessHeap(), 0, current_resource->lpType);
884         if(HIWORD(current_resource->lpName)) HeapFree(GetProcessHeap(), 0, current_resource->lpName);
885         HeapFree(GetProcessHeap(), 0, current_resource->lpData);
886         HeapFree(GetProcessHeap(), 0, current_resource);
887     }
888     if(found) GlobalUnlock(hUpdate);
889     return ret;
890 }
891
892
893 /***********************************************************************
894  *           UpdateResourceA                 (KERNEL32.@)
895  */
896 BOOL WINAPI UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
897                              WORD wLanguage, LPVOID lpData, DWORD cbData)
898 {
899     BOOL ret;
900     UNICODE_STRING TypeW;
901     UNICODE_STRING NameW;
902     if(!HIWORD(lpType))
903         TypeW.Buffer = (LPWSTR)lpType;
904     else
905         RtlCreateUnicodeStringFromAsciiz(&TypeW, lpType);
906     if(!HIWORD(lpName))
907         NameW.Buffer = (LPWSTR)lpName;
908     else
909         RtlCreateUnicodeStringFromAsciiz(&NameW, lpName);
910     ret = UpdateResourceW(hUpdate, TypeW.Buffer, NameW.Buffer, wLanguage, lpData, cbData);
911     if(HIWORD(lpType)) RtlFreeUnicodeString(&TypeW);
912     if(HIWORD(lpName)) RtlFreeUnicodeString(&NameW);
913     return ret;
914 }