pe_resource.c 17 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1
/*
Alexandre Julliard's avatar
Alexandre Julliard committed
2
 * PE (Portable Execute) File Resources
Alexandre Julliard's avatar
Alexandre Julliard committed
3
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4 5
 * Copyright 1995 Thomas Sandford
 * Copyright 1996 Martin von Loewis
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
7 8 9
 * Based on the Win16 resource handling code in loader/resource.c
 * Copyright 1993 Robert J. Amstadt
 * Copyright 1995 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
10
 * Copyright 1997 Marcus Meissner
11 12 13 14 15 16 17 18 19 20 21 22 23 24
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Alexandre Julliard's avatar
Alexandre Julliard committed
25 26
 */

27 28
#include "config.h"

Alexandre Julliard's avatar
Alexandre Julliard committed
29
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
30
#include <sys/types.h>
31

32 33
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
34
#include "wine/unicode.h"
35
#include "windef.h"
36
#include "winnls.h"
37
#include "winternl.h"
38
#include "winerror.h"
39
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
40

41
WINE_DEFAULT_DEBUG_CHANNEL(resource);
42

43

44 45 46 47 48 49 50 51 52 53 54
/**********************************************************************
 *  is_data_file_module
 *
 * Check if a module handle is for a LOAD_LIBRARY_AS_DATAFILE module.
 */
inline static int is_data_file_module( HMODULE hmod )
{
    return (ULONG_PTR)hmod & 1;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
55
/**********************************************************************
56
 *  get_resdir
Alexandre Julliard's avatar
Alexandre Julliard committed
57
 *
58
 * Get the resource directory of a PE module
Alexandre Julliard's avatar
Alexandre Julliard committed
59
 */
60
static const IMAGE_RESOURCE_DIRECTORY* get_resdir( HMODULE hmod )
61
{
62
    DWORD size;
63

64 65
    if (!hmod) hmod = GetModuleHandleA( NULL );
    else if (!HIWORD(hmod))
66
    {
67 68 69
        FIXME("Enumeration of 16-bit resources is not supported\n");
        SetLastError(ERROR_INVALID_HANDLE);
        return NULL;
70
    }
71
    return RtlImageDirectoryEntryToData( hmod, TRUE, IMAGE_DIRECTORY_ENTRY_RESOURCE, &size );
Alexandre Julliard's avatar
Alexandre Julliard committed
72
}
Alexandre Julliard's avatar
Alexandre Julliard committed
73

74

75 76 77 78 79
/**********************************************************************
 *  find_entry_by_id
 *
 * Find an entry by id in a resource directory
 */
80 81
static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
                                                         WORD id, const void *root )
82 83 84 85 86 87 88 89 90 91
{
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
    int min, max, pos;

    entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
    min = dir->NumberOfNamedEntries;
    max = min + dir->NumberOfIdEntries - 1;
    while (min <= max)
    {
        pos = (min + max) / 2;
92
        if (entry[pos].u1.s2.Id == id)
93
            return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
94
        if (entry[pos].u1.s2.Id > id) max = pos - 1;
95 96 97 98 99 100 101
        else min = pos + 1;
    }
    return NULL;
}


/**********************************************************************
102
 *  find_entry_by_nameW
103
 *
104
 * Find an entry by name in a resource directory
105
 */
106 107
static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameW( const IMAGE_RESOURCE_DIRECTORY *dir,
                                                            LPCWSTR name, const void *root )
