loadorder.c 21.6 KB
Newer Older
1 2 3 4
/*
 * Module/Library loadorder
 *
 * Copyright 1999 Bertho Stultiens
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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
19 20
 */

21
#include "config.h"
22
#include "wine/port.h"
23

24 25 26 27 28
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "windef.h"
29
#include "winerror.h"
30
#include "winternl.h"
31
#include "file.h"
32
#include "module.h"
33
#include "wine/debug.h"
34

35
WINE_DEFAULT_DEBUG_CHANNEL(module);
36

37
#define LOADORDER_ALLOC_CLUSTER	32	/* Allocate with 32 entries at a time */
38

39 40 41 42 43
typedef struct module_loadorder
{
    const char         *modulename;
    enum loadorder_type loadorder[LOADORDER_NTYPES];
} module_loadorder_t;
44

45 46 47 48 49 50
struct loadorder_list
{
    int                 count;
    int                 alloc;
    module_loadorder_t *order;
};
51

52 53 54 55 56
/* default load-order if nothing specified */
/* the list must remain sorted by dll name */
static module_loadorder_t default_order_list[] =
{
    { "display",      { LOADORDER_BI,  0,             0, 0 } },
57
    { "gdi.exe",      { LOADORDER_BI,  0,             0, 0 } },
58 59 60 61 62 63 64
    { "gdi32",        { LOADORDER_BI,  0,             0, 0 } },
    { "glide2x",      { LOADORDER_SO,  LOADORDER_DLL, 0, 0 } },
    { "glide3x",      { LOADORDER_SO,  LOADORDER_DLL, 0, 0 } },
    { "icmp",         { LOADORDER_BI,  0,             0, 0 } },
    { "kernel",       { LOADORDER_BI,  0,             0, 0 } },
    { "kernel32",     { LOADORDER_BI,  0,             0, 0 } },
    { "keyboard",     { LOADORDER_BI,  0,             0, 0 } },
65
    { "krnl386.exe",  { LOADORDER_BI,  0,             0, 0 } },
66 67 68 69 70 71 72
    { "mmsystem",     { LOADORDER_BI,  0,             0, 0 } },
    { "mouse",        { LOADORDER_BI,  0,             0, 0 } },
    { "ntdll",        { LOADORDER_BI,  0,             0, 0 } },
    { "odbc32",       { LOADORDER_BI,  0,             0, 0 } },
    { "system",       { LOADORDER_BI,  0,             0, 0 } },
    { "toolhelp",     { LOADORDER_BI,  0,             0, 0 } },
    { "ttydrv",       { LOADORDER_BI,  0,             0, 0 } },
73
    { "user.exe",     { LOADORDER_BI,  0,             0, 0 } },
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
    { "user32",       { LOADORDER_BI,  0,             0, 0 } },
    { "w32skrnl",     { LOADORDER_BI,  0,             0, 0 } },
    { "winaspi",      { LOADORDER_BI,  0,             0, 0 } },
    { "windebug",     { LOADORDER_DLL, LOADORDER_BI,  0, 0 } },
    { "winedos",      { LOADORDER_BI,  0,             0, 0 } },
    { "wineps",       { LOADORDER_BI,  0,             0, 0 } },
    { "wing",         { LOADORDER_BI,  0,             0, 0 } },
    { "winmm",        { LOADORDER_BI,  0,             0, 0 } },
    { "winsock",      { LOADORDER_BI,  0,             0, 0 } },
    { "wnaspi32",     { LOADORDER_BI,  0,             0, 0 } },
    { "wow32",        { LOADORDER_BI,  0,             0, 0 } },
    { "wprocs",       { LOADORDER_BI,  0,             0, 0 } },
    { "ws2_32",       { LOADORDER_BI,  0,             0, 0 } },
    { "wsock32",      { LOADORDER_BI,  0,             0, 0 } },
    { "x11drv",       { LOADORDER_BI,  0,             0, 0 } }
89 90
};

91 92 93 94 95
static const struct loadorder_list default_list =
{
    sizeof(default_order_list)/sizeof(default_order_list[0]),
    sizeof(default_order_list)/sizeof(default_order_list[0]),
    default_order_list
96 97
};

