2 * PE (Portable Execute) File Resources
4 * Copyright 1995 Thomas Sandford
5 * Copyright 1996 Martin von Loewis
7 * Based on the Win16 resource handling code in loader/resource.c
8 * Copyright 1993 Robert J. Amstadt
9 * Copyright 1995 Alexandre Julliard
10 * Copyright 1997 Marcus Meissner
14 #include <sys/types.h>
15 #include "wine/winestring.h"
16 #include "wine/unicode.h"
23 #include "stackframe.h"
25 #include "debugtools.h"
27 /**********************************************************************
30 * Get the resource directory of a PE module
32 static IMAGE_RESOURCE_DIRECTORY
* get_resdir( HMODULE hmod
)
34 IMAGE_DATA_DIRECTORY
*dir
;
35 IMAGE_RESOURCE_DIRECTORY
*ret
= NULL
;
37 if (!hmod
) hmod
= GetModuleHandleA( NULL
);
38 dir
= &PE_HEADER(hmod
)->OptionalHeader
.DataDirectory
[IMAGE_DIRECTORY_ENTRY_RESOURCE
];
39 if (dir
->Size
&& dir
->VirtualAddress
)
40 ret
= (IMAGE_RESOURCE_DIRECTORY
*)((char *)hmod
+ dir
->VirtualAddress
);
45 /**********************************************************************
48 * Helper function - goes down one level of PE resource tree
51 PIMAGE_RESOURCE_DIRECTORY
GetResDirEntryW(PIMAGE_RESOURCE_DIRECTORY resdirptr
,
52 LPCWSTR name
,DWORD root
,
56 PIMAGE_RESOURCE_DIRECTORY_ENTRY entryTable
;
62 if (!WideCharToMultiByte( CP_ACP
, 0, name
+1, -1, buf
, sizeof(buf
), NULL
, NULL
))
64 return GetResDirEntryW(resdirptr
,(LPCWSTR
)atoi(buf
),root
,allowdefault
);
66 entryTable
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdirptr
+ 1);
67 namelen
= strlenW(name
);
68 for (entrynum
= 0; entrynum
< resdirptr
->NumberOfNamedEntries
; entrynum
++)
70 PIMAGE_RESOURCE_DIR_STRING_U str
=
71 (PIMAGE_RESOURCE_DIR_STRING_U
) (root
+
72 entryTable
[entrynum
].u1
.s
.NameOffset
);
73 if(namelen
!= str
->Length
)
75 if(strncmpiW(name
,str
->NameString
,str
->Length
)==0)
76 return (PIMAGE_RESOURCE_DIRECTORY
) (
78 entryTable
[entrynum
].u2
.s
.OffsetToDirectory
);
82 entryTable
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
) (
84 sizeof(IMAGE_RESOURCE_DIRECTORY
) +
85 resdirptr
->NumberOfNamedEntries
* sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY
));
86 for (entrynum
= 0; entrynum
< resdirptr
->NumberOfIdEntries
; entrynum
++)
87 if ((DWORD
)entryTable
[entrynum
].u1
.Name
== (DWORD
)name
)
88 return (PIMAGE_RESOURCE_DIRECTORY
) (
90 entryTable
[entrynum
].u2
.s
.OffsetToDirectory
);
91 /* just use first entry if no default can be found */
92 if (allowdefault
&& !name
&& resdirptr
->NumberOfIdEntries
)
93 return (PIMAGE_RESOURCE_DIRECTORY
) (
95 entryTable
[0].u2
.s
.OffsetToDirectory
);
100 /**********************************************************************
103 PIMAGE_RESOURCE_DIRECTORY
GetResDirEntryA( PIMAGE_RESOURCE_DIRECTORY resdirptr
,
104 LPCSTR name
, DWORD root
,
107 PIMAGE_RESOURCE_DIRECTORY retv
;
108 LPWSTR nameW
= HIWORD(name
)? HEAP_strdupAtoW( GetProcessHeap(), 0, name
)
111 retv
= GetResDirEntryW( resdirptr
, nameW
, root
, allowdefault
);
113 if ( HIWORD(name
) ) HeapFree( GetProcessHeap(), 0, nameW
);
118 /**********************************************************************
121 * FindResourceExA/W does search in the following order:
122 * 1. Exact specified language
123 * 2. Language with neutral sublanguage
124 * 3. Neutral language with neutral sublanguage
125 * 4. Neutral language with default sublanguage
127 HRSRC
PE_FindResourceExW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
, WORD lang
)
129 PIMAGE_RESOURCE_DIRECTORY resdirptr
= get_resdir(hmod
);
133 if (!resdirptr
) return 0;
135 root
= (DWORD
) resdirptr
;
136 if ((resdirptr
= GetResDirEntryW(resdirptr
, type
, root
, FALSE
)) == NULL
)
138 if ((resdirptr
= GetResDirEntryW(resdirptr
, name
, root
, FALSE
)) == NULL
)
141 /* 1. Exact specified language */
142 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
146 /* 2. Language with neutral sublanguage */
147 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
148 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
153 /* 3. Neutral language with neutral sublanguage */
154 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
155 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
160 /* 4. Neutral language with default sublanguage */
161 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
162 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
168 /**********************************************************************
171 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
172 * FindResourceA/W does search in the following order:
173 * 1. Neutral language with neutral sublanguage
174 * 2. Neutral language with default sublanguage
175 * 3. Current locale lang id
176 * 4. Current locale lang id with neutral sublanguage
177 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
178 * 6. Return first in the list
180 HRSRC
PE_FindResourceW( HMODULE hmod
, LPCWSTR name
, LPCWSTR type
)
182 PIMAGE_RESOURCE_DIRECTORY resdirptr
= get_resdir(hmod
);
187 if (!resdirptr
) return 0;
189 root
= (DWORD
) resdirptr
;
190 if ((resdirptr
= GetResDirEntryW(resdirptr
, type
, root
, FALSE
)) == NULL
)
192 if ((resdirptr
= GetResDirEntryW(resdirptr
, name
, root
, FALSE
)) == NULL
)
195 /* 1. Neutral language with neutral sublanguage */
196 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_NEUTRAL
);
197 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
201 /* 2. Neutral language with default sublanguage */
202 lang
= MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
);
203 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
208 /* 3. Current locale lang id */
209 lang
= LANGIDFROMLCID(GetUserDefaultLCID());
210 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
215 /* 4. Current locale lang id with neutral sublanguage */
216 lang
= MAKELANGID(PRIMARYLANGID(lang
), SUBLANG_NEUTRAL
);
217 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
222 /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
223 lang
= MAKELANGID(LANG_ENGLISH
, SUBLANG_DEFAULT
);
224 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)lang
, root
, FALSE
);
229 /* 6. Return first in the list */
230 result
= (HANDLE
)GetResDirEntryW(resdirptr
, (LPCWSTR
)(UINT
)0, root
, TRUE
);
237 /**********************************************************************
240 HANDLE
PE_LoadResource( HMODULE hmod
, HANDLE hRsrc
)
242 if (!hRsrc
) return 0;
243 return (HANDLE
)(hmod
+ ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->OffsetToData
);
247 /**********************************************************************
250 DWORD
PE_SizeofResource( HANDLE hRsrc
)
252 if (!hRsrc
) return 0;
253 return ((PIMAGE_RESOURCE_DATA_ENTRY
)hRsrc
)->Size
;
257 /**********************************************************************
258 * EnumResourceTypesA (KERNEL32.90)
260 BOOL WINAPI
EnumResourceTypesA( HMODULE hmod
, ENUMRESTYPEPROCA lpfun
, LONG lparam
)
263 PIMAGE_RESOURCE_DIRECTORY resdir
= get_resdir(hmod
);
264 PIMAGE_RESOURCE_DIRECTORY_ENTRY et
;
267 if (!resdir
) return FALSE
;
269 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
271 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
274 if (et
[i
].u1
.s
.NameIsString
)
276 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s
.NameOffset
);
277 DWORD len
= WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
278 NULL
, 0, NULL
, NULL
);
279 if (!(type
= HeapAlloc(GetProcessHeap(), 0, len
+ 1)))
281 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
282 type
, len
, NULL
, NULL
);
284 ret
= lpfun(hmod
,type
,lparam
);
285 HeapFree(GetProcessHeap(), 0, type
);
289 type
= (LPSTR
)(int)et
[i
].u1
.Id
;
290 ret
= lpfun(hmod
,type
,lparam
);
299 /**********************************************************************
300 * EnumResourceTypesW (KERNEL32.91)
302 BOOL WINAPI
EnumResourceTypesW( HMODULE hmod
, ENUMRESTYPEPROCW lpfun
, LONG lparam
)
305 PIMAGE_RESOURCE_DIRECTORY resdir
= get_resdir(hmod
);
306 PIMAGE_RESOURCE_DIRECTORY_ENTRY et
;
309 if (!resdir
) return FALSE
;
311 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
313 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
316 if (et
[i
].u1
.s
.NameIsString
)
318 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) resdir
+ et
[i
].u1
.s
.NameOffset
);
319 if (!(type
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+1) * sizeof (WCHAR
))))
321 memcpy(type
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
322 type
[pResString
->Length
] = '\0';
323 ret
= lpfun(hmod
,type
,lparam
);
324 HeapFree(GetProcessHeap(), 0, type
);
328 type
= (LPWSTR
)(int)et
[i
].u1
.Id
;
329 ret
= lpfun(hmod
,type
,lparam
);
338 /**********************************************************************
339 * EnumResourceNamesA (KERNEL32.88)
341 BOOL WINAPI
EnumResourceNamesA( HMODULE hmod
, LPCSTR type
, ENUMRESNAMEPROCA lpfun
, LONG lparam
)
344 PIMAGE_RESOURCE_DIRECTORY basedir
= get_resdir(hmod
);
345 PIMAGE_RESOURCE_DIRECTORY resdir
;
346 PIMAGE_RESOURCE_DIRECTORY_ENTRY et
;
349 if (!basedir
) return FALSE
;
351 if (!(resdir
= GetResDirEntryA(basedir
,type
,(DWORD
)basedir
,FALSE
))) return FALSE
;
353 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
355 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
358 if (et
[i
].u1
.s
.NameIsString
)
360 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s
.NameOffset
);
361 DWORD len
= WideCharToMultiByte(CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
362 NULL
, 0, NULL
, NULL
);
363 if (!(name
= HeapAlloc(GetProcessHeap(), 0, len
+ 1 )))
365 WideCharToMultiByte( CP_ACP
, 0, pResString
->NameString
, pResString
->Length
,
366 name
, len
, NULL
, NULL
);
368 ret
= lpfun(hmod
,type
,name
,lparam
);
369 HeapFree( GetProcessHeap(), 0, name
);
373 name
= (LPSTR
)(int)et
[i
].u1
.Id
;
374 ret
= lpfun(hmod
,type
,name
,lparam
);
383 /**********************************************************************
384 * EnumResourceNamesW (KERNEL32.89)
386 BOOL WINAPI
EnumResourceNamesW( HMODULE hmod
, LPCWSTR type
, ENUMRESNAMEPROCW lpfun
, LONG lparam
)
389 PIMAGE_RESOURCE_DIRECTORY basedir
= get_resdir(hmod
);
390 PIMAGE_RESOURCE_DIRECTORY resdir
;
391 PIMAGE_RESOURCE_DIRECTORY_ENTRY et
;
394 if (!basedir
) return FALSE
;
396 resdir
= GetResDirEntryW(basedir
,type
,(DWORD
)basedir
,FALSE
);
399 et
= (PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
401 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
404 if (et
[i
].u1
.s
.NameIsString
)
406 PIMAGE_RESOURCE_DIR_STRING_U pResString
= (PIMAGE_RESOURCE_DIR_STRING_U
) ((LPBYTE
) basedir
+ et
[i
].u1
.s
.NameOffset
);
407 if (!(name
= HeapAlloc(GetProcessHeap(), 0, (pResString
->Length
+ 1) * sizeof (WCHAR
))))
409 memcpy(name
, pResString
->NameString
, pResString
->Length
* sizeof (WCHAR
));
410 name
[pResString
->Length
] = '\0';
411 ret
= lpfun(hmod
,type
,name
,lparam
);
412 HeapFree(GetProcessHeap(), 0, name
);
416 name
= (LPWSTR
)(int)et
[i
].u1
.Id
;
417 ret
= lpfun(hmod
,type
,name
,lparam
);
426 /**********************************************************************
427 * EnumResourceLanguagesA (KERNEL32.86)
429 BOOL WINAPI
EnumResourceLanguagesA( HMODULE hmod
, LPCSTR type
, LPCSTR name
,
430 ENUMRESLANGPROCA lpfun
, LONG lparam
)
433 PIMAGE_RESOURCE_DIRECTORY basedir
= get_resdir(hmod
);
434 PIMAGE_RESOURCE_DIRECTORY resdir
;
435 PIMAGE_RESOURCE_DIRECTORY_ENTRY et
;
438 if (!basedir
) return FALSE
;
439 if (!(resdir
= GetResDirEntryA(basedir
,type
,(DWORD
)basedir
,FALSE
))) return FALSE
;
440 if (!(resdir
= GetResDirEntryA(resdir
,name
,(DWORD
)basedir
,FALSE
))) return FALSE
;
442 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
444 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
445 /* languages are just ids... I hope */
446 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.Id
,lparam
);
454 /**********************************************************************
455 * EnumResourceLanguagesW (KERNEL32.87)
457 BOOL WINAPI
EnumResourceLanguagesW( HMODULE hmod
, LPCWSTR type
, LPCWSTR name
,
458 ENUMRESLANGPROCW lpfun
, LONG lparam
)
461 PIMAGE_RESOURCE_DIRECTORY basedir
= get_resdir(hmod
);
462 PIMAGE_RESOURCE_DIRECTORY resdir
;
463 PIMAGE_RESOURCE_DIRECTORY_ENTRY et
;
466 if (!basedir
) return FALSE
;
468 resdir
= GetResDirEntryW(basedir
,type
,(DWORD
)basedir
,FALSE
);
471 resdir
= GetResDirEntryW(resdir
,name
,(DWORD
)basedir
,FALSE
);
474 et
=(PIMAGE_RESOURCE_DIRECTORY_ENTRY
)(resdir
+ 1);
476 for (i
=0;i
<resdir
->NumberOfNamedEntries
+resdir
->NumberOfIdEntries
;i
++) {
477 ret
= lpfun(hmod
,type
,name
,et
[i
].u1
.Id
,lparam
);