Don't depend on the name of the main binary, always load
[wine] / dlls / ntdll / loadorder.c
CommitLineData
cebb2f11 1/*
2052538a 2 * Dlls load order support
cebb2f11
BS
3 *
4 * Copyright 1999 Bertho Stultiens
2052538a 5 * Copyright 2003 Alexandre Julliard
0799c1a7
AJ
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
cebb2f11
BS
20 */
21
e5ddd26d 22#include "config.h"
9aab47ed 23#include "wine/port.h"
e5ddd26d 24
e37c6e18 25#include <stdarg.h>
cebb2f11
BS
26#include <stdlib.h>
27#include <string.h>
28#include <assert.h>
29
30#include "windef.h"
e37c6e18 31#include "winbase.h"
b9c9cdc5 32#include "winerror.h"
e37c6e18 33#include "winreg.h"
81bdcf12 34#include "winternl.h"
2052538a 35#include "ntdll_misc.h"
f9be2f3d 36#include "module.h"
cf07e100 37
0799c1a7 38#include "wine/debug.h"
cf07e100 39#include "wine/unicode.h"
cebb2f11 40
0799c1a7 41WINE_DEFAULT_DEBUG_CHANNEL(module);
b4b9fae6 42
b9c9cdc5 43#define LOADORDER_ALLOC_CLUSTER 32 /* Allocate with 32 entries at a time */
cebb2f11 44
b9c9cdc5
AJ
45typedef struct module_loadorder
46{
1cb92bbe 47 const WCHAR *modulename;
b9c9cdc5
AJ
48 enum loadorder_type loadorder[LOADORDER_NTYPES];
49} module_loadorder_t;
cebb2f11 50
b9c9cdc5
AJ
51struct loadorder_list
52{
53 int count;
54 int alloc;
55 module_loadorder_t *order;
56};
cebb2f11 57
1cb92bbe 58/* dll to load as builtins if not explicitly specified otherwise */
b9c9cdc5 59/* the list must remain sorted by dll name */
7412125e 60static const WCHAR default_builtins[][10] =
b9c9cdc5 61{
1cb92bbe
AJ
62 { 'g','d','i','3','2',0 },
63 { 'i','c','m','p',0 },
64 { 'k','e','r','n','e','l','3','2',0 },
1cb92bbe
AJ
65 { 'n','t','d','l','l',0 },
66 { 'o','d','b','c','3','2',0 },
1cb92bbe
AJ
67 { 't','t','y','d','r','v',0 },
68 { 'u','s','e','r','3','2',0 },
69 { 'w','3','2','s','k','r','n','l',0 },
1cb92bbe 70 { 'w','i','n','e','d','o','s',0 },
1cb92bbe
AJ
71 { 'w','i','n','e','p','s',0 },
72 { 'w','i','n','m','m',0 },
1cb92bbe
AJ
73 { 'w','n','a','s','p','i','3','2',0 },
74 { 'w','o','w','3','2',0 },
75 { 'w','s','2','_','3','2',0 },
76 { 'w','s','o','c','k','3','2',0 },
77 { 'x','1','1','d','r','v',0 }
431cf324
AJ
78};
79
69622dbd
AJ
80/* default if nothing else specified */
81static const enum loadorder_type default_loadorder[LOADORDER_NTYPES] =
82{
d4fcc4bd 83 LOADORDER_BI, LOADORDER_DLL, 0
69622dbd
AJ
84};
85
851d25d9
AJ
86/* default for modules with an explicit path */
87static const enum loadorder_type default_path_loadorder[LOADORDER_NTYPES] =
88{
d4fcc4bd 89 LOADORDER_DLL, LOADORDER_BI, 0
851d25d9
AJ
90};
91
1cb92bbe
AJ
92static const WCHAR separatorsW[] = {',',' ','\t',0};
93
2052538a
AJ
94static int init_done;
95static struct loadorder_list env_list;
b9c9cdc5
AJ
96
97
cebb2f11
BS
98/***************************************************************************
99 * cmp_sort_func (internal, static)
100 *
101 * Sorting and comparing function used in sort and search of loadorder
102 * entries.
103 */
104static int cmp_sort_func(const void *s1, const void *s2)
105{
1cb92bbe
AJ
106 return strcmpiW(((module_loadorder_t *)s1)->modulename, ((module_loadorder_t *)s2)->modulename);
107}
108
109
110/***************************************************************************
111 * strcmp_func
112 */
113static int strcmp_func(const void *s1, const void *s2)
114{
115 return strcmpiW( (WCHAR *)s1, (WCHAR *)s2 );
cebb2f11
BS
116}
117
118
69622dbd
AJ
119/***************************************************************************
120 * get_basename
121 *
122 * Return the base name of a file name (i.e. remove the path components).
123 */
1cb92bbe 124static const WCHAR *get_basename( const WCHAR *name )
69622dbd 125{
1cb92bbe 126 const WCHAR *ptr;
69622dbd
AJ
127
128 if (name[0] && name[1] == ':') name += 2; /* strip drive specification */
1cb92bbe
AJ
129 if ((ptr = strrchrW( name, '\\' ))) name = ptr + 1;
130 if ((ptr = strrchrW( name, '/' ))) name = ptr + 1;
69622dbd
AJ
131 return name;
132}
133
1cb92bbe
AJ
134/***************************************************************************
135 * remove_dll_ext
136 *
137 * Remove extension if it is ".dll".
138 */
139static inline void remove_dll_ext( WCHAR *ext )
140{
141 if (ext[0] == '.' &&
142 toupperW(ext[1]) == 'D' &&
143 toupperW(ext[2]) == 'L' &&
144 toupperW(ext[3]) == 'L' &&
145 !ext[4]) ext[0] = 0;
146}
147
69622dbd
AJ
148
149/***************************************************************************
150 * debugstr_loadorder
151 *
152 * Return a loadorder in printable form.
153 */
154static const char *debugstr_loadorder( enum loadorder_type lo[] )
155{
156 int i;
157 char buffer[LOADORDER_NTYPES*3+1];
158
159 buffer[0] = 0;
160 for(i = 0; i < LOADORDER_NTYPES; i++)
161 {
162 if (lo[i] == LOADORDER_INVALID) break;
163 switch(lo[i])
164 {
165 case LOADORDER_DLL: strcat( buffer, "n," ); break;
69622dbd
AJ
166 case LOADORDER_BI: strcat( buffer, "b," ); break;
167 default: strcat( buffer, "?," ); break;
168 }
169 }
170 if (buffer[0]) buffer[strlen(buffer)-1] = 0;
171 return debugstr_a(buffer);
172}
173
174
cebb2f11 175/***************************************************************************
2052538a 176 * append_load_order
cebb2f11 177 *
2052538a 178 * Append a load order to the list if necessary.
cebb2f11 179 */
2052538a 180static void append_load_order(enum loadorder_type lo[], enum loadorder_type append)
cebb2f11 181{
2052538a 182 int i;
cebb2f11 183
2052538a
AJ
184 for (i = 0; i < LOADORDER_NTYPES; i++)
185 {
186 if (lo[i] == LOADORDER_INVALID) /* append it here */
187 {
188 lo[i++] = append;
189 lo[i] = LOADORDER_INVALID;
190 return;
191 }
192 if (lo[i] == append) return; /* already in the list */
193 }
194 assert(0); /* cannot get here */
195}
cebb2f11 196
cebb2f11 197
2052538a
AJ
198/***************************************************************************
199 * parse_load_order
200 *
201 * Parses the loadorder options from the configuration and puts it into
202 * a structure.
203 */
1cb92bbe 204static void parse_load_order( const WCHAR *order, enum loadorder_type lo[] )
2052538a
AJ
205{
206 lo[0] = LOADORDER_INVALID;
207 while (*order)
208 {
1cb92bbe 209 order += strspnW( order, separatorsW );
2052538a
AJ
210 switch(*order)
211 {
212 case 'N': /* Native */
213 case 'n':
214 append_load_order( lo, LOADORDER_DLL );
215 break;
216 case 'B': /* Builtin */
217 case 'b':
218 append_load_order( lo, LOADORDER_BI );
219 break;
220 }
1cb92bbe 221 order += strcspnW( order, separatorsW );
2052538a 222 }
cebb2f11
BS
223}
224
225
226/***************************************************************************
2052538a 227 * add_load_order
cebb2f11 228 *
2052538a 229 * Adds an entry in the list of environment overrides.
cebb2f11 230 */
2052538a 231static void add_load_order( const module_loadorder_t *plo )
cebb2f11 232{
2052538a 233 int i;
cebb2f11 234
2052538a
AJ
235 for(i = 0; i < env_list.count; i++)
236 {
237 if(!cmp_sort_func(plo, &env_list.order[i] ))
238 {
239 /* replace existing option */
240 memcpy( env_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
241 return;
242 }
243 }
cebb2f11 244
2052538a
AJ
245 if (i >= env_list.alloc)
246 {
247 /* No space in current array, make it larger */
248 env_list.alloc += LOADORDER_ALLOC_CLUSTER;
249 if (env_list.order)
250 env_list.order = RtlReAllocateHeap(GetProcessHeap(), 0, env_list.order,
251 env_list.alloc * sizeof(module_loadorder_t));
252 else
253 env_list.order = RtlAllocateHeap(GetProcessHeap(), 0,
254 env_list.alloc * sizeof(module_loadorder_t));
255 if(!env_list.order)
256 {
257 MESSAGE("Virtual memory exhausted\n");
258 exit(1);
259 }
260 }
261 memcpy(env_list.order[i].loadorder, plo->loadorder, sizeof(plo->loadorder));
1cb92bbe 262 env_list.order[i].modulename = plo->modulename;
2052538a 263 env_list.count++;
cebb2f11
BS
264}
265
266
267/***************************************************************************
2052538a 268 * add_load_order_set
cebb2f11 269 *
b9c9cdc5 270 * Adds a set of entries in the list of command-line overrides from the key parameter.
cebb2f11 271 */
1cb92bbe 272static void add_load_order_set( WCHAR *entry )
cebb2f11 273{
2052538a 274 module_loadorder_t ldo;
1cb92bbe 275 WCHAR *end = strchrW( entry, '=' );
cebb2f11 276
2052538a
AJ
277 if (!end) return;
278 *end++ = 0;
279 parse_load_order( end, ldo.loadorder );
cebb2f11 280
2052538a
AJ
281 while (*entry)
282 {
1cb92bbe
AJ
283 entry += strspnW( entry, separatorsW );
284 end = entry + strcspnW( entry, separatorsW );
2052538a
AJ
285 if (*end) *end++ = 0;
286 if (*entry)
1cb92bbe
AJ
287 {
288 WCHAR *ext = strrchrW(entry, '.');
289 if (ext) remove_dll_ext( ext );
2052538a
AJ
290 ldo.modulename = entry;
291 add_load_order( &ldo );
292 entry = end;
1cb92bbe 293 }
2052538a 294 }
cebb2f11
BS
295}
296
297
298/***************************************************************************
2052538a 299 * init_load_order
cebb2f11 300 */
2052538a 301static void init_load_order(void)
cebb2f11 302{
2052538a 303 const char *order = getenv( "WINEDLLOVERRIDES" );
1cb92bbe
AJ
304 UNICODE_STRING strW;
305 WCHAR *entry, *next;
b9c9cdc5 306
2052538a
AJ
307 init_done = 1;
308 if (!order) return;
b9c9cdc5 309
2052538a
AJ
310 if (!strcmp( order, "help" ))
311 {
312 MESSAGE( "Syntax:\n"
313 " WINEDLLOVERRIDES=\"entry;entry;entry...\"\n"
314 " where each entry is of the form:\n"
315 " module[,module...]={native|builtin}[,{b|n}]\n"
316 "\n"
317 " Only the first letter of the override (native or builtin)\n"
318 " is significant.\n\n"
319 "Example:\n"
7412125e 320 " WINEDLLOVERRIDES=\"comdlg32=n,b;shell32,shlwapi=b\"\n" );
2052538a
AJ
321 exit(0);
322 }
b9c9cdc5 323
1cb92bbe
AJ
324 RtlCreateUnicodeStringFromAsciiz( &strW, order );
325 entry = strW.Buffer;
2052538a
AJ
326 while (*entry)
327 {
328 while (*entry && *entry == ';') entry++;
329 if (!*entry) break;
1cb92bbe 330 next = strchrW( entry, ';' );
2052538a 331 if (next) *next++ = 0;
1cb92bbe 332 else next = entry + strlenW(entry);
2052538a
AJ
333 add_load_order_set( entry );
334 entry = next;
335 }
b9c9cdc5
AJ
336
337 /* sort the array for quick lookup */
2052538a
AJ
338 if (env_list.count)
339 qsort(env_list.order, env_list.count, sizeof(env_list.order[0]), cmp_sort_func);
1cb92bbe
AJ
340
341 /* Note: we don't free the Unicode string because the
342 * stored module names point inside it */
cebb2f11
BS
343}
344
345
b9c9cdc5 346/***************************************************************************
1cb92bbe 347 * get_env_load_order
b9c9cdc5 348 *
1cb92bbe 349 * Get the load order for a given module from the WINEDLLOVERRIDES environment variable.
b9c9cdc5 350 */
1cb92bbe 351static inline BOOL get_env_load_order( const WCHAR *module, enum loadorder_type lo[] )
cebb2f11 352{
624cbd7c 353 module_loadorder_t tmp, *res = NULL;
cebb2f11 354
b9c9cdc5 355 tmp.modulename = module;
624cbd7c 356 /* some bsearch implementations (Solaris) are buggy when the number of items is 0 */
1cb92bbe
AJ
357 if (env_list.count &&
358 (res = bsearch(&tmp, env_list.order, env_list.count, sizeof(env_list.order[0]), cmp_sort_func)))
b9c9cdc5
AJ
359 memcpy( lo, res->loadorder, sizeof(res->loadorder) );
360 return (res != NULL);
361}
cebb2f11 362
cebb2f11 363
1cb92bbe
AJ
364/***************************************************************************
365 * get_default_load_order
366 *
367 * Get the load order for a given module from the default list.
368 */
369static inline BOOL get_default_load_order( const WCHAR *module, enum loadorder_type lo[] )
370{
371 const int count = sizeof(default_builtins) / sizeof(default_builtins[0]);
372 if (!bsearch( module, default_builtins, count, sizeof(default_builtins[0]), strcmp_func ))
373 return FALSE;
374 lo[0] = LOADORDER_BI;
375 lo[1] = LOADORDER_INVALID;
376 return TRUE;
377}
378
379
b9c9cdc5 380/***************************************************************************
69622dbd 381 * open_app_key
b9c9cdc5 382 *
69622dbd 383 * Open the registry key to the app-specific DllOverrides list.
b9c9cdc5 384 */
1cb92bbe 385static HKEY open_app_key( const WCHAR *app_name, const WCHAR *module )
b9c9cdc5 386{
81bdcf12
AJ
387 OBJECT_ATTRIBUTES attr;
388 UNICODE_STRING nameW;
2052538a
AJ
389 HKEY hkey;
390 WCHAR *str;
81bdcf12
AJ
391 static const WCHAR AppDefaultsW[] = {'M','a','c','h','i','n','e','\\',
392 'S','o','f','t','w','a','r','e','\\',
393 'W','i','n','e','\\',
394 'W','i','n','e','\\',
395 'C','o','n','f','i','g','\\',
2052538a
AJ
396 'A','p','p','D','e','f','a','u','l','t','s','\\',0};
397 static const WCHAR DllOverridesW[] = {'\\','D','l','l','O','v','e','r','r','i','d','e','s',0};
b9c9cdc5 398
2052538a
AJ
399 str = RtlAllocateHeap( GetProcessHeap(), 0,
400 sizeof(AppDefaultsW) + sizeof(DllOverridesW) +
401 strlenW(app_name) * sizeof(WCHAR) );
402 if (!str) return 0;
403 strcpyW( str, AppDefaultsW );
404 strcatW( str, app_name );
405 strcatW( str, DllOverridesW );
b9c9cdc5 406
1cb92bbe 407 TRACE( "searching %s in %s\n", debugstr_w(module), debugstr_w(str) );
b9c9cdc5 408
81bdcf12
AJ
409 attr.Length = sizeof(attr);
410 attr.RootDirectory = 0;
411 attr.ObjectName = &nameW;
412 attr.Attributes = 0;
413 attr.SecurityDescriptor = NULL;
414 attr.SecurityQualityOfService = NULL;
2052538a
AJ
415 RtlInitUnicodeString( &nameW, str );
416
417 if (NtOpenKey( &hkey, KEY_ALL_ACCESS, &attr )) hkey = 0;
418 RtlFreeHeap( GetProcessHeap(), 0, str );
419 return hkey;
b9c9cdc5 420}
a739a69c 421
cebb2f11 422
b9c9cdc5 423/***************************************************************************
69622dbd 424 * get_registry_value
b9c9cdc5 425 *
69622dbd 426 * Load the registry loadorder value for a given module.
b9c9cdc5 427 */
1cb92bbe 428static BOOL get_registry_value( HKEY hkey, const WCHAR *module, enum loadorder_type lo[] )
b9c9cdc5 429{
81bdcf12 430 UNICODE_STRING valueW;
b9c9cdc5 431 char buffer[80];
81bdcf12
AJ
432 DWORD count;
433 BOOL ret;
434
1cb92bbe 435 RtlInitUnicodeString( &valueW, module );
81bdcf12
AJ
436
437 if ((ret = !NtQueryValueKey( hkey, &valueW, KeyValuePartialInformation,
438 buffer, sizeof(buffer), &count )))
439 {
440 int i, n = 0;
441 WCHAR *str = (WCHAR *)((KEY_VALUE_PARTIAL_INFORMATION *)buffer)->Data;
b9c9cdc5 442
81bdcf12
AJ
443 while (*str)
444 {
445 enum loadorder_type type = LOADORDER_INVALID;
446
447 while (*str == ',' || isspaceW(*str)) str++;
448 if (!*str) break;
449
450 switch(tolowerW(*str))
451 {
452 case 'n': type = LOADORDER_DLL; break;
81bdcf12 453 case 'b': type = LOADORDER_BI; break;
7dd3f7c7 454 case 's': break; /* no longer supported, ignore */
81bdcf12
AJ
455 case 0: break; /* end of string */
456 default:
457 ERR("Invalid load order module-type %s, ignored\n", debugstr_w(str));
458 break;
459 }
460 if (type != LOADORDER_INVALID)
461 {
462 for (i = 0; i < n; i++) if (lo[i] == type) break; /* already specified */
463 if (i == n) lo[n++] = type;
464 }
465 while (*str && *str != ',' && !isspaceW(*str)) str++;
466 }
467 lo[n] = LOADORDER_INVALID;
468 }
81bdcf12 469 return ret;
b9c9cdc5 470}
cebb2f11 471
cebb2f11 472
146afcc9
AJ
473/***************************************************************************
474 * MODULE_GetSystemDirectory
475 *
476 * Retrieve the system directory. The string must be freed by the caller.
477 */
478BOOL MODULE_GetSystemDirectory( UNICODE_STRING *sysdir )
479{
480 static const WCHAR winsysdirW[] = {'w','i','n','s','y','s','d','i','r',0};
481 UNICODE_STRING name;
482
483 RtlInitUnicodeString( &name, winsysdirW );
484 sysdir->MaximumLength = 0;
485 if (RtlQueryEnvironmentVariable_U( NULL, &name, sysdir ) != STATUS_BUFFER_TOO_SMALL)
486 return FALSE;
487 sysdir->MaximumLength = sysdir->Length + sizeof(WCHAR);
488 if (!(sysdir->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, sysdir->MaximumLength )))
489 return FALSE;
490 if (RtlQueryEnvironmentVariable_U( NULL, &name, sysdir ) == STATUS_SUCCESS)
491 return TRUE;
492 RtlFreeUnicodeString( sysdir );
493 return FALSE;
494}
495
496
cebb2f11 497/***************************************************************************
1cb92bbe 498 * MODULE_GetLoadOrderW (internal)
cebb2f11
BS
499 *
500 * Locate the loadorder of a module.
501 * Any path is stripped from the path-argument and so are the extension
c672c00f 502 * '.dll' and '.exe'. A lookup in the table can yield an override for
5fce6fb7 503 * the specific dll. Otherwise the default load order is returned.
cebb2f11 504 */
1cb92bbe 505void MODULE_GetLoadOrderW( enum loadorder_type loadorder[], const WCHAR *app_name,
16b44116 506 const WCHAR *path )
cebb2f11 507{
81bdcf12
AJ
508 static const WCHAR DllOverridesW[] = {'M','a','c','h','i','n','e','\\',
509 'S','o','f','t','w','a','r','e','\\',
510 'W','i','n','e','\\',
511 'W','i','n','e','\\',
512 'C','o','n','f','i','g','\\',
513 'D','l','l','O','v','e','r','r','i','d','e','s',0};
514
69622dbd 515 static HKEY std_key = (HKEY)-1; /* key to standard section, cached */
16b44116
AJ
516 static UNICODE_STRING sysdir;
517
69622dbd 518 HKEY app_key = 0;
1cb92bbe 519 WCHAR *module, *basename;
16b44116 520 UNICODE_STRING path_str;
69622dbd 521 int len;
cebb2f11 522
2052538a
AJ
523 if (!init_done) init_load_order();
524
1cb92bbe 525 TRACE("looking for %s\n", debugstr_w(path));
cebb2f11 526
69622dbd 527 loadorder[0] = LOADORDER_INVALID; /* in case something bad happens below */
cebb2f11 528
9ca159b6 529 /* Strip path information if the module resides in the system directory
9ca159b6 530 */
16b44116
AJ
531 if (!sysdir.Buffer && !MODULE_GetSystemDirectory( &sysdir )) return;
532 RtlInitUnicodeString( &path_str, path );
533 if (RtlPrefixUnicodeString( &sysdir, &path_str, TRUE ))
69622dbd 534 {
16b44116
AJ
535 const WCHAR *p = path + sysdir.Length / sizeof(WCHAR);
536 while (*p == '\\' || *p == '/') p++;
537 if (!strchrW( p, '\\' ) && !strchrW( p, '/' )) path = p;
69622dbd
AJ
538 }
539
1cb92bbe
AJ
540 if (!(len = strlenW(path))) return;
541 if (!(module = RtlAllocateHeap( GetProcessHeap(), 0, (len + 2) * sizeof(WCHAR) ))) return;
542 strcpyW( module+1, path ); /* reserve module[0] for the wildcard char */
9a624916 543
1cb92bbe 544 if (len >= 4) remove_dll_ext( module + 1 + len - 4 );
9a624916 545
2052538a 546 /* check environment variable first */
1cb92bbe 547 if (get_env_load_order( module+1, loadorder ))
69622dbd 548 {
2052538a 549 TRACE( "got environment %s for %s\n",
1cb92bbe 550 debugstr_loadorder(loadorder), debugstr_w(path) );
69622dbd
AJ
551 goto done;
552 }
9a624916 553
69622dbd 554 /* then explicit module name in AppDefaults */
2052538a 555 if (app_name)
69622dbd 556 {
2052538a
AJ
557 app_key = open_app_key( app_name, module+1 );
558 if (app_key && get_registry_value( app_key, module+1, loadorder ))
559 {
560 TRACE( "got app defaults %s for %s\n",
1cb92bbe 561 debugstr_loadorder(loadorder), debugstr_w(path) );
2052538a
AJ
562 goto done;
563 }
69622dbd 564 }
9a624916 565
69622dbd
AJ
566 /* then explicit module name in standard section */
567 if (std_key == (HKEY)-1)
81bdcf12
AJ
568 {
569 OBJECT_ATTRIBUTES attr;
570 UNICODE_STRING nameW;
571
572 attr.Length = sizeof(attr);
573 attr.RootDirectory = 0;
574 attr.ObjectName = &nameW;
575 attr.Attributes = 0;
576 attr.SecurityDescriptor = NULL;
577 attr.SecurityQualityOfService = NULL;
578 RtlInitUnicodeString( &nameW, DllOverridesW );
579
580 if (NtOpenKey( &std_key, KEY_ALL_ACCESS, &attr )) std_key = 0;
581 }
69622dbd
AJ
582
583 if (std_key && get_registry_value( std_key, module+1, loadorder ))
584 {
585 TRACE( "got standard entry %s for %s\n",
1cb92bbe 586 debugstr_loadorder(loadorder), debugstr_w(path) );
69622dbd
AJ
587 goto done;
588 }
cebb2f11 589
69622dbd 590 /* then module basename preceded by '*' in AppDefaults */
1cb92bbe 591 basename = (WCHAR *)get_basename( module+1 );
69622dbd
AJ
592 basename[-1] = '*';
593 if (app_key && get_registry_value( app_key, basename-1, loadorder ))
594 {
595 TRACE( "got app defaults basename %s for %s\n",
1cb92bbe 596 debugstr_loadorder(loadorder), debugstr_w(path) );
69622dbd
AJ
597 goto done;
598 }
cebb2f11 599
69622dbd
AJ
600 /* then module name preceded by '*' in standard section */
601 if (std_key && get_registry_value( std_key, basename-1, loadorder ))
602 {
603 TRACE( "got standard base name %s for %s\n",
1cb92bbe 604 debugstr_loadorder(loadorder), debugstr_w(path) );
69622dbd
AJ
605 goto done;
606 }
cebb2f11 607
69622dbd 608 /* then base name matching compiled-in defaults */
1cb92bbe 609 if (get_default_load_order( basename, loadorder ))
69622dbd
AJ
610 {
611 TRACE( "got compiled-in default %s for %s\n",
1cb92bbe 612 debugstr_loadorder(loadorder), debugstr_w(path) );
69622dbd
AJ
613 goto done;
614 }
615
616 if (basename == module+1)
617 {
1cb92bbe
AJ
618 static const WCHAR wildcardW[] = {'*',0};
619
69622dbd 620 /* then wildcard entry in AppDefaults (only if no explicit path) */
1cb92bbe 621 if (app_key && get_registry_value( app_key, wildcardW, loadorder ))
fde1b0cb 622 {
69622dbd 623 TRACE( "got app defaults wildcard %s for %s\n",
1cb92bbe 624 debugstr_loadorder(loadorder), debugstr_w(path) );
69622dbd 625 goto done;
fde1b0cb 626 }
cebb2f11 627
69622dbd 628 /* then wildcard entry in standard section (only if no explicit path) */
1cb92bbe 629 if (std_key && get_registry_value( std_key, wildcardW, loadorder ))
fde1b0cb 630 {
69622dbd 631 TRACE( "got standard wildcard %s for %s\n",
1cb92bbe 632 debugstr_loadorder(loadorder), debugstr_w(path) );
69622dbd 633 goto done;
fde1b0cb 634 }
cebb2f11 635
851d25d9
AJ
636 /* and last the hard-coded default */
637 memcpy( loadorder, default_loadorder, sizeof(default_loadorder) );
638 TRACE( "got hardcoded default %s for %s\n",
1cb92bbe 639 debugstr_loadorder(loadorder), debugstr_w(path) );
851d25d9
AJ
640 }
641 else /* module contains an explicit path */
642 {
643 memcpy( loadorder, default_path_loadorder, sizeof(default_path_loadorder) );
644 TRACE( "got hardcoded path default %s for %s\n",
1cb92bbe 645 debugstr_loadorder(loadorder), debugstr_w(path) );
851d25d9 646 }
b9c9cdc5
AJ
647
648 done:
81bdcf12 649 if (app_key) NtClose( app_key );
2052538a 650 RtlFreeHeap( GetProcessHeap(), 0, module );
b9c9cdc5 651}