98 99 100
/* default if nothing else specified */
static const enum loadorder_type default_loadorder[LOADORDER_NTYPES] =
{
101
    LOADORDER_BI, LOADORDER_DLL, 0, 0
102 103
};

104 105 106
static struct loadorder_list cmdline_list;


107 108 109 110 111 112 113 114
/***************************************************************************
 *	cmp_sort_func	(internal, static)
 *
 * Sorting and comparing function used in sort and search of loadorder
 * entries.
 */
static int cmp_sort_func(const void *s1, const void *s2)
{
115 116
    return FILE_strcasecmp(((module_loadorder_t *)s1)->modulename,
                           ((module_loadorder_t *)s2)->modulename);
117 118 119 120 121 122 123 124 125 126 127 128 129 130
}


/***************************************************************************
 *	get_tok	(internal, static)
 *
 * strtok wrapper for non-destructive buffer writing.
 * NOTE: strtok is not reentrant and therefore this code is neither.
 */
static char *get_tok(const char *str, const char *delim)
{
	static char *buf = NULL;
	char *cptr;

131
	if(!str && !buf)
132 133 134 135
		return NULL;

	if(str && buf)
	{
136
		HeapFree(GetProcessHeap(), 0, buf);
137 138 139 140 141
		buf = NULL;
	}

	if(str && !buf)
	{
142 143
		buf = HeapAlloc(GetProcessHeap(), 0, strlen(str)+1);
		strcpy( buf, str );
144 145 146 147 148 149 150 151 152
		cptr = strtok(buf, delim);
	}
	else
	{
		cptr = strtok(NULL, delim);
	}

	if(!cptr)
	{
153
		HeapFree(GetProcessHeap(), 0, buf);
154 155 156 157 158 159
		buf = NULL;
	}
	return cptr;
}


160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
/***************************************************************************
 *	get_basename
 *
 * Return the base name of a file name (i.e. remove the path components).
 */
static const char *get_basename( const char *name )
{
    const char *ptr;

    if (name[0] && name[1] == ':') name += 2;  /* strip drive specification */
    if ((ptr = strrchr( name, '\\' ))) name = ptr + 1;
    if ((ptr = strrchr( name, '/' ))) name = ptr + 1;
    return name;
}


/***************************************************************************
 *	debugstr_loadorder
 *
 * Return a loadorder in printable form.
 */
static const char *debugstr_loadorder( enum loadorder_type lo[] )
{
    int i;
    char buffer[LOADORDER_NTYPES*3+1];

    buffer[0] = 0;
    for(i = 0; i < LOADORDER_NTYPES; i++)
    {
        if (lo[i] == LOADORDER_INVALID) break;
        switch(lo[i])
        {
        case LOADORDER_DLL: strcat( buffer, "n," ); break;
        case LOADORDER_SO:  strcat( buffer, "s," ); break;
        case LOADORDER_BI:  strcat( buffer, "b," ); break;
        default:            strcat( buffer, "?," ); break;
        }
    }
    if (buffer[0]) buffer[strlen(buffer)-1] = 0;
    return debugstr_a(buffer);
}


203 204 205 206 207 208
/***************************************************************************
 *	ParseLoadOrder	(internal, static)
 *
 * Parses the loadorder options from the configuration and puts it into
 * a structure.
 */
209
static BOOL ParseLoadOrder(char *order, enum loadorder_type lo[])
210
{
211
    static int warn;
212 213 214 215 216 217
	char *cptr;
	int n = 0;

	cptr = get_tok(order, ", \t");
	while(cptr)
	{
218
            enum loadorder_type type = LOADORDER_INVALID;
219

220
		if(n >= LOADORDER_NTYPES-1)
221
		{
222
			ERR("More than existing %d module-types specified, rest ignored\n", LOADORDER_NTYPES-1);
223 224 225 226 227 228
			break;
		}

		switch(*cptr)
		{
		case 'N':	/* Native */
229
		case 'n': type = LOADORDER_DLL; break;
230 231

		case 'E':	/* Elfdll */
232
		case 'e':
233
                    if (!warn++) MESSAGE("Load order 'elfdll' no longer supported, ignored\n");
234
                    break;
235
		case 'S':	/* So */
236
		case 's': type = LOADORDER_SO; break;
237 238

		case 'B':	/* Builtin */
239
		case 'b': type = LOADORDER_BI; break;
240 241

		default:
242
			ERR("Invalid load order module-type '%s', ignored\n", cptr);
243 244
		}

245
                if(type != LOADORDER_INVALID) lo[n++] = type;
246 247
		cptr = get_tok(NULL, ", \t");
	}
248
        lo[n] = LOADORDER_INVALID;
249 250 251 252 253 254 255
	return TRUE;
}


