push 8b07bf1f08b23b9893a622b47d2be359556765b1
[wine/hacks.git] / dlls / kernel32 / resource.c
blobd405b95ec9d64d1cf798e1d07f7561b071d19d0b
1 /*
2 * Resources
4 * Copyright 1993 Robert J. Amstadt
5 * Copyright 1995, 2003 Alexandre Julliard
6 * Copyright 2006 Mike McCormack
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30 #include "ntstatus.h"
31 #define WIN32_NO_STATUS
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winternl.h"
35 #include "wine/winbase16.h"
36 #include "wine/debug.h"
37 #include "wine/exception.h"
38 #include "wine/unicode.h"
39 #include "wine/list.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(resource);
43 /* handle conversions */
44 #define HRSRC_32(h16) ((HRSRC)(ULONG_PTR)(h16))
45 #define HRSRC_16(h32) (LOWORD(h32))
46 #define HGLOBAL_32(h16) ((HGLOBAL)(ULONG_PTR)(h16))
47 #define HGLOBAL_16(h32) (LOWORD(h32))
48 #define HMODULE_16(h32) (LOWORD(h32))
50 /* retrieve the resource name to pass to the ntdll functions */
51 static NTSTATUS get_res_nameA( LPCSTR name, UNICODE_STRING *str )
53 if (!HIWORD(name))
55 str->Buffer = ULongToPtr(LOWORD(name));
56 return STATUS_SUCCESS;
58 if (name[0] == '#')
60 ULONG value;
61 if (RtlCharToInteger( name + 1, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
62 return STATUS_INVALID_PARAMETER;
63 str->Buffer = ULongToPtr(value);
64 return STATUS_SUCCESS;
66 RtlCreateUnicodeStringFromAsciiz( str, name );
67 RtlUpcaseUnicodeString( str, str, FALSE );
68 return STATUS_SUCCESS;
71 /* retrieve the resource name to pass to the ntdll functions */
72 static NTSTATUS get_res_nameW( LPCWSTR name, UNICODE_STRING *str )
74 if (!HIWORD(name))
76 str->Buffer = ULongToPtr(LOWORD(name));
77 return STATUS_SUCCESS;
79 if (name[0] == '#')
81 ULONG value;
82 RtlInitUnicodeString( str, name + 1 );
83 if (RtlUnicodeStringToInteger( str, 10, &value ) != STATUS_SUCCESS || HIWORD(value))
84 return STATUS_INVALID_PARAMETER;
85 str->Buffer = ULongToPtr(value);
86 return STATUS_SUCCESS;
88 RtlCreateUnicodeString( str, name );
89 RtlUpcaseUnicodeString( str, str, FALSE );
90 return STATUS_SUCCESS;
93 /* retrieve the resource names for the 16-bit FindResource function */
94 static BOOL get_res_name_type_WtoA( LPCWSTR name, LPCWSTR type, LPSTR *nameA, LPSTR *typeA )
96 *nameA = *typeA = NULL;
98 __TRY
100 if (HIWORD(name))
102 DWORD len = WideCharToMultiByte( CP_ACP, 0, name, -1, NULL, 0, NULL, NULL );
103 *nameA = HeapAlloc( GetProcessHeap(), 0, len );
104 if (*nameA) WideCharToMultiByte( CP_ACP, 0, name, -1, *nameA, len, NULL, NULL );
106 else *nameA = ULongToPtr(LOWORD(name));
108 if (HIWORD(type))
110 DWORD len = WideCharToMultiByte( CP_ACP, 0, type, -1, NULL, 0, NULL, NULL );
111 *typeA = HeapAlloc( GetProcessHeap(), 0, len );
112 if (*typeA) WideCharToMultiByte( CP_ACP, 0, type, -1, *typeA, len, NULL, NULL );
114 else *typeA = ULongToPtr(LOWORD(type));
116 __EXCEPT_PAGE_FAULT
118 if (HIWORD(*nameA)) HeapFree( GetProcessHeap(), 0, *nameA );
119 if (HIWORD(*typeA)) HeapFree( GetProcessHeap(), 0, *typeA );
120 SetLastError( ERROR_INVALID_PARAMETER );
121 return FALSE;
123 __ENDTRY
124 return TRUE;
127 /* implementation of FindResourceExA */
128 static HRSRC find_resourceA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
130 NTSTATUS status;
131 UNICODE_STRING nameW, typeW;
132 LDR_RESOURCE_INFO info;
133 const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
135 nameW.Buffer = NULL;
136 typeW.Buffer = NULL;
138 __TRY
140 if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS) goto done;
141 if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS) goto done;
142 info.Type = (ULONG_PTR)typeW.Buffer;
143 info.Name = (ULONG_PTR)nameW.Buffer;
144 info.Language = lang;
145 status = LdrFindResource_U( hModule, &info, 3, &entry );
146 done:
147 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
149 __EXCEPT_PAGE_FAULT
151 SetLastError( ERROR_INVALID_PARAMETER );
153 __ENDTRY
155 if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
156 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
157 return (HRSRC)entry;
161 /* implementation of FindResourceExW */
162 static HRSRC find_resourceW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
164 NTSTATUS status;
165 UNICODE_STRING nameW, typeW;
166 LDR_RESOURCE_INFO info;
167 const IMAGE_RESOURCE_DATA_ENTRY *entry = NULL;
169 nameW.Buffer = typeW.Buffer = NULL;
171 __TRY
173 if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS) goto done;
174 if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS) goto done;
175 info.Type = (ULONG_PTR)typeW.Buffer;
176 info.Name = (ULONG_PTR)nameW.Buffer;
177 info.Language = lang;
178 status = LdrFindResource_U( hModule, &info, 3, &entry );
179 done:
180 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
182 __EXCEPT_PAGE_FAULT
184 SetLastError( ERROR_INVALID_PARAMETER );
186 __ENDTRY
188 if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
189 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
190 return (HRSRC)entry;
193 /**********************************************************************
194 * FindResourceExA (KERNEL32.@)
196 HRSRC WINAPI FindResourceExA( HMODULE hModule, LPCSTR type, LPCSTR name, WORD lang )
198 TRACE( "%p %s %s %04x\n", hModule, debugstr_a(type), debugstr_a(name), lang );
200 if (!hModule) hModule = GetModuleHandleW(0);
201 else if (!HIWORD(hModule))
203 return HRSRC_32( FindResource16( HMODULE_16(hModule), name, type ) );
205 return find_resourceA( hModule, type, name, lang );
209 /**********************************************************************
210 * FindResourceA (KERNEL32.@)
212 HRSRC WINAPI FindResourceA( HMODULE hModule, LPCSTR name, LPCSTR type )
214 return FindResourceExA( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
218 /**********************************************************************
219 * FindResourceExW (KERNEL32.@)
221 HRSRC WINAPI FindResourceExW( HMODULE hModule, LPCWSTR type, LPCWSTR name, WORD lang )
223 TRACE( "%p %s %s %04x\n", hModule, debugstr_w(type), debugstr_w(name), lang );
225 if (!hModule) hModule = GetModuleHandleW(0);
226 else if (!HIWORD(hModule))
228 LPSTR nameA, typeA;
229 HRSRC16 ret;
231 if (!get_res_name_type_WtoA( name, type, &nameA, &typeA )) return NULL;
233 ret = FindResource16( HMODULE_16(hModule), nameA, typeA );
234 if (HIWORD(nameA)) HeapFree( GetProcessHeap(), 0, nameA );
235 if (HIWORD(typeA)) HeapFree( GetProcessHeap(), 0, typeA );
236 return HRSRC_32(ret);
239 return find_resourceW( hModule, type, name, lang );
243 /**********************************************************************
244 * FindResourceW (KERNEL32.@)
246 HRSRC WINAPI FindResourceW( HINSTANCE hModule, LPCWSTR name, LPCWSTR type )
248 return FindResourceExW( hModule, type, name, MAKELANGID( LANG_NEUTRAL, SUBLANG_NEUTRAL ) );
252 /**********************************************************************
253 * EnumResourceTypesA (KERNEL32.@)
255 BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG_PTR lparam )
257 int i;
258 BOOL ret = FALSE;
259 LPSTR type = NULL;
260 DWORD len = 0, newlen;
261 NTSTATUS status;
262 const IMAGE_RESOURCE_DIRECTORY *resdir;
263 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
264 const IMAGE_RESOURCE_DIR_STRING_U *str;
266 TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
268 if (!hmod) hmod = GetModuleHandleA( NULL );
270 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
272 SetLastError( RtlNtStatusToDosError(status) );
273 return FALSE;
275 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
276 for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
278 if (et[i].u1.s1.NameIsString)
280 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
281 newlen = WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
282 if (newlen + 1 > len)
284 len = newlen + 1;
285 HeapFree( GetProcessHeap(), 0, type );
286 if (!(type = HeapAlloc( GetProcessHeap(), 0, len ))) return FALSE;
288 WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, type, len, NULL, NULL);
289 type[newlen] = 0;
290 ret = lpfun(hmod,type,lparam);
292 else
294 ret = lpfun( hmod, UIntToPtr(et[i].u1.s2.Id), lparam );
296 if (!ret) break;
298 HeapFree( GetProcessHeap(), 0, type );
299 return ret;
303 /**********************************************************************
304 * EnumResourceTypesW (KERNEL32.@)
306 BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG_PTR lparam )
308 int i, len = 0;
309 BOOL ret = FALSE;
310 LPWSTR type = NULL;
311 NTSTATUS status;
312 const IMAGE_RESOURCE_DIRECTORY *resdir;
313 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
314 const IMAGE_RESOURCE_DIR_STRING_U *str;
316 TRACE( "%p %p %lx\n", hmod, lpfun, lparam );
318 if (!hmod) hmod = GetModuleHandleW( NULL );
320 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &resdir )) != STATUS_SUCCESS)
322 SetLastError( RtlNtStatusToDosError(status) );
323 return FALSE;
325 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
326 for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
328 if (et[i].u1.s1.NameIsString)
330 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)resdir + et[i].u1.s1.NameOffset);
331 if (str->Length + 1 > len)
333 len = str->Length + 1;
334 HeapFree( GetProcessHeap(), 0, type );
335 if (!(type = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
337 memcpy(type, str->NameString, str->Length * sizeof (WCHAR));
338 type[str->Length] = 0;
339 ret = lpfun(hmod,type,lparam);
341 else
343 ret = lpfun( hmod, UIntToPtr(et[i].u1.s2.Id), lparam );
345 if (!ret) break;
347 HeapFree( GetProcessHeap(), 0, type );
348 return ret;
352 /**********************************************************************
353 * EnumResourceNamesA (KERNEL32.@)
355 BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG_PTR lparam )
357 int i;
358 BOOL ret = FALSE;
359 DWORD len = 0, newlen;
360 LPSTR name = NULL;
361 NTSTATUS status;
362 UNICODE_STRING typeW;
363 LDR_RESOURCE_INFO info;
364 const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
365 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
366 const IMAGE_RESOURCE_DIR_STRING_U *str;
368 TRACE( "%p %s %p %lx\n", hmod, debugstr_a(type), lpfun, lparam );
370 if (!hmod) hmod = GetModuleHandleA( NULL );
371 typeW.Buffer = NULL;
372 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
373 goto done;
374 if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
375 goto done;
376 info.Type = (ULONG_PTR)typeW.Buffer;
377 if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
378 goto done;
380 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
381 __TRY
383 for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
385 if (et[i].u1.s1.NameIsString)
387 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
388 newlen = WideCharToMultiByte(CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
389 if (newlen + 1 > len)
391 len = newlen + 1;
392 HeapFree( GetProcessHeap(), 0, name );
393 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
395 ret = FALSE;
396 break;
399 WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, name, len, NULL, NULL );
400 name[newlen] = 0;
401 ret = lpfun(hmod,type,name,lparam);
403 else
405 ret = lpfun( hmod, type, UIntToPtr(et[i].u1.s2.Id), lparam );
407 if (!ret) break;
410 __EXCEPT_PAGE_FAULT
412 ret = FALSE;
413 status = STATUS_ACCESS_VIOLATION;
415 __ENDTRY
417 done:
418 HeapFree( GetProcessHeap(), 0, name );
419 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
420 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
421 return ret;
425 /**********************************************************************
426 * EnumResourceNamesW (KERNEL32.@)
428 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG_PTR lparam )
430 int i, len = 0;
431 BOOL ret = FALSE;
432 LPWSTR name = NULL;
433 NTSTATUS status;
434 UNICODE_STRING typeW;
435 LDR_RESOURCE_INFO info;
436 const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
437 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
438 const IMAGE_RESOURCE_DIR_STRING_U *str;
440 TRACE( "%p %s %p %lx\n", hmod, debugstr_w(type), lpfun, lparam );
442 if (!hmod) hmod = GetModuleHandleW( NULL );
443 typeW.Buffer = NULL;
444 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
445 goto done;
446 if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
447 goto done;
448 info.Type = (ULONG_PTR)typeW.Buffer;
449 if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
450 goto done;
452 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
453 __TRY
455 for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
457 if (et[i].u1.s1.NameIsString)
459 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
460 if (str->Length + 1 > len)
462 len = str->Length + 1;
463 HeapFree( GetProcessHeap(), 0, name );
464 if (!(name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
466 ret = FALSE;
467 break;
470 memcpy(name, str->NameString, str->Length * sizeof (WCHAR));
471 name[str->Length] = 0;
472 ret = lpfun(hmod,type,name,lparam);
474 else
476 ret = lpfun( hmod, type, UIntToPtr(et[i].u1.s2.Id), lparam );
478 if (!ret) break;
481 __EXCEPT_PAGE_FAULT
483 ret = FALSE;
484 status = STATUS_ACCESS_VIOLATION;
486 __ENDTRY
487 done:
488 HeapFree( GetProcessHeap(), 0, name );
489 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
490 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
491 return ret;
495 /**********************************************************************
496 * EnumResourceLanguagesA (KERNEL32.@)
498 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
499 ENUMRESLANGPROCA lpfun, LONG_PTR lparam )
501 int i;
502 BOOL ret = FALSE;
503 NTSTATUS status;
504 UNICODE_STRING typeW, nameW;
505 LDR_RESOURCE_INFO info;
506 const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
507 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
509 TRACE( "%p %s %s %p %lx\n", hmod, debugstr_a(type), debugstr_a(name), lpfun, lparam );
511 if (!hmod) hmod = GetModuleHandleA( NULL );
512 typeW.Buffer = nameW.Buffer = NULL;
513 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
514 goto done;
515 if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
516 goto done;
517 if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS)
518 goto done;
519 info.Type = (ULONG_PTR)typeW.Buffer;
520 info.Name = (ULONG_PTR)nameW.Buffer;
521 if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
522 goto done;
524 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
525 __TRY
527 for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
529 ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
530 if (!ret) break;
533 __EXCEPT_PAGE_FAULT
535 ret = FALSE;
536 status = STATUS_ACCESS_VIOLATION;
538 __ENDTRY
539 done:
540 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
541 if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
542 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
543 return ret;
547 /**********************************************************************
548 * EnumResourceLanguagesW (KERNEL32.@)
550 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
551 ENUMRESLANGPROCW lpfun, LONG_PTR lparam )
553 int i;
554 BOOL ret = FALSE;
555 NTSTATUS status;
556 UNICODE_STRING typeW, nameW;
557 LDR_RESOURCE_INFO info;
558 const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
559 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
561 TRACE( "%p %s %s %p %lx\n", hmod, debugstr_w(type), debugstr_w(name), lpfun, lparam );
563 if (!hmod) hmod = GetModuleHandleW( NULL );
564 typeW.Buffer = nameW.Buffer = NULL;
565 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
566 goto done;
567 if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
568 goto done;
569 if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS)
570 goto done;
571 info.Type = (ULONG_PTR)typeW.Buffer;
572 info.Name = (ULONG_PTR)nameW.Buffer;
573 if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
574 goto done;
576 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
577 __TRY
579 for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
581 ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
582 if (!ret) break;
585 __EXCEPT_PAGE_FAULT
587 ret = FALSE;
588 status = STATUS_ACCESS_VIOLATION;
590 __ENDTRY
591 done:
592 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
593 if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
594 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
595 return ret;
599 /**********************************************************************
600 * LoadResource (KERNEL32.@)
602 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
604 NTSTATUS status;
605 void *ret = NULL;
607 TRACE( "%p %p\n", hModule, hRsrc );
609 if (hModule && !HIWORD(hModule))
610 /* FIXME: should convert return to 32-bit resource */
611 return HGLOBAL_32( LoadResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) ) );
613 if (!hRsrc) return 0;
614 if (!hModule) hModule = GetModuleHandleA( NULL );
615 status = LdrAccessResource( hModule, (IMAGE_RESOURCE_DATA_ENTRY *)hRsrc, &ret, NULL );
616 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
617 return ret;
621 /**********************************************************************
622 * LockResource (KERNEL32.@)
624 LPVOID WINAPI LockResource( HGLOBAL handle )
626 TRACE("(%p)\n", handle );
628 if (HIWORD( handle )) /* 32-bit memory handle */
629 return handle;
631 /* 16-bit memory handle */
632 return LockResource16( HGLOBAL_16(handle) );
636 /**********************************************************************
637 * FreeResource (KERNEL32.@)
639 BOOL WINAPI FreeResource( HGLOBAL handle )
641 if (HIWORD(handle)) return 0; /* 32-bit memory handle: nothing to do */
642 return FreeResource16( HGLOBAL_16(handle) );
646 /**********************************************************************
647 * SizeofResource (KERNEL32.@)
649 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
651 if (hModule && !HIWORD(hModule))
652 return SizeofResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) );
654 if (!hRsrc) return 0;
655 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
659 * Data structure for updating resources.
660 * Type/Name/Language is a keyset for accessing resource data.
662 * QUEUEDUPDATES (root) ->
663 * list of struct resource_dir_entry (Type) ->
664 * list of struct resource_dir_entry (Name) ->
665 * list of struct resource_data Language + Data
668 typedef struct
670 LPWSTR pFileName;
671 BOOL bDeleteExistingResources;
672 struct list root;
673 } QUEUEDUPDATES;
675 /* this structure is shared for types and names */
676 struct resource_dir_entry {
677 struct list entry;
678 LPWSTR id;
679 struct list children;
682 /* this structure is the leaf */
683 struct resource_data {
684 struct list entry;
685 LANGID lang;
686 DWORD codepage;
687 DWORD cbData;
688 void *lpData;
691 static int resource_strcmp( LPCWSTR a, LPCWSTR b )
693 if ( a == b )
694 return 0;
695 if (HIWORD( a ) && HIWORD( b ) )
696 return lstrcmpW( a, b );
697 /* strings come before ids */
698 if (HIWORD( a ) && !HIWORD( b ))
699 return -1;
700 if (HIWORD( b ) && !HIWORD( a ))
701 return 1;
702 return ( a < b ) ? -1 : 1;
705 static struct resource_dir_entry *find_resource_dir_entry( struct list *dir, LPCWSTR id )
707 struct resource_dir_entry *ent;
709 /* match either IDs or strings */
710 LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
711 if (!resource_strcmp( id, ent->id ))
712 return ent;
714 return NULL;
717 static struct resource_data *find_resource_data( struct list *dir, LANGID lang )
719 struct resource_data *res_data;
721 /* match only languages here */
722 LIST_FOR_EACH_ENTRY( res_data, dir, struct resource_data, entry )
723 if ( lang == res_data->lang )
724 return res_data;
726 return NULL;
729 static void add_resource_dir_entry( struct list *dir, struct resource_dir_entry *resdir )
731 struct resource_dir_entry *ent;
733 LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
735 if (0>resource_strcmp( ent->id, resdir->id ))
736 continue;
738 list_add_before( &ent->entry, &resdir->entry );
739 return;
741 list_add_tail( dir, &resdir->entry );
744 static void add_resource_data_entry( struct list *dir, struct resource_data *resdata )
746 struct resource_data *ent;
748 LIST_FOR_EACH_ENTRY( ent, dir, struct resource_data, entry )
750 if (ent->lang < resdata->lang)
751 continue;
753 list_add_before( &ent->entry, &resdata->entry );
754 return;
756 list_add_tail( dir, &resdata->entry );
759 static LPWSTR res_strdupW( LPCWSTR str )
761 LPWSTR ret;
762 UINT len;
764 if (HIWORD(str) == 0)
765 return (LPWSTR) (UINT_PTR) LOWORD(str);
766 len = (lstrlenW( str ) + 1) * sizeof (WCHAR);
767 ret = HeapAlloc( GetProcessHeap(), 0, len );
768 memcpy( ret, str, len );
769 return ret;
772 static void res_free_str( LPWSTR str )
774 if (HIWORD(str))
775 HeapFree( GetProcessHeap(), 0, str );
778 static BOOL update_add_resource( QUEUEDUPDATES *updates, LPCWSTR Type, LPCWSTR Name,
779 struct resource_data *resdata, BOOL overwrite_existing )
781 struct resource_dir_entry *restype, *resname;
782 struct resource_data *existing;
784 TRACE("%p %s %s %p %d\n", updates,
785 debugstr_w(Type), debugstr_w(Name), resdata, overwrite_existing );
787 restype = find_resource_dir_entry( &updates->root, Type );
788 if (!restype)
790 restype = HeapAlloc( GetProcessHeap(), 0, sizeof *restype );
791 restype->id = res_strdupW( Type );
792 list_init( &restype->children );
793 add_resource_dir_entry( &updates->root, restype );
796 resname = find_resource_dir_entry( &restype->children, Name );
797 if (!resname)
799 resname = HeapAlloc( GetProcessHeap(), 0, sizeof *resname );
800 resname->id = res_strdupW( Name );
801 list_init( &resname->children );
802 add_resource_dir_entry( &restype->children, resname );
806 * If there's an existing resource entry with matching (Type,Name,Language)
807 * it needs to be removed before adding the new data.
809 existing = find_resource_data( &resname->children, resdata->lang );
810 if (existing)
812 if (!overwrite_existing)
813 return TRUE;
814 list_remove( &existing->entry );
815 HeapFree( GetProcessHeap(), 0, existing );
818 add_resource_data_entry( &resname->children, resdata );
820 return TRUE;
823 static struct resource_data *allocate_resource_data( WORD Language, DWORD codepage,
824 LPVOID lpData, DWORD cbData, BOOL copy_data )
826 struct resource_data *resdata;
828 if (!lpData || !cbData)
829 return NULL;
831 resdata = HeapAlloc( GetProcessHeap(), 0, sizeof *resdata + (copy_data ? cbData : 0) );
832 if (resdata)
834 resdata->lang = Language;
835 resdata->codepage = codepage;
836 resdata->cbData = cbData;
837 if (copy_data)
839 resdata->lpData = &resdata[1];
840 memcpy( resdata->lpData, lpData, cbData );
842 else
843 resdata->lpData = lpData;
846 return resdata;
849 static void free_resource_directory( struct list *head, int level )
851 struct list *ptr = NULL;
853 while ((ptr = list_head( head )))
855 list_remove( ptr );
856 if (level)
858 struct resource_dir_entry *ent;
860 ent = LIST_ENTRY( ptr, struct resource_dir_entry, entry );
861 res_free_str( ent->id );
862 free_resource_directory( &ent->children, level - 1 );
863 HeapFree(GetProcessHeap(), 0, ent);
865 else
867 struct resource_data *data;
869 data = LIST_ENTRY( ptr, struct resource_data, entry );
870 HeapFree( GetProcessHeap(), 0, data );
875 static IMAGE_NT_HEADERS *get_nt_header( void *base, DWORD mapping_size )
877 IMAGE_NT_HEADERS *nt;
878 IMAGE_DOS_HEADER *dos;
880 if (mapping_size<sizeof (*dos))
881 return NULL;
883 dos = base;
884 if (dos->e_magic != IMAGE_DOS_SIGNATURE)
885 return NULL;
887 if ((dos->e_lfanew + sizeof (*nt)) > mapping_size)
888 return NULL;
890 nt = (void*) ((BYTE*)base + dos->e_lfanew);
892 if (nt->Signature != IMAGE_NT_SIGNATURE)
893 return NULL;
895 return nt;
898 static IMAGE_SECTION_HEADER *get_section_header( void *base, DWORD mapping_size, DWORD *num_sections )
900 IMAGE_NT_HEADERS *nt;
901 IMAGE_SECTION_HEADER *sec;
902 DWORD section_ofs;
904 nt = get_nt_header( base, mapping_size );
905 if (!nt)
906 return NULL;
908 /* check that we don't go over the end of the file accessing the sections */
909 section_ofs = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + nt->FileHeader.SizeOfOptionalHeader;
910 if ((nt->FileHeader.NumberOfSections * sizeof (*sec) + section_ofs) > mapping_size)
911 return NULL;
913 if (num_sections)
914 *num_sections = nt->FileHeader.NumberOfSections;
916 /* from here we have a valid PE exe to update */
917 return (void*) ((BYTE*)nt + section_ofs);
920 static BOOL check_pe_exe( HANDLE file, QUEUEDUPDATES *updates )
922 const IMAGE_NT_HEADERS *nt;
923 const IMAGE_SECTION_HEADER *sec;
924 BOOL ret = FALSE;
925 HANDLE mapping;
926 DWORD mapping_size, num_sections = 0;
927 void *base = NULL;
929 mapping_size = GetFileSize( file, NULL );
931 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
932 if (!mapping)
933 goto done;
935 base = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, mapping_size );
936 if (!base)
937 goto done;
939 nt = get_nt_header( base, mapping_size );
940 if (!nt)
941 goto done;
943 TRACE("resources: %08x %08x\n",
944 nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
945 nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
947 sec = get_section_header( base, mapping_size, &num_sections );
948 if (!sec)
949 goto done;
951 ret = TRUE;
953 done:
954 if (base)
955 UnmapViewOfFile( base );
956 if (mapping)
957 CloseHandle( mapping );
959 return ret;
962 struct resource_size_info {
963 DWORD types_ofs;
964 DWORD names_ofs;
965 DWORD langs_ofs;
966 DWORD data_entry_ofs;
967 DWORD strings_ofs;
968 DWORD data_ofs;
969 DWORD total_size;
972 struct mapping_info {
973 HANDLE file;
974 HANDLE mapping;
975 void *base;
976 DWORD size;
977 BOOL read_write;
980 static const IMAGE_SECTION_HEADER *section_from_rva( void *base, DWORD mapping_size, DWORD rva )
982 const IMAGE_SECTION_HEADER *sec;
983 DWORD num_sections = 0;
984 int i;
986 sec = get_section_header( base, mapping_size, &num_sections );
987 if (!sec)
988 return NULL;
990 for (i=num_sections-1; i>=0; i--)
992 if (sec[i].VirtualAddress <= rva &&
993 rva <= (DWORD)sec[i].VirtualAddress + sec[i].SizeOfRawData)
995 return &sec[i];
999 return NULL;
1002 static void *address_from_rva( void *base, DWORD mapping_size, DWORD rva, DWORD len )
1004 const IMAGE_SECTION_HEADER *sec;
1006 sec = section_from_rva( base, mapping_size, rva );
1007 if (!sec)
1008 return NULL;
1010 if (rva + len <= (DWORD)sec->VirtualAddress + sec->SizeOfRawData)
1011 return (void*)((LPBYTE) base + (sec->PointerToRawData + rva - sec->VirtualAddress));
1013 return NULL;
1016 static LPWSTR resource_dup_string( const IMAGE_RESOURCE_DIRECTORY *root, const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry )
1018 const IMAGE_RESOURCE_DIR_STRING_U* string;
1019 LPWSTR s;
1021 if (!entry->u1.s1.NameIsString)
1022 return UIntToPtr(entry->u1.s2.Id);
1024 string = (const IMAGE_RESOURCE_DIR_STRING_U*) (((const char *)root) + entry->u1.s1.NameOffset);
1025 s = HeapAlloc(GetProcessHeap(), 0, (string->Length + 1)*sizeof (WCHAR) );
1026 memcpy( s, string->NameString, (string->Length + 1)*sizeof (WCHAR) );
1027 s[string->Length] = 0;
1029 return s;
1032 /* this function is based on the code in winedump's pe.c */
1033 static BOOL enumerate_mapped_resources( QUEUEDUPDATES *updates,
1034 void *base, DWORD mapping_size,
1035 const IMAGE_RESOURCE_DIRECTORY *root )
1037 const IMAGE_RESOURCE_DIRECTORY *namedir, *langdir;
1038 const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
1039 const IMAGE_RESOURCE_DATA_ENTRY *data;
1040 DWORD i, j, k;
1042 TRACE("version (%d.%d) %d named %d id entries\n",
1043 root->MajorVersion, root->MinorVersion, root->NumberOfNamedEntries, root->NumberOfIdEntries);
1045 for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
1047 LPWSTR Type;
1049 e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
1051 Type = resource_dup_string( root, e1 );
1053 namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
1054 for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
1056 LPWSTR Name;
1058 e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
1060 Name = resource_dup_string( root, e2 );
1062 langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
1063 for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
1065 LANGID Lang;
1066 void *p;
1067 struct resource_data *resdata;
1069 e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
1071 Lang = e3->u1.s2.Id;
1073 data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
1075 p = address_from_rva( base, mapping_size, data->OffsetToData, data->Size );
1077 resdata = allocate_resource_data( Lang, data->CodePage, p, data->Size, FALSE );
1078 if (resdata)
1079 update_add_resource( updates, Type, Name, resdata, FALSE );
1081 res_free_str( Name );
1083 res_free_str( Type );
1086 return TRUE;
1089 static BOOL read_mapped_resources( QUEUEDUPDATES *updates, void *base, DWORD mapping_size )
1091 const IMAGE_RESOURCE_DIRECTORY *root;
1092 const IMAGE_NT_HEADERS *nt;
1093 const IMAGE_SECTION_HEADER *sec;
1094 DWORD num_sections = 0, i;
1096 nt = get_nt_header( base, mapping_size );
1097 if (!nt)
1098 return FALSE;
1100 sec = get_section_header( base, mapping_size, &num_sections );
1101 if (!sec)
1102 return FALSE;
1104 for (i=0; i<num_sections; i++)
1105 if (!memcmp(sec[i].Name, ".rsrc", 6))
1106 break;
1108 if (i == num_sections)
1109 return TRUE;
1111 /* check the resource data is inside the mapping */
1112 if (sec[i].PointerToRawData > mapping_size ||
1113 (sec[i].PointerToRawData + sec[i].SizeOfRawData) > mapping_size)
1114 return TRUE;
1116 TRACE("found .rsrc at %08x, size %08x\n", sec[i].PointerToRawData, sec[i].SizeOfRawData);
1118 if (!sec[i].PointerToRawData || sec[i].SizeOfRawData < sizeof(IMAGE_RESOURCE_DIRECTORY))
1119 return TRUE;
1121 root = (void*) ((BYTE*)base + sec[i].PointerToRawData);
1122 enumerate_mapped_resources( updates, base, mapping_size, root );
1124 return TRUE;
1127 static BOOL map_file_into_memory( struct mapping_info *mi )
1129 DWORD page_attr, perm;
1131 if (mi->read_write)
1133 page_attr = PAGE_READWRITE;
1134 perm = FILE_MAP_WRITE | FILE_MAP_READ;
1136 else
1138 page_attr = PAGE_READONLY;
1139 perm = FILE_MAP_READ;
1142 mi->mapping = CreateFileMappingW( mi->file, NULL, page_attr, 0, 0, NULL );
1143 if (!mi->mapping)
1144 return FALSE;
1146 mi->base = MapViewOfFile( mi->mapping, perm, 0, 0, mi->size );
1147 if (!mi->base)
1148 return FALSE;
1150 return TRUE;
1153 static BOOL unmap_file_from_memory( struct mapping_info *mi )
1155 if (mi->base)
1156 UnmapViewOfFile( mi->base );
1157 mi->base = NULL;
1158 if (mi->mapping)
1159 CloseHandle( mi->mapping );
1160 mi->mapping = NULL;
1161 return TRUE;
1164 static void destroy_mapping( struct mapping_info *mi )
1166 if (!mi)
1167 return;
1168 unmap_file_from_memory( mi );
1169 if (mi->file)
1170 CloseHandle( mi->file );
1171 HeapFree( GetProcessHeap(), 0, mi );
1174 static struct mapping_info *create_mapping( LPCWSTR name, BOOL rw )
1176 struct mapping_info *mi;
1178 mi = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *mi );
1179 if (!mi)
1180 return NULL;
1182 mi->read_write = rw;
1184 mi->file = CreateFileW( name, GENERIC_READ | (rw ? GENERIC_WRITE : 0),
1185 0, NULL, OPEN_EXISTING, 0, 0 );
1187 if (mi->file != INVALID_HANDLE_VALUE)
1189 mi->size = GetFileSize( mi->file, NULL );
1191 if (map_file_into_memory( mi ))
1192 return mi;
1195 unmap_file_from_memory( mi );
1196 HeapFree( GetProcessHeap(), 0, mi );
1198 return NULL;
1201 static BOOL resize_mapping( struct mapping_info *mi, DWORD new_size )
1203 if (!unmap_file_from_memory( mi ))
1204 return FALSE;
1206 /* change the file size */
1207 SetFilePointer( mi->file, new_size, NULL, FILE_BEGIN );
1208 if (!SetEndOfFile( mi->file ))
1210 ERR("failed to set file size to %08x\n", new_size );
1211 return FALSE;
1214 mi->size = new_size;
1216 return map_file_into_memory( mi );
1219 static void get_resource_sizes( QUEUEDUPDATES *updates, struct resource_size_info *si )
1221 struct resource_dir_entry *types, *names;
1222 struct resource_data *data;
1223 DWORD num_types = 0, num_names = 0, num_langs = 0, strings_size = 0, data_size = 0;
1225 memset( si, 0, sizeof *si );
1227 LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
1229 num_types++;
1230 if (HIWORD( types->id ))
1231 strings_size += sizeof (WORD) + lstrlenW( types->id )*sizeof (WCHAR);
1233 LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
1235 num_names++;
1237 if (HIWORD( names->id ))
1238 strings_size += sizeof (WORD) + lstrlenW( names->id )*sizeof (WCHAR);
1240 LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
1242 num_langs++;
1243 data_size += (data->cbData + 3) & ~3;
1248 /* names are at the end of the types */
1249 si->names_ofs = sizeof (IMAGE_RESOURCE_DIRECTORY) +
1250 num_types * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1252 /* language directories are at the end of the names */
1253 si->langs_ofs = si->names_ofs +
1254 num_types * sizeof (IMAGE_RESOURCE_DIRECTORY) +
1255 num_names * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1257 si->data_entry_ofs = si->langs_ofs +
1258 num_names * sizeof (IMAGE_RESOURCE_DIRECTORY) +
1259 num_langs * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1261 si->strings_ofs = si->data_entry_ofs +
1262 num_langs * sizeof (IMAGE_RESOURCE_DATA_ENTRY);
1264 si->data_ofs = si->strings_ofs + ((strings_size + 3) & ~3);
1266 si->total_size = si->data_ofs + data_size;
1268 TRACE("names %08x langs %08x data entries %08x strings %08x data %08x total %08x\n",
1269 si->names_ofs, si->langs_ofs, si->data_entry_ofs,
1270 si->strings_ofs, si->data_ofs, si->total_size);
1273 static void res_write_padding( BYTE *res_base, DWORD size )
1275 static const BYTE pad[] = {
1276 'P','A','D','D','I','N','G','X','X','P','A','D','D','I','N','G' };
1277 DWORD i;
1279 for ( i = 0; i < size / sizeof pad; i++ )
1280 memcpy( &res_base[i*sizeof pad], pad, sizeof pad );
1281 memcpy( &res_base[i*sizeof pad], pad, size%sizeof pad );
1284 static BOOL write_resources( QUEUEDUPDATES *updates, LPBYTE base, struct resource_size_info *si, DWORD rva )
1286 struct resource_dir_entry *types, *names;
1287 struct resource_data *data;
1288 IMAGE_RESOURCE_DIRECTORY *root;
1290 TRACE("%p %p %p %08x\n", updates, base, si, rva );
1292 memset( base, 0, si->total_size );
1294 /* the root entry always exists */
1295 root = (IMAGE_RESOURCE_DIRECTORY*) base;
1296 memset( root, 0, sizeof *root );
1297 root->MajorVersion = 4;
1298 si->types_ofs = sizeof *root;
1299 LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
1301 IMAGE_RESOURCE_DIRECTORY_ENTRY *e1;
1302 IMAGE_RESOURCE_DIRECTORY *namedir;
1304 e1 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->types_ofs];
1305 memset( e1, 0, sizeof *e1 );
1306 if (HIWORD( types->id ))
1308 WCHAR *strings;
1309 DWORD len;
1311 root->NumberOfNamedEntries++;
1312 e1->u1.s1.NameIsString = 1;
1313 e1->u1.s1.NameOffset = si->strings_ofs;
1315 strings = (WCHAR*) &base[si->strings_ofs];
1316 len = lstrlenW( types->id );
1317 strings[0] = len;
1318 memcpy( &strings[1], types->id, len * sizeof (WCHAR) );
1319 si->strings_ofs += (len + 1) * sizeof (WCHAR);
1321 else
1323 root->NumberOfIdEntries++;
1324 e1->u1.s2.Id = LOWORD( types->id );
1326 e1->u2.s3.OffsetToDirectory = si->names_ofs;
1327 e1->u2.s3.DataIsDirectory = TRUE;
1328 si->types_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1330 namedir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->names_ofs];
1331 memset( namedir, 0, sizeof *namedir );
1332 namedir->MajorVersion = 4;
1333 si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
1335 LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
1337 IMAGE_RESOURCE_DIRECTORY_ENTRY *e2;
1338 IMAGE_RESOURCE_DIRECTORY *langdir;
1340 e2 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->names_ofs];
1341 memset( e2, 0, sizeof *e2 );
1342 if (HIWORD( names->id ))
1344 WCHAR *strings;
1345 DWORD len;
1347 namedir->NumberOfNamedEntries++;
1348 e2->u1.s1.NameIsString = 1;
1349 e2->u1.s1.NameOffset = si->strings_ofs;
1351 strings = (WCHAR*) &base[si->strings_ofs];
1352 len = lstrlenW( names->id );
1353 strings[0] = len;
1354 memcpy( &strings[1], names->id, len * sizeof (WCHAR) );
1355 si->strings_ofs += (len + 1) * sizeof (WCHAR);
1357 else
1359 namedir->NumberOfIdEntries++;
1360 e2->u1.s2.Id = LOWORD( names->id );
1362 e2->u2.s3.OffsetToDirectory = si->langs_ofs;
1363 e2->u2.s3.DataIsDirectory = TRUE;
1364 si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1366 langdir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->langs_ofs];
1367 memset( langdir, 0, sizeof *langdir );
1368 langdir->MajorVersion = 4;
1369 si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
1371 LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
1373 IMAGE_RESOURCE_DIRECTORY_ENTRY *e3;
1374 IMAGE_RESOURCE_DATA_ENTRY *de;
1375 int pad_size;
1377 e3 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->langs_ofs];
1378 memset( e3, 0, sizeof *e3 );
1379 langdir->NumberOfIdEntries++;
1380 e3->u1.s2.Id = LOWORD( data->lang );
1381 e3->u2.OffsetToData = si->data_entry_ofs;
1383 si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1385 /* write out all the data entries */
1386 de = (IMAGE_RESOURCE_DATA_ENTRY*) &base[si->data_entry_ofs];
1387 memset( de, 0, sizeof *de );
1388 de->OffsetToData = si->data_ofs + rva;
1389 de->Size = data->cbData;
1390 de->CodePage = data->codepage;
1391 si->data_entry_ofs += sizeof (IMAGE_RESOURCE_DATA_ENTRY);
1393 /* write out the resource data */
1394 memcpy( &base[si->data_ofs], data->lpData, data->cbData );
1395 si->data_ofs += data->cbData;
1397 pad_size = (-si->data_ofs)&3;
1398 res_write_padding( &base[si->data_ofs], pad_size );
1399 si->data_ofs += pad_size;
1404 return TRUE;
1408 * FIXME:
1409 * Assumes that the resources are in .rsrc
1410 * and .rsrc is the last section in the file.
1411 * Not sure whether updating resources will other cases on Windows.
1412 * If the resources lie in a section containing other data,
1413 * resizing that section could possibly cause trouble.
1414 * If the section with the resources isn't last, the remaining
1415 * sections need to be moved down in the file, and the section header
1416 * would need to be adjusted.
1417 * If we needed to add a section, what would we name it?
1418 * If we needed to add a section and there wasn't space in the file
1419 * header, how would that work?
1420 * Seems that at least some of these cases can't be handled properly.
1422 static IMAGE_SECTION_HEADER *get_resource_section( void *base, DWORD mapping_size )
1424 IMAGE_SECTION_HEADER *sec;
1425 IMAGE_NT_HEADERS *nt;
1426 DWORD i, num_sections = 0;
1428 nt = get_nt_header( base, mapping_size );
1429 if (!nt)
1430 return NULL;
1432 sec = get_section_header( base, mapping_size, &num_sections );
1433 if (!sec)
1434 return NULL;
1436 /* find the resources section */
1437 for (i=0; i<num_sections; i++)
1438 if (!memcmp(sec[i].Name, ".rsrc", 6))
1439 break;
1441 if (i == num_sections)
1443 FIXME(".rsrc doesn't exist\n");
1444 return NULL;
1447 return &sec[i];
1450 static DWORD get_init_data_size( void *base, DWORD mapping_size )
1452 DWORD i, sz = 0, num_sections = 0;
1453 IMAGE_SECTION_HEADER *s;
1455 s = get_section_header( base, mapping_size, &num_sections );
1457 for (i=0; i<num_sections; i++)
1458 if (s[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
1459 sz += s[i].SizeOfRawData;
1461 TRACE("size = %08x\n", sz);
1463 return sz;
1466 static BOOL write_raw_resources( QUEUEDUPDATES *updates )
1468 static const WCHAR prefix[] = { 'r','e','s','u',0 };
1469 WCHAR tempdir[MAX_PATH], tempfile[MAX_PATH];
1470 DWORD mapping_size, section_size, old_size;
1471 BOOL ret = FALSE;
1472 IMAGE_SECTION_HEADER *sec;
1473 IMAGE_NT_HEADERS *nt;
1474 struct resource_size_info res_size;
1475 BYTE *res_base;
1476 struct mapping_info *read_map = NULL, *write_map = NULL;
1478 /* copy the exe to a temp file then update the temp file... */
1479 tempdir[0] = 0;
1480 if (!GetTempPathW( MAX_PATH, tempdir ))
1481 return ret;
1483 if (!GetTempFileNameW( tempdir, prefix, 0, tempfile ))
1484 return ret;
1486 if (!CopyFileW( updates->pFileName, tempfile, FALSE ))
1487 goto done;
1489 TRACE("tempfile %s\n", debugstr_w(tempfile));
1491 if (!updates->bDeleteExistingResources)
1493 read_map = create_mapping( updates->pFileName, FALSE );
1494 if (!read_map)
1495 goto done;
1497 ret = read_mapped_resources( updates, read_map->base, read_map->size );
1498 if (!ret)
1500 ERR("failed to read existing resources\n");
1501 goto done;
1505 write_map = create_mapping( tempfile, TRUE );
1506 if (!write_map)
1507 goto done;
1509 nt = get_nt_header( write_map->base, write_map->size );
1510 if (!nt)
1511 goto done;
1513 if (nt->OptionalHeader.SectionAlignment <= 0)
1515 ERR("invalid section alignment %04x\n", nt->OptionalHeader.SectionAlignment);
1516 goto done;
1519 sec = get_resource_section( write_map->base, write_map->size );
1520 if (!sec)
1521 goto done;
1523 if (!sec->PointerToRawData) /* empty section */
1525 sec->PointerToRawData = write_map->size;
1526 sec->SizeOfRawData = 0;
1528 else if ((sec->SizeOfRawData + sec->PointerToRawData) != write_map->size)
1530 FIXME(".rsrc isn't at the end of the image %08x + %08x != %08x for %s\n",
1531 sec->SizeOfRawData, sec->PointerToRawData, write_map->size, debugstr_w(updates->pFileName));
1532 goto done;
1535 TRACE("before .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1537 get_resource_sizes( updates, &res_size );
1539 /* round up the section size */
1540 section_size = res_size.total_size;
1541 section_size += (-section_size) % nt->OptionalHeader.SectionAlignment;
1543 mapping_size = sec->PointerToRawData + section_size;
1545 TRACE("requires %08x (%08x) bytes\n", res_size.total_size, section_size );
1547 /* check if the file size needs to be changed */
1548 if (section_size != sec->SizeOfRawData)
1550 old_size = write_map->size;
1552 TRACE("file size %08x -> %08x\n", old_size, mapping_size);
1554 /* unmap the file before changing the file size */
1555 ret = resize_mapping( write_map, mapping_size );
1557 /* get the pointers again - they might be different after remapping */
1558 nt = get_nt_header( write_map->base, mapping_size );
1559 if (!nt)
1561 ERR("couldn't get NT header\n");
1562 goto done;
1565 sec = get_resource_section( write_map->base, mapping_size );
1566 if (!sec)
1567 goto done;
1569 /* adjust the PE header information */
1570 nt->OptionalHeader.SizeOfImage += (mapping_size - old_size);
1571 sec->SizeOfRawData = section_size;
1572 sec->Misc.VirtualSize = section_size;
1573 nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = res_size.total_size;
1574 nt->OptionalHeader.SizeOfInitializedData = get_init_data_size( write_map->base, mapping_size );
1577 res_base = (LPBYTE) write_map->base + sec->PointerToRawData;
1579 TRACE("base = %p offset = %08x\n", write_map->base, sec->PointerToRawData);
1581 ret = write_resources( updates, res_base, &res_size, sec->VirtualAddress );
1583 res_write_padding( res_base + res_size.total_size, section_size - res_size.total_size );
1585 TRACE("after .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1587 done:
1588 destroy_mapping( read_map );
1589 destroy_mapping( write_map );
1591 if (ret)
1592 ret = CopyFileW( tempfile, updates->pFileName, FALSE );
1594 DeleteFileW( tempfile );
1596 return ret;
1599 /***********************************************************************
1600 * BeginUpdateResourceW (KERNEL32.@)
1602 HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources )
1604 QUEUEDUPDATES *updates = NULL;
1605 HANDLE hUpdate, file, ret = NULL;
1607 TRACE("%s, %d\n", debugstr_w(pFileName), bDeleteExistingResources);
1609 hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES));
1610 if (!hUpdate)
1611 return ret;
1613 updates = GlobalLock(hUpdate);
1614 if (updates)
1616 list_init( &updates->root );
1617 updates->bDeleteExistingResources = bDeleteExistingResources;
1618 updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
1619 if (updates->pFileName)
1621 lstrcpyW(updates->pFileName, pFileName);
1623 file = CreateFileW( pFileName, GENERIC_READ | GENERIC_WRITE,
1624 0, NULL, OPEN_EXISTING, 0, 0 );
1626 /* if resources are deleted, only the file's presence is checked */
1627 if (file != INVALID_HANDLE_VALUE &&
1628 (bDeleteExistingResources || check_pe_exe( file, updates )))
1629 ret = hUpdate;
1630 else
1631 HeapFree( GetProcessHeap(), 0, updates->pFileName );
1633 CloseHandle( file );
1635 GlobalUnlock(hUpdate);
1638 if (!ret)
1639 GlobalFree(hUpdate);
1641 return ret;
1645 /***********************************************************************
1646 * BeginUpdateResourceA (KERNEL32.@)
1648 HANDLE WINAPI BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources )
1650 UNICODE_STRING FileNameW;
1651 HANDLE ret;
1652 RtlCreateUnicodeStringFromAsciiz(&FileNameW, pFileName);
1653 ret = BeginUpdateResourceW(FileNameW.Buffer, bDeleteExistingResources);
1654 RtlFreeUnicodeString(&FileNameW);
1655 return ret;
1659 /***********************************************************************
1660 * EndUpdateResourceW (KERNEL32.@)
1662 BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
1664 QUEUEDUPDATES *updates;
1665 BOOL ret;
1667 TRACE("%p %d\n", hUpdate, fDiscard);
1669 updates = GlobalLock(hUpdate);
1670 if (!updates)
1671 return FALSE;
1673 ret = fDiscard || write_raw_resources( updates );
1675 free_resource_directory( &updates->root, 2 );
1677 HeapFree( GetProcessHeap(), 0, updates->pFileName );
1678 GlobalUnlock( hUpdate );
1679 GlobalFree( hUpdate );
1681 return ret;
1685 /***********************************************************************
1686 * EndUpdateResourceA (KERNEL32.@)
1688 BOOL WINAPI EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard )
1690 return EndUpdateResourceW(hUpdate, fDiscard);
1694 /***********************************************************************
1695 * UpdateResourceW (KERNEL32.@)
1697 BOOL WINAPI UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
1698 WORD wLanguage, LPVOID lpData, DWORD cbData)
1700 QUEUEDUPDATES *updates;
1701 BOOL ret = FALSE;
1703 TRACE("%p %s %s %08x %p %d\n", hUpdate,
1704 debugstr_w(lpType), debugstr_w(lpName), wLanguage, lpData, cbData);
1706 updates = GlobalLock(hUpdate);
1707 if (updates)
1709 struct resource_data *data;
1710 data = allocate_resource_data( wLanguage, 0, lpData, cbData, TRUE );
1711 if (data)
1712 ret = update_add_resource( updates, lpType, lpName, data, TRUE );
1713 GlobalUnlock(hUpdate);
1715 return ret;
1719 /***********************************************************************
1720 * UpdateResourceA (KERNEL32.@)
1722 BOOL WINAPI UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
1723 WORD wLanguage, LPVOID lpData, DWORD cbData)
1725 BOOL ret;
1726 UNICODE_STRING TypeW;
1727 UNICODE_STRING NameW;
1728 if(!HIWORD(lpType))
1729 TypeW.Buffer = ULongToPtr(LOWORD(lpType));
1730 else
1731 RtlCreateUnicodeStringFromAsciiz(&TypeW, lpType);
1732 if(!HIWORD(lpName))
1733 NameW.Buffer = ULongToPtr(LOWORD(lpName));
1734 else
1735 RtlCreateUnicodeStringFromAsciiz(&NameW, lpName);
1736 ret = UpdateResourceW(hUpdate, TypeW.Buffer, NameW.Buffer, wLanguage, lpData, cbData);
1737 if(HIWORD(lpType)) RtlFreeUnicodeString(&TypeW);
1738 if(HIWORD(lpName)) RtlFreeUnicodeString(&NameW);
1739 return ret;