108 109
{
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
110 111 112 113 114 115 116 117 118 119 120
    const IMAGE_RESOURCE_DIR_STRING_U *str;
    int min, max, res, pos, namelen;

    if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
    if (name[0] == '#')
    {
        char buf[16];
        if (!WideCharToMultiByte( CP_ACP, 0, name+1, -1, buf, sizeof(buf), NULL, NULL ))
            return NULL;
        return find_entry_by_id( dir, atoi(buf), root );
    }
121 122

    entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
123 124 125 126 127 128
    namelen = strlenW(name);
    min = 0;
    max = dir->NumberOfNamedEntries - 1;
    while (min <= max)
    {
        pos = (min + max) / 2;
129
        str = (IMAGE_RESOURCE_DIR_STRING_U *)((char *)root + entry[pos].u1.s1.NameOffset);
130 131
        res = strncmpiW( name, str->NameString, str->Length );
        if (!res && namelen == str->Length)
132
            return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry[pos].u2.s3.OffsetToDirectory);
133 134 135
        if (res < 0) max = pos - 1;
        else min = pos + 1;
    }
136 137 138 139
    return NULL;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
140
/**********************************************************************
141
 *  find_entry_by_nameA
Alexandre Julliard's avatar
Alexandre Julliard committed
142
 *
143
 * Find an entry by name in a resource directory
Alexandre Julliard's avatar
Alexandre Julliard committed
144
 */
145 146
static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_nameA( const IMAGE_RESOURCE_DIRECTORY *dir,
                                                            LPCSTR name, const void *root )