/***************************************************************************
 *	AddLoadOrder	(internal, static)
 *
256
 * Adds an entry in the list of command-line overrides.
257
 */
258
static BOOL AddLoadOrder(module_loadorder_t *plo)
259 260 261 262 263
{
	int i;

	/* TRACE(module, "'%s' -> %08lx\n", plo->modulename, *(DWORD *)(plo->loadorder)); */

264
	for(i = 0; i < cmdline_list.count; i++)
265
	{
266 267 268 269 270 271
            if(!cmp_sort_func(plo, &cmdline_list.order[i] ))
            {
                /* replace existing option */
                memcpy( cmdline_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
                return TRUE;
            }
272 273
	}

274
	if (i >= cmdline_list.alloc)
275 276
	{
		/* No space in current array, make it larger */
277 278 279 280
		cmdline_list.alloc += LOADORDER_ALLOC_CLUSTER;
		cmdline_list.order = HeapReAlloc(GetProcessHeap(), 0, cmdline_list.order,
                                          cmdline_list.alloc * sizeof(module_loadorder_t));
		if(!cmdline_list.order)
281
		{
282
			MESSAGE("Virtual memory exhausted\n");
283 284 285
			exit(1);
		}
	}
286
	memcpy(cmdline_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
287 288
	cmdline_list.order[i].modulename = HeapAlloc(GetProcessHeap(), 0, strlen(plo->modulename)+1);
	strcpy( (char *)cmdline_list.order[i].modulename, plo->modulename );
289
	cmdline_list.count++;
290 291 292 293 294 295 296
	return TRUE;
}


/***************************************************************************
 *	AddLoadOrderSet	(internal, static)
 *
297
 * Adds a set of entries in the list of command-line overrides from the key parameter.
298
 */
299
static BOOL AddLoadOrderSet(char *key, char *order)
300 301 302 303 304
{
	module_loadorder_t ldo;
	char *cptr;

	/* Parse the loadorder before the rest because strtok is not reentrant */
305
	if(!ParseLoadOrder(order, ldo.loadorder))
306 307 308 309 310
		return FALSE;

	cptr = get_tok(key, ", \t");
	while(cptr)
	{
311
		char *ext = strrchr(cptr, '.');
312
		if(ext && !FILE_strcasecmp( ext, ".dll" )) *ext = 0;
313
		ldo.modulename = cptr;
314
		if(!AddLoadOrder(&ldo)) return FALSE;
315 316 317 318 319 320 321
		cptr = get_tok(NULL, ", \t");
	}
	return TRUE;
}


/***************************************************************************
322
 *	MODULE_AddLoadOrderOption
323
 *
324 325
 * The commandline option is in the form:
 * name[,name,...]=native[,b,...]
326
 */
327
void MODULE_AddLoadOrderOption( const char *option )
328
{
329
    char *value, *key = HeapAlloc(GetProcessHeap(), 0, strlen(option)+1);
330

331 332
    strcpy( key, option );
    if (!(value = strchr(key, '='))) goto error;
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352
    *value++ = '\0';

    TRACE("Commandline override '%s' = '%s'\n", key, value);

    if (!AddLoadOrderSet(key, value)) goto error;
    HeapFree(GetProcessHeap(), 0, key);

    /* sort the array for quick lookup */
    qsort(cmdline_list.order, cmdline_list.count, sizeof(cmdline_list.order[0]), cmp_sort_func);
    return;

 error:
    MESSAGE( "Syntax: -dll name[,name[,...]]={native|so|builtin}[,{n|s|b}[,...]]\n"
             "    - 'name' is the name of any dll without extension\n"
             "    - the order of loading (native, so and builtin) can be abbreviated\n"
             "      with the first letter\n"
             "    - the option can be specified multiple times\n"
             "    Example:\n"
             "    -dll comdlg32,commdlg=n -dll shell,shell32=b\n" );
    ExitProcess(1);
353 354 355
}


356 357 358 359 360 361 362 363
/***************************************************************************
 *	get_list_load_order
 *
 * Get the load order for a given module from the command-line or
 * default lists.
 */
static BOOL get_list_load_order( const char *module, const struct loadorder_list *list,
                                 enum loadorder_type lo[] )
364
{
Eric Pouech's avatar
Eric Pouech committed
365
    module_loadorder_t tmp, *res = NULL;
366

367
    tmp.modulename = module;
Eric Pouech's avatar
Eric Pouech committed
368 369
    /* some bsearch implementations (Solaris) are buggy when the number of items is 0 */
    if (list->count && (res = bsearch(&tmp, list->order, list->count, sizeof(list->order[0]), cmp_sort_func)))
370 371 372
        memcpy( lo, res->loadorder, sizeof(res->loadorder) );
    return (res != NULL);
}
373 374


375
/***************************************************************************
376
 *	open_app_key
377
 *
378
 * Open the registry key to the app-specific DllOverrides list.
379
 */
380
static HKEY open_app_key( const char *module )
381
{
382 383
    OBJECT_ATTRIBUTES attr;
    UNICODE_STRING nameW;
384
    HKEY hkey, appkey;
385
    char buffer[MAX_PATH+16], *appname;
386 387 388 389 390 391
    static const WCHAR AppDefaultsW[] = {'M','a','c','h','i','n','e','\\',
                                         'S','o','f','t','w','a','r','e','\\',
                                         'W','i','n','e','\\',
                                         'W','i','n','e','\\',
                                         'C','o','n','f','i','g','\\',
                                         'A','p','p','D','e','f','a','u','l','t','s',0};
392

393
    if (!GetModuleFileNameA( 0, buffer, MAX_PATH ))
394 395
    {
        WARN( "could not get module file name loading %s\n", module );
396
        return 0;
397
    }
398
    appname = (char *)get_basename( buffer );
399 400 401

    TRACE( "searching '%s' in AppDefaults\\%s\\DllOverrides\n", module, appname );

402 403 404 405 406 407 408 409 410 411
    attr.Length = sizeof(attr);
    attr.RootDirectory = 0;
    attr.ObjectName = &nameW;
    attr.Attributes = 0;
    attr.SecurityDescriptor = NULL;
    attr.SecurityQualityOfService = NULL;
    RtlInitUnicodeString( &nameW, AppDefaultsW );

    if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) return 0;
    attr.RootDirectory = hkey;
412 413 414

    /* open AppDefaults\\appname\\DllOverrides key */
    strcat( appname, "\\DllOverrides" );
415 416 417 418
    RtlCreateUnicodeStringFromAsciiz( &nameW, appname );
    if (NtOpenKey( &appkey, KEY_ALL_ACCESS, &attr )) appkey = 0;
    RtlFreeUnicodeString( &nameW );
    NtClose( hkey );
419
    return appkey;
420
}
421

422

423
/***************************************************************************
424
 *	get_registry_value
425
 *
426
 * Load the registry loadorder value for a given module.
427
 */
428
static BOOL get_registry_value( HKEY hkey, const char *module, enum loadorder_type lo[] )
429
{
430
    UNICODE_STRING valueW;
431
    char buffer[80];
432 433 434 435 436 437 438 439 440 441
    DWORD count;
    BOOL ret;

    RtlCreateUnicodeStringFromAsciiz( &valueW, module );

    if ((ret = !NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation,
                                 buffer, sizeof(buffer), &count )))
    {
        int i, n = 0;
        WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
442

443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
        while (*str)
        {
            enum loadorder_type type = LOADORDER_INVALID;

            while (*str == ',' || isspaceW(*str)) str++;
            if (!*str) break;

            switch(tolowerW(*str))
            {
            case 'n': type = LOADORDER_DLL; break;
            case 's': type = LOADORDER_SO; break;
            case 'b': type = LOADORDER_BI; break;
            case 0:   break;  /* end of string */
            default:
                ERR("Invalid load order module-type %s, ignored\n", debugstr_w(str));
                break;
            }
            if (type != LOADORDER_INVALID)
            {
                for (i = 0; i < n; i++) if (lo[i] == type) break;  /* already specified */
                if (i == n) lo[n++] = type;
            }
            while (*str && *str != ',' && !isspaceW(*str)) str++;
        }
        lo[n] = LOADORDER_INVALID;
    }
    RtlFreeUnicodeString( &valueW );
    return ret;
471
}
472 473


