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
25 #include <wine/list.h>
29 DEBUG_CHANNEL(resource
);
31 /* retrieve the resource name to pass to the ntdll functions */
32 static NTSTATUS
get_res_nameA( LPCSTR name
, UNICODE_STRING
*str
)
34 if (IS_INTRESOURCE(name
))
36 str
->Buffer
= ULongToPtr(LOWORD(name
));
37 return STATUS_SUCCESS
;
42 if (RtlCharToInteger( name
+ 1, 10, &value
) != STATUS_SUCCESS
|| HIWORD(value
))
43 return STATUS_INVALID_PARAMETER
;
44 str
->Buffer
= ULongToPtr(value
);
45 return STATUS_SUCCESS
;
47 RtlCreateUnicodeStringFromAsciiz( str
, name
);
48 RtlUpcaseUnicodeString( str
, str
, FALSE
);
49 return STATUS_SUCCESS
;
52 /* retrieve the resource name to pass to the ntdll functions */
53 static NTSTATUS
get_res_nameW( LPCWSTR name
, UNICODE_STRING
*str
)
55 if (IS_INTRESOURCE(name
))
57 str
->Buffer
= ULongToPtr(LOWORD(name
));
58 return STATUS_SUCCESS
;
63 RtlInitUnicodeString( str
, name
+ 1 );
64 if (RtlUnicodeStringToInteger( str
, 10, &value
) != STATUS_SUCCESS
|| HIWORD(value
))
65 return STATUS_INVALID_PARAMETER
;
66 str
->Buffer
= ULongToPtr(value
);
67 return STATUS_SUCCESS
;
69 RtlCreateUnicodeString( str
, name
);
70 RtlUpcaseUnicodeString( str
, str
, FALSE
);
71 return STATUS_SUCCESS
;
74 /* implementation of FindResourceExA */
75 static HRSRC
find_resourceA( HMODULE hModule
, LPCSTR type
, LPCSTR name
, WORD lang
)
78 UNICODE_STRING nameW
, typeW
;
79 LDR_RESOURCE_INFO info
;
80 IMAGE_RESOURCE_DATA_ENTRY
*entry
= NULL
;
87 if ((status
= get_res_nameA( name
, &nameW
)) != STATUS_SUCCESS
) goto done
;
88 if ((status
= get_res_nameA( type
, &typeW
)) != STATUS_SUCCESS
) goto done
;
89 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
90 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
92 status
= LdrFindResource_U( hModule
, &info
, 3, &entry
);
94 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
98 SetLastError( ERROR_INVALID_PARAMETER
);
102 if (!IS_INTRESOURCE(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
103 if (!IS_INTRESOURCE(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
108 /* implementation of FindResourceExW */
109 static HRSRC
find_resourceW( HMODULE hModule
, LPCWSTR type
, LPCWSTR name
, WORD lang
)
112 UNICODE_STRING nameW
, typeW
;
113 LDR_RESOURCE_INFO info
;
114 IMAGE_RESOURCE_DATA_ENTRY
*entry
= NULL
;
116 nameW
.Buffer
= typeW
.Buffer
= NULL
;
120 if ((status
= get_res_nameW( name
, &nameW
)) != STATUS_SUCCESS
) goto done
;
121 if ((status
= get_res_nameW( type
, &typeW
)) != STATUS_SUCCESS
) goto done
;
122 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
123 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
124 info
.Language
= lang
;
125 status
= LdrFindResource_U( hModule
, &info
, 3, &entry
);
127 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
131 SetLastError( ERROR_INVALID_PARAMETER
);
135 if (!IS_INTRESOURCE(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
136 if (!IS_INTRESOURCE(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
140 /**********************************************************************
141 * FindResourceExA (KERNEL32.@)
143 HRSRC WINAPI
FindResourceExA( HMODULE hModule
, LPCSTR type
, LPCSTR name
, WORD lang
)
145 TRACE( "%p %s %s %04x\n", hModule
, debugstr_a(type
), debugstr_a(name
), lang
);
147 if (!hModule
) hModule
= GetModuleHandleW(0);
148 return find_resourceA( hModule
, type
, name
, lang
);
152 /**********************************************************************
153 * FindResourceA (KERNEL32.@)
155 HRSRC WINAPI
FindResourceA( HMODULE hModule
, LPCSTR name
, LPCSTR type
)
157 return FindResourceExA( hModule
, type
, name
, MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
161 /**********************************************************************
162 * FindResourceExW (KERNEL32.@)
164 HRSRC WINAPI
FindResourceExW( HMODULE hModule
, LPCWSTR type
, LPCWSTR name
, WORD lang
)
166 TRACE( "%p %s %s %04x\n", hModule
, debugstr_w(type
), debugstr_w(name
), lang
);
168 if (!hModule
) hModule
= GetModuleHandleW(0);
169 return find_resourceW( hModule
, type
, name
, lang
);
173 /**********************************************************************
174 * FindResourceW (KERNEL32.@)
176 HRSRC WINAPI
FindResourceW( HINSTANCE hModule
, LPCWSTR name
, LPCWSTR type
)
178 return FindResourceExW( hModule
, type
, name
, MAKELANGID( LANG_NEUTRAL
, SUBLANG_NEUTRAL
) );
182 /**********************************************************************
183 * EnumResourceTypesA (KERNEL32.@)
185 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG_PTR lparam
)
190 DWORD len
= 0, newlen
;
192 IMAGE_RESOURCE_DIRECTORY
*resdir
;
193 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
194 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
196 TRACE( "%p %p %lx\n", hmod
, lpfun
, lparam
);
198 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
200 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &resdir
)) != STATUS_SUCCESS
)
202 SetLastError( RtlNtStatusToDosError(status
) );
205 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
206 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
; i
++)
208 if (et
[i
].NameIsString
)
210 str
= (const IMAGE_RESOURCE_DIR_STRING_U
*)((const BYTE
*)resdir
+ et
[i
].NameOffset
);
211 newlen
= WideCharToMultiByte( CP_ACP
, 0, str
->NameString
, str
->Length
, NULL
, 0, NULL
, NULL
);
212 if (newlen
+ 1 > len
)
215 HeapFree( GetProcessHeap(), 0, type
);
216 if (!(type
= HeapAlloc( GetProcessHeap(), 0, len
))) return FALSE
;
218 WideCharToMultiByte( CP_ACP
, 0, str
->NameString
, str
->Length
, type
, len
, NULL
, NULL
);
220 ret
= lpfun(hmod
,type
,lparam
);
224 ret
= lpfun( hmod
, UIntToPtr(et
[i
].Id
), lparam
);
228 HeapFree( GetProcessHeap(), 0, type
);
233 /**********************************************************************
234 * EnumResourceTypesW (KERNEL32.@)
236 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG_PTR lparam
)
242 IMAGE_RESOURCE_DIRECTORY
*resdir
;
243 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
244 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
246 TRACE( "%p %p %lx\n", hmod
, lpfun
, lparam
);
248 if (!hmod
) hmod
= GetModuleHandleW( NULL
);
250 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &resdir
)) != STATUS_SUCCESS
)
252 SetLastError( RtlNtStatusToDosError(status
) );
255 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
256 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+ resdir
->NumberOfIdEntries
; i
++)
258 if (et
[i
].NameIsString
)
260 str
= (const IMAGE_RESOURCE_DIR_STRING_U
*)((const BYTE
*)resdir
+ et
[i
].NameOffset
);
261 if (str
->Length
+ 1 > len
)
263 len
= str
->Length
+ 1;
264 HeapFree( GetProcessHeap(), 0, type
);
265 if (!(type
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
267 memcpy(type
, str
->NameString
, str
->Length
* sizeof (WCHAR
));
268 type
[str
->Length
] = 0;
269 ret
= lpfun(hmod
,type
,lparam
);
273 ret
= lpfun( hmod
, UIntToPtr(et
[i
].Id
), lparam
);
277 HeapFree( GetProcessHeap(), 0, type
);
282 /**********************************************************************
283 * EnumResourceNamesA (KERNEL32.@)
285 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG_PTR lparam
)
289 DWORD len
= 0, newlen
;
292 UNICODE_STRING typeW
;
293 LDR_RESOURCE_INFO info
;
294 IMAGE_RESOURCE_DIRECTORY
*basedir
, *resdir
;
295 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
296 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
298 TRACE( "%p %s %p %lx\n", hmod
, debugstr_a(type
), lpfun
, lparam
);
300 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
302 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
304 if ((status
= get_res_nameA( type
, &typeW
)) != STATUS_SUCCESS
)
306 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
307 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 1, &resdir
)) != STATUS_SUCCESS
)
310 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
313 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
; i
++)
315 if (et
[i
].NameIsString
)
317 str
= (const IMAGE_RESOURCE_DIR_STRING_U
*)((const BYTE
*)basedir
+ et
[i
].NameOffset
);
318 newlen
= WideCharToMultiByte(CP_ACP
, 0, str
->NameString
, str
->Length
, NULL
, 0, NULL
, NULL
);
319 if (newlen
+ 1 > len
)
322 HeapFree( GetProcessHeap(), 0, name
);
323 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
329 WideCharToMultiByte( CP_ACP
, 0, str
->NameString
, str
->Length
, name
, len
, NULL
, NULL
);
331 ret
= lpfun(hmod
,type
,name
,lparam
);
335 ret
= lpfun( hmod
, type
, UIntToPtr(et
[i
].Id
), lparam
);
343 status
= STATUS_ACCESS_VIOLATION
;
348 HeapFree( GetProcessHeap(), 0, name
);
349 if (!IS_INTRESOURCE(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
350 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
355 /**********************************************************************
356 * EnumResourceNamesW (KERNEL32.@)
358 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG_PTR lparam
)
364 UNICODE_STRING typeW
;
365 LDR_RESOURCE_INFO info
;
366 IMAGE_RESOURCE_DIRECTORY
*basedir
, *resdir
;
367 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
368 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
370 TRACE( "%p %s %p %lx\n", hmod
, debugstr_w(type
), lpfun
, lparam
);
372 if (!hmod
) hmod
= GetModuleHandleW( NULL
);
374 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
376 if ((status
= get_res_nameW( type
, &typeW
)) != STATUS_SUCCESS
)
378 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
379 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 1, &resdir
)) != STATUS_SUCCESS
)
382 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
385 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
; i
++)
387 if (et
[i
].NameIsString
)
389 str
= (const IMAGE_RESOURCE_DIR_STRING_U
*)((const BYTE
*)basedir
+ et
[i
].NameOffset
);
390 if (str
->Length
+ 1 > len
)
392 len
= str
->Length
+ 1;
393 HeapFree( GetProcessHeap(), 0, name
);
394 if (!(name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
400 memcpy(name
, str
->NameString
, str
->Length
* sizeof (WCHAR
));
401 name
[str
->Length
] = 0;
402 ret
= lpfun(hmod
,type
,name
,lparam
);
406 ret
= lpfun( hmod
, type
, UIntToPtr(et
[i
].Id
), lparam
);
414 status
= STATUS_ACCESS_VIOLATION
;
418 HeapFree( GetProcessHeap(), 0, name
);
419 if (!IS_INTRESOURCE(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
420 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
425 /**********************************************************************
426 * EnumResourceLanguagesA (KERNEL32.@)
428 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
429 ENUMRESLANGPROCA lpfun
, LONG_PTR lparam
)
434 UNICODE_STRING typeW
, nameW
;
435 LDR_RESOURCE_INFO info
;
436 IMAGE_RESOURCE_DIRECTORY
*basedir
, *resdir
;
437 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
439 TRACE( "%p %s %s %p %lx\n", hmod
, debugstr_a(type
), debugstr_a(name
), lpfun
, lparam
);
441 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
442 typeW
.Buffer
= nameW
.Buffer
= NULL
;
443 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
445 if ((status
= get_res_nameA( type
, &typeW
)) != STATUS_SUCCESS
)
447 if ((status
= get_res_nameA( name
, &nameW
)) != STATUS_SUCCESS
)
449 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
450 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
451 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 2, &resdir
)) != STATUS_SUCCESS
)
454 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
457 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+ resdir
->NumberOfIdEntries
; i
++)
459 ret
= lpfun( hmod
, type
, name
, et
[i
].Id
, lparam
);
466 status
= STATUS_ACCESS_VIOLATION
;
470 if (!IS_INTRESOURCE(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
471 if (!IS_INTRESOURCE(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
472 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
477 /**********************************************************************
478 * EnumResourceLanguagesW (KERNEL32.@)
480 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
481 ENUMRESLANGPROCW lpfun
, LONG_PTR lparam
)
486 UNICODE_STRING typeW
, nameW
;
487 LDR_RESOURCE_INFO info
;
488 IMAGE_RESOURCE_DIRECTORY
*basedir
, *resdir
;
489 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
491 TRACE( "%p %s %s %p %lx\n", hmod
, debugstr_w(type
), debugstr_w(name
), lpfun
, lparam
);
493 if (!hmod
) hmod
= GetModuleHandleW( NULL
);
494 typeW
.Buffer
= nameW
.Buffer
= NULL
;
495 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
497 if ((status
= get_res_nameW( type
, &typeW
)) != STATUS_SUCCESS
)
499 if ((status
= get_res_nameW( name
, &nameW
)) != STATUS_SUCCESS
)
501 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
502 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
503 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 2, &resdir
)) != STATUS_SUCCESS
)
506 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
509 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+ resdir
->NumberOfIdEntries
; i
++)
511 ret
= lpfun( hmod
, type
, name
, et
[i
].Id
, lparam
);
518 status
= STATUS_ACCESS_VIOLATION
;
522 if (!IS_INTRESOURCE(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
523 if (!IS_INTRESOURCE(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
524 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
529 /**********************************************************************
530 * LoadResource (KERNEL32.@)
532 HGLOBAL WINAPI
LoadResource( HINSTANCE hModule
, HRSRC hRsrc
)
537 TRACE( "%p %p\n", hModule
, hRsrc
);
539 if (!hRsrc
) return 0;
540 if (!hModule
) hModule
= GetModuleHandleA( NULL
);
541 status
= LdrAccessResource( hModule
, (IMAGE_RESOURCE_DATA_ENTRY
*)hRsrc
, &ret
, NULL
);
542 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
547 /**********************************************************************
548 * LockResource (KERNEL32.@)
550 LPVOID WINAPI
LockResource( HGLOBAL handle
)
556 /**********************************************************************
557 * FreeResource (KERNEL32.@)
559 BOOL WINAPI
FreeResource( HGLOBAL handle
)
565 /**********************************************************************
566 * SizeofResource (KERNEL32.@)
568 DWORD WINAPI
SizeofResource( HINSTANCE hModule
, HRSRC hRsrc
)
570 if (!hRsrc
) return 0;
571 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
575 * Data structure for updating resources.
576 * Type/Name/Language is a keyset for accessing resource data.
578 * QUEUEDUPDATES (root) ->
579 * list of struct resource_dir_entry (Type) ->
580 * list of struct resource_dir_entry (Name) ->
581 * list of struct resource_data Language + Data
587 BOOL bDeleteExistingResources
;
591 /* this structure is shared for types and names */
592 struct resource_dir_entry
{
595 struct list children
;
598 /* this structure is the leaf */
599 struct resource_data
{
607 static int resource_strcmp( LPCWSTR a
, LPCWSTR b
)
611 if (!IS_INTRESOURCE( a
) && !IS_INTRESOURCE( b
) )
612 return lstrcmpW( a
, b
);
613 /* strings come before ids */
614 if (!IS_INTRESOURCE( a
) && IS_INTRESOURCE( b
))
616 if (!IS_INTRESOURCE( b
) && IS_INTRESOURCE( a
))
618 return ( a
< b
) ? -1 : 1;
621 static struct resource_dir_entry
*find_resource_dir_entry( struct list
*dir
, LPCWSTR id
)
623 struct resource_dir_entry
*ent
;
625 /* match either IDs or strings */
626 LIST_FOR_EACH_ENTRY( ent
, dir
, struct resource_dir_entry
, entry
)
627 if (!resource_strcmp( id
, ent
->id
))
633 static struct resource_data
*find_resource_data( struct list
*dir
, LANGID lang
)
635 struct resource_data
*res_data
;
637 /* match only languages here */
638 LIST_FOR_EACH_ENTRY( res_data
, dir
, struct resource_data
, entry
)
639 if ( lang
== res_data
->lang
)
645 static void add_resource_dir_entry( struct list
*dir
, struct resource_dir_entry
*resdir
)
647 struct resource_dir_entry
*ent
;
649 LIST_FOR_EACH_ENTRY( ent
, dir
, struct resource_dir_entry
, entry
)
651 if (0>resource_strcmp( ent
->id
, resdir
->id
))
654 list_add_before( &ent
->entry
, &resdir
->entry
);
657 list_add_tail( dir
, &resdir
->entry
);
660 static void add_resource_data_entry( struct list
*dir
, struct resource_data
*resdata
)
662 struct resource_data
*ent
;
664 LIST_FOR_EACH_ENTRY( ent
, dir
, struct resource_data
, entry
)
666 if (ent
->lang
< resdata
->lang
)
669 list_add_before( &ent
->entry
, &resdata
->entry
);
672 list_add_tail( dir
, &resdata
->entry
);
675 static LPWSTR
res_strdupW( LPCWSTR str
)
680 if (IS_INTRESOURCE(str
))
681 return (LPWSTR
) (UINT_PTR
) LOWORD(str
);
682 len
= (lstrlenW( str
) + 1) * sizeof (WCHAR
);
683 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
684 memcpy( ret
, str
, len
);
688 static void res_free_str( LPWSTR str
)
690 if (!IS_INTRESOURCE(str
))
691 HeapFree( GetProcessHeap(), 0, str
);
694 static BOOL
update_add_resource( QUEUEDUPDATES
*updates
, LPCWSTR Type
, LPCWSTR Name
,
695 LANGID Lang
, struct resource_data
*resdata
,
696 BOOL overwrite_existing
)
698 struct resource_dir_entry
*restype
, *resname
;
699 struct resource_data
*existing
;
701 TRACE("%p %s %s %p %d\n", updates
,
702 debugstr_w(Type
), debugstr_w(Name
), resdata
, overwrite_existing
);
704 restype
= find_resource_dir_entry( &updates
->root
, Type
);
707 restype
= HeapAlloc( GetProcessHeap(), 0, sizeof *restype
);
708 restype
->id
= res_strdupW( Type
);
709 list_init( &restype
->children
);
710 add_resource_dir_entry( &updates
->root
, restype
);
713 resname
= find_resource_dir_entry( &restype
->children
, Name
);
716 resname
= HeapAlloc( GetProcessHeap(), 0, sizeof *resname
);
717 resname
->id
= res_strdupW( Name
);
718 list_init( &resname
->children
);
719 add_resource_dir_entry( &restype
->children
, resname
);
723 * If there's an existing resource entry with matching (Type,Name,Language)
724 * it needs to be removed before adding the new data.
726 existing
= find_resource_data( &resname
->children
, Lang
);
729 if (!overwrite_existing
)
731 list_remove( &existing
->entry
);
732 HeapFree( GetProcessHeap(), 0, existing
);
736 add_resource_data_entry( &resname
->children
, resdata
);
741 static struct resource_data
*allocate_resource_data( WORD Language
, DWORD codepage
,
742 LPVOID lpData
, DWORD cbData
, BOOL copy_data
)
744 struct resource_data
*resdata
;
746 if (!lpData
|| !cbData
)
749 resdata
= HeapAlloc( GetProcessHeap(), 0, sizeof *resdata
+ (copy_data
? cbData
: 0) );
752 resdata
->lang
= Language
;
753 resdata
->codepage
= codepage
;
754 resdata
->cbData
= cbData
;
757 resdata
->lpData
= &resdata
[1];
758 memcpy( resdata
->lpData
, lpData
, cbData
);
761 resdata
->lpData
= lpData
;
767 static void free_resource_directory( struct list
*head
, int level
)
769 struct list
*ptr
= NULL
;
771 while ((ptr
= list_head( head
)))
776 struct resource_dir_entry
*ent
;
778 ent
= LIST_ENTRY( ptr
, struct resource_dir_entry
, entry
);
779 res_free_str( ent
->id
);
780 free_resource_directory( &ent
->children
, level
- 1 );
781 HeapFree(GetProcessHeap(), 0, ent
);
785 struct resource_data
*data
;
787 data
= LIST_ENTRY( ptr
, struct resource_data
, entry
);
788 HeapFree( GetProcessHeap(), 0, data
);
793 static IMAGE_NT_HEADERS
*get_nt_header( void *base
, DWORD mapping_size
)
795 IMAGE_NT_HEADERS
*nt
;
796 IMAGE_DOS_HEADER
*dos
;
798 if (mapping_size
<sizeof (*dos
))
802 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
)
805 if ((dos
->e_lfanew
+ sizeof (*nt
)) > mapping_size
)
808 nt
= (void*) ((BYTE
*)base
+ dos
->e_lfanew
);
810 if (nt
->Signature
!= IMAGE_NT_SIGNATURE
)
816 static IMAGE_SECTION_HEADER
*get_section_header( void *base
, DWORD mapping_size
, DWORD
*num_sections
)
818 IMAGE_NT_HEADERS
*nt
;
821 nt
= get_nt_header( base
, mapping_size
);
825 /* check that we don't go over the end of the file accessing the sections */
826 section_ofs
= FIELD_OFFSET(IMAGE_NT_HEADERS
, OptionalHeader
) + nt
->FileHeader
.SizeOfOptionalHeader
;
827 if ((nt
->FileHeader
.NumberOfSections
* sizeof (IMAGE_SECTION_HEADER
) + section_ofs
) > mapping_size
)
831 *num_sections
= nt
->FileHeader
.NumberOfSections
;
833 /* from here we have a valid PE exe to update */
834 return (void*) ((BYTE
*)nt
+ section_ofs
);
837 static BOOL
check_pe_exe( HANDLE file
, QUEUEDUPDATES
*updates
)
839 const IMAGE_NT_HEADERS32
*nt
;
840 const IMAGE_NT_HEADERS64
*nt64
;
841 const IMAGE_SECTION_HEADER
*sec
;
842 const IMAGE_DATA_DIRECTORY
*dd
;
845 DWORD mapping_size
, num_sections
= 0;
848 mapping_size
= GetFileSize( file
, NULL
);
850 mapping
= CreateFileMappingW( file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
854 base
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, mapping_size
);
858 nt
= (IMAGE_NT_HEADERS32
*)get_nt_header( base
, mapping_size
);
862 nt64
= (IMAGE_NT_HEADERS64
*)nt
;
863 dd
= &nt
->OptionalHeader
.DataDirectory
[0];
864 if (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
)
865 dd
= &nt64
->OptionalHeader
.DataDirectory
[0];
867 TRACE("resources: %08x %08x\n",
868 dd
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
,
869 dd
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].Size
);
871 sec
= get_section_header( base
, mapping_size
, &num_sections
);
879 UnmapViewOfFile( base
);
881 CloseHandle( mapping
);
886 struct resource_size_info
{
890 DWORD data_entry_ofs
;
896 struct mapping_info
{
903 static const IMAGE_SECTION_HEADER
*section_from_rva( void *base
, DWORD mapping_size
, DWORD rva
)
905 const IMAGE_SECTION_HEADER
*sec
;
906 DWORD num_sections
= 0;
909 sec
= get_section_header( base
, mapping_size
, &num_sections
);
913 for (i
=num_sections
-1; i
>=0; i
--)
915 if (sec
[i
].VirtualAddress
<= rva
&&
916 rva
<= (DWORD
)sec
[i
].VirtualAddress
+ sec
[i
].SizeOfRawData
)
925 static void *address_from_rva( void *base
, DWORD mapping_size
, DWORD rva
, DWORD len
)
927 const IMAGE_SECTION_HEADER
*sec
;
929 sec
= section_from_rva( base
, mapping_size
, rva
);
933 if (rva
+ len
<= (DWORD
)sec
->VirtualAddress
+ sec
->SizeOfRawData
)
934 return (void*)((LPBYTE
) base
+ (sec
->PointerToRawData
+ rva
- sec
->VirtualAddress
));
939 static LPWSTR
resource_dup_string( const IMAGE_RESOURCE_DIRECTORY
*root
, const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
)
941 const IMAGE_RESOURCE_DIR_STRING_U
* string
;
944 if (!entry
->NameIsString
)
945 return UIntToPtr(entry
->Id
);
947 string
= (const IMAGE_RESOURCE_DIR_STRING_U
*) (((const char *)root
) + entry
->NameOffset
);
948 s
= HeapAlloc(GetProcessHeap(), 0, (string
->Length
+ 1)*sizeof (WCHAR
) );
949 memcpy( s
, string
->NameString
, (string
->Length
+ 1)*sizeof (WCHAR
) );
950 s
[string
->Length
] = 0;
955 /* this function is based on the code in winedump's pe.c */
956 static BOOL
enumerate_mapped_resources( QUEUEDUPDATES
*updates
,
957 void *base
, DWORD mapping_size
,
958 const IMAGE_RESOURCE_DIRECTORY
*root
)
960 const IMAGE_RESOURCE_DIRECTORY
*namedir
, *langdir
;
961 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*e1
, *e2
, *e3
;
962 const IMAGE_RESOURCE_DATA_ENTRY
*data
;
965 TRACE("version (%d.%d) %d named %d id entries\n",
966 root
->MajorVersion
, root
->MinorVersion
, root
->NumberOfNamedEntries
, root
->NumberOfIdEntries
);
968 for (i
= 0; i
< root
->NumberOfNamedEntries
+ root
->NumberOfIdEntries
; i
++)
972 e1
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(root
+ 1) + i
;
974 Type
= resource_dup_string( root
, e1
);
976 namedir
= (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ e1
->OffsetToDirectory
);
977 for (j
= 0; j
< namedir
->NumberOfNamedEntries
+ namedir
->NumberOfIdEntries
; j
++)
981 e2
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(namedir
+ 1) + j
;
983 Name
= resource_dup_string( root
, e2
);
985 langdir
= (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ e2
->OffsetToDirectory
);
986 for (k
= 0; k
< langdir
->NumberOfNamedEntries
+ langdir
->NumberOfIdEntries
; k
++)
990 struct resource_data
*resdata
;
992 e3
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(langdir
+ 1) + k
;
996 data
= (const IMAGE_RESOURCE_DATA_ENTRY
*)((const char *)root
+ e3
->OffsetToData
);
998 p
= address_from_rva( base
, mapping_size
, data
->OffsetToData
, data
->Size
);
1000 resdata
= allocate_resource_data( Lang
, data
->CodePage
, p
, data
->Size
, FALSE
);
1003 if (!update_add_resource( updates
, Type
, Name
, Lang
, resdata
, FALSE
))
1004 HeapFree( GetProcessHeap(), 0, resdata
);
1007 res_free_str( Name
);
1009 res_free_str( Type
);
1015 static BOOL
read_mapped_resources( QUEUEDUPDATES
*updates
, void *base
, DWORD mapping_size
)
1017 const IMAGE_RESOURCE_DIRECTORY
*root
;
1018 const IMAGE_NT_HEADERS
*nt
;
1019 const IMAGE_SECTION_HEADER
*sec
;
1020 DWORD num_sections
= 0, i
;
1022 nt
= get_nt_header( base
, mapping_size
);
1026 sec
= get_section_header( base
, mapping_size
, &num_sections
);
1030 for (i
=0; i
<num_sections
; i
++)
1031 if (!memcmp(sec
[i
].Name
, ".rsrc", 6))
1034 if (i
== num_sections
)
1037 /* check the resource data is inside the mapping */
1038 if (sec
[i
].PointerToRawData
> mapping_size
||
1039 (sec
[i
].PointerToRawData
+ sec
[i
].SizeOfRawData
) > mapping_size
)
1042 TRACE("found .rsrc at %08x, size %08x\n", sec
[i
].PointerToRawData
, sec
[i
].SizeOfRawData
);
1044 if (!sec
[i
].PointerToRawData
|| sec
[i
].SizeOfRawData
< sizeof(IMAGE_RESOURCE_DIRECTORY
))
1047 root
= (void*) ((BYTE
*)base
+ sec
[i
].PointerToRawData
);
1048 enumerate_mapped_resources( updates
, base
, mapping_size
, root
);
1053 static BOOL
map_file_into_memory( struct mapping_info
*mi
)
1055 DWORD page_attr
, perm
;
1060 page_attr
= PAGE_READWRITE
;
1061 perm
= FILE_MAP_WRITE
| FILE_MAP_READ
;
1065 page_attr
= PAGE_READONLY
;
1066 perm
= FILE_MAP_READ
;
1069 mapping
= CreateFileMappingW( mi
->file
, NULL
, page_attr
, 0, 0, NULL
);
1070 if (!mapping
) return FALSE
;
1072 mi
->base
= MapViewOfFile( mapping
, perm
, 0, 0, mi
->size
);
1073 CloseHandle( mapping
);
1075 return mi
->base
!= NULL
;
1078 static BOOL
unmap_file_from_memory( struct mapping_info
*mi
)
1081 UnmapViewOfFile( mi
->base
);
1086 static void destroy_mapping( struct mapping_info
*mi
)
1090 unmap_file_from_memory( mi
);
1092 CloseHandle( mi
->file
);
1093 HeapFree( GetProcessHeap(), 0, mi
);
1096 static struct mapping_info
*create_mapping( LPCWSTR name
, BOOL rw
)
1098 struct mapping_info
*mi
;
1100 mi
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof *mi
);
1104 mi
->read_write
= rw
;
1106 mi
->file
= CreateFileW( name
, GENERIC_READ
| (rw
? GENERIC_WRITE
: 0),
1107 0, NULL
, OPEN_EXISTING
, 0, 0 );
1109 if (mi
->file
!= INVALID_HANDLE_VALUE
)
1111 mi
->size
= GetFileSize( mi
->file
, NULL
);
1113 if (map_file_into_memory( mi
))
1116 destroy_mapping( mi
);
1120 static BOOL
resize_mapping( struct mapping_info
*mi
, DWORD new_size
)
1122 if (!unmap_file_from_memory( mi
))
1125 /* change the file size */
1126 SetFilePointer( mi
->file
, new_size
, NULL
, FILE_BEGIN
);
1127 if (!SetEndOfFile( mi
->file
))
1129 ERR("failed to set file size to %08x\n", new_size
);
1133 mi
->size
= new_size
;
1135 return map_file_into_memory( mi
);
1138 static void get_resource_sizes( QUEUEDUPDATES
*updates
, struct resource_size_info
*si
)
1140 struct resource_dir_entry
*types
, *names
;
1141 struct resource_data
*data
;
1142 DWORD num_types
= 0, num_names
= 0, num_langs
= 0, strings_size
= 0, data_size
= 0;
1144 memset( si
, 0, sizeof *si
);
1146 LIST_FOR_EACH_ENTRY( types
, &updates
->root
, struct resource_dir_entry
, entry
)
1149 if (!IS_INTRESOURCE( types
->id
))
1150 strings_size
+= sizeof (WORD
) + lstrlenW( types
->id
)*sizeof (WCHAR
);
1152 LIST_FOR_EACH_ENTRY( names
, &types
->children
, struct resource_dir_entry
, entry
)
1156 if (!IS_INTRESOURCE( names
->id
))
1157 strings_size
+= sizeof (WORD
) + lstrlenW( names
->id
)*sizeof (WCHAR
);
1159 LIST_FOR_EACH_ENTRY( data
, &names
->children
, struct resource_data
, entry
)
1162 data_size
+= (data
->cbData
+ 3) & ~3;
1167 /* names are at the end of the types */
1168 si
->names_ofs
= sizeof (IMAGE_RESOURCE_DIRECTORY
) +
1169 num_types
* sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1171 /* language directories are at the end of the names */
1172 si
->langs_ofs
= si
->names_ofs
+
1173 num_types
* sizeof (IMAGE_RESOURCE_DIRECTORY
) +
1174 num_names
* sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1176 si
->data_entry_ofs
= si
->langs_ofs
+
1177 num_names
* sizeof (IMAGE_RESOURCE_DIRECTORY
) +
1178 num_langs
* sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1180 si
->strings_ofs
= si
->data_entry_ofs
+
1181 num_langs
* sizeof (IMAGE_RESOURCE_DATA_ENTRY
);
1183 si
->data_ofs
= si
->strings_ofs
+ ((strings_size
+ 3) & ~3);
1185 si
->total_size
= si
->data_ofs
+ data_size
;
1187 TRACE("names %08x langs %08x data entries %08x strings %08x data %08x total %08x\n",
1188 si
->names_ofs
, si
->langs_ofs
, si
->data_entry_ofs
,
1189 si
->strings_ofs
, si
->data_ofs
, si
->total_size
);
1192 static void res_write_padding( BYTE
*res_base
, DWORD size
)
1194 static const BYTE pad
[] = {
1195 'P','A','D','D','I','N','G','X','X','P','A','D','D','I','N','G' };
1198 for ( i
= 0; i
< size
/ sizeof pad
; i
++ )
1199 memcpy( &res_base
[i
*sizeof pad
], pad
, sizeof pad
);
1200 memcpy( &res_base
[i
*sizeof pad
], pad
, size
%sizeof pad
);
1203 static BOOL
write_resources( QUEUEDUPDATES
*updates
, LPBYTE base
, struct resource_size_info
*si
, DWORD rva
)
1205 struct resource_dir_entry
*types
, *names
;
1206 struct resource_data
*data
;
1207 IMAGE_RESOURCE_DIRECTORY
*root
;
1209 TRACE("%p %p %p %08x\n", updates
, base
, si
, rva
);
1211 memset( base
, 0, si
->total_size
);
1213 /* the root entry always exists */
1214 root
= (IMAGE_RESOURCE_DIRECTORY
*) base
;
1215 memset( root
, 0, sizeof *root
);
1216 root
->MajorVersion
= 4;
1217 si
->types_ofs
= sizeof *root
;
1218 LIST_FOR_EACH_ENTRY( types
, &updates
->root
, struct resource_dir_entry
, entry
)
1220 IMAGE_RESOURCE_DIRECTORY_ENTRY
*e1
;
1221 IMAGE_RESOURCE_DIRECTORY
*namedir
;
1223 e1
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*) &base
[si
->types_ofs
];
1224 memset( e1
, 0, sizeof *e1
);
1225 if (!IS_INTRESOURCE( types
->id
))
1230 root
->NumberOfNamedEntries
++;
1231 e1
->NameIsString
= 1;
1232 e1
->NameOffset
= si
->strings_ofs
;
1234 strings
= (WCHAR
*) &base
[si
->strings_ofs
];
1235 len
= lstrlenW( types
->id
);
1237 memcpy( &strings
[1], types
->id
, len
* sizeof (WCHAR
) );
1238 si
->strings_ofs
+= (len
+ 1) * sizeof (WCHAR
);
1242 root
->NumberOfIdEntries
++;
1243 e1
->Id
= LOWORD( types
->id
);
1245 e1
->OffsetToDirectory
= si
->names_ofs
;
1246 e1
->DataIsDirectory
= TRUE
;
1247 si
->types_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1249 namedir
= (IMAGE_RESOURCE_DIRECTORY
*) &base
[si
->names_ofs
];
1250 memset( namedir
, 0, sizeof *namedir
);
1251 namedir
->MajorVersion
= 4;
1252 si
->names_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY
);
1254 LIST_FOR_EACH_ENTRY( names
, &types
->children
, struct resource_dir_entry
, entry
)
1256 IMAGE_RESOURCE_DIRECTORY_ENTRY
*e2
;
1257 IMAGE_RESOURCE_DIRECTORY
*langdir
;
1259 e2
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*) &base
[si
->names_ofs
];
1260 memset( e2
, 0, sizeof *e2
);
1261 if (!IS_INTRESOURCE( names
->id
))
1266 namedir
->NumberOfNamedEntries
++;
1267 e2
->NameIsString
= 1;
1268 e2
->NameOffset
= si
->strings_ofs
;
1270 strings
= (WCHAR
*) &base
[si
->strings_ofs
];
1271 len
= lstrlenW( names
->id
);
1273 memcpy( &strings
[1], names
->id
, len
* sizeof (WCHAR
) );
1274 si
->strings_ofs
+= (len
+ 1) * sizeof (WCHAR
);
1278 namedir
->NumberOfIdEntries
++;
1279 e2
->Id
= LOWORD( names
->id
);
1281 e2
->OffsetToDirectory
= si
->langs_ofs
;
1282 e2
->DataIsDirectory
= TRUE
;
1283 si
->names_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1285 langdir
= (IMAGE_RESOURCE_DIRECTORY
*) &base
[si
->langs_ofs
];
1286 memset( langdir
, 0, sizeof *langdir
);
1287 langdir
->MajorVersion
= 4;
1288 si
->langs_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY
);
1290 LIST_FOR_EACH_ENTRY( data
, &names
->children
, struct resource_data
, entry
)
1292 IMAGE_RESOURCE_DIRECTORY_ENTRY
*e3
;
1293 IMAGE_RESOURCE_DATA_ENTRY
*de
;
1296 e3
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*) &base
[si
->langs_ofs
];
1297 memset( e3
, 0, sizeof *e3
);
1298 langdir
->NumberOfIdEntries
++;
1299 e3
->Id
= LOWORD( data
->lang
);
1300 e3
->OffsetToData
= si
->data_entry_ofs
;
1302 si
->langs_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1304 /* write out all the data entries */
1305 de
= (IMAGE_RESOURCE_DATA_ENTRY
*) &base
[si
->data_entry_ofs
];
1306 memset( de
, 0, sizeof *de
);
1307 de
->OffsetToData
= si
->data_ofs
+ rva
;
1308 de
->Size
= data
->cbData
;
1309 de
->CodePage
= data
->codepage
;
1310 si
->data_entry_ofs
+= sizeof (IMAGE_RESOURCE_DATA_ENTRY
);
1312 /* write out the resource data */
1313 memcpy( &base
[si
->data_ofs
], data
->lpData
, data
->cbData
);
1314 si
->data_ofs
+= data
->cbData
;
1316 pad_size
= (-si
->data_ofs
)&3;
1317 res_write_padding( &base
[si
->data_ofs
], pad_size
);
1318 si
->data_ofs
+= pad_size
;
1328 * Assumes that the resources are in .rsrc
1329 * and .rsrc is the last section in the file.
1330 * Not sure whether updating resources will other cases on Windows.
1331 * If the resources lie in a section containing other data,
1332 * resizing that section could possibly cause trouble.
1333 * If the section with the resources isn't last, the remaining
1334 * sections need to be moved down in the file, and the section header
1335 * would need to be adjusted.
1336 * If we needed to add a section, what would we name it?
1337 * If we needed to add a section and there wasn't space in the file
1338 * header, how would that work?
1339 * Seems that at least some of these cases can't be handled properly.
1341 static IMAGE_SECTION_HEADER
*get_resource_section( void *base
, DWORD mapping_size
)
1343 IMAGE_SECTION_HEADER
*sec
;
1344 IMAGE_NT_HEADERS
*nt
;
1345 DWORD i
, num_sections
= 0;
1347 nt
= get_nt_header( base
, mapping_size
);
1351 sec
= get_section_header( base
, mapping_size
, &num_sections
);
1355 /* find the resources section */
1356 for (i
=0; i
<num_sections
; i
++)
1357 if (!memcmp(sec
[i
].Name
, ".rsrc", 6))
1360 if (i
== num_sections
)
1366 static DWORD
get_init_data_size( void *base
, DWORD mapping_size
)
1368 DWORD i
, sz
= 0, num_sections
= 0;
1369 IMAGE_SECTION_HEADER
*s
;
1371 s
= get_section_header( base
, mapping_size
, &num_sections
);
1373 for (i
=0; i
<num_sections
; i
++)
1374 if (s
[i
].Characteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
1375 sz
+= s
[i
].SizeOfRawData
;
1377 TRACE("size = %08x\n", sz
);
1382 static BOOL
write_raw_resources( QUEUEDUPDATES
*updates
)
1384 static const WCHAR prefix
[] = { 'r','e','s','u',0 };
1385 WCHAR tempdir
[MAX_PATH
], tempfile
[MAX_PATH
];
1388 IMAGE_SECTION_HEADER
*sec
;
1389 IMAGE_NT_HEADERS32
*nt
;
1390 IMAGE_NT_HEADERS64
*nt64
;
1391 struct resource_size_info res_size
;
1393 struct mapping_info
*read_map
= NULL
, *write_map
= NULL
;
1394 DWORD PeSectionAlignment
, PeFileAlignment
, PeSizeOfImage
;
1396 /* copy the exe to a temp file then update the temp file... */
1398 if (!GetTempPathW( MAX_PATH
, tempdir
))
1401 if (!GetTempFileNameW( tempdir
, prefix
, 0, tempfile
))
1404 if (!CopyFileW( updates
->pFileName
, tempfile
, FALSE
))
1407 TRACE("tempfile %s\n", debugstr_w(tempfile
));
1409 if (!updates
->bDeleteExistingResources
)
1411 read_map
= create_mapping( updates
->pFileName
, FALSE
);
1415 ret
= read_mapped_resources( updates
, read_map
->base
, read_map
->size
);
1418 ERR("failed to read existing resources\n");
1423 write_map
= create_mapping( tempfile
, TRUE
);
1427 nt
= (IMAGE_NT_HEADERS32
*)get_nt_header( write_map
->base
, write_map
->size
);
1431 nt64
= (IMAGE_NT_HEADERS64
*)nt
;
1432 if (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1433 PeSectionAlignment
= nt64
->OptionalHeader
.SectionAlignment
;
1434 PeFileAlignment
= nt64
->OptionalHeader
.FileAlignment
;
1435 PeSizeOfImage
= nt64
->OptionalHeader
.SizeOfImage
;
1437 PeSectionAlignment
= nt
->OptionalHeader
.SectionAlignment
;
1438 PeFileAlignment
= nt
->OptionalHeader
.FileAlignment
;
1439 PeSizeOfImage
= nt
->OptionalHeader
.SizeOfImage
;
1442 if ((LONG
)PeSectionAlignment
<= 0)
1444 ERR("invalid section alignment %08x\n", PeSectionAlignment
);
1448 if ((LONG
)PeFileAlignment
<= 0)
1450 ERR("invalid file alignment %08x\n", PeFileAlignment
);
1454 sec
= get_resource_section( write_map
->base
, write_map
->size
);
1455 if (!sec
) /* no section, add one */
1459 sec
= get_section_header( write_map
->base
, write_map
->size
, &num_sections
);
1463 sec
+= num_sections
;
1464 nt
->FileHeader
.NumberOfSections
++;
1466 memset( sec
, 0, sizeof *sec
);
1467 memcpy( sec
->Name
, ".rsrc", 5 );
1468 sec
->Characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
| IMAGE_SCN_MEM_READ
;
1469 sec
->VirtualAddress
= PeSizeOfImage
;
1472 if (!sec
->PointerToRawData
) /* empty section */
1474 sec
->PointerToRawData
= write_map
->size
+ (-write_map
->size
) % PeFileAlignment
;
1475 sec
->SizeOfRawData
= 0;
1478 TRACE("before .rsrc at %08x, size %08x\n", sec
->PointerToRawData
, sec
->SizeOfRawData
);
1480 get_resource_sizes( updates
, &res_size
);
1482 /* round up the section size */
1483 section_size
= res_size
.total_size
;
1484 section_size
+= (-section_size
) % PeFileAlignment
;
1486 TRACE("requires %08x (%08x) bytes\n", res_size
.total_size
, section_size
);
1488 /* check if the file size needs to be changed */
1489 if (section_size
!= sec
->SizeOfRawData
)
1491 DWORD old_size
= write_map
->size
;
1492 DWORD virtual_section_size
= res_size
.total_size
+ (-res_size
.total_size
) % PeSectionAlignment
;
1493 int delta
= section_size
- (sec
->SizeOfRawData
+ (-sec
->SizeOfRawData
) % PeFileAlignment
);
1494 int rva_delta
= virtual_section_size
-
1495 (sec
->Misc
.VirtualSize
+ (-sec
->Misc
.VirtualSize
) % PeSectionAlignment
);
1496 /* when new section is added it could end past current mapping size */
1497 BOOL rsrc_is_last
= sec
->PointerToRawData
+ sec
->SizeOfRawData
>= old_size
;
1498 /* align .rsrc size when possible */
1499 DWORD mapping_size
= rsrc_is_last
? sec
->PointerToRawData
+ section_size
: old_size
+ delta
;
1501 /* postpone file truncation if there are some data to be moved down from file end */
1502 BOOL resize_after
= mapping_size
< old_size
&& !rsrc_is_last
;
1504 TRACE("file size %08x -> %08x\n", old_size
, mapping_size
);
1508 /* unmap the file before changing the file size */
1509 ret
= resize_mapping( write_map
, mapping_size
);
1511 /* get the pointers again - they might be different after remapping */
1512 nt
= (IMAGE_NT_HEADERS32
*)get_nt_header( write_map
->base
, mapping_size
);
1515 ERR("couldn't get NT header\n");
1518 nt64
= (IMAGE_NT_HEADERS64
*)nt
;
1520 sec
= get_resource_section( write_map
->base
, mapping_size
);
1525 if (!rsrc_is_last
) /* not last section, relocate trailing sections */
1527 IMAGE_SECTION_HEADER
*s
;
1528 DWORD tail_start
= sec
->PointerToRawData
+ sec
->SizeOfRawData
;
1529 DWORD i
, num_sections
= 0;
1531 memmove( (char*)write_map
->base
+ tail_start
+ delta
, (char*)write_map
->base
+ tail_start
, old_size
- tail_start
);
1533 s
= get_section_header( write_map
->base
, mapping_size
, &num_sections
);
1535 for (i
=0; i
<num_sections
; i
++)
1537 if (s
[i
].PointerToRawData
> sec
->PointerToRawData
)
1539 s
[i
].PointerToRawData
+= delta
;
1540 s
[i
].VirtualAddress
+= rva_delta
;
1547 ret
= resize_mapping( write_map
, mapping_size
);
1549 nt
= (IMAGE_NT_HEADERS32
*)get_nt_header( write_map
->base
, mapping_size
);
1552 ERR("couldn't get NT header\n");
1555 nt64
= (IMAGE_NT_HEADERS64
*)nt
;
1557 sec
= get_resource_section( write_map
->base
, mapping_size
);
1562 /* adjust the PE header information */
1563 sec
->SizeOfRawData
= section_size
;
1564 sec
->Misc
.VirtualSize
= virtual_section_size
;
1565 if (nt
->OptionalHeader
.Magic
== IMAGE_NT_OPTIONAL_HDR64_MAGIC
) {
1566 nt64
->OptionalHeader
.SizeOfImage
+= rva_delta
;
1567 nt64
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
= sec
->VirtualAddress
;
1568 nt64
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].Size
= res_size
.total_size
;
1569 nt64
->OptionalHeader
.SizeOfInitializedData
= get_init_data_size( write_map
->base
, mapping_size
);
1571 nt
->OptionalHeader
.SizeOfImage
+= rva_delta
;
1572 nt
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
= sec
->VirtualAddress
;
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
);
1578 res_base
= (LPBYTE
) write_map
->base
+ sec
->PointerToRawData
;
1580 TRACE("base = %p offset = %08x\n", write_map
->base
, sec
->PointerToRawData
);
1582 ret
= write_resources( updates
, res_base
, &res_size
, sec
->VirtualAddress
);
1584 res_write_padding( res_base
+ res_size
.total_size
, section_size
- res_size
.total_size
);
1586 TRACE("after .rsrc at %08x, size %08x\n", sec
->PointerToRawData
, sec
->SizeOfRawData
);
1589 destroy_mapping( read_map
);
1590 destroy_mapping( write_map
);
1593 ret
= CopyFileW( tempfile
, updates
->pFileName
, FALSE
);
1595 DeleteFileW( tempfile
);
1600 /***********************************************************************
1601 * BeginUpdateResourceW (KERNEL32.@)
1603 HANDLE WINAPI
BeginUpdateResourceW( LPCWSTR pFileName
, BOOL bDeleteExistingResources
)
1605 QUEUEDUPDATES
*updates
= NULL
;
1606 HANDLE hUpdate
, file
, ret
= NULL
;
1608 TRACE("%s, %d\n", debugstr_w(pFileName
), bDeleteExistingResources
);
1610 hUpdate
= GlobalAlloc(GHND
, sizeof(QUEUEDUPDATES
));
1614 updates
= GlobalLock(hUpdate
);
1617 list_init( &updates
->root
);
1618 updates
->bDeleteExistingResources
= bDeleteExistingResources
;
1619 updates
->pFileName
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName
)+1)*sizeof(WCHAR
));
1620 if (updates
->pFileName
)
1622 lstrcpyW(updates
->pFileName
, pFileName
);
1624 file
= CreateFileW( pFileName
, GENERIC_READ
| GENERIC_WRITE
,
1625 0, NULL
, OPEN_EXISTING
, 0, 0 );
1627 /* if resources are deleted, only the file's presence is checked */
1628 if (file
!= INVALID_HANDLE_VALUE
&&
1629 (bDeleteExistingResources
|| check_pe_exe( file
, updates
)))
1632 HeapFree( GetProcessHeap(), 0, updates
->pFileName
);
1634 CloseHandle( file
);
1636 GlobalUnlock(hUpdate
);
1640 GlobalFree(hUpdate
);
1646 /***********************************************************************
1647 * BeginUpdateResourceA (KERNEL32.@)
1649 HANDLE WINAPI
BeginUpdateResourceA( LPCSTR pFileName
, BOOL bDeleteExistingResources
)
1651 UNICODE_STRING FileNameW
;
1653 RtlCreateUnicodeStringFromAsciiz(&FileNameW
, pFileName
);
1654 ret
= BeginUpdateResourceW(FileNameW
.Buffer
, bDeleteExistingResources
);
1655 RtlFreeUnicodeString(&FileNameW
);
1660 /***********************************************************************
1661 * EndUpdateResourceW (KERNEL32.@)
1663 BOOL WINAPI
EndUpdateResourceW( HANDLE hUpdate
, BOOL fDiscard
)
1665 QUEUEDUPDATES
*updates
;
1668 TRACE("%p %d\n", hUpdate
, fDiscard
);
1670 updates
= GlobalLock(hUpdate
);
1674 ret
= fDiscard
|| write_raw_resources( updates
);
1676 free_resource_directory( &updates
->root
, 2 );
1678 HeapFree( GetProcessHeap(), 0, updates
->pFileName
);
1679 GlobalUnlock( hUpdate
);
1680 GlobalFree( hUpdate
);
1686 /***********************************************************************
1687 * EndUpdateResourceA (KERNEL32.@)
1689 BOOL WINAPI
EndUpdateResourceA( HANDLE hUpdate
, BOOL fDiscard
)
1691 return EndUpdateResourceW(hUpdate
, fDiscard
);
1695 /***********************************************************************
1696 * UpdateResourceW (KERNEL32.@)
1698 BOOL WINAPI
UpdateResourceW( HANDLE hUpdate
, LPCWSTR lpType
, LPCWSTR lpName
,
1699 WORD wLanguage
, LPVOID lpData
, DWORD cbData
)
1701 QUEUEDUPDATES
*updates
;
1704 TRACE("%p %s %s %08x %p %d\n", hUpdate
,
1705 debugstr_w(lpType
), debugstr_w(lpName
), wLanguage
, lpData
, cbData
);
1707 updates
= GlobalLock(hUpdate
);
1710 if (lpData
== NULL
&& cbData
== 0) /* remove resource */
1712 ret
= update_add_resource( updates
, lpType
, lpName
, wLanguage
, NULL
, TRUE
);
1716 struct resource_data
*data
;
1717 data
= allocate_resource_data( wLanguage
, 0, lpData
, cbData
, TRUE
);
1719 ret
= update_add_resource( updates
, lpType
, lpName
, wLanguage
, data
, TRUE
);
1721 GlobalUnlock(hUpdate
);
1727 /***********************************************************************
1728 * UpdateResourceA (KERNEL32.@)
1730 BOOL WINAPI
UpdateResourceA( HANDLE hUpdate
, LPCSTR lpType
, LPCSTR lpName
,
1731 WORD wLanguage
, LPVOID lpData
, DWORD cbData
)
1734 UNICODE_STRING TypeW
;
1735 UNICODE_STRING NameW
;
1736 if(IS_INTRESOURCE(lpType
))
1737 TypeW
.Buffer
= ULongToPtr(LOWORD(lpType
));
1739 RtlCreateUnicodeStringFromAsciiz(&TypeW
, lpType
);
1740 if(IS_INTRESOURCE(lpName
))
1741 NameW
.Buffer
= ULongToPtr(LOWORD(lpName
));
1743 RtlCreateUnicodeStringFromAsciiz(&NameW
, lpName
);
1744 ret
= UpdateResourceW(hUpdate
, TypeW
.Buffer
, NameW
.Buffer
, wLanguage
, lpData
, cbData
);
1745 if(!IS_INTRESOURCE(lpType
)) RtlFreeUnicodeString(&TypeW
);
1746 if(!IS_INTRESOURCE(lpName
)) RtlFreeUnicodeString(&NameW
);