Alexandre Julliard's avatar
Alexandre Julliard committed
147
{
148 149
    const IMAGE_RESOURCE_DIRECTORY *ret = NULL;
    LPWSTR nameW;
150
    INT len;
151 152 153

    if (!HIWORD(name)) return find_entry_by_id( dir, LOWORD(name), root );
    if (name[0] == '#')
154
    {
155
        return find_entry_by_id( dir, atoi(name+1), root );
156
    }
157

158 159
    len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
    if ((nameW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
160
    {
161
        MultiByteToWideChar( CP_ACP, 0, name, -1, nameW, len );
162 163
        ret = find_entry_by_nameW( dir, nameW, root );
        HeapFree( GetProcessHeap(), 0, nameW );
Alexandre Julliard's avatar
Alexandre Julliard committed
164
    }
165
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
166 167
}

168

169
/**********************************************************************
170 171 172
 *  find_entry_default
 *
 * Find a default entry in a resource directory
173
 */
174 175
static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
                                                           const void *root )
176
{
177
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
178

179
    entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
180
    return (IMAGE_RESOURCE_DIRECTORY *)((char *)root + entry->u2.s3.OffsetToDirectory);
181 182
}

183

Alexandre Julliard's avatar
Alexandre Julliard committed
184
/**********************************************************************
185
 *	    PE_FindResourceExW
186 187 188 189 190 191
 *
 * FindResourceExA/W does search in the following order:
 * 1. Exact specified language
 * 2. Language with neutral sublanguage
 * 3. Neutral language with neutral sublanguage
 * 4. Neutral language with default sublanguage
Alexandre Julliard's avatar
Alexandre Julliard committed
192
 */
193
HRSRC PE_FindResourceExW( HMODULE hmod, LPCWSTR name, LPCWSTR type, WORD lang )
194
{
195 196
    const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
    const void *root;
197
    HRSRC result;
Alexandre Julliard's avatar
Alexandre Julliard committed
198

199
    if (!resdirptr) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
200

201
    root = resdirptr;
202 203
    if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
    if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
204 205

    /* 1. Exact specified language */
206
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
207

208 209 210
    /* 2. Language with neutral sublanguage */
    lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
211

212 213 214
    /* 3. Neutral language with neutral sublanguage */
    lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
215

216 217 218
    /* 4. Neutral language with default sublanguage */
    lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
    result = (HRSRC)find_entry_by_id( resdirptr, lang, root );
219

220
 found:
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    return result;
}

/**********************************************************************
 *	    PE_FindResourceW
 *
 * Load[String]/[Icon]/[Menu]/[etc.] does use FindResourceA/W.
 * FindResourceA/W does search in the following order:
 * 1. Neutral language with neutral sublanguage
 * 2. Neutral language with default sublanguage
 * 3. Current locale lang id
 * 4. Current locale lang id with neutral sublanguage
 * 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT
 * 6. Return first in the list
 */
HRSRC PE_FindResourceW( HMODULE hmod, LPCWSTR name, LPCWSTR type )
{
238 239
    const IMAGE_RESOURCE_DIRECTORY *resdirptr = get_resdir(hmod);
    const void *root;
240 241 242 243 244
    HRSRC result;
    WORD lang;

    if (!resdirptr) return 0;

245
    root = resdirptr;
246 247
    if (!(resdirptr = find_entry_by_nameW(resdirptr, type, root))) return 0;
    if (!(resdirptr = find_entry_by_nameW(resdirptr, name, root))) return 0;
248 249 250

    /* 1. Neutral language with neutral sublanguage */
    lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
251
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
252

253 254 255
    /* 2. Neutral language with default sublanguage */
    lang = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
256

257 258 259
    /* 3. Current locale lang id */
    lang = LANGIDFROMLCID(GetUserDefaultLCID());
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
260

261 262 263
    /* 4. Current locale lang id with neutral sublanguage */
    lang = MAKELANGID(PRIMARYLANGID(lang), SUBLANG_NEUTRAL);
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
264

265 266 267
    /* 5. (!) LANG_ENGLISH, SUBLANG_DEFAULT */
    lang = MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
    if ((result = (HRSRC)find_entry_by_id( resdirptr, lang, root ))) goto found;
268

269 270
    /* 6. Return first in the list */
    result = (HRSRC)find_entry_default( resdirptr, root );
271

272
 found:
Alexandre Julliard's avatar
Alexandre Julliard committed
273
    return result;
Alexandre Julliard's avatar
Alexandre Julliard committed
274 275
}

Alexandre Julliard's avatar
Alexandre Julliard committed
276

Alexandre Julliard's avatar
Alexandre Julliard committed
277
/**********************************************************************
278
 *	    PE_LoadResource
Alexandre Julliard's avatar
Alexandre Julliard committed
279
 */
280
HGLOBAL PE_LoadResource( HMODULE hmod, HRSRC hRsrc )
Alexandre Julliard's avatar
Alexandre Julliard committed
281
{
282 283
    DWORD offset;

284 285
    if (!hRsrc) return 0;
    if (!hmod) hmod = GetModuleHandleA( NULL );
286 287 288 289

    offset = ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->OffsetToData;

    if (is_data_file_module(hmod))
290 291 292 293
    {
        hmod = (HMODULE)((ULONG_PTR)hmod & ~1);
        return (HGLOBAL)RtlImageRvaToVa( RtlImageNtHeader(hmod), hmod, offset, NULL );
    }
294
    else
295
        return (HGLOBAL)((char *)hmod + offset);
Alexandre Julliard's avatar
Alexandre Julliard committed
296 297
}

Alexandre Julliard's avatar
Alexandre Julliard committed
298

Alexandre Julliard's avatar
Alexandre Julliard committed
299
/**********************************************************************
300
 *	    PE_SizeofResource
Alexandre Julliard's avatar
Alexandre Julliard committed
301
 */
302
DWORD PE_SizeofResource( HRSRC hRsrc )
Alexandre Julliard's avatar
Alexandre Julliard committed
303
{
304
    if (!hRsrc) return 0;
305
    return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
Alexandre Julliard's avatar
Alexandre Julliard committed
306 307
}

308

Alexandre Julliard's avatar
Alexandre Julliard committed
309
/**********************************************************************
310
 *	EnumResourceTypesA	(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
311
 */
312 313
BOOL WINAPI EnumResourceTypesA( HMODULE hmod, ENUMRESTYPEPROCA lpfun, LONG lparam)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
314
    int		i;
315 316
    const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
317
    BOOL	ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
318

319
    if (!resdir) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
320

321
    et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
322 323
    ret = FALSE;
    for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
324 325
        LPSTR type;

326
        if (et[i].u1.s1.NameIsString)
327
        {
328
            PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
329 330 331 332 333 334 335 336 337 338 339 340
            DWORD len = WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
                                             NULL, 0, NULL, NULL);
            if (!(type = HeapAlloc(GetProcessHeap(), 0, len + 1)))
                return FALSE;
            WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
                                 type, len, NULL, NULL);
            type[len] = '\0';
            ret = lpfun(hmod,type,lparam);
            HeapFree(GetProcessHeap(), 0, type);
        }
        else
        {
341
            type = (LPSTR)(int)et[i].u1.s2.Id;
342 343
            ret = lpfun(hmod,type,lparam);
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
344 345 346 347 348 349
	if (!ret)
		break;
    }
    return ret;
}

350

Alexandre Julliard's avatar
Alexandre Julliard committed
351
/**********************************************************************
352
 *	EnumResourceTypesW	(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
353
 */
354 355
BOOL WINAPI EnumResourceTypesW( HMODULE hmod, ENUMRESTYPEPROCW lpfun, LONG lparam)
{
Alexandre Julliard's avatar
Alexandre Julliard committed
356
    int		i;
357 358
    const IMAGE_RESOURCE_DIRECTORY *resdir = get_resdir(hmod);
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
359
    BOOL	ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
360

361
    if (!resdir) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
362

363
    et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
364 365 366 367
    ret = FALSE;
    for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
	LPWSTR	type;

368
        if (et[i].u1.s1.NameIsString)
369
        {
370
            PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) resdir + et[i].u1.s1.NameOffset);
371 372 373 374 375 376 377 378 379
            if (!(type = HeapAlloc(GetProcessHeap(), 0, (pResString->Length+1) * sizeof (WCHAR))))
                return FALSE;
            memcpy(type, pResString->NameString, pResString->Length * sizeof (WCHAR));
            type[pResString->Length] = '\0';
            ret = lpfun(hmod,type,lparam);
            HeapFree(GetProcessHeap(), 0, type);
        }
        else
        {
380
            type = (LPWSTR)(int)et[i].u1.s2.Id;
381 382
            ret = lpfun(hmod,type,lparam);
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
383 384 385 386 387 388
	if (!ret)
		break;
    }
    return ret;
}

389

Alexandre Julliard's avatar
Alexandre Julliard committed
390
/**********************************************************************
391
 *	EnumResourceNamesA	(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
392
 */
393 394
BOOL WINAPI EnumResourceNamesA( HMODULE hmod, LPCSTR type, ENUMRESNAMEPROCA lpfun, LONG lparam )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
395
    int		i;
396 397 398
    const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
    const IMAGE_RESOURCE_DIRECTORY *resdir;
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
399
    BOOL	ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
400

401 402
    if (!basedir) return FALSE;

403
    if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
404

405
    et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
406 407
    ret = FALSE;
    for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
408 409
        LPSTR name;

410
        if (et[i].u1.s1.NameIsString)
411
        {
412
            PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
413 414 415 416 417 418 419 420 421 422 423 424
            DWORD len = WideCharToMultiByte(CP_ACP, 0, pResString->NameString, pResString->Length,
                                            NULL, 0, NULL, NULL);
            if (!(name = HeapAlloc(GetProcessHeap(), 0, len + 1 )))
                return FALSE;
            WideCharToMultiByte( CP_ACP, 0, pResString->NameString, pResString->Length,
                                 name, len, NULL, NULL );
            name[len] = '\0';
            ret = lpfun(hmod,type,name,lparam);
            HeapFree( GetProcessHeap(), 0, name );
        }
        else
        {
425
            name = (LPSTR)(int)et[i].u1.s2.Id;
426 427
            ret = lpfun(hmod,type,name,lparam);
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
428 429 430 431 432 433
	if (!ret)
		break;
    }
    return ret;
}

434

Alexandre Julliard's avatar
Alexandre Julliard committed
435
/**********************************************************************
436
 *	EnumResourceNamesW	(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
437
 */
438 439
BOOL WINAPI EnumResourceNamesW( HMODULE hmod, LPCWSTR type, ENUMRESNAMEPROCW lpfun, LONG lparam )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
440
    int		i;
441 442 443
    const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
    const IMAGE_RESOURCE_DIRECTORY *resdir;
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
444
    BOOL	ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
445

446
    if (!basedir) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
447

448 449
    if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;

450
    et = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
451 452
    ret = FALSE;
    for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
453 454
        LPWSTR name;

455
        if (et[i].u1.s1.NameIsString)
456
        {
457
            PIMAGE_RESOURCE_DIR_STRING_U pResString = (PIMAGE_RESOURCE_DIR_STRING_U) ((LPBYTE) basedir + et[i].u1.s1.NameOffset);
458 459 460 461 462 463 464 465 466
            if (!(name = HeapAlloc(GetProcessHeap(), 0, (pResString->Length + 1) * sizeof (WCHAR))))
                return FALSE;
            memcpy(name, pResString->NameString, pResString->Length * sizeof (WCHAR));
            name[pResString->Length] = '\0';
            ret = lpfun(hmod,type,name,lparam);
            HeapFree(GetProcessHeap(), 0, name);
        }
        else
        {
467
            name = (LPWSTR)(int)et[i].u1.s2.Id;
468 469
            ret = lpfun(hmod,type,name,lparam);
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
470 471 472 473 474 475
	if (!ret)
		break;
    }
    return ret;
}

476

Alexandre Julliard's avatar
Alexandre Julliard committed
477
/**********************************************************************
478
 *	EnumResourceLanguagesA	(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
479
 */
480 481 482
BOOL WINAPI EnumResourceLanguagesA( HMODULE hmod, LPCSTR type, LPCSTR name,
                                    ENUMRESLANGPROCA lpfun, LONG lparam )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
483
    int		i;
484 485 486
    const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
    const IMAGE_RESOURCE_DIRECTORY *resdir;
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
487
    BOOL	ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
488

489
    if (!basedir) return FALSE;
490 491
    if (!(resdir = find_entry_by_nameA( basedir, type, basedir ))) return FALSE;
    if (!(resdir = find_entry_by_nameA( resdir, name, basedir ))) return FALSE;
492 493

    et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
494 495
    ret = FALSE;
    for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
496
        /* languages are just ids... I hope */
497
	ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
Alexandre Julliard's avatar
Alexandre Julliard committed
498 499 500 501 502 503
	if (!ret)
		break;
    }
    return ret;
}

504

Alexandre Julliard's avatar
Alexandre Julliard committed
505
/**********************************************************************
506
 *	EnumResourceLanguagesW	(KERNEL32.@)
Alexandre Julliard's avatar
Alexandre Julliard committed
507
 */
508 509 510
BOOL WINAPI EnumResourceLanguagesW( HMODULE hmod, LPCWSTR type, LPCWSTR name,
                                    ENUMRESLANGPROCW lpfun, LONG lparam )
{
Alexandre Julliard's avatar
Alexandre Julliard committed
511
    int		i;
512 513 514
    const IMAGE_RESOURCE_DIRECTORY *basedir = get_resdir(hmod);
    const IMAGE_RESOURCE_DIRECTORY *resdir;
    const IMAGE_RESOURCE_DIRECTORY_ENTRY *et;
515
    BOOL	ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
516

517
    if (!basedir) return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
518

519 520 521
    if (!(resdir = find_entry_by_nameW( basedir, type, basedir ))) return FALSE;
    if (!(resdir = find_entry_by_nameW( resdir, name, basedir ))) return FALSE;

522
    et =(PIMAGE_RESOURCE_DIRECTORY_ENTRY)(resdir + 1);
Alexandre Julliard's avatar
Alexandre Julliard committed
523 524
    ret = FALSE;
    for (i=0;i<resdir->NumberOfNamedEntries+resdir->NumberOfIdEntries;i++) {
525
	ret = lpfun(hmod,type,name,et[i].u1.s2.Id,lparam);
Alexandre Julliard's avatar
Alexandre Julliard committed
526 527 528 529
	if (!ret)
		break;
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
530
}