474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529
/***************************************************************************
 *	MODULE_GetBuiltinPath
 *
 * Get the path of a builtin module when the native file does not exist.
 */
BOOL MODULE_GetBuiltinPath( const char *libname, const char *ext, char *filename, UINT size )
{
    char *p;
    BOOL ret = FALSE;
    UINT len = GetSystemDirectoryA( filename, size );

    if (FILE_contains_path( libname ))
    {
        char *tmp;

        /* if the library name contains a path and can not be found,
         * return an error.
         * exception: if the path is the system directory, proceed,
         * so that modules which are not PE modules can be loaded.
         * If the library name does not contain a path and can not
         * be found, assume the system directory is meant */

        if (strlen(libname) >= size) return FALSE;  /* too long */
        if (strchr( libname, '/' ))  /* need to convert slashes */
        {
            if (!(tmp = HeapAlloc( GetProcessHeap(), 0, strlen(libname)+1 ))) return FALSE;
            strcpy( tmp, libname );
            for (p = tmp; *p; p++) if (*p == '/') *p = '\\';
        }
        else tmp = (char *)libname;

        if (!FILE_strncasecmp( filename, tmp, len ) && tmp[len] == '\\')
        {
            strcpy( filename, tmp );
            ret = TRUE;
        }
        if (tmp != libname) HeapFree( GetProcessHeap(), 0, tmp );
        if (!ret) return FALSE;
    }
    else
    {
        if (strlen(libname) >= size - len - 1) return FALSE;
        filename[len] = '\\';
        strcpy( filename+len+1, libname );
    }

    /* if the filename doesn't have an extension, append the default */
    if (!(p = strrchr( filename, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
    {
        if (strlen(filename) + strlen(ext) >= size) return FALSE;
        strcat( filename, ext );
    }
    return TRUE;
}


530 531 532 533 534
/***************************************************************************
 *	MODULE_GetLoadOrder	(internal)
 *
 * Locate the loadorder of a module.
 * Any path is stripped from the path-argument and so are the extension
535
 * '.dll' and '.exe'. A lookup in the table can yield an override for
536
 * the specific dll. Otherwise the default load order is returned.
537
 */
538
void MODULE_GetLoadOrder( enum loadorder_type loadorder[], const char *path, BOOL win32 )
539
{
540 541 542 543 544 545 546
    static const WCHAR DllOverridesW[] = {'M','a','c','h','i','n','e','\\',
                                          'S','o','f','t','w','a','r','e','\\',
                                          'W','i','n','e','\\',
                                          'W','i','n','e','\\',
                                          'C','o','n','f','i','g','\\',
                                          'D','l','l','O','v','e','r','r','i','d','e','s',0};

547 548 549 550
    static HKEY std_key = (HKEY)-1;  /* key to standard section, cached */
    HKEY app_key = 0;
    char *module, *basename;
    int len;
551

552
    TRACE("looking for %s\n", path);
553

554
    loadorder[0] = LOADORDER_INVALID;  /* in case something bad happens below */
555

556 557
    /* Strip path information for 16 bit modules or if the module
     * resides in the system directory */
558 559 560 561 562 563 564 565 566 567 568 569
    if (!win32)
    {
        path = get_basename( path );
        if (BUILTIN_IsPresent(path))
        {
            TRACE( "forcing loadorder to builtin for %s\n", debugstr_a(path) );
            /* force builtin loadorder since the dll is already in memory */
            loadorder[0] = LOADORDER_BI;
            loadorder[1] = LOADORDER_INVALID;
            return;
        }
    }
570 571 572 573 574 575 576 577 578 579 580 581 582 583
    else
    {
        char sysdir[MAX_PATH+1];
        if (!GetSystemDirectoryA( sysdir, MAX_PATH )) return;
        if (!FILE_strncasecmp( sysdir, path, strlen (sysdir) ))
        {
            path += strlen(sysdir);
            while (*path == '\\' || *path == '/') path++;
        }
    }

    if (!(len = strlen(path))) return;
    if (!(module = HeapAlloc( GetProcessHeap(), 0, len + 2 ))) return;
    strcpy( module+1, path );  /* reserve module[0] for the wildcard char */
584

585 586 587 588 589
    if (len >= 4)
    {
        char *ext = module + 1 + len - 4;
        if (!FILE_strcasecmp( ext, ".dll" )) *ext = 0;
    }
590

591 592 593 594 595 596 597
    /* check command-line first */
    if (get_list_load_order( module+1, &cmdline_list, loadorder ))
    {
        TRACE( "got cmdline %s for %s\n",
               debugstr_loadorder(loadorder), debugstr_a(path) );
        goto done;
    }
598

599 600 601 602 603 604 605 606
    /* then explicit module name in AppDefaults */
    app_key = open_app_key( module+1 );
    if (app_key && get_registry_value( app_key, module+1, loadorder ))
    {
        TRACE( "got app defaults %s for %s\n",
               debugstr_loadorder(loadorder), debugstr_a(path) );
        goto done;
    }
607

608 609
    /* then explicit module name in standard section */
    if (std_key == (HKEY)-1)
610 611 612 613 614 615 616 617 618 619 620 621 622 623
    {
        OBJECT_ATTRIBUTES attr;
        UNICODE_STRING nameW;

        attr.Length = sizeof(attr);
        attr.RootDirectory = 0;
        attr.ObjectName = &nameW;
        attr.Attributes = 0;
        attr.SecurityDescriptor = NULL;
        attr.SecurityQualityOfService = NULL;
        RtlInitUnicodeString( &nameW, DllOverridesW );

        if (NtOpenKey( &std_key, KEY_ALL_ACCESS, &attr )) std_key = 0;
    }
624 625 626 627 628 629 630

    if (std_key && get_registry_value( std_key, module+1, loadorder ))
    {
        TRACE( "got standard entry %s for %s\n",
               debugstr_loadorder(loadorder), debugstr_a(path) );
        goto done;
    }
631

632 633 634 635 636 637 638 639 640
    /* then module basename preceded by '*' in AppDefaults */
    basename = (char *)get_basename( module+1 );
    basename[-1] = '*';
    if (app_key && get_registry_value( app_key, basename-1, loadorder ))
    {
        TRACE( "got app defaults basename %s for %s\n",
               debugstr_loadorder(loadorder), debugstr_a(path) );
        goto done;
    }
641

642 643 644 645 646 647 648
    /* then module name preceded by '*' in standard section */
    if (std_key && get_registry_value( std_key, basename-1, loadorder ))
    {
        TRACE( "got standard base name %s for %s\n",
               debugstr_loadorder(loadorder), debugstr_a(path) );
        goto done;
    }
649

650 651 652 653 654 655 656 657 658 659 660 661
    /* then base name matching compiled-in defaults */
    if (get_list_load_order( basename, &default_list, loadorder ))
    {
        TRACE( "got compiled-in default %s for %s\n",
               debugstr_loadorder(loadorder), debugstr_a(path) );
        goto done;
    }

    if (basename == module+1)
    {
        /* then wildcard entry in AppDefaults (only if no explicit path) */
        if (app_key && get_registry_value( app_key, "*", loadorder ))
662
        {
663 664 665
            TRACE( "got app defaults wildcard %s for %s\n",
                   debugstr_loadorder(loadorder), debugstr_a(path) );
            goto done;
666
        }
667

668 669
        /* then wildcard entry in standard section (only if no explicit path) */
        if (std_key && get_registry_value( std_key, "*", loadorder ))
670
        {
671 672 673
            TRACE( "got standard wildcard %s for %s\n",
                   debugstr_loadorder(loadorder), debugstr_a(path) );
            goto done;
674
        }
675 676 677 678 679 680
    }

    /* and last the hard-coded default */
    memcpy( loadorder, default_loadorder, sizeof(default_loadorder) );
    TRACE( "got hardcoded default %s for %s\n",
           debugstr_loadorder(loadorder), debugstr_a(path) );
681

682 683

 done:
684
    if (app_key) NtClose( app_key );
685
    HeapFree( GetProcessHeap(), 0, module );
686
}