msvcrt/tests: Remove a space before a '\n'.
[wine/gsoc-2012-control.git] / dlls / kernel32 / resource.c
blobf49ea2400d2e26762e7be13ab8d875673ee6b58f
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 for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
383 if (et[i].u1.s1.NameIsString)
385 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
386 newlen = WideCharToMultiByte(CP_ACP, 0, str->NameString, str->Length, NULL, 0, NULL, NULL);
387 if (newlen + 1 > len)
389 len = newlen + 1;
390 HeapFree( GetProcessHeap(), 0, name );
391 if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
393 ret = FALSE;
394 break;
397 WideCharToMultiByte( CP_ACP, 0, str->NameString, str->Length, name, len, NULL, NULL );
398 name[newlen] = 0;
399 ret = lpfun(hmod,type,name,lparam);
401 else
403 ret = lpfun( hmod, type, UIntToPtr(et[i].u1.s2.Id), lparam );
405 if (!ret) break;
407 done:
408 HeapFree( GetProcessHeap(), 0, name );
409 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
410 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
411 return ret;
415 /**********************************************************************
416 * EnumResourceNamesW (KERNEL32.@)
418 BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG_PTR lparam )
420 int i, len = 0;
421 BOOL ret = FALSE;
422 LPWSTR name = NULL;
423 NTSTATUS status;
424 UNICODE_STRING typeW;
425 LDR_RESOURCE_INFO info;
426 const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
427 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
428 const IMAGE_RESOURCE_DIR_STRING_U *str;
430 TRACE( "%p %s %p %lx\n", hmod, debugstr_w(type), lpfun, lparam );
432 if (!hmod) hmod = GetModuleHandleW( NULL );
433 typeW.Buffer = NULL;
434 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
435 goto done;
436 if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
437 goto done;
438 info.Type = (ULONG_PTR)typeW.Buffer;
439 if ((status = LdrFindResourceDirectory_U( hmod, &info, 1, &resdir )) != STATUS_SUCCESS)
440 goto done;
442 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
443 for (i = 0; i < resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries; i++)
445 if (et[i].u1.s1.NameIsString)
447 str = (const IMAGE_RESOURCE_DIR_STRING_U *)((const BYTE *)basedir + et[i].u1.s1.NameOffset);
448 if (str->Length + 1 > len)
450 len = str->Length + 1;
451 HeapFree( GetProcessHeap(), 0, name );
452 if (!(name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
454 ret = FALSE;
455 break;
458 memcpy(name, str->NameString, str->Length * sizeof (WCHAR));
459 name[str->Length] = 0;
460 ret = lpfun(hmod,type,name,lparam);
462 else
464 ret = lpfun( hmod, type, UIntToPtr(et[i].u1.s2.Id), lparam );
466 if (!ret) break;
468 done:
469 HeapFree( GetProcessHeap(), 0, name );
470 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
471 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
472 return ret;
476 /**********************************************************************
477 * EnumResourceLanguagesA (KERNEL32.@)
479 BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
480 ENUMRESLANGPROCA lpfun, LONG_PTR lparam )
482 int i;
483 BOOL ret = FALSE;
484 NTSTATUS status;
485 UNICODE_STRING typeW, nameW;
486 LDR_RESOURCE_INFO info;
487 const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
488 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
490 TRACE( "%p %s %s %p %lx\n", hmod, debugstr_a(type), debugstr_a(name), lpfun, lparam );
492 if (!hmod) hmod = GetModuleHandleA( NULL );
493 typeW.Buffer = nameW.Buffer = NULL;
494 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
495 goto done;
496 if ((status = get_res_nameA( type, &typeW )) != STATUS_SUCCESS)
497 goto done;
498 if ((status = get_res_nameA( name, &nameW )) != STATUS_SUCCESS)
499 goto done;
500 info.Type = (ULONG_PTR)typeW.Buffer;
501 info.Name = (ULONG_PTR)nameW.Buffer;
502 if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
503 goto done;
505 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
506 for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
508 ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
509 if (!ret) break;
511 done:
512 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
513 if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
514 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
515 return ret;
519 /**********************************************************************
520 * EnumResourceLanguagesW (KERNEL32.@)
522 BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
523 ENUMRESLANGPROCW lpfun, LONG_PTR lparam )
525 int i;
526 BOOL ret = FALSE;
527 NTSTATUS status;
528 UNICODE_STRING typeW, nameW;
529 LDR_RESOURCE_INFO info;
530 const IMAGE_RESOURCE_DIRECTORY *basedir, *resdir;
531 const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
533 TRACE( "%p %s %s %p %lx\n", hmod, debugstr_w(type), debugstr_w(name), lpfun, lparam );
535 if (!hmod) hmod = GetModuleHandleW( NULL );
536 typeW.Buffer = nameW.Buffer = NULL;
537 if ((status = LdrFindResourceDirectory_U( hmod, NULL, 0, &basedir )) != STATUS_SUCCESS)
538 goto done;
539 if ((status = get_res_nameW( type, &typeW )) != STATUS_SUCCESS)
540 goto done;
541 if ((status = get_res_nameW( name, &nameW )) != STATUS_SUCCESS)
542 goto done;
543 info.Type = (ULONG_PTR)typeW.Buffer;
544 info.Name = (ULONG_PTR)nameW.Buffer;
545 if ((status = LdrFindResourceDirectory_U( hmod, &info, 2, &resdir )) != STATUS_SUCCESS)
546 goto done;
548 et = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(resdir + 1);
549 for (i = 0; i < resdir->NumberOfNamedEntries + resdir->NumberOfIdEntries; i++)
551 ret = lpfun( hmod, type, name, et[i].u1.s2.Id, lparam );
552 if (!ret) break;
554 done:
555 if (HIWORD(typeW.Buffer)) HeapFree( GetProcessHeap(), 0, typeW.Buffer );
556 if (HIWORD(nameW.Buffer)) HeapFree( GetProcessHeap(), 0, nameW.Buffer );
557 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
558 return ret;
562 /**********************************************************************
563 * LoadResource (KERNEL32.@)
565 HGLOBAL WINAPI LoadResource( HINSTANCE hModule, HRSRC hRsrc )
567 NTSTATUS status;
568 void *ret = NULL;
570 TRACE( "%p %p\n", hModule, hRsrc );
572 if (hModule && !HIWORD(hModule))
573 /* FIXME: should convert return to 32-bit resource */
574 return HGLOBAL_32( LoadResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) ) );
576 if (!hRsrc) return 0;
577 if (!hModule) hModule = GetModuleHandleA( NULL );
578 status = LdrAccessResource( hModule, (IMAGE_RESOURCE_DATA_ENTRY *)hRsrc, &ret, NULL );
579 if (status != STATUS_SUCCESS) SetLastError( RtlNtStatusToDosError(status) );
580 return ret;
584 /**********************************************************************
585 * LockResource (KERNEL32.@)
587 LPVOID WINAPI LockResource( HGLOBAL handle )
589 TRACE("(%p)\n", handle );
591 if (HIWORD( handle )) /* 32-bit memory handle */
592 return handle;
594 /* 16-bit memory handle */
595 return LockResource16( HGLOBAL_16(handle) );
599 /**********************************************************************
600 * FreeResource (KERNEL32.@)
602 BOOL WINAPI FreeResource( HGLOBAL handle )
604 if (HIWORD(handle)) return 0; /* 32-bit memory handle: nothing to do */
605 return FreeResource16( HGLOBAL_16(handle) );
609 /**********************************************************************
610 * SizeofResource (KERNEL32.@)
612 DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
614 if (hModule && !HIWORD(hModule))
615 return SizeofResource16( HMODULE_16(hModule), HRSRC_16(hRsrc) );
617 if (!hRsrc) return 0;
618 return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
622 * Data structure for updating resources.
623 * Type/Name/Language is a keyset for accessing resource data.
625 * QUEUEDUPDATES (root) ->
626 * list of struct resource_dir_entry (Type) ->
627 * list of struct resource_dir_entry (Name) ->
628 * list of struct resource_data Language + Data
631 typedef struct
633 LPWSTR pFileName;
634 BOOL bDeleteExistingResources;
635 struct list root;
636 } QUEUEDUPDATES;
638 /* this structure is shared for types and names */
639 struct resource_dir_entry {
640 struct list entry;
641 LPWSTR id;
642 struct list children;
645 /* this structure is the leaf */
646 struct resource_data {
647 struct list entry;
648 LANGID lang;
649 DWORD codepage;
650 DWORD cbData;
651 void *lpData;
654 static int resource_strcmp( LPCWSTR a, LPCWSTR b )
656 if ( a == b )
657 return 0;
658 if (HIWORD( a ) && HIWORD( b ) )
659 return lstrcmpW( a, b );
660 /* strings come before ids */
661 if (HIWORD( a ) && !HIWORD( b ))
662 return -1;
663 if (HIWORD( b ) && !HIWORD( a ))
664 return 1;
665 return ( a < b ) ? -1 : 1;
668 static struct resource_dir_entry *find_resource_dir_entry( struct list *dir, LPCWSTR id )
670 struct resource_dir_entry *ent;
672 /* match either IDs or strings */
673 LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
674 if (!resource_strcmp( id, ent->id ))
675 return ent;
677 return NULL;
680 static struct resource_data *find_resource_data( struct list *dir, LANGID lang )
682 struct resource_data *res_data;
684 /* match only languages here */
685 LIST_FOR_EACH_ENTRY( res_data, dir, struct resource_data, entry )
686 if ( lang == res_data->lang )
687 return res_data;
689 return NULL;
692 static void add_resource_dir_entry( struct list *dir, struct resource_dir_entry *resdir )
694 struct resource_dir_entry *ent;
696 LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
698 if (0>resource_strcmp( ent->id, resdir->id ))
699 continue;
701 list_add_before( &ent->entry, &resdir->entry );
702 return;
704 list_add_tail( dir, &resdir->entry );
707 static void add_resource_data_entry( struct list *dir, struct resource_data *resdata )
709 struct resource_data *ent;
711 LIST_FOR_EACH_ENTRY( ent, dir, struct resource_data, entry )
713 if (ent->lang < resdata->lang)
714 continue;
716 list_add_before( &ent->entry, &resdata->entry );
717 return;
719 list_add_tail( dir, &resdata->entry );
722 static LPWSTR res_strdupW( LPCWSTR str )
724 LPWSTR ret;
725 UINT len;
727 if (HIWORD(str) == 0)
728 return (LPWSTR) (UINT_PTR) LOWORD(str);
729 len = (lstrlenW( str ) + 1) * sizeof (WCHAR);
730 ret = HeapAlloc( GetProcessHeap(), 0, len );
731 memcpy( ret, str, len );
732 return ret;
735 static void res_free_str( LPWSTR str )
737 if (HIWORD(str))
738 HeapFree( GetProcessHeap(), 0, str );
741 static BOOL update_add_resource( QUEUEDUPDATES *updates, LPCWSTR Type, LPCWSTR Name,
742 struct resource_data *resdata, BOOL overwrite_existing )
744 struct resource_dir_entry *restype, *resname;
745 struct resource_data *existing;
747 TRACE("%p %s %s %p %d\n", updates,
748 debugstr_w(Type), debugstr_w(Name), resdata, overwrite_existing );
750 restype = find_resource_dir_entry( &updates->root, Type );
751 if (!restype)
753 restype = HeapAlloc( GetProcessHeap(), 0, sizeof *restype );
754 restype->id = res_strdupW( Type );
755 list_init( &restype->children );
756 add_resource_dir_entry( &updates->root, restype );
759 resname = find_resource_dir_entry( &restype->children, Name );
760 if (!resname)
762 resname = HeapAlloc( GetProcessHeap(), 0, sizeof *resname );
763 resname->id = res_strdupW( Name );
764 list_init( &resname->children );
765 add_resource_dir_entry( &restype->children, resname );
769 * If there's an existing resource entry with matching (Type,Name,Language)
770 * it needs to be removed before adding the new data.
772 existing = find_resource_data( &resname->children, resdata->lang );
773 if (existing)
775 if (!overwrite_existing)
776 return TRUE;
777 list_remove( &existing->entry );
778 HeapFree( GetProcessHeap(), 0, existing );
781 add_resource_data_entry( &resname->children, resdata );
783 return TRUE;
786 static struct resource_data *allocate_resource_data( WORD Language, DWORD codepage,
787 LPVOID lpData, DWORD cbData, BOOL copy_data )
789 struct resource_data *resdata;
791 if (!lpData || !cbData)
792 return NULL;
794 resdata = HeapAlloc( GetProcessHeap(), 0, sizeof *resdata + (copy_data ? cbData : 0) );
795 if (resdata)
797 resdata->lang = Language;
798 resdata->codepage = codepage;
799 resdata->cbData = cbData;
800 if (copy_data)
802 resdata->lpData = &resdata[1];
803 memcpy( resdata->lpData, lpData, cbData );
805 else
806 resdata->lpData = lpData;
809 return resdata;
812 static void free_resource_directory( struct list *head, int level )
814 struct list *ptr = NULL;
816 while ((ptr = list_head( head )))
818 list_remove( ptr );
819 if (level)
821 struct resource_dir_entry *ent;
823 ent = LIST_ENTRY( ptr, struct resource_dir_entry, entry );
824 res_free_str( ent->id );
825 free_resource_directory( &ent->children, level - 1 );
826 HeapFree(GetProcessHeap(), 0, ent);
828 else
830 struct resource_data *data;
832 data = LIST_ENTRY( ptr, struct resource_data, entry );
833 HeapFree( GetProcessHeap(), 0, data );
838 static IMAGE_NT_HEADERS *get_nt_header( void *base, DWORD mapping_size )
840 IMAGE_NT_HEADERS *nt;
841 IMAGE_DOS_HEADER *dos;
843 if (mapping_size<sizeof (*dos))
844 return NULL;
846 dos = base;
847 if (dos->e_magic != IMAGE_DOS_SIGNATURE)
848 return NULL;
850 if ((dos->e_lfanew + sizeof (*nt)) > mapping_size)
851 return NULL;
853 nt = (void*) ((BYTE*)base + dos->e_lfanew);
855 if (nt->Signature != IMAGE_NT_SIGNATURE)
856 return NULL;
858 return nt;
861 static IMAGE_SECTION_HEADER *get_section_header( void *base, DWORD mapping_size, DWORD *num_sections )
863 IMAGE_NT_HEADERS *nt;
864 IMAGE_SECTION_HEADER *sec;
865 DWORD section_ofs;
867 nt = get_nt_header( base, mapping_size );
868 if (!nt)
869 return NULL;
871 /* check that we don't go over the end of the file accessing the sections */
872 section_ofs = FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) + nt->FileHeader.SizeOfOptionalHeader;
873 if ((nt->FileHeader.NumberOfSections * sizeof (*sec) + section_ofs) > mapping_size)
874 return NULL;
876 if (num_sections)
877 *num_sections = nt->FileHeader.NumberOfSections;
879 /* from here we have a valid PE exe to update */
880 return (void*) ((BYTE*)nt + section_ofs);
883 static BOOL check_pe_exe( HANDLE file, QUEUEDUPDATES *updates )
885 const IMAGE_NT_HEADERS *nt;
886 const IMAGE_SECTION_HEADER *sec;
887 BOOL ret = FALSE;
888 HANDLE mapping;
889 DWORD mapping_size, num_sections = 0;
890 void *base = NULL;
892 mapping_size = GetFileSize( file, NULL );
894 mapping = CreateFileMappingW( file, NULL, PAGE_READONLY, 0, 0, NULL );
895 if (!mapping)
896 goto done;
898 base = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, mapping_size );
899 if (!base)
900 goto done;
902 nt = get_nt_header( base, mapping_size );
903 if (!nt)
904 goto done;
906 TRACE("resources: %08x %08x\n",
907 nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress,
908 nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size);
910 sec = get_section_header( base, mapping_size, &num_sections );
911 if (!sec)
912 goto done;
914 ret = TRUE;
916 done:
917 if (base)
918 UnmapViewOfFile( base );
919 if (mapping)
920 CloseHandle( mapping );
922 return ret;
925 struct resource_size_info {
926 DWORD types_ofs;
927 DWORD names_ofs;
928 DWORD langs_ofs;
929 DWORD data_entry_ofs;
930 DWORD strings_ofs;
931 DWORD data_ofs;
932 DWORD total_size;
935 struct mapping_info {
936 HANDLE file;
937 HANDLE mapping;
938 void *base;
939 DWORD size;
940 BOOL read_write;
943 static const IMAGE_SECTION_HEADER *section_from_rva( void *base, DWORD mapping_size, DWORD rva )
945 const IMAGE_SECTION_HEADER *sec;
946 DWORD num_sections = 0;
947 int i;
949 sec = get_section_header( base, mapping_size, &num_sections );
950 if (!sec)
951 return NULL;
953 for (i=num_sections-1; i>=0; i--)
955 if (sec[i].VirtualAddress <= rva &&
956 rva <= (DWORD)sec[i].VirtualAddress + sec[i].SizeOfRawData)
958 return &sec[i];
962 return NULL;
965 static void *address_from_rva( void *base, DWORD mapping_size, DWORD rva, DWORD len )
967 const IMAGE_SECTION_HEADER *sec;
969 sec = section_from_rva( base, mapping_size, rva );
970 if (!sec)
971 return NULL;
973 if (rva + len <= (DWORD)sec->VirtualAddress + sec->SizeOfRawData)
974 return (void*)((LPBYTE) base + (sec->PointerToRawData + rva - sec->VirtualAddress));
976 return NULL;
979 static LPWSTR resource_dup_string( const IMAGE_RESOURCE_DIRECTORY *root, const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry )
981 const IMAGE_RESOURCE_DIR_STRING_U* string;
982 LPWSTR s;
984 if (!entry->u1.s1.NameIsString)
985 return UIntToPtr(entry->u1.s2.Id);
987 string = (const IMAGE_RESOURCE_DIR_STRING_U*) (((const char *)root) + entry->u1.s1.NameOffset);
988 s = HeapAlloc(GetProcessHeap(), 0, (string->Length + 1)*sizeof (WCHAR) );
989 memcpy( s, string->NameString, (string->Length + 1)*sizeof (WCHAR) );
990 s[string->Length] = 0;
992 return s;
995 /* this function is based on the code in winedump's pe.c */
996 static BOOL enumerate_mapped_resources( QUEUEDUPDATES *updates,
997 void *base, DWORD mapping_size,
998 const IMAGE_RESOURCE_DIRECTORY *root )
1000 const IMAGE_RESOURCE_DIRECTORY *namedir, *langdir;
1001 const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
1002 const IMAGE_RESOURCE_DATA_ENTRY *data;
1003 DWORD i, j, k;
1005 TRACE("version (%d.%d) %d named %d id entries\n",
1006 root->MajorVersion, root->MinorVersion, root->NumberOfNamedEntries, root->NumberOfIdEntries);
1008 for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
1010 LPWSTR Type;
1012 e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
1014 Type = resource_dup_string( root, e1 );
1016 namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
1017 for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
1019 LPWSTR Name;
1021 e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
1023 Name = resource_dup_string( root, e2 );
1025 langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
1026 for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
1028 LANGID Lang;
1029 void *p;
1030 struct resource_data *resdata;
1032 e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
1034 Lang = e3->u1.s2.Id;
1036 data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
1038 p = address_from_rva( base, mapping_size, data->OffsetToData, data->Size );
1040 resdata = allocate_resource_data( Lang, data->CodePage, p, data->Size, FALSE );
1041 if (resdata)
1042 update_add_resource( updates, Type, Name, resdata, FALSE );
1044 res_free_str( Name );
1046 res_free_str( Type );
1049 return TRUE;
1052 static BOOL read_mapped_resources( QUEUEDUPDATES *updates, void *base, DWORD mapping_size )
1054 const IMAGE_RESOURCE_DIRECTORY *root;
1055 const IMAGE_NT_HEADERS *nt;
1056 const IMAGE_SECTION_HEADER *sec;
1057 DWORD num_sections = 0, i;
1059 nt = get_nt_header( base, mapping_size );
1060 if (!nt)
1061 return FALSE;
1063 sec = get_section_header( base, mapping_size, &num_sections );
1064 if (!sec)
1065 return FALSE;
1067 for (i=0; i<num_sections; i++)
1068 if (!memcmp(sec[i].Name, ".rsrc", 6))
1069 break;
1071 if (i == num_sections)
1072 return TRUE;
1074 /* check the resource data is inside the mapping */
1075 if (sec[i].PointerToRawData > mapping_size ||
1076 (sec[i].PointerToRawData + sec[i].SizeOfRawData) > mapping_size)
1077 return TRUE;
1079 TRACE("found .rsrc at %08x, size %08x\n", sec[i].PointerToRawData, sec[i].SizeOfRawData);
1081 root = (void*) ((BYTE*)base + sec[i].PointerToRawData);
1082 enumerate_mapped_resources( updates, base, mapping_size, root );
1084 return TRUE;
1087 static BOOL map_file_into_memory( struct mapping_info *mi )
1089 DWORD page_attr, perm;
1091 if (mi->read_write)
1093 page_attr = PAGE_READWRITE;
1094 perm = FILE_MAP_WRITE | FILE_MAP_READ;
1096 else
1098 page_attr = PAGE_READONLY;
1099 perm = FILE_MAP_READ;
1102 mi->mapping = CreateFileMappingW( mi->file, NULL, page_attr, 0, 0, NULL );
1103 if (!mi->mapping)
1104 return FALSE;
1106 mi->base = MapViewOfFile( mi->mapping, perm, 0, 0, mi->size );
1107 if (!mi->base)
1108 return FALSE;
1110 return TRUE;
1113 static BOOL unmap_file_from_memory( struct mapping_info *mi )
1115 if (mi->base)
1116 UnmapViewOfFile( mi->base );
1117 mi->base = NULL;
1118 if (mi->mapping)
1119 CloseHandle( mi->mapping );
1120 mi->mapping = NULL;
1121 return TRUE;
1124 static void destroy_mapping( struct mapping_info *mi )
1126 if (!mi)
1127 return;
1128 unmap_file_from_memory( mi );
1129 if (mi->file)
1130 CloseHandle( mi->file );
1131 HeapFree( GetProcessHeap(), 0, mi );
1134 static struct mapping_info *create_mapping( LPCWSTR name, BOOL rw )
1136 struct mapping_info *mi;
1138 mi = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof *mi );
1139 if (!mi)
1140 return NULL;
1142 mi->read_write = rw;
1144 mi->file = CreateFileW( name, GENERIC_READ | (rw ? GENERIC_WRITE : 0),
1145 0, NULL, OPEN_EXISTING, 0, 0 );
1147 if (mi->file != INVALID_HANDLE_VALUE)
1149 mi->size = GetFileSize( mi->file, NULL );
1151 if (map_file_into_memory( mi ))
1152 return mi;
1155 unmap_file_from_memory( mi );
1156 HeapFree( GetProcessHeap(), 0, mi );
1158 return NULL;
1161 static BOOL resize_mapping( struct mapping_info *mi, DWORD new_size )
1163 if (!unmap_file_from_memory( mi ))
1164 return FALSE;
1166 /* change the file size */
1167 SetFilePointer( mi->file, new_size, NULL, FILE_BEGIN );
1168 if (!SetEndOfFile( mi->file ))
1170 ERR("failed to set file size to %08x\n", new_size );
1171 return FALSE;
1174 mi->size = new_size;
1176 return map_file_into_memory( mi );
1179 static void get_resource_sizes( QUEUEDUPDATES *updates, struct resource_size_info *si )
1181 struct resource_dir_entry *types, *names;
1182 struct resource_data *data;
1183 DWORD num_types = 0, num_names = 0, num_langs = 0, strings_size = 0, data_size = 0;
1185 memset( si, 0, sizeof *si );
1187 LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
1189 num_types++;
1190 if (HIWORD( types->id ))
1191 strings_size += sizeof (WORD) + lstrlenW( types->id )*sizeof (WCHAR);
1193 LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
1195 num_names++;
1197 if (HIWORD( names->id ))
1198 strings_size += sizeof (WORD) + lstrlenW( names->id )*sizeof (WCHAR);
1200 LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
1202 num_langs++;
1203 data_size += (data->cbData + 3) & ~3;
1208 /* names are at the end of the types */
1209 si->names_ofs = sizeof (IMAGE_RESOURCE_DIRECTORY) +
1210 num_types * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1212 /* language directories are at the end of the names */
1213 si->langs_ofs = si->names_ofs +
1214 num_types * sizeof (IMAGE_RESOURCE_DIRECTORY) +
1215 num_names * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1217 si->data_entry_ofs = si->langs_ofs +
1218 num_names * sizeof (IMAGE_RESOURCE_DIRECTORY) +
1219 num_langs * sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1221 si->strings_ofs = si->data_entry_ofs +
1222 num_langs * sizeof (IMAGE_RESOURCE_DATA_ENTRY);
1224 si->data_ofs = si->strings_ofs + ((strings_size + 3) & ~3);
1226 si->total_size = si->data_ofs + data_size;
1228 TRACE("names %08x langs %08x data entries %08x strings %08x data %08x total %08x\n",
1229 si->names_ofs, si->langs_ofs, si->data_entry_ofs,
1230 si->strings_ofs, si->data_ofs, si->total_size);
1233 static void res_write_padding( BYTE *res_base, DWORD size )
1235 static const BYTE pad[] = {
1236 'P','A','D','D','I','N','G','X','X','P','A','D','D','I','N','G' };
1237 DWORD i;
1239 for ( i = 0; i < size / sizeof pad; i++ )
1240 memcpy( &res_base[i*sizeof pad], pad, sizeof pad );
1241 memcpy( &res_base[i*sizeof pad], pad, size%sizeof pad );
1244 static BOOL write_resources( QUEUEDUPDATES *updates, LPBYTE base, struct resource_size_info *si, DWORD rva )
1246 struct resource_dir_entry *types, *names;
1247 struct resource_data *data;
1248 IMAGE_RESOURCE_DIRECTORY *root;
1250 TRACE("%p %p %p %08x\n", updates, base, si, rva );
1252 memset( base, 0, si->total_size );
1254 /* the root entry always exists */
1255 root = (IMAGE_RESOURCE_DIRECTORY*) base;
1256 memset( root, 0, sizeof *root );
1257 root->MajorVersion = 4;
1258 si->types_ofs = sizeof *root;
1259 LIST_FOR_EACH_ENTRY( types, &updates->root, struct resource_dir_entry, entry )
1261 IMAGE_RESOURCE_DIRECTORY_ENTRY *e1;
1262 IMAGE_RESOURCE_DIRECTORY *namedir;
1264 e1 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->types_ofs];
1265 memset( e1, 0, sizeof *e1 );
1266 if (HIWORD( types->id ))
1268 WCHAR *strings;
1269 DWORD len;
1271 root->NumberOfNamedEntries++;
1272 e1->u1.s1.NameIsString = 1;
1273 e1->u1.s1.NameOffset = si->strings_ofs;
1275 strings = (WCHAR*) &base[si->strings_ofs];
1276 len = lstrlenW( types->id );
1277 strings[0] = len;
1278 memcpy( &strings[1], types->id, len * sizeof (WCHAR) );
1279 si->strings_ofs += (len + 1) * sizeof (WCHAR);
1281 else
1283 root->NumberOfIdEntries++;
1284 e1->u1.s2.Id = LOWORD( types->id );
1286 e1->u2.s3.OffsetToDirectory = si->names_ofs;
1287 e1->u2.s3.DataIsDirectory = TRUE;
1288 si->types_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1290 namedir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->names_ofs];
1291 memset( namedir, 0, sizeof *namedir );
1292 namedir->MajorVersion = 4;
1293 si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
1295 LIST_FOR_EACH_ENTRY( names, &types->children, struct resource_dir_entry, entry )
1297 IMAGE_RESOURCE_DIRECTORY_ENTRY *e2;
1298 IMAGE_RESOURCE_DIRECTORY *langdir;
1300 e2 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->names_ofs];
1301 memset( e2, 0, sizeof *e2 );
1302 if (HIWORD( names->id ))
1304 WCHAR *strings;
1305 DWORD len;
1307 namedir->NumberOfNamedEntries++;
1308 e2->u1.s1.NameIsString = 1;
1309 e2->u1.s1.NameOffset = si->strings_ofs;
1311 strings = (WCHAR*) &base[si->strings_ofs];
1312 len = lstrlenW( names->id );
1313 strings[0] = len;
1314 memcpy( &strings[1], names->id, len * sizeof (WCHAR) );
1315 si->strings_ofs += (len + 1) * sizeof (WCHAR);
1317 else
1319 namedir->NumberOfIdEntries++;
1320 e2->u1.s2.Id = LOWORD( names->id );
1322 e2->u2.s3.OffsetToDirectory = si->langs_ofs;
1323 e2->u2.s3.DataIsDirectory = TRUE;
1324 si->names_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1326 langdir = (IMAGE_RESOURCE_DIRECTORY*) &base[si->langs_ofs];
1327 memset( langdir, 0, sizeof *langdir );
1328 langdir->MajorVersion = 4;
1329 si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY);
1331 LIST_FOR_EACH_ENTRY( data, &names->children, struct resource_data, entry )
1333 IMAGE_RESOURCE_DIRECTORY_ENTRY *e3;
1334 IMAGE_RESOURCE_DATA_ENTRY *de;
1335 int pad_size;
1337 e3 = (IMAGE_RESOURCE_DIRECTORY_ENTRY*) &base[si->langs_ofs];
1338 memset( e3, 0, sizeof *e3 );
1339 langdir->NumberOfIdEntries++;
1340 e3->u1.s2.Id = LOWORD( data->lang );
1341 e3->u2.OffsetToData = si->data_entry_ofs;
1343 si->langs_ofs += sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY);
1345 /* write out all the data entries */
1346 de = (IMAGE_RESOURCE_DATA_ENTRY*) &base[si->data_entry_ofs];
1347 memset( de, 0, sizeof *de );
1348 de->OffsetToData = si->data_ofs + rva;
1349 de->Size = data->cbData;
1350 de->CodePage = data->codepage;
1351 si->data_entry_ofs += sizeof (IMAGE_RESOURCE_DATA_ENTRY);
1353 /* write out the resource data */
1354 memcpy( &base[si->data_ofs], data->lpData, data->cbData );
1355 si->data_ofs += data->cbData;
1357 pad_size = (-si->data_ofs)&3;
1358 res_write_padding( &base[si->data_ofs], pad_size );
1359 si->data_ofs += pad_size;
1364 return TRUE;
1368 * FIXME:
1369 * Assumes that the resources are in .rsrc
1370 * and .rsrc is the last section in the file.
1371 * Not sure whether updating resources will other cases on Windows.
1372 * If the resources lie in a section containing other data,
1373 * resizing that section could possibly cause trouble.
1374 * If the section with the resources isn't last, the remaining
1375 * sections need to be moved down in the file, and the section header
1376 * would need to be adjusted.
1377 * If we needed to add a section, what would we name it?
1378 * If we needed to add a section and there wasn't space in the file
1379 * header, how would that work?
1380 * Seems that at least some of these cases can't be handled properly.
1382 static IMAGE_SECTION_HEADER *get_resource_section( void *base, DWORD mapping_size )
1384 IMAGE_SECTION_HEADER *sec;
1385 IMAGE_NT_HEADERS *nt;
1386 DWORD i, num_sections = 0;
1388 nt = get_nt_header( base, mapping_size );
1389 if (!nt)
1390 return NULL;
1392 sec = get_section_header( base, mapping_size, &num_sections );
1393 if (!sec)
1394 return NULL;
1396 /* find the resources section */
1397 for (i=0; i<num_sections; i++)
1398 if (!memcmp(sec[i].Name, ".rsrc", 6))
1399 break;
1401 if (i == num_sections)
1403 FIXME(".rsrc doesn't exist\n");
1404 return NULL;
1407 /* check that the resources section is last */
1408 if (i != num_sections - 1)
1410 FIXME(".rsrc isn't the last section\n");
1411 return NULL;
1414 return &sec[i];
1417 static DWORD get_init_data_size( void *base, DWORD mapping_size )
1419 DWORD i, sz = 0, num_sections = 0;
1420 IMAGE_SECTION_HEADER *s;
1422 s = get_section_header( base, mapping_size, &num_sections );
1424 for (i=0; i<num_sections; i++)
1425 if (s[i].Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA)
1426 sz += s[i].SizeOfRawData;
1428 TRACE("size = %08x\n", sz);
1430 return sz;
1433 static BOOL write_raw_resources( QUEUEDUPDATES *updates )
1435 static const WCHAR prefix[] = { 'r','e','s','u',0 };
1436 WCHAR tempdir[MAX_PATH], tempfile[MAX_PATH];
1437 DWORD mapping_size, section_size, old_size;
1438 BOOL ret = FALSE;
1439 IMAGE_SECTION_HEADER *sec;
1440 IMAGE_NT_HEADERS *nt;
1441 struct resource_size_info res_size;
1442 BYTE *res_base;
1443 struct mapping_info *read_map = NULL, *write_map = NULL;
1445 /* copy the exe to a temp file then update the temp file... */
1446 tempdir[0] = 0;
1447 if (!GetTempPathW( MAX_PATH, tempdir ))
1448 return ret;
1450 if (!GetTempFileNameW( tempdir, prefix, 0, tempfile ))
1451 return ret;
1453 if (!CopyFileW( updates->pFileName, tempfile, FALSE ))
1454 goto done;
1456 TRACE("tempfile %s\n", debugstr_w(tempfile));
1458 if (!updates->bDeleteExistingResources)
1460 read_map = create_mapping( updates->pFileName, FALSE );
1461 if (!read_map)
1462 goto done;
1464 ret = read_mapped_resources( updates, read_map->base, read_map->size );
1465 if (!ret)
1467 ERR("failed to read existing resources\n");
1468 goto done;
1472 write_map = create_mapping( tempfile, TRUE );
1473 if (!write_map)
1474 goto done;
1476 nt = get_nt_header( write_map->base, write_map->size );
1477 if (!nt)
1478 goto done;
1480 if (nt->OptionalHeader.SectionAlignment <= 0)
1482 ERR("invalid section alignment %04x\n", nt->OptionalHeader.SectionAlignment);
1483 goto done;
1486 sec = get_resource_section( write_map->base, write_map->size );
1487 if (!sec)
1488 goto done;
1490 if ((sec->SizeOfRawData + sec->PointerToRawData) != write_map->size)
1492 FIXME(".rsrc isn't at the end of the image %08x + %08x != %08x\n",
1493 sec->SizeOfRawData, sec->PointerToRawData, write_map->size);
1494 goto done;
1497 TRACE("before .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1499 get_resource_sizes( updates, &res_size );
1501 /* round up the section size */
1502 section_size = res_size.total_size;
1503 section_size += (-section_size) % nt->OptionalHeader.SectionAlignment;
1505 mapping_size = sec->PointerToRawData + section_size;
1507 TRACE("requires %08x (%08x) bytes\n", res_size.total_size, section_size );
1509 /* check if the file size needs to be changed */
1510 if (section_size != sec->SizeOfRawData)
1512 old_size = write_map->size;
1514 TRACE("file size %08x -> %08x\n", old_size, mapping_size);
1516 /* unmap the file before changing the file size */
1517 ret = resize_mapping( write_map, mapping_size );
1519 /* get the pointers again - they might be different after remapping */
1520 nt = get_nt_header( write_map->base, mapping_size );
1521 if (!nt)
1523 ERR("couldn't get NT header\n");
1524 goto done;
1527 sec = get_resource_section( write_map->base, mapping_size );
1528 if (!sec)
1529 goto done;
1531 /* adjust the PE header information */
1532 nt->OptionalHeader.SizeOfImage += (mapping_size - old_size);
1533 sec->SizeOfRawData = section_size;
1534 sec->Misc.VirtualSize = section_size;
1535 nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = res_size.total_size;
1536 nt->OptionalHeader.SizeOfInitializedData = get_init_data_size( write_map->base, mapping_size );
1539 res_base = (LPBYTE) write_map->base + sec->PointerToRawData;
1541 TRACE("base = %p offset = %08x\n", write_map->base, sec->PointerToRawData);
1543 ret = write_resources( updates, res_base, &res_size, sec->VirtualAddress );
1545 res_write_padding( res_base + res_size.total_size, section_size - res_size.total_size );
1547 TRACE("after .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
1549 done:
1550 destroy_mapping( read_map );
1551 destroy_mapping( write_map );
1553 if (ret)
1554 ret = CopyFileW( tempfile, updates->pFileName, FALSE );
1556 DeleteFileW( tempfile );
1558 return ret;
1561 /***********************************************************************
1562 * BeginUpdateResourceW (KERNEL32.@)
1564 HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResources )
1566 QUEUEDUPDATES *updates = NULL;
1567 HANDLE hUpdate, file, ret = NULL;
1569 TRACE("%s, %d\n", debugstr_w(pFileName), bDeleteExistingResources);
1571 hUpdate = GlobalAlloc(GHND, sizeof(QUEUEDUPDATES));
1572 if (!hUpdate)
1573 return ret;
1575 updates = GlobalLock(hUpdate);
1576 if (updates)
1578 list_init( &updates->root );
1579 updates->bDeleteExistingResources = bDeleteExistingResources;
1580 updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
1581 if (updates->pFileName)
1583 lstrcpyW(updates->pFileName, pFileName);
1585 file = CreateFileW( pFileName, GENERIC_READ | GENERIC_WRITE,
1586 0, NULL, OPEN_EXISTING, 0, 0 );
1588 /* if resources are deleted, only the file's presence is checked */
1589 if (file != INVALID_HANDLE_VALUE &&
1590 (bDeleteExistingResources || check_pe_exe( file, updates )))
1591 ret = hUpdate;
1592 else
1593 HeapFree( GetProcessHeap(), 0, updates->pFileName );
1595 CloseHandle( file );
1597 GlobalUnlock(hUpdate);
1600 if (!ret)
1601 GlobalFree(hUpdate);
1603 return ret;
1607 /***********************************************************************
1608 * BeginUpdateResourceA (KERNEL32.@)
1610 HANDLE WINAPI BeginUpdateResourceA( LPCSTR pFileName, BOOL bDeleteExistingResources )
1612 UNICODE_STRING FileNameW;
1613 HANDLE ret;
1614 RtlCreateUnicodeStringFromAsciiz(&FileNameW, pFileName);
1615 ret = BeginUpdateResourceW(FileNameW.Buffer, bDeleteExistingResources);
1616 RtlFreeUnicodeString(&FileNameW);
1617 return ret;
1621 /***********************************************************************
1622 * EndUpdateResourceW (KERNEL32.@)
1624 BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
1626 QUEUEDUPDATES *updates;
1627 BOOL ret;
1629 TRACE("%p %d\n", hUpdate, fDiscard);
1631 updates = GlobalLock(hUpdate);
1632 if (!updates)
1633 return FALSE;
1635 ret = fDiscard || write_raw_resources( updates );
1637 free_resource_directory( &updates->root, 2 );
1639 HeapFree( GetProcessHeap(), 0, updates->pFileName );
1640 GlobalUnlock( hUpdate );
1641 GlobalFree( hUpdate );
1643 return ret;
1647 /***********************************************************************
1648 * EndUpdateResourceA (KERNEL32.@)
1650 BOOL WINAPI EndUpdateResourceA( HANDLE hUpdate, BOOL fDiscard )
1652 return EndUpdateResourceW(hUpdate, fDiscard);
1656 /***********************************************************************
1657 * UpdateResourceW (KERNEL32.@)
1659 BOOL WINAPI UpdateResourceW( HANDLE hUpdate, LPCWSTR lpType, LPCWSTR lpName,
1660 WORD wLanguage, LPVOID lpData, DWORD cbData)
1662 QUEUEDUPDATES *updates;
1663 BOOL ret = FALSE;
1665 TRACE("%p %s %s %08x %p %d\n", hUpdate,
1666 debugstr_w(lpType), debugstr_w(lpName), wLanguage, lpData, cbData);
1668 updates = GlobalLock(hUpdate);
1669 if (updates)
1671 struct resource_data *data;
1672 data = allocate_resource_data( wLanguage, 0, lpData, cbData, TRUE );
1673 if (data)
1674 ret = update_add_resource( updates, lpType, lpName, data, TRUE );
1675 GlobalUnlock(hUpdate);
1677 return ret;
1681 /***********************************************************************
1682 * UpdateResourceA (KERNEL32.@)
1684 BOOL WINAPI UpdateResourceA( HANDLE hUpdate, LPCSTR lpType, LPCSTR lpName,
1685 WORD wLanguage, LPVOID lpData, DWORD cbData)
1687 BOOL ret;
1688 UNICODE_STRING TypeW;
1689 UNICODE_STRING NameW;
1690 if(!HIWORD(lpType))
1691 TypeW.Buffer = ULongToPtr(LOWORD(lpType));
1692 else
1693 RtlCreateUnicodeStringFromAsciiz(&TypeW, lpType);
1694 if(!HIWORD(lpName))
1695 NameW.Buffer = ULongToPtr(LOWORD(lpName));
1696 else
1697 RtlCreateUnicodeStringFromAsciiz(&NameW, lpName);
1698 ret = UpdateResourceW(hUpdate, TypeW.Buffer, NameW.Buffer, wLanguage, lpData, cbData);
1699 if(HIWORD(lpType)) RtlFreeUnicodeString(&TypeW);
1700 if(HIWORD(lpName)) RtlFreeUnicodeString(&NameW);
1701 return ret;