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
24 #include "wine/port.h"
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
31 #define WIN32_NO_STATUS
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
)
55 str
->Buffer
= ULongToPtr(LOWORD(name
));
56 return STATUS_SUCCESS
;
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
)
76 str
->Buffer
= ULongToPtr(LOWORD(name
));
77 return STATUS_SUCCESS
;
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
;
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
));
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
));
118 if (HIWORD(*nameA
)) HeapFree( GetProcessHeap(), 0, *nameA
);
119 if (HIWORD(*typeA
)) HeapFree( GetProcessHeap(), 0, *typeA
);
120 SetLastError( ERROR_INVALID_PARAMETER
);
127 /* implementation of FindResourceExA */
128 static HRSRC
find_resourceA( HMODULE hModule
, LPCSTR type
, LPCSTR name
, WORD lang
)
131 UNICODE_STRING nameW
, typeW
;
132 LDR_RESOURCE_INFO info
;
133 const IMAGE_RESOURCE_DATA_ENTRY
*entry
= NULL
;
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
);
147 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
151 SetLastError( ERROR_INVALID_PARAMETER
);
155 if (HIWORD(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
156 if (HIWORD(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
161 /* implementation of FindResourceExW */
162 static HRSRC
find_resourceW( HMODULE hModule
, LPCWSTR type
, LPCWSTR name
, WORD lang
)
165 UNICODE_STRING nameW
, typeW
;
166 LDR_RESOURCE_INFO info
;
167 const IMAGE_RESOURCE_DATA_ENTRY
*entry
= NULL
;
169 nameW
.Buffer
= typeW
.Buffer
= NULL
;
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
);
180 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
184 SetLastError( ERROR_INVALID_PARAMETER
);
188 if (HIWORD(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
189 if (HIWORD(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
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
))
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
)
260 DWORD len
= 0, newlen
;
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
) );
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
)
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
);
290 ret
= lpfun(hmod
,type
,lparam
);
294 ret
= lpfun( hmod
, UIntToPtr(et
[i
].u1
.s2
.Id
), lparam
);
298 HeapFree( GetProcessHeap(), 0, type
);
303 /**********************************************************************
304 * EnumResourceTypesW (KERNEL32.@)
306 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG_PTR lparam
)
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
) );
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
);
343 ret
= lpfun( hmod
, UIntToPtr(et
[i
].u1
.s2
.Id
), lparam
);
347 HeapFree( GetProcessHeap(), 0, type
);
352 /**********************************************************************
353 * EnumResourceNamesA (KERNEL32.@)
355 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG_PTR lparam
)
359 DWORD len
= 0, newlen
;
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
);
372 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
374 if ((status
= get_res_nameA( type
, &typeW
)) != STATUS_SUCCESS
)
376 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
377 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 1, &resdir
)) != STATUS_SUCCESS
)
380 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
383 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
; i
++)
385 if (et
[i
].u1
.s1
.NameIsString
)
387 str
= (const IMAGE_RESOURCE_DIR_STRING_U
*)((const BYTE
*)basedir
+ et
[i
].u1
.s1
.NameOffset
);
388 newlen
= WideCharToMultiByte(CP_ACP
, 0, str
->NameString
, str
->Length
, NULL
, 0, NULL
, NULL
);
389 if (newlen
+ 1 > len
)
392 HeapFree( GetProcessHeap(), 0, name
);
393 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
399 WideCharToMultiByte( CP_ACP
, 0, str
->NameString
, str
->Length
, name
, len
, NULL
, NULL
);
401 ret
= lpfun(hmod
,type
,name
,lparam
);
405 ret
= lpfun( hmod
, type
, UIntToPtr(et
[i
].u1
.s2
.Id
), lparam
);
413 status
= STATUS_ACCESS_VIOLATION
;
418 HeapFree( GetProcessHeap(), 0, name
);
419 if (HIWORD(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
420 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
425 /**********************************************************************
426 * EnumResourceNamesW (KERNEL32.@)
428 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG_PTR lparam
)
434 UNICODE_STRING typeW
;
435 LDR_RESOURCE_INFO info
;
436 const IMAGE_RESOURCE_DIRECTORY
*basedir
, *resdir
;
437 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
438 const IMAGE_RESOURCE_DIR_STRING_U
*str
;
440 TRACE( "%p %s %p %lx\n", hmod
, debugstr_w(type
), lpfun
, lparam
);
442 if (!hmod
) hmod
= GetModuleHandleW( NULL
);
444 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
446 if ((status
= get_res_nameW( type
, &typeW
)) != STATUS_SUCCESS
)
448 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
449 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 1, &resdir
)) != STATUS_SUCCESS
)
452 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
455 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
; i
++)
457 if (et
[i
].u1
.s1
.NameIsString
)
459 str
= (const IMAGE_RESOURCE_DIR_STRING_U
*)((const BYTE
*)basedir
+ et
[i
].u1
.s1
.NameOffset
);
460 if (str
->Length
+ 1 > len
)
462 len
= str
->Length
+ 1;
463 HeapFree( GetProcessHeap(), 0, name
);
464 if (!(name
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
470 memcpy(name
, str
->NameString
, str
->Length
* sizeof (WCHAR
));
471 name
[str
->Length
] = 0;
472 ret
= lpfun(hmod
,type
,name
,lparam
);
476 ret
= lpfun( hmod
, type
, UIntToPtr(et
[i
].u1
.s2
.Id
), lparam
);
484 status
= STATUS_ACCESS_VIOLATION
;
488 HeapFree( GetProcessHeap(), 0, name
);
489 if (HIWORD(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
490 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
495 /**********************************************************************
496 * EnumResourceLanguagesA (KERNEL32.@)
498 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
499 ENUMRESLANGPROCA lpfun
, LONG_PTR lparam
)
504 UNICODE_STRING typeW
, nameW
;
505 LDR_RESOURCE_INFO info
;
506 const IMAGE_RESOURCE_DIRECTORY
*basedir
, *resdir
;
507 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
509 TRACE( "%p %s %s %p %lx\n", hmod
, debugstr_a(type
), debugstr_a(name
), lpfun
, lparam
);
511 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
512 typeW
.Buffer
= nameW
.Buffer
= NULL
;
513 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
515 if ((status
= get_res_nameA( type
, &typeW
)) != STATUS_SUCCESS
)
517 if ((status
= get_res_nameA( name
, &nameW
)) != STATUS_SUCCESS
)
519 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
520 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
521 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 2, &resdir
)) != STATUS_SUCCESS
)
524 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
527 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+ resdir
->NumberOfIdEntries
; i
++)
529 ret
= lpfun( hmod
, type
, name
, et
[i
].u1
.s2
.Id
, lparam
);
536 status
= STATUS_ACCESS_VIOLATION
;
540 if (HIWORD(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
541 if (HIWORD(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
542 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
547 /**********************************************************************
548 * EnumResourceLanguagesW (KERNEL32.@)
550 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
551 ENUMRESLANGPROCW lpfun
, LONG_PTR lparam
)
556 UNICODE_STRING typeW
, nameW
;
557 LDR_RESOURCE_INFO info
;
558 const IMAGE_RESOURCE_DIRECTORY
*basedir
, *resdir
;
559 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*et
;
561 TRACE( "%p %s %s %p %lx\n", hmod
, debugstr_w(type
), debugstr_w(name
), lpfun
, lparam
);
563 if (!hmod
) hmod
= GetModuleHandleW( NULL
);
564 typeW
.Buffer
= nameW
.Buffer
= NULL
;
565 if ((status
= LdrFindResourceDirectory_U( hmod
, NULL
, 0, &basedir
)) != STATUS_SUCCESS
)
567 if ((status
= get_res_nameW( type
, &typeW
)) != STATUS_SUCCESS
)
569 if ((status
= get_res_nameW( name
, &nameW
)) != STATUS_SUCCESS
)
571 info
.Type
= (ULONG_PTR
)typeW
.Buffer
;
572 info
.Name
= (ULONG_PTR
)nameW
.Buffer
;
573 if ((status
= LdrFindResourceDirectory_U( hmod
, &info
, 2, &resdir
)) != STATUS_SUCCESS
)
576 et
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(resdir
+ 1);
579 for (i
= 0; i
< resdir
->NumberOfNamedEntries
+ resdir
->NumberOfIdEntries
; i
++)
581 ret
= lpfun( hmod
, type
, name
, et
[i
].u1
.s2
.Id
, lparam
);
588 status
= STATUS_ACCESS_VIOLATION
;
592 if (HIWORD(typeW
.Buffer
)) HeapFree( GetProcessHeap(), 0, typeW
.Buffer
);
593 if (HIWORD(nameW
.Buffer
)) HeapFree( GetProcessHeap(), 0, nameW
.Buffer
);
594 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
599 /**********************************************************************
600 * LoadResource (KERNEL32.@)
602 HGLOBAL WINAPI
LoadResource( HINSTANCE hModule
, HRSRC hRsrc
)
607 TRACE( "%p %p\n", hModule
, hRsrc
);
609 if (hModule
&& !HIWORD(hModule
))
610 /* FIXME: should convert return to 32-bit resource */
611 return HGLOBAL_32( LoadResource16( HMODULE_16(hModule
), HRSRC_16(hRsrc
) ) );
613 if (!hRsrc
) return 0;
614 if (!hModule
) hModule
= GetModuleHandleA( NULL
);
615 status
= LdrAccessResource( hModule
, (IMAGE_RESOURCE_DATA_ENTRY
*)hRsrc
, &ret
, NULL
);
616 if (status
!= STATUS_SUCCESS
) SetLastError( RtlNtStatusToDosError(status
) );
621 /**********************************************************************
622 * LockResource (KERNEL32.@)
624 LPVOID WINAPI
LockResource( HGLOBAL handle
)
626 TRACE("(%p)\n", handle
);
628 if (HIWORD( handle
)) /* 32-bit memory handle */
631 /* 16-bit memory handle */
632 return LockResource16( HGLOBAL_16(handle
) );
636 /**********************************************************************
637 * FreeResource (KERNEL32.@)
639 BOOL WINAPI
FreeResource( HGLOBAL handle
)
641 if (HIWORD(handle
)) return 0; /* 32-bit memory handle: nothing to do */
642 return FreeResource16( HGLOBAL_16(handle
) );
646 /**********************************************************************
647 * SizeofResource (KERNEL32.@)
649 DWORD WINAPI
SizeofResource( HINSTANCE hModule
, HRSRC hRsrc
)
651 if (hModule
&& !HIWORD(hModule
))
652 return SizeofResource16( HMODULE_16(hModule
), HRSRC_16(hRsrc
) );
654 if (!hRsrc
) return 0;
655 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
659 * Data structure for updating resources.
660 * Type/Name/Language is a keyset for accessing resource data.
662 * QUEUEDUPDATES (root) ->
663 * list of struct resource_dir_entry (Type) ->
664 * list of struct resource_dir_entry (Name) ->
665 * list of struct resource_data Language + Data
671 BOOL bDeleteExistingResources
;
675 /* this structure is shared for types and names */
676 struct resource_dir_entry
{
679 struct list children
;
682 /* this structure is the leaf */
683 struct resource_data
{
691 static int resource_strcmp( LPCWSTR a
, LPCWSTR b
)
695 if (HIWORD( a
) && HIWORD( b
) )
696 return lstrcmpW( a
, b
);
697 /* strings come before ids */
698 if (HIWORD( a
) && !HIWORD( b
))
700 if (HIWORD( b
) && !HIWORD( a
))
702 return ( a
< b
) ? -1 : 1;
705 static struct resource_dir_entry
*find_resource_dir_entry( struct list
*dir
, LPCWSTR id
)
707 struct resource_dir_entry
*ent
;
709 /* match either IDs or strings */
710 LIST_FOR_EACH_ENTRY( ent
, dir
, struct resource_dir_entry
, entry
)
711 if (!resource_strcmp( id
, ent
->id
))
717 static struct resource_data
*find_resource_data( struct list
*dir
, LANGID lang
)
719 struct resource_data
*res_data
;
721 /* match only languages here */
722 LIST_FOR_EACH_ENTRY( res_data
, dir
, struct resource_data
, entry
)
723 if ( lang
== res_data
->lang
)
729 static void add_resource_dir_entry( struct list
*dir
, struct resource_dir_entry
*resdir
)
731 struct resource_dir_entry
*ent
;
733 LIST_FOR_EACH_ENTRY( ent
, dir
, struct resource_dir_entry
, entry
)
735 if (0>resource_strcmp( ent
->id
, resdir
->id
))
738 list_add_before( &ent
->entry
, &resdir
->entry
);
741 list_add_tail( dir
, &resdir
->entry
);
744 static void add_resource_data_entry( struct list
*dir
, struct resource_data
*resdata
)
746 struct resource_data
*ent
;
748 LIST_FOR_EACH_ENTRY( ent
, dir
, struct resource_data
, entry
)
750 if (ent
->lang
< resdata
->lang
)
753 list_add_before( &ent
->entry
, &resdata
->entry
);
756 list_add_tail( dir
, &resdata
->entry
);
759 static LPWSTR
res_strdupW( LPCWSTR str
)
764 if (HIWORD(str
) == 0)
765 return (LPWSTR
) (UINT_PTR
) LOWORD(str
);
766 len
= (lstrlenW( str
) + 1) * sizeof (WCHAR
);
767 ret
= HeapAlloc( GetProcessHeap(), 0, len
);
768 memcpy( ret
, str
, len
);
772 static void res_free_str( LPWSTR str
)
775 HeapFree( GetProcessHeap(), 0, str
);
778 static BOOL
update_add_resource( QUEUEDUPDATES
*updates
, LPCWSTR Type
, LPCWSTR Name
,
779 struct resource_data
*resdata
, BOOL overwrite_existing
)
781 struct resource_dir_entry
*restype
, *resname
;
782 struct resource_data
*existing
;
784 TRACE("%p %s %s %p %d\n", updates
,
785 debugstr_w(Type
), debugstr_w(Name
), resdata
, overwrite_existing
);
787 restype
= find_resource_dir_entry( &updates
->root
, Type
);
790 restype
= HeapAlloc( GetProcessHeap(), 0, sizeof *restype
);
791 restype
->id
= res_strdupW( Type
);
792 list_init( &restype
->children
);
793 add_resource_dir_entry( &updates
->root
, restype
);
796 resname
= find_resource_dir_entry( &restype
->children
, Name
);
799 resname
= HeapAlloc( GetProcessHeap(), 0, sizeof *resname
);
800 resname
->id
= res_strdupW( Name
);
801 list_init( &resname
->children
);
802 add_resource_dir_entry( &restype
->children
, resname
);
806 * If there's an existing resource entry with matching (Type,Name,Language)
807 * it needs to be removed before adding the new data.
809 existing
= find_resource_data( &resname
->children
, resdata
->lang
);
812 if (!overwrite_existing
)
814 list_remove( &existing
->entry
);
815 HeapFree( GetProcessHeap(), 0, existing
);
818 add_resource_data_entry( &resname
->children
, resdata
);
823 static struct resource_data
*allocate_resource_data( WORD Language
, DWORD codepage
,
824 LPVOID lpData
, DWORD cbData
, BOOL copy_data
)
826 struct resource_data
*resdata
;
828 if (!lpData
|| !cbData
)
831 resdata
= HeapAlloc( GetProcessHeap(), 0, sizeof *resdata
+ (copy_data
? cbData
: 0) );
834 resdata
->lang
= Language
;
835 resdata
->codepage
= codepage
;
836 resdata
->cbData
= cbData
;
839 resdata
->lpData
= &resdata
[1];
840 memcpy( resdata
->lpData
, lpData
, cbData
);
843 resdata
->lpData
= lpData
;
849 static void free_resource_directory( struct list
*head
, int level
)
851 struct list
*ptr
= NULL
;
853 while ((ptr
= list_head( head
)))
858 struct resource_dir_entry
*ent
;
860 ent
= LIST_ENTRY( ptr
, struct resource_dir_entry
, entry
);
861 res_free_str( ent
->id
);
862 free_resource_directory( &ent
->children
, level
- 1 );
863 HeapFree(GetProcessHeap(), 0, ent
);
867 struct resource_data
*data
;
869 data
= LIST_ENTRY( ptr
, struct resource_data
, entry
);
870 HeapFree( GetProcessHeap(), 0, data
);
875 static IMAGE_NT_HEADERS
*get_nt_header( void *base
, DWORD mapping_size
)
877 IMAGE_NT_HEADERS
*nt
;
878 IMAGE_DOS_HEADER
*dos
;
880 if (mapping_size
<sizeof (*dos
))
884 if (dos
->e_magic
!= IMAGE_DOS_SIGNATURE
)
887 if ((dos
->e_lfanew
+ sizeof (*nt
)) > mapping_size
)
890 nt
= (void*) ((BYTE
*)base
+ dos
->e_lfanew
);
892 if (nt
->Signature
!= IMAGE_NT_SIGNATURE
)
898 static IMAGE_SECTION_HEADER
*get_section_header( void *base
, DWORD mapping_size
, DWORD
*num_sections
)
900 IMAGE_NT_HEADERS
*nt
;
901 IMAGE_SECTION_HEADER
*sec
;
904 nt
= get_nt_header( base
, mapping_size
);
908 /* check that we don't go over the end of the file accessing the sections */
909 section_ofs
= FIELD_OFFSET(IMAGE_NT_HEADERS
, OptionalHeader
) + nt
->FileHeader
.SizeOfOptionalHeader
;
910 if ((nt
->FileHeader
.NumberOfSections
* sizeof (*sec
) + section_ofs
) > mapping_size
)
914 *num_sections
= nt
->FileHeader
.NumberOfSections
;
916 /* from here we have a valid PE exe to update */
917 return (void*) ((BYTE
*)nt
+ section_ofs
);
920 static BOOL
check_pe_exe( HANDLE file
, QUEUEDUPDATES
*updates
)
922 const IMAGE_NT_HEADERS
*nt
;
923 const IMAGE_SECTION_HEADER
*sec
;
926 DWORD mapping_size
, num_sections
= 0;
929 mapping_size
= GetFileSize( file
, NULL
);
931 mapping
= CreateFileMappingW( file
, NULL
, PAGE_READONLY
, 0, 0, NULL
);
935 base
= MapViewOfFile( mapping
, FILE_MAP_READ
, 0, 0, mapping_size
);
939 nt
= get_nt_header( base
, mapping_size
);
943 TRACE("resources: %08x %08x\n",
944 nt
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].VirtualAddress
,
945 nt
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].Size
);
947 sec
= get_section_header( base
, mapping_size
, &num_sections
);
955 UnmapViewOfFile( base
);
957 CloseHandle( mapping
);
962 struct resource_size_info
{
966 DWORD data_entry_ofs
;
972 struct mapping_info
{
980 static const IMAGE_SECTION_HEADER
*section_from_rva( void *base
, DWORD mapping_size
, DWORD rva
)
982 const IMAGE_SECTION_HEADER
*sec
;
983 DWORD num_sections
= 0;
986 sec
= get_section_header( base
, mapping_size
, &num_sections
);
990 for (i
=num_sections
-1; i
>=0; i
--)
992 if (sec
[i
].VirtualAddress
<= rva
&&
993 rva
<= (DWORD
)sec
[i
].VirtualAddress
+ sec
[i
].SizeOfRawData
)
1002 static void *address_from_rva( void *base
, DWORD mapping_size
, DWORD rva
, DWORD len
)
1004 const IMAGE_SECTION_HEADER
*sec
;
1006 sec
= section_from_rva( base
, mapping_size
, rva
);
1010 if (rva
+ len
<= (DWORD
)sec
->VirtualAddress
+ sec
->SizeOfRawData
)
1011 return (void*)((LPBYTE
) base
+ (sec
->PointerToRawData
+ rva
- sec
->VirtualAddress
));
1016 static LPWSTR
resource_dup_string( const IMAGE_RESOURCE_DIRECTORY
*root
, const IMAGE_RESOURCE_DIRECTORY_ENTRY
*entry
)
1018 const IMAGE_RESOURCE_DIR_STRING_U
* string
;
1021 if (!entry
->u1
.s1
.NameIsString
)
1022 return UIntToPtr(entry
->u1
.s2
.Id
);
1024 string
= (const IMAGE_RESOURCE_DIR_STRING_U
*) (((const char *)root
) + entry
->u1
.s1
.NameOffset
);
1025 s
= HeapAlloc(GetProcessHeap(), 0, (string
->Length
+ 1)*sizeof (WCHAR
) );
1026 memcpy( s
, string
->NameString
, (string
->Length
+ 1)*sizeof (WCHAR
) );
1027 s
[string
->Length
] = 0;
1032 /* this function is based on the code in winedump's pe.c */
1033 static BOOL
enumerate_mapped_resources( QUEUEDUPDATES
*updates
,
1034 void *base
, DWORD mapping_size
,
1035 const IMAGE_RESOURCE_DIRECTORY
*root
)
1037 const IMAGE_RESOURCE_DIRECTORY
*namedir
, *langdir
;
1038 const IMAGE_RESOURCE_DIRECTORY_ENTRY
*e1
, *e2
, *e3
;
1039 const IMAGE_RESOURCE_DATA_ENTRY
*data
;
1042 TRACE("version (%d.%d) %d named %d id entries\n",
1043 root
->MajorVersion
, root
->MinorVersion
, root
->NumberOfNamedEntries
, root
->NumberOfIdEntries
);
1045 for (i
= 0; i
< root
->NumberOfNamedEntries
+ root
->NumberOfIdEntries
; i
++)
1049 e1
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(root
+ 1) + i
;
1051 Type
= resource_dup_string( root
, e1
);
1053 namedir
= (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ e1
->u2
.s3
.OffsetToDirectory
);
1054 for (j
= 0; j
< namedir
->NumberOfNamedEntries
+ namedir
->NumberOfIdEntries
; j
++)
1058 e2
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(namedir
+ 1) + j
;
1060 Name
= resource_dup_string( root
, e2
);
1062 langdir
= (const IMAGE_RESOURCE_DIRECTORY
*)((const char *)root
+ e2
->u2
.s3
.OffsetToDirectory
);
1063 for (k
= 0; k
< langdir
->NumberOfNamedEntries
+ langdir
->NumberOfIdEntries
; k
++)
1067 struct resource_data
*resdata
;
1069 e3
= (const IMAGE_RESOURCE_DIRECTORY_ENTRY
*)(langdir
+ 1) + k
;
1071 Lang
= e3
->u1
.s2
.Id
;
1073 data
= (const IMAGE_RESOURCE_DATA_ENTRY
*)((const char *)root
+ e3
->u2
.OffsetToData
);
1075 p
= address_from_rva( base
, mapping_size
, data
->OffsetToData
, data
->Size
);
1077 resdata
= allocate_resource_data( Lang
, data
->CodePage
, p
, data
->Size
, FALSE
);
1079 update_add_resource( updates
, Type
, Name
, resdata
, FALSE
);
1081 res_free_str( Name
);
1083 res_free_str( Type
);
1089 static BOOL
read_mapped_resources( QUEUEDUPDATES
*updates
, void *base
, DWORD mapping_size
)
1091 const IMAGE_RESOURCE_DIRECTORY
*root
;
1092 const IMAGE_NT_HEADERS
*nt
;
1093 const IMAGE_SECTION_HEADER
*sec
;
1094 DWORD num_sections
= 0, i
;
1096 nt
= get_nt_header( base
, mapping_size
);
1100 sec
= get_section_header( base
, mapping_size
, &num_sections
);
1104 for (i
=0; i
<num_sections
; i
++)
1105 if (!memcmp(sec
[i
].Name
, ".rsrc", 6))
1108 if (i
== num_sections
)
1111 /* check the resource data is inside the mapping */
1112 if (sec
[i
].PointerToRawData
> mapping_size
||
1113 (sec
[i
].PointerToRawData
+ sec
[i
].SizeOfRawData
) > mapping_size
)
1116 TRACE("found .rsrc at %08x, size %08x\n", sec
[i
].PointerToRawData
, sec
[i
].SizeOfRawData
);
1118 if (!sec
[i
].PointerToRawData
|| sec
[i
].SizeOfRawData
< sizeof(IMAGE_RESOURCE_DIRECTORY
))
1121 root
= (void*) ((BYTE
*)base
+ sec
[i
].PointerToRawData
);
1122 enumerate_mapped_resources( updates
, base
, mapping_size
, root
);
1127 static BOOL
map_file_into_memory( struct mapping_info
*mi
)
1129 DWORD page_attr
, perm
;
1133 page_attr
= PAGE_READWRITE
;
1134 perm
= FILE_MAP_WRITE
| FILE_MAP_READ
;
1138 page_attr
= PAGE_READONLY
;
1139 perm
= FILE_MAP_READ
;
1142 mi
->mapping
= CreateFileMappingW( mi
->file
, NULL
, page_attr
, 0, 0, NULL
);
1146 mi
->base
= MapViewOfFile( mi
->mapping
, perm
, 0, 0, mi
->size
);
1153 static BOOL
unmap_file_from_memory( struct mapping_info
*mi
)
1156 UnmapViewOfFile( mi
->base
);
1159 CloseHandle( mi
->mapping
);
1164 static void destroy_mapping( struct mapping_info
*mi
)
1168 unmap_file_from_memory( mi
);
1170 CloseHandle( mi
->file
);
1171 HeapFree( GetProcessHeap(), 0, mi
);
1174 static struct mapping_info
*create_mapping( LPCWSTR name
, BOOL rw
)
1176 struct mapping_info
*mi
;
1178 mi
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof *mi
);
1182 mi
->read_write
= rw
;
1184 mi
->file
= CreateFileW( name
, GENERIC_READ
| (rw
? GENERIC_WRITE
: 0),
1185 0, NULL
, OPEN_EXISTING
, 0, 0 );
1187 if (mi
->file
!= INVALID_HANDLE_VALUE
)
1189 mi
->size
= GetFileSize( mi
->file
, NULL
);
1191 if (map_file_into_memory( mi
))
1195 unmap_file_from_memory( mi
);
1196 HeapFree( GetProcessHeap(), 0, mi
);
1201 static BOOL
resize_mapping( struct mapping_info
*mi
, DWORD new_size
)
1203 if (!unmap_file_from_memory( mi
))
1206 /* change the file size */
1207 SetFilePointer( mi
->file
, new_size
, NULL
, FILE_BEGIN
);
1208 if (!SetEndOfFile( mi
->file
))
1210 ERR("failed to set file size to %08x\n", new_size
);
1214 mi
->size
= new_size
;
1216 return map_file_into_memory( mi
);
1219 static void get_resource_sizes( QUEUEDUPDATES
*updates
, struct resource_size_info
*si
)
1221 struct resource_dir_entry
*types
, *names
;
1222 struct resource_data
*data
;
1223 DWORD num_types
= 0, num_names
= 0, num_langs
= 0, strings_size
= 0, data_size
= 0;
1225 memset( si
, 0, sizeof *si
);
1227 LIST_FOR_EACH_ENTRY( types
, &updates
->root
, struct resource_dir_entry
, entry
)
1230 if (HIWORD( types
->id
))
1231 strings_size
+= sizeof (WORD
) + lstrlenW( types
->id
)*sizeof (WCHAR
);
1233 LIST_FOR_EACH_ENTRY( names
, &types
->children
, struct resource_dir_entry
, entry
)
1237 if (HIWORD( names
->id
))
1238 strings_size
+= sizeof (WORD
) + lstrlenW( names
->id
)*sizeof (WCHAR
);
1240 LIST_FOR_EACH_ENTRY( data
, &names
->children
, struct resource_data
, entry
)
1243 data_size
+= (data
->cbData
+ 3) & ~3;
1248 /* names are at the end of the types */
1249 si
->names_ofs
= sizeof (IMAGE_RESOURCE_DIRECTORY
) +
1250 num_types
* sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1252 /* language directories are at the end of the names */
1253 si
->langs_ofs
= si
->names_ofs
+
1254 num_types
* sizeof (IMAGE_RESOURCE_DIRECTORY
) +
1255 num_names
* sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1257 si
->data_entry_ofs
= si
->langs_ofs
+
1258 num_names
* sizeof (IMAGE_RESOURCE_DIRECTORY
) +
1259 num_langs
* sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1261 si
->strings_ofs
= si
->data_entry_ofs
+
1262 num_langs
* sizeof (IMAGE_RESOURCE_DATA_ENTRY
);
1264 si
->data_ofs
= si
->strings_ofs
+ ((strings_size
+ 3) & ~3);
1266 si
->total_size
= si
->data_ofs
+ data_size
;
1268 TRACE("names %08x langs %08x data entries %08x strings %08x data %08x total %08x\n",
1269 si
->names_ofs
, si
->langs_ofs
, si
->data_entry_ofs
,
1270 si
->strings_ofs
, si
->data_ofs
, si
->total_size
);
1273 static void res_write_padding( BYTE
*res_base
, DWORD size
)
1275 static const BYTE pad
[] = {
1276 'P','A','D','D','I','N','G','X','X','P','A','D','D','I','N','G' };
1279 for ( i
= 0; i
< size
/ sizeof pad
; i
++ )
1280 memcpy( &res_base
[i
*sizeof pad
], pad
, sizeof pad
);
1281 memcpy( &res_base
[i
*sizeof pad
], pad
, size
%sizeof pad
);
1284 static BOOL
write_resources( QUEUEDUPDATES
*updates
, LPBYTE base
, struct resource_size_info
*si
, DWORD rva
)
1286 struct resource_dir_entry
*types
, *names
;
1287 struct resource_data
*data
;
1288 IMAGE_RESOURCE_DIRECTORY
*root
;
1290 TRACE("%p %p %p %08x\n", updates
, base
, si
, rva
);
1292 memset( base
, 0, si
->total_size
);
1294 /* the root entry always exists */
1295 root
= (IMAGE_RESOURCE_DIRECTORY
*) base
;
1296 memset( root
, 0, sizeof *root
);
1297 root
->MajorVersion
= 4;
1298 si
->types_ofs
= sizeof *root
;
1299 LIST_FOR_EACH_ENTRY( types
, &updates
->root
, struct resource_dir_entry
, entry
)
1301 IMAGE_RESOURCE_DIRECTORY_ENTRY
*e1
;
1302 IMAGE_RESOURCE_DIRECTORY
*namedir
;
1304 e1
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*) &base
[si
->types_ofs
];
1305 memset( e1
, 0, sizeof *e1
);
1306 if (HIWORD( types
->id
))
1311 root
->NumberOfNamedEntries
++;
1312 e1
->u1
.s1
.NameIsString
= 1;
1313 e1
->u1
.s1
.NameOffset
= si
->strings_ofs
;
1315 strings
= (WCHAR
*) &base
[si
->strings_ofs
];
1316 len
= lstrlenW( types
->id
);
1318 memcpy( &strings
[1], types
->id
, len
* sizeof (WCHAR
) );
1319 si
->strings_ofs
+= (len
+ 1) * sizeof (WCHAR
);
1323 root
->NumberOfIdEntries
++;
1324 e1
->u1
.s2
.Id
= LOWORD( types
->id
);
1326 e1
->u2
.s3
.OffsetToDirectory
= si
->names_ofs
;
1327 e1
->u2
.s3
.DataIsDirectory
= TRUE
;
1328 si
->types_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1330 namedir
= (IMAGE_RESOURCE_DIRECTORY
*) &base
[si
->names_ofs
];
1331 memset( namedir
, 0, sizeof *namedir
);
1332 namedir
->MajorVersion
= 4;
1333 si
->names_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY
);
1335 LIST_FOR_EACH_ENTRY( names
, &types
->children
, struct resource_dir_entry
, entry
)
1337 IMAGE_RESOURCE_DIRECTORY_ENTRY
*e2
;
1338 IMAGE_RESOURCE_DIRECTORY
*langdir
;
1340 e2
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*) &base
[si
->names_ofs
];
1341 memset( e2
, 0, sizeof *e2
);
1342 if (HIWORD( names
->id
))
1347 namedir
->NumberOfNamedEntries
++;
1348 e2
->u1
.s1
.NameIsString
= 1;
1349 e2
->u1
.s1
.NameOffset
= si
->strings_ofs
;
1351 strings
= (WCHAR
*) &base
[si
->strings_ofs
];
1352 len
= lstrlenW( names
->id
);
1354 memcpy( &strings
[1], names
->id
, len
* sizeof (WCHAR
) );
1355 si
->strings_ofs
+= (len
+ 1) * sizeof (WCHAR
);
1359 namedir
->NumberOfIdEntries
++;
1360 e2
->u1
.s2
.Id
= LOWORD( names
->id
);
1362 e2
->u2
.s3
.OffsetToDirectory
= si
->langs_ofs
;
1363 e2
->u2
.s3
.DataIsDirectory
= TRUE
;
1364 si
->names_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1366 langdir
= (IMAGE_RESOURCE_DIRECTORY
*) &base
[si
->langs_ofs
];
1367 memset( langdir
, 0, sizeof *langdir
);
1368 langdir
->MajorVersion
= 4;
1369 si
->langs_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY
);
1371 LIST_FOR_EACH_ENTRY( data
, &names
->children
, struct resource_data
, entry
)
1373 IMAGE_RESOURCE_DIRECTORY_ENTRY
*e3
;
1374 IMAGE_RESOURCE_DATA_ENTRY
*de
;
1377 e3
= (IMAGE_RESOURCE_DIRECTORY_ENTRY
*) &base
[si
->langs_ofs
];
1378 memset( e3
, 0, sizeof *e3
);
1379 langdir
->NumberOfIdEntries
++;
1380 e3
->u1
.s2
.Id
= LOWORD( data
->lang
);
1381 e3
->u2
.OffsetToData
= si
->data_entry_ofs
;
1383 si
->langs_ofs
+= sizeof (IMAGE_RESOURCE_DIRECTORY_ENTRY
);
1385 /* write out all the data entries */
1386 de
= (IMAGE_RESOURCE_DATA_ENTRY
*) &base
[si
->data_entry_ofs
];
1387 memset( de
, 0, sizeof *de
);
1388 de
->OffsetToData
= si
->data_ofs
+ rva
;
1389 de
->Size
= data
->cbData
;
1390 de
->CodePage
= data
->codepage
;
1391 si
->data_entry_ofs
+= sizeof (IMAGE_RESOURCE_DATA_ENTRY
);
1393 /* write out the resource data */
1394 memcpy( &base
[si
->data_ofs
], data
->lpData
, data
->cbData
);
1395 si
->data_ofs
+= data
->cbData
;
1397 pad_size
= (-si
->data_ofs
)&3;
1398 res_write_padding( &base
[si
->data_ofs
], pad_size
);
1399 si
->data_ofs
+= pad_size
;
1409 * Assumes that the resources are in .rsrc
1410 * and .rsrc is the last section in the file.
1411 * Not sure whether updating resources will other cases on Windows.
1412 * If the resources lie in a section containing other data,
1413 * resizing that section could possibly cause trouble.
1414 * If the section with the resources isn't last, the remaining
1415 * sections need to be moved down in the file, and the section header
1416 * would need to be adjusted.
1417 * If we needed to add a section, what would we name it?
1418 * If we needed to add a section and there wasn't space in the file
1419 * header, how would that work?
1420 * Seems that at least some of these cases can't be handled properly.
1422 static IMAGE_SECTION_HEADER
*get_resource_section( void *base
, DWORD mapping_size
)
1424 IMAGE_SECTION_HEADER
*sec
;
1425 IMAGE_NT_HEADERS
*nt
;
1426 DWORD i
, num_sections
= 0;
1428 nt
= get_nt_header( base
, mapping_size
);
1432 sec
= get_section_header( base
, mapping_size
, &num_sections
);
1436 /* find the resources section */
1437 for (i
=0; i
<num_sections
; i
++)
1438 if (!memcmp(sec
[i
].Name
, ".rsrc", 6))
1441 if (i
== num_sections
)
1443 FIXME(".rsrc doesn't exist\n");
1450 static DWORD
get_init_data_size( void *base
, DWORD mapping_size
)
1452 DWORD i
, sz
= 0, num_sections
= 0;
1453 IMAGE_SECTION_HEADER
*s
;
1455 s
= get_section_header( base
, mapping_size
, &num_sections
);
1457 for (i
=0; i
<num_sections
; i
++)
1458 if (s
[i
].Characteristics
& IMAGE_SCN_CNT_INITIALIZED_DATA
)
1459 sz
+= s
[i
].SizeOfRawData
;
1461 TRACE("size = %08x\n", sz
);
1466 static BOOL
write_raw_resources( QUEUEDUPDATES
*updates
)
1468 static const WCHAR prefix
[] = { 'r','e','s','u',0 };
1469 WCHAR tempdir
[MAX_PATH
], tempfile
[MAX_PATH
];
1470 DWORD mapping_size
, section_size
, old_size
;
1472 IMAGE_SECTION_HEADER
*sec
;
1473 IMAGE_NT_HEADERS
*nt
;
1474 struct resource_size_info res_size
;
1476 struct mapping_info
*read_map
= NULL
, *write_map
= NULL
;
1478 /* copy the exe to a temp file then update the temp file... */
1480 if (!GetTempPathW( MAX_PATH
, tempdir
))
1483 if (!GetTempFileNameW( tempdir
, prefix
, 0, tempfile
))
1486 if (!CopyFileW( updates
->pFileName
, tempfile
, FALSE
))
1489 TRACE("tempfile %s\n", debugstr_w(tempfile
));
1491 if (!updates
->bDeleteExistingResources
)
1493 read_map
= create_mapping( updates
->pFileName
, FALSE
);
1497 ret
= read_mapped_resources( updates
, read_map
->base
, read_map
->size
);
1500 ERR("failed to read existing resources\n");
1505 write_map
= create_mapping( tempfile
, TRUE
);
1509 nt
= get_nt_header( write_map
->base
, write_map
->size
);
1513 if (nt
->OptionalHeader
.SectionAlignment
<= 0)
1515 ERR("invalid section alignment %04x\n", nt
->OptionalHeader
.SectionAlignment
);
1519 sec
= get_resource_section( write_map
->base
, write_map
->size
);
1523 if (!sec
->PointerToRawData
) /* empty section */
1525 sec
->PointerToRawData
= write_map
->size
;
1526 sec
->SizeOfRawData
= 0;
1528 else if ((sec
->SizeOfRawData
+ sec
->PointerToRawData
) != write_map
->size
)
1530 FIXME(".rsrc isn't at the end of the image %08x + %08x != %08x for %s\n",
1531 sec
->SizeOfRawData
, sec
->PointerToRawData
, write_map
->size
, debugstr_w(updates
->pFileName
));
1535 TRACE("before .rsrc at %08x, size %08x\n", sec
->PointerToRawData
, sec
->SizeOfRawData
);
1537 get_resource_sizes( updates
, &res_size
);
1539 /* round up the section size */
1540 section_size
= res_size
.total_size
;
1541 section_size
+= (-section_size
) % nt
->OptionalHeader
.SectionAlignment
;
1543 mapping_size
= sec
->PointerToRawData
+ section_size
;
1545 TRACE("requires %08x (%08x) bytes\n", res_size
.total_size
, section_size
);
1547 /* check if the file size needs to be changed */
1548 if (section_size
!= sec
->SizeOfRawData
)
1550 old_size
= write_map
->size
;
1552 TRACE("file size %08x -> %08x\n", old_size
, mapping_size
);
1554 /* unmap the file before changing the file size */
1555 ret
= resize_mapping( write_map
, mapping_size
);
1557 /* get the pointers again - they might be different after remapping */
1558 nt
= get_nt_header( write_map
->base
, mapping_size
);
1561 ERR("couldn't get NT header\n");
1565 sec
= get_resource_section( write_map
->base
, mapping_size
);
1569 /* adjust the PE header information */
1570 nt
->OptionalHeader
.SizeOfImage
+= (mapping_size
- old_size
);
1571 sec
->SizeOfRawData
= section_size
;
1572 sec
->Misc
.VirtualSize
= section_size
;
1573 nt
->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
].Size
= res_size
.total_size
;
1574 nt
->OptionalHeader
.SizeOfInitializedData
= get_init_data_size( write_map
->base
, mapping_size
);
1577 res_base
= (LPBYTE
) write_map
->base
+ sec
->PointerToRawData
;
1579 TRACE("base = %p offset = %08x\n", write_map
->base
, sec
->PointerToRawData
);
1581 ret
= write_resources( updates
, res_base
, &res_size
, sec
->VirtualAddress
);
1583 res_write_padding( res_base
+ res_size
.total_size
, section_size
- res_size
.total_size
);
1585 TRACE("after .rsrc at %08x, size %08x\n", sec
->PointerToRawData
, sec
->SizeOfRawData
);
1588 destroy_mapping( read_map
);
1589 destroy_mapping( write_map
);
1592 ret
= CopyFileW( tempfile
, updates
->pFileName
, FALSE
);
1594 DeleteFileW( tempfile
);
1599 /***********************************************************************
1600 * BeginUpdateResourceW (KERNEL32.@)
1602 HANDLE WINAPI
BeginUpdateResourceW( LPCWSTR pFileName
, BOOL bDeleteExistingResources
)
1604 QUEUEDUPDATES
*updates
= NULL
;
1605 HANDLE hUpdate
, file
, ret
= NULL
;
1607 TRACE("%s, %d\n", debugstr_w(pFileName
), bDeleteExistingResources
);
1609 hUpdate
= GlobalAlloc(GHND
, sizeof(QUEUEDUPDATES
));
1613 updates
= GlobalLock(hUpdate
);
1616 list_init( &updates
->root
);
1617 updates
->bDeleteExistingResources
= bDeleteExistingResources
;
1618 updates
->pFileName
= HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName
)+1)*sizeof(WCHAR
));
1619 if (updates
->pFileName
)
1621 lstrcpyW(updates
->pFileName
, pFileName
);
1623 file
= CreateFileW( pFileName
, GENERIC_READ
| GENERIC_WRITE
,
1624 0, NULL
, OPEN_EXISTING
, 0, 0 );
1626 /* if resources are deleted, only the file's presence is checked */
1627 if (file
!= INVALID_HANDLE_VALUE
&&
1628 (bDeleteExistingResources
|| check_pe_exe( file
, updates
)))
1631 HeapFree( GetProcessHeap(), 0, updates
->pFileName
);
1633 CloseHandle( file
);
1635 GlobalUnlock(hUpdate
);
1639 GlobalFree(hUpdate
);
1645 /***********************************************************************
1646 * BeginUpdateResourceA (KERNEL32.@)
1648 HANDLE WINAPI
BeginUpdateResourceA( LPCSTR pFileName
, BOOL bDeleteExistingResources
)
1650 UNICODE_STRING FileNameW
;
1652 RtlCreateUnicodeStringFromAsciiz(&FileNameW
, pFileName
);
1653 ret
= BeginUpdateResourceW(FileNameW
.Buffer
, bDeleteExistingResources
);
1654 RtlFreeUnicodeString(&FileNameW
);
1659 /***********************************************************************
1660 * EndUpdateResourceW (KERNEL32.@)
1662 BOOL WINAPI
EndUpdateResourceW( HANDLE hUpdate
, BOOL fDiscard
)
1664 QUEUEDUPDATES
*updates
;
1667 TRACE("%p %d\n", hUpdate
, fDiscard
);
1669 updates
= GlobalLock(hUpdate
);
1673 ret
= fDiscard
|| write_raw_resources( updates
);
1675 free_resource_directory( &updates
->root
, 2 );
1677 HeapFree( GetProcessHeap(), 0, updates
->pFileName
);
1678 GlobalUnlock( hUpdate
);
1679 GlobalFree( hUpdate
);
1685 /***********************************************************************
1686 * EndUpdateResourceA (KERNEL32.@)
1688 BOOL WINAPI
EndUpdateResourceA( HANDLE hUpdate
, BOOL fDiscard
)
1690 return EndUpdateResourceW(hUpdate
, fDiscard
);
1694 /***********************************************************************
1695 * UpdateResourceW (KERNEL32.@)
1697 BOOL WINAPI
UpdateResourceW( HANDLE hUpdate
, LPCWSTR lpType
, LPCWSTR lpName
,
1698 WORD wLanguage
, LPVOID lpData
, DWORD cbData
)
1700 QUEUEDUPDATES
*updates
;
1703 TRACE("%p %s %s %08x %p %d\n", hUpdate
,
1704 debugstr_w(lpType
), debugstr_w(lpName
), wLanguage
, lpData
, cbData
);
1706 updates
= GlobalLock(hUpdate
);
1709 struct resource_data
*data
;
1710 data
= allocate_resource_data( wLanguage
, 0, lpData
, cbData
, TRUE
);
1712 ret
= update_add_resource( updates
, lpType
, lpName
, data
, TRUE
);
1713 GlobalUnlock(hUpdate
);
1719 /***********************************************************************
1720 * UpdateResourceA (KERNEL32.@)
1722 BOOL WINAPI
UpdateResourceA( HANDLE hUpdate
, LPCSTR lpType
, LPCSTR lpName
,
1723 WORD wLanguage
, LPVOID lpData
, DWORD cbData
)
1726 UNICODE_STRING TypeW
;
1727 UNICODE_STRING NameW
;
1729 TypeW
.Buffer
= ULongToPtr(LOWORD(lpType
));
1731 RtlCreateUnicodeStringFromAsciiz(&TypeW
, lpType
);
1733 NameW
.Buffer
= ULongToPtr(LOWORD(lpName
));
1735 RtlCreateUnicodeStringFromAsciiz(&NameW
, lpName
);
1736 ret
= UpdateResourceW(hUpdate
, TypeW
.Buffer
, NameW
.Buffer
, wLanguage
, lpData
, cbData
);
1737 if(HIWORD(lpType
)) RtlFreeUnicodeString(&TypeW
);
1738 if(HIWORD(lpName
)) RtlFreeUnicodeString(&NameW
);