ntdll: Load the locale.nls file at startup.
[wine.git] / dlls / ntdll / loader.c
blobf84746b7f1b1eaae97bc18f8b44ca81941671ed3
1 /*
2 * Loader functions
4 * Copyright 1995, 2003 Alexandre Julliard
5 * Copyright 2002 Dmitry Timoshkov for CodeWeavers
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <assert.h>
23 #include <stdarg.h>
24 #include <stdlib.h>
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #define NONAMELESSUNION
29 #define NONAMELESSSTRUCT
30 #include "windef.h"
31 #include "winnt.h"
32 #include "winioctl.h"
33 #include "winternl.h"
34 #include "delayloadhandler.h"
36 #include "wine/exception.h"
37 #include "wine/debug.h"
38 #include "wine/list.h"
39 #include "ntdll_misc.h"
40 #include "ddk/wdm.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(module);
43 WINE_DECLARE_DEBUG_CHANNEL(relay);
44 WINE_DECLARE_DEBUG_CHANNEL(snoop);
45 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
46 WINE_DECLARE_DEBUG_CHANNEL(imports);
48 #ifdef _WIN64
49 #define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
50 #endif
51 #define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
52 #define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
54 #ifdef __i386__
55 static const WCHAR pe_dir[] = L"\\i386-windows";
56 #elif defined __x86_64__
57 static const WCHAR pe_dir[] = L"\\x86_64-windows";
58 #elif defined __arm__
59 static const WCHAR pe_dir[] = L"\\arm-windows";
60 #elif defined __aarch64__
61 static const WCHAR pe_dir[] = L"\\aarch64-windows";
62 #else
63 static const WCHAR pe_dir[] = L"";
64 #endif
66 /* we don't want to include winuser.h */
67 #define RT_MANIFEST ((ULONG_PTR)24)
68 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
70 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
71 typedef void (CALLBACK *LDRENUMPROC)(LDR_DATA_TABLE_ENTRY *, void *, BOOLEAN *);
73 void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) = NULL;
75 static DWORD (WINAPI *pCtrlRoutine)(void *);
77 SYSTEM_DLL_INIT_BLOCK LdrSystemDllInitBlock = { 0xf0 };
79 /* windows directory */
80 const WCHAR windows_dir[] = L"C:\\windows";
81 /* system directory with trailing backslash */
82 const WCHAR system_dir[] = L"C:\\windows\\system32\\";
84 HMODULE kernel32_handle = 0;
86 /* system search path */
87 static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows";
89 static BOOL is_prefix_bootstrap; /* are we bootstrapping the prefix? */
90 static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */
91 static BOOL process_detaching = FALSE; /* set on process detach to avoid deadlocks with thread detach */
92 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
93 static LONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
94 static LONG dll_safe_mode = 1; /* dll search mode */
95 static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
96 static UNICODE_STRING system_dll_path; /* path to search for system dependency dlls */
97 static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
98 static WCHAR *default_load_path; /* default dll search path */
100 struct dll_dir_entry
102 struct list entry;
103 WCHAR dir[1];
106 static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from LdrAddDllDirectory */
108 struct ldr_notification
110 struct list entry;
111 PLDR_DLL_NOTIFICATION_FUNCTION callback;
112 void *context;
115 static struct list ldr_notifications = LIST_INIT( ldr_notifications );
117 static const char * const reason_names[] =
119 "PROCESS_DETACH",
120 "PROCESS_ATTACH",
121 "THREAD_ATTACH",
122 "THREAD_DETACH",
125 struct file_id
127 BYTE ObjectId[16];
130 /* internal representation of loaded modules */
131 typedef struct _wine_modref
133 LDR_DATA_TABLE_ENTRY ldr;
134 struct file_id id;
135 ULONG CheckSum;
136 BOOL system;
137 } WINE_MODREF;
139 static UINT tls_module_count; /* number of modules with TLS directory */
140 static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
141 LIST_ENTRY tls_links = { &tls_links, &tls_links };
143 static RTL_CRITICAL_SECTION loader_section;
144 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
146 0, 0, &loader_section,
147 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
148 0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
150 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
152 static CRITICAL_SECTION dlldir_section;
153 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
155 0, 0, &dlldir_section,
156 { &dlldir_critsect_debug.ProcessLocksList, &dlldir_critsect_debug.ProcessLocksList },
157 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
159 static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 };
161 static RTL_CRITICAL_SECTION peb_lock;
162 static RTL_CRITICAL_SECTION_DEBUG peb_critsect_debug =
164 0, 0, &peb_lock,
165 { &peb_critsect_debug.ProcessLocksList, &peb_critsect_debug.ProcessLocksList },
166 0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
168 static RTL_CRITICAL_SECTION peb_lock = { &peb_critsect_debug, -1, 0, 0, 0, 0 };
170 static PEB_LDR_DATA ldr =
172 sizeof(ldr), TRUE, NULL,
173 { &ldr.InLoadOrderModuleList, &ldr.InLoadOrderModuleList },
174 { &ldr.InMemoryOrderModuleList, &ldr.InMemoryOrderModuleList },
175 { &ldr.InInitializationOrderModuleList, &ldr.InInitializationOrderModuleList }
178 static RTL_BITMAP tls_bitmap;
179 static RTL_BITMAP tls_expansion_bitmap;
181 static WINE_MODREF *cached_modref;
182 static WINE_MODREF *current_modref;
183 static WINE_MODREF *last_failed_modref;
185 static LDR_DDAG_NODE *node_ntdll, *node_kernel32;
187 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system );
188 static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved );
189 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
190 DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
191 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
192 DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
194 /* convert PE image VirtualAddress to Real Address */
195 static inline void *get_rva( HMODULE module, DWORD va )
197 return (void *)((char *)module + va);
200 /* check whether the file name contains a path */
201 static inline BOOL contains_path( LPCWSTR name )
203 return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
206 #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
208 typedef struct _RTL_UNLOAD_EVENT_TRACE
210 void *BaseAddress;
211 SIZE_T SizeOfImage;
212 ULONG Sequence;
213 ULONG TimeDateStamp;
214 ULONG CheckSum;
215 WCHAR ImageName[32];
216 } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;
218 static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER];
219 static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr;
220 static unsigned int unload_trace_seq;
222 static void module_push_unload_trace( const WINE_MODREF *wm )
224 RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq];
225 const LDR_DATA_TABLE_ENTRY *ldr = &wm->ldr;
226 unsigned int len = min(sizeof(ptr->ImageName) - sizeof(WCHAR), ldr->BaseDllName.Length);
228 ptr->BaseAddress = ldr->DllBase;
229 ptr->SizeOfImage = ldr->SizeOfImage;
230 ptr->Sequence = unload_trace_seq;
231 ptr->TimeDateStamp = ldr->TimeDateStamp;
232 ptr->CheckSum = wm->CheckSum;
233 memcpy(ptr->ImageName, ldr->BaseDllName.Buffer, len);
234 ptr->ImageName[len / sizeof(*ptr->ImageName)] = 0;
236 unload_trace_seq = (unload_trace_seq + 1) % ARRAY_SIZE(unload_traces);
237 unload_trace_ptr = unload_traces;
240 /*********************************************************************
241 * RtlGetUnloadEventTrace [NTDLL.@]
243 RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
245 return unload_traces;
248 /*********************************************************************
249 * RtlGetUnloadEventTraceEx [NTDLL.@]
251 void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
253 static ULONG element_size = sizeof(*unload_traces);
254 static ULONG element_count = ARRAY_SIZE(unload_traces);
256 *size = &element_size;
257 *count = &element_count;
258 *trace = &unload_trace_ptr;
261 /*************************************************************************
262 * call_dll_entry_point
264 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
265 * their entry point, so we need a small asm wrapper. Testing indicates
266 * that only modifying esi leads to a crash, so use this one to backup
267 * ebp while running the dll entry proc.
269 #ifdef __i386__
270 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
271 __ASM_GLOBAL_FUNC(call_dll_entry_point,
272 "pushl %ebp\n\t"
273 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
274 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
275 "movl %esp,%ebp\n\t"
276 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
277 "pushl %ebx\n\t"
278 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
279 "pushl %esi\n\t"
280 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
281 "pushl %edi\n\t"
282 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
283 "movl %ebp,%esi\n\t"
284 __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
285 "pushl 20(%ebp)\n\t"
286 "pushl 16(%ebp)\n\t"
287 "pushl 12(%ebp)\n\t"
288 "movl 8(%ebp),%eax\n\t"
289 "call *%eax\n\t"
290 "movl %esi,%ebp\n\t"
291 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
292 "leal -12(%ebp),%esp\n\t"
293 "popl %edi\n\t"
294 __ASM_CFI(".cfi_same_value %edi\n\t")
295 "popl %esi\n\t"
296 __ASM_CFI(".cfi_same_value %esi\n\t")
297 "popl %ebx\n\t"
298 __ASM_CFI(".cfi_same_value %ebx\n\t")
299 "popl %ebp\n\t"
300 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
301 __ASM_CFI(".cfi_same_value %ebp\n\t")
302 "ret" )
303 #else /* __i386__ */
304 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
305 UINT reason, void *reserved )
307 return proc( module, reason, reserved );
309 #endif /* __i386__ */
312 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
313 /*************************************************************************
314 * stub_entry_point
316 * Entry point for stub functions.
318 static void WINAPI stub_entry_point( const char *dll, const char *name, void *ret_addr )
320 EXCEPTION_RECORD rec;
322 rec.ExceptionCode = EXCEPTION_WINE_STUB;
323 rec.ExceptionFlags = EH_NONCONTINUABLE;
324 rec.ExceptionRecord = NULL;
325 rec.ExceptionAddress = ret_addr;
326 rec.NumberParameters = 2;
327 rec.ExceptionInformation[0] = (ULONG_PTR)dll;
328 rec.ExceptionInformation[1] = (ULONG_PTR)name;
329 for (;;) RtlRaiseException( &rec );
333 #include "pshpack1.h"
334 #ifdef __i386__
335 struct stub
337 BYTE pushl1; /* pushl $name */
338 const char *name;
339 BYTE pushl2; /* pushl $dll */
340 const char *dll;
341 BYTE call; /* call stub_entry_point */
342 DWORD entry;
344 #elif defined(__arm__)
345 struct stub
347 DWORD ldr_r0; /* ldr r0, $dll */
348 DWORD ldr_r1; /* ldr r1, $name */
349 DWORD mov_r2_lr; /* mov r2, lr */
350 DWORD ldr_pc_pc; /* ldr pc, [pc, #4] */
351 const char *dll;
352 const char *name;
353 const void* entry;
355 #elif defined(__aarch64__)
356 struct stub
358 DWORD ldr_x0; /* ldr x0, $dll */
359 DWORD ldr_x1; /* ldr x1, $name */
360 DWORD mov_x2_lr; /* mov x2, lr */
361 DWORD ldr_x16; /* ldr x16, $entry */
362 DWORD br_x16; /* br x16 */
363 const char *dll;
364 const char *name;
365 const void *entry;
367 #else
368 struct stub
370 BYTE movq_rdi[2]; /* movq $dll,%rdi */
371 const char *dll;
372 BYTE movq_rsi[2]; /* movq $name,%rsi */
373 const char *name;
374 BYTE movq_rsp_rdx[4]; /* movq (%rsp),%rdx */
375 BYTE movq_rax[2]; /* movq $entry, %rax */
376 const void* entry;
377 BYTE jmpq_rax[2]; /* jmp %rax */
379 #endif
380 #include "poppack.h"
382 /*************************************************************************
383 * allocate_stub
385 * Allocate a stub entry point.
387 static ULONG_PTR allocate_stub( const char *dll, const char *name )
389 #define MAX_SIZE 65536
390 static struct stub *stubs;
391 static unsigned int nb_stubs;
392 struct stub *stub;
394 if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
396 if (!stubs)
398 SIZE_T size = MAX_SIZE;
399 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
400 MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
401 return 0xdeadbeef;
403 stub = &stubs[nb_stubs++];
404 #ifdef __i386__
405 stub->pushl1 = 0x68; /* pushl $name */
406 stub->name = name;
407 stub->pushl2 = 0x68; /* pushl $dll */
408 stub->dll = dll;
409 stub->call = 0xe8; /* call stub_entry_point */
410 stub->entry = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
411 #elif defined(__arm__)
412 stub->ldr_r0 = 0xe59f0008; /* ldr r0, [pc, #8] ($dll) */
413 stub->ldr_r1 = 0xe59f1008; /* ldr r1, [pc, #8] ($name) */
414 stub->mov_r2_lr = 0xe1a0200e; /* mov r2, lr */
415 stub->ldr_pc_pc = 0xe59ff004; /* ldr pc, [pc, #4] */
416 stub->dll = dll;
417 stub->name = name;
418 stub->entry = stub_entry_point;
419 #elif defined(__aarch64__)
420 stub->ldr_x0 = 0x580000a0; /* ldr x0, #20 ($dll) */
421 stub->ldr_x1 = 0x580000c1; /* ldr x1, #24 ($name) */
422 stub->mov_x2_lr = 0xaa1e03e2; /* mov x2, lr */
423 stub->ldr_x16 = 0x580000d0; /* ldr x16, #24 ($entry) */
424 stub->br_x16 = 0xd61f0200; /* br x16 */
425 stub->dll = dll;
426 stub->name = name;
427 stub->entry = stub_entry_point;
428 #else
429 stub->movq_rdi[0] = 0x48; /* movq $dll,%rcx */
430 stub->movq_rdi[1] = 0xb9;
431 stub->dll = dll;
432 stub->movq_rsi[0] = 0x48; /* movq $name,%rdx */
433 stub->movq_rsi[1] = 0xba;
434 stub->name = name;
435 stub->movq_rsp_rdx[0] = 0x4c; /* movq (%rsp),%r8 */
436 stub->movq_rsp_rdx[1] = 0x8b;
437 stub->movq_rsp_rdx[2] = 0x04;
438 stub->movq_rsp_rdx[3] = 0x24;
439 stub->movq_rax[0] = 0x48; /* movq $entry, %rax */
440 stub->movq_rax[1] = 0xb8;
441 stub->entry = stub_entry_point;
442 stub->jmpq_rax[0] = 0xff; /* jmp %rax */
443 stub->jmpq_rax[1] = 0xe0;
444 #endif
445 return (ULONG_PTR)stub;
448 #else /* __i386__ */
449 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
450 #endif /* __i386__ */
452 /* call ldr notifications */
453 static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
455 struct ldr_notification *notify, *notify_next;
456 LDR_DLL_NOTIFICATION_DATA data;
458 data.Loaded.Flags = 0;
459 data.Loaded.FullDllName = &module->FullDllName;
460 data.Loaded.BaseDllName = &module->BaseDllName;
461 data.Loaded.DllBase = module->DllBase;
462 data.Loaded.SizeOfImage = module->SizeOfImage;
464 LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
466 TRACE_(relay)("\1Call LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
467 notify->callback, reason, &data, notify->context );
469 notify->callback(reason, &data, notify->context);
471 TRACE_(relay)("\1Ret LDR notification callback (proc=%p,reason=%u,data=%p,context=%p)\n",
472 notify->callback, reason, &data, notify->context );
476 /*************************************************************************
477 * get_modref
479 * Looks for the referenced HMODULE in the current process
480 * The loader_section must be locked while calling this function.
482 static WINE_MODREF *get_modref( HMODULE hmod )
484 PLIST_ENTRY mark, entry;
485 PLDR_DATA_TABLE_ENTRY mod;
487 if (cached_modref && cached_modref->ldr.DllBase == hmod) return cached_modref;
489 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
490 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
492 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
493 if (mod->DllBase == hmod)
494 return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
496 return NULL;
500 /**********************************************************************
501 * find_basename_module
503 * Find a module from its base name.
504 * The loader_section must be locked while calling this function
506 static WINE_MODREF *find_basename_module( LPCWSTR name )
508 PLIST_ENTRY mark, entry;
509 UNICODE_STRING name_str;
511 RtlInitUnicodeString( &name_str, name );
513 if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
514 return cached_modref;
516 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
517 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
519 WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.InLoadOrderLinks);
520 if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && !mod->system)
522 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
523 return cached_modref;
526 return NULL;
530 /**********************************************************************
531 * find_fullname_module
533 * Find a module from its full path name.
534 * The loader_section must be locked while calling this function
536 static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
538 PLIST_ENTRY mark, entry;
539 UNICODE_STRING name = *nt_name;
541 if (name.Length <= 4 * sizeof(WCHAR)) return NULL;
542 name.Length -= 4 * sizeof(WCHAR); /* for \??\ prefix */
543 name.Buffer += 4;
545 if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE ))
546 return cached_modref;
548 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
549 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
551 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
552 if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
554 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
555 return cached_modref;
558 return NULL;
562 /**********************************************************************
563 * find_fileid_module
565 * Find a module from its file id.
566 * The loader_section must be locked while calling this function
568 static WINE_MODREF *find_fileid_module( const struct file_id *id )
570 LIST_ENTRY *mark, *entry;
572 if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref;
574 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
575 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
577 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
578 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
580 if (!memcmp( &wm->id, id, sizeof(*id) ))
582 cached_modref = wm;
583 return wm;
586 return NULL;
590 /******************************************************************************
591 * get_apiset_entry
593 static NTSTATUS get_apiset_entry( const API_SET_NAMESPACE *map, const WCHAR *name, ULONG len,
594 const API_SET_NAMESPACE_ENTRY **entry )
596 const API_SET_HASH_ENTRY *hash_entry;
597 ULONG hash, i, hash_len;
598 int min, max;
600 if (len <= 4) return STATUS_INVALID_PARAMETER;
601 if (wcsnicmp( name, L"api-", 4 ) && wcsnicmp( name, L"ext-", 4 )) return STATUS_INVALID_PARAMETER;
602 if (!map) return STATUS_APISET_NOT_PRESENT;
604 for (i = hash_len = 0; i < len; i++)
606 if (name[i] == '.') break;
607 if (name[i] == '-') hash_len = i;
609 for (i = hash = 0; i < hash_len; i++)
610 hash = hash * map->HashFactor + ((name[i] >= 'A' && name[i] <= 'Z') ? name[i] + 32 : name[i]);
612 hash_entry = (API_SET_HASH_ENTRY *)((char *)map + map->HashOffset);
613 min = 0;
614 max = map->Count - 1;
615 while (min <= max)
617 int pos = (min + max) / 2;
618 if (hash_entry[pos].Hash < hash) min = pos + 1;
619 else if (hash_entry[pos].Hash > hash) max = pos - 1;
620 else
622 *entry = (API_SET_NAMESPACE_ENTRY *)((char *)map + map->EntryOffset) + hash_entry[pos].Index;
623 if ((*entry)->HashedLength != hash_len * sizeof(WCHAR)) break;
624 if (wcsnicmp( (WCHAR *)((char *)map + (*entry)->NameOffset), name, hash_len )) break;
625 return STATUS_SUCCESS;
628 return STATUS_APISET_NOT_PRESENT;
632 /******************************************************************************
633 * get_apiset_target
635 static NTSTATUS get_apiset_target( const API_SET_NAMESPACE *map, const API_SET_NAMESPACE_ENTRY *entry,
636 const WCHAR *host, UNICODE_STRING *ret )
638 const API_SET_VALUE_ENTRY *value = (API_SET_VALUE_ENTRY *)((char *)map + entry->ValueOffset);
639 ULONG i, len;
641 if (!entry->ValueCount) return STATUS_DLL_NOT_FOUND;
642 if (host)
644 /* look for specific host in entries 1..n, entry 0 is the default */
645 for (i = 1; i < entry->ValueCount; i++)
647 len = value[i].NameLength / sizeof(WCHAR);
648 if (!wcsnicmp( host, (WCHAR *)((char *)map + value[i].NameOffset), len ) && !host[len])
650 value += i;
651 break;
655 if (!value->ValueOffset) return STATUS_DLL_NOT_FOUND;
656 ret->Buffer = (WCHAR *)((char *)map + value->ValueOffset);
657 ret->Length = value->ValueLength;
658 return STATUS_SUCCESS;
662 /**********************************************************************
663 * build_import_name
665 static NTSTATUS build_import_name( WCHAR buffer[256], const char *import, int len )
667 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
668 const API_SET_NAMESPACE_ENTRY *entry;
669 const WCHAR *host = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
670 UNICODE_STRING str;
672 while (len && import[len-1] == ' ') len--; /* remove trailing spaces */
673 if (len + sizeof(".dll") > 256) return STATUS_DLL_NOT_FOUND;
674 ascii_to_unicode( buffer, import, len );
675 buffer[len] = 0;
676 if (!wcschr( buffer, '.' )) wcscpy( buffer + len, L".dll" );
678 if (get_apiset_entry( map, buffer, wcslen(buffer), &entry )) return STATUS_SUCCESS;
680 if (get_apiset_target( map, entry, host, &str )) return STATUS_DLL_NOT_FOUND;
681 if (str.Length >= 256 * sizeof(WCHAR)) return STATUS_DLL_NOT_FOUND;
683 TRACE( "found %s for %s\n", debugstr_us(&str), debugstr_w(buffer));
684 memcpy( buffer, str.Buffer, str.Length );
685 buffer[str.Length / sizeof(WCHAR)] = 0;
686 return STATUS_SUCCESS;
690 /**********************************************************************
691 * append_dll_ext
693 static WCHAR *append_dll_ext( const WCHAR *name )
695 const WCHAR *ext = wcsrchr( name, '.' );
697 if (!ext || wcschr( ext, '/' ) || wcschr( ext, '\\'))
699 WCHAR *ret = RtlAllocateHeap( GetProcessHeap(), 0,
700 wcslen(name) * sizeof(WCHAR) + sizeof(L".dll") );
701 if (!ret) return NULL;
702 wcscpy( ret, name );
703 wcscat( ret, L".dll" );
704 return ret;
706 return NULL;
710 /***********************************************************************
711 * is_import_dll_system
713 static BOOL is_import_dll_system( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_IMPORT_DESCRIPTOR *import )
715 const char *name = get_rva( mod->DllBase, import->Name );
717 return !_stricmp( name, "ntdll.dll" ) || !_stricmp( name, "kernel32.dll" );
720 /**********************************************************************
721 * insert_single_list_tail
723 static void insert_single_list_after( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *prev, SINGLE_LIST_ENTRY *entry )
725 if (!list->Tail)
727 assert( !prev );
728 entry->Next = entry;
729 list->Tail = entry;
730 return;
732 if (!prev)
734 /* Insert at head. */
735 entry->Next = list->Tail->Next;
736 list->Tail->Next = entry;
737 return;
739 entry->Next = prev->Next;
740 prev->Next = entry;
741 if (prev == list->Tail) list->Tail = entry;
744 /**********************************************************************
745 * remove_single_list_entry
747 static void remove_single_list_entry( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *entry )
749 SINGLE_LIST_ENTRY *prev;
751 assert( list->Tail );
753 if (entry->Next == entry)
755 assert( list->Tail == entry );
756 list->Tail = NULL;
757 return;
760 prev = list->Tail->Next;
761 while (prev->Next != entry && prev != list->Tail)
762 prev = prev->Next;
763 assert( prev->Next == entry );
764 prev->Next = entry->Next;
765 if (list->Tail == entry) list->Tail = prev;
766 entry->Next = NULL;
769 /**********************************************************************
770 * add_module_dependency_after
772 static BOOL add_module_dependency_after( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to,
773 SINGLE_LIST_ENTRY *dep_after )
775 LDR_DEPENDENCY *dep;
777 if (!(dep = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*dep) ))) return FALSE;
779 dep->dependency_from = from;
780 insert_single_list_after( &from->Dependencies, dep_after, &dep->dependency_to_entry );
781 dep->dependency_to = to;
782 insert_single_list_after( &to->IncomingDependencies, NULL, &dep->dependency_from_entry );
784 return TRUE;
787 /**********************************************************************
788 * add_module_dependency
790 static BOOL add_module_dependency( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to )
792 return add_module_dependency_after( from, to, from->Dependencies.Tail );
795 /**********************************************************************
796 * remove_module_dependency
798 static void remove_module_dependency( LDR_DEPENDENCY *dep )
800 remove_single_list_entry( &dep->dependency_to->IncomingDependencies, &dep->dependency_from_entry );
801 remove_single_list_entry( &dep->dependency_from->Dependencies, &dep->dependency_to_entry );
802 RtlFreeHeap( GetProcessHeap(), 0, dep );
805 /**********************************************************************
806 * walk_node_dependencies
808 static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context,
809 NTSTATUS (*callback)( LDR_DDAG_NODE *, void * ))
811 SINGLE_LIST_ENTRY *entry;
812 LDR_DEPENDENCY *dep;
813 NTSTATUS status;
815 if (!(entry = node->Dependencies.Tail)) return STATUS_SUCCESS;
819 entry = entry->Next;
820 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
821 assert( dep->dependency_from == node );
822 if ((status = callback( dep->dependency_to, context ))) break;
823 } while (entry != node->Dependencies.Tail);
825 return status;
828 /*************************************************************************
829 * find_forwarded_export
831 * Find the final function pointer for a forwarded function.
832 * The loader_section must be locked while calling this function.
834 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
836 const IMAGE_EXPORT_DIRECTORY *exports;
837 DWORD exp_size;
838 WINE_MODREF *wm;
839 WCHAR mod_name[256];
840 const char *end = strrchr(forward, '.');
841 FARPROC proc = NULL;
843 if (!end) return NULL;
844 if (build_import_name( mod_name, forward, end - forward )) return NULL;
846 if (!(wm = find_basename_module( mod_name )))
848 WINE_MODREF *imp = get_modref( module );
849 TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
850 if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS &&
851 !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
853 if (!imports_fixup_done && current_modref)
855 add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode );
857 else if (process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS)
859 LdrUnloadDll( wm->ldr.DllBase );
860 wm = NULL;
864 if (!wm)
866 ERR( "module not found for forward '%s' used by %s\n",
867 forward, debugstr_w(imp->ldr.FullDllName.Buffer) );
868 return NULL;
871 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
872 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
874 const char *name = end + 1;
876 if (*name == '#') { /* ordinal */
877 proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size,
878 atoi(name+1) - exports->Base, load_path );
879 } else
880 proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path );
883 if (!proc)
885 ERR("function not found for forward '%s' used by %s."
886 " If you are using builtin %s, try using the native one instead.\n",
887 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
888 debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
890 return proc;
894 /*************************************************************************
895 * find_ordinal_export
897 * Find an exported function by ordinal.
898 * The exports base must have been subtracted from the ordinal already.
899 * The loader_section must be locked while calling this function.
901 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
902 DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
904 FARPROC proc;
905 const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
907 if (ordinal >= exports->NumberOfFunctions)
909 TRACE(" ordinal %d out of range!\n", ordinal + exports->Base );
910 return NULL;
912 if (!functions[ordinal]) return NULL;
914 proc = get_rva( module, functions[ordinal] );
916 /* if the address falls into the export dir, it's a forward */
917 if (((const char *)proc >= (const char *)exports) &&
918 ((const char *)proc < (const char *)exports + exp_size))
919 return find_forwarded_export( module, (const char *)proc, load_path );
921 if (TRACE_ON(snoop))
923 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
924 proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
926 if (TRACE_ON(relay))
928 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
929 proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
931 return proc;
935 /*************************************************************************
936 * find_name_in_exports
938 * Helper for find_named_export.
940 static int find_name_in_exports( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, const char *name )
942 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
943 const DWORD *names = get_rva( module, exports->AddressOfNames );
944 int min = 0, max = exports->NumberOfNames - 1;
946 while (min <= max)
948 int res, pos = (min + max) / 2;
949 char *ename = get_rva( module, names[pos] );
950 if (!(res = strcmp( ename, name ))) return ordinals[pos];
951 if (res > 0) max = pos - 1;
952 else min = pos + 1;
954 return -1;
958 /*************************************************************************
959 * find_named_export
961 * Find an exported function by name.
962 * The loader_section must be locked while calling this function.
964 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
965 DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
967 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
968 const DWORD *names = get_rva( module, exports->AddressOfNames );
969 int ordinal;
971 /* first check the hint */
972 if (hint >= 0 && hint < exports->NumberOfNames)
974 char *ename = get_rva( module, names[hint] );
975 if (!strcmp( ename, name ))
976 return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
979 /* then do a binary search */
980 if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
981 return find_ordinal_export( module, exports, exp_size, ordinal, load_path );
986 /*************************************************************************
987 * RtlFindExportedRoutineByName
989 void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
991 const IMAGE_EXPORT_DIRECTORY *exports;
992 const DWORD *functions;
993 DWORD exp_size;
994 int ordinal;
996 exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
997 if (!exports || exp_size < sizeof(*exports)) return NULL;
999 if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
1000 if (ordinal >= exports->NumberOfFunctions) return NULL;
1001 functions = get_rva( module, exports->AddressOfFunctions );
1002 if (!functions[ordinal]) return NULL;
1003 return get_rva( module, functions[ordinal] );
1007 /*************************************************************************
1008 * import_dll
1010 * Import the dll specified by the given import descriptor.
1011 * The loader_section must be locked while calling this function.
1013 static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
1015 BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL);
1016 NTSTATUS status;
1017 WINE_MODREF *wmImp;
1018 HMODULE imp_mod;
1019 const IMAGE_EXPORT_DIRECTORY *exports;
1020 DWORD exp_size;
1021 const IMAGE_THUNK_DATA *import_list;
1022 IMAGE_THUNK_DATA *thunk_list;
1023 WCHAR buffer[256];
1024 const char *name = get_rva( module, descr->Name );
1025 DWORD len = strlen(name);
1026 PVOID protect_base;
1027 SIZE_T protect_size = 0;
1028 DWORD protect_old;
1030 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
1031 if (descr->u.OriginalFirstThunk)
1032 import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
1033 else
1034 import_list = thunk_list;
1036 if (!import_list->u1.Ordinal)
1038 WARN( "Skipping unused import %s\n", name );
1039 *pwm = NULL;
1040 return TRUE;
1043 status = build_import_name( buffer, name, len );
1044 if (!status) status = load_dll( load_path, buffer, 0, &wmImp, system );
1046 if (status)
1048 if (status == STATUS_DLL_NOT_FOUND)
1049 ERR("Library %s (which is needed by %s) not found\n",
1050 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
1051 else
1052 ERR("Loading library %s (which is needed by %s) failed (error %x).\n",
1053 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
1054 return FALSE;
1057 /* unprotect the import address table since it can be located in
1058 * readonly section */
1059 while (import_list[protect_size].u1.Ordinal) protect_size++;
1060 protect_base = thunk_list;
1061 protect_size *= sizeof(*thunk_list);
1062 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
1063 &protect_size, PAGE_READWRITE, &protect_old );
1065 imp_mod = wmImp->ldr.DllBase;
1066 exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
1068 if (!exports)
1070 /* set all imported function to deadbeef */
1071 while (import_list->u1.Ordinal)
1073 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
1075 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
1076 WARN("No implementation for %s.%d", name, ordinal );
1077 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1079 else
1081 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1082 WARN("No implementation for %s.%s", name, pe_name->Name );
1083 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1085 WARN(" imported from %s, allocating stub %p\n",
1086 debugstr_w(current_modref->ldr.FullDllName.Buffer),
1087 (void *)thunk_list->u1.Function );
1088 import_list++;
1089 thunk_list++;
1091 goto done;
1094 while (import_list->u1.Ordinal)
1096 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
1098 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
1100 thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
1101 ordinal - exports->Base, load_path );
1102 if (!thunk_list->u1.Function)
1104 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1105 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
1106 name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
1107 (void *)thunk_list->u1.Function );
1109 TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
1111 else /* import by name */
1113 IMAGE_IMPORT_BY_NAME *pe_name;
1114 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1115 thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
1116 (const char*)pe_name->Name,
1117 pe_name->Hint, load_path );
1118 if (!thunk_list->u1.Function)
1120 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1121 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
1122 name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
1123 (void *)thunk_list->u1.Function );
1125 TRACE_(imports)("--- %s %s.%d = %p\n",
1126 pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
1128 import_list++;
1129 thunk_list++;
1132 done:
1133 /* restore old protection of the import address table */
1134 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
1135 *pwm = wmImp;
1136 return TRUE;
1140 /***********************************************************************
1141 * create_module_activation_context
1143 static NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module )
1145 NTSTATUS status;
1146 LDR_RESOURCE_INFO info;
1147 const IMAGE_RESOURCE_DATA_ENTRY *entry;
1149 info.Type = RT_MANIFEST;
1150 info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
1151 info.Language = 0;
1152 if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry )))
1154 ACTCTXW ctx;
1155 ctx.cbSize = sizeof(ctx);
1156 ctx.lpSource = NULL;
1157 ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
1158 ctx.hModule = module->DllBase;
1159 ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
1160 status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
1162 return status;
1166 /*************************************************************************
1167 * is_dll_native_subsystem
1169 * Check if dll is a proper native driver.
1170 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
1171 * while being perfectly normal DLLs. This heuristic should catch such breakages.
1173 static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
1175 const IMAGE_IMPORT_DESCRIPTOR *imports;
1176 DWORD i, size;
1178 if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
1179 if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
1180 if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
1182 if ((imports = RtlImageDirectoryEntryToData( mod->DllBase, TRUE,
1183 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1185 for (i = 0; imports[i].Name; i++)
1186 if (is_import_dll_system( mod, &imports[i] ))
1188 TRACE( "%s imports system dll, assuming not native\n", debugstr_w(filename) );
1189 return FALSE;
1192 return TRUE;
1195 /*************************************************************************
1196 * alloc_tls_slot
1198 * Allocate a TLS slot for a newly-loaded module.
1199 * The loader_section must be locked while calling this function.
1201 static SHORT alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1203 const IMAGE_TLS_DIRECTORY *dir;
1204 ULONG i, size;
1205 void *new_ptr;
1206 LIST_ENTRY *entry;
1208 if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
1209 return -1;
1211 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1212 if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return -1;
1214 for (i = 0; i < tls_module_count; i++)
1216 if (!tls_dirs[i].StartAddressOfRawData && !tls_dirs[i].EndAddressOfRawData &&
1217 !tls_dirs[i].SizeOfZeroFill && !tls_dirs[i].AddressOfCallBacks)
1218 break;
1221 TRACE( "module %p data %p-%p zerofill %u index %p callback %p flags %x -> slot %u\n", mod->DllBase,
1222 (void *)dir->StartAddressOfRawData, (void *)dir->EndAddressOfRawData, dir->SizeOfZeroFill,
1223 (void *)dir->AddressOfIndex, (void *)dir->AddressOfCallBacks, dir->Characteristics, i );
1225 if (i == tls_module_count)
1227 UINT new_count = max( 32, tls_module_count * 2 );
1229 if (!tls_dirs)
1230 new_ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*tls_dirs) );
1231 else
1232 new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
1233 new_count * sizeof(*tls_dirs) );
1234 if (!new_ptr) return -1;
1236 /* resize the pointer block in all running threads */
1237 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1239 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1240 void **old = teb->ThreadLocalStoragePointer;
1241 void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
1243 if (!new) return -1;
1244 if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
1245 teb->ThreadLocalStoragePointer = new;
1246 #ifdef __x86_64__ /* macOS-specific hack */
1247 if (teb->Reserved5[0]) ((TEB *)teb->Reserved5[0])->ThreadLocalStoragePointer = new;
1248 #endif
1249 TRACE( "thread %04lx tls block %p -> %p\n", (ULONG_PTR)teb->ClientId.UniqueThread, old, new );
1250 /* FIXME: can't free old block here, should be freed at thread exit */
1253 tls_dirs = new_ptr;
1254 tls_module_count = new_count;
1257 /* allocate the data block in all running threads */
1258 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1260 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1262 if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
1263 memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
1264 memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
1266 TRACE( "thread %04lx slot %u: %u/%u bytes at %p\n",
1267 (ULONG_PTR)teb->ClientId.UniqueThread, i, size, dir->SizeOfZeroFill, new_ptr );
1269 RtlFreeHeap( GetProcessHeap(), 0,
1270 InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1273 *(DWORD *)dir->AddressOfIndex = i;
1274 tls_dirs[i] = *dir;
1275 return i;
1279 /*************************************************************************
1280 * free_tls_slot
1282 * Free the module TLS slot on unload.
1283 * The loader_section must be locked while calling this function.
1285 static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1287 ULONG i = (USHORT)mod->TlsIndex;
1289 if (mod->TlsIndex == -1) return;
1290 assert( i < tls_module_count );
1291 memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1295 /****************************************************************
1296 * fixup_imports_ilonly
1298 * Fixup imports for an IL-only module. All we do is import mscoree.
1299 * The loader_section must be locked while calling this function.
1301 static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
1303 NTSTATUS status;
1304 void *proc;
1305 const char *name;
1306 WINE_MODREF *prev, *imp;
1308 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1309 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1311 prev = current_modref;
1312 current_modref = wm;
1313 assert( !wm->ldr.DdagNode->Dependencies.Tail );
1314 if (!(status = load_dll( load_path, L"mscoree.dll", 0, &imp, FALSE ))
1315 && !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
1316 status = STATUS_NO_MEMORY;
1317 current_modref = prev;
1318 if (status)
1320 ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
1321 debugstr_w(wm->ldr.BaseDllName.Buffer) );
1322 return status;
1325 TRACE( "loaded mscoree for %s\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
1327 name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
1328 if (!(proc = RtlFindExportedRoutineByName( imp->ldr.DllBase, name ))) return STATUS_PROCEDURE_NOT_FOUND;
1329 *entry = proc;
1330 return STATUS_SUCCESS;
1334 /****************************************************************
1335 * fixup_imports
1337 * Fixup all imports of a given module.
1338 * The loader_section must be locked while calling this function.
1340 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
1342 const IMAGE_IMPORT_DESCRIPTOR *imports;
1343 SINGLE_LIST_ENTRY *dep_after;
1344 WINE_MODREF *prev, *imp;
1345 int i, nb_imports;
1346 DWORD size;
1347 NTSTATUS status;
1348 ULONG_PTR cookie;
1350 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1351 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1353 wm->ldr.TlsIndex = alloc_tls_slot( &wm->ldr );
1355 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
1356 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1357 return STATUS_SUCCESS;
1359 nb_imports = 0;
1360 while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
1362 if (!nb_imports) return STATUS_SUCCESS; /* no imports */
1364 if (!create_module_activation_context( &wm->ldr ))
1365 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1367 /* load the imported modules. They are automatically
1368 * added to the modref list of the process.
1370 prev = current_modref;
1371 current_modref = wm;
1372 status = STATUS_SUCCESS;
1373 for (i = 0; i < nb_imports; i++)
1375 dep_after = wm->ldr.DdagNode->Dependencies.Tail;
1376 if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp ))
1378 imp = NULL;
1379 status = STATUS_DLL_NOT_FOUND;
1381 else if (imp && !is_import_dll_system( &wm->ldr, &imports[i] ))
1383 add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, dep_after );
1386 current_modref = prev;
1387 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1388 return status;
1392 /*************************************************************************
1393 * alloc_module
1395 * Allocate a WINE_MODREF structure and add it to the process list
1396 * The loader_section must be locked while calling this function.
1398 static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1400 WCHAR *buffer;
1401 WINE_MODREF *wm;
1402 const WCHAR *p;
1403 const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1405 if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1407 wm->ldr.DllBase = hModule;
1408 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
1409 wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1410 wm->ldr.TlsIndex = -1;
1411 wm->ldr.LoadCount = 1;
1412 wm->CheckSum = nt->OptionalHeader.CheckSum;
1413 wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp;
1415 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) )))
1417 RtlFreeHeap( GetProcessHeap(), 0, wm );
1418 return NULL;
1421 if (!(wm->ldr.DdagNode = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm->ldr.DdagNode) )))
1423 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1424 RtlFreeHeap( GetProcessHeap(), 0, wm );
1425 return NULL;
1427 InitializeListHead(&wm->ldr.DdagNode->Modules);
1428 InsertTailList(&wm->ldr.DdagNode->Modules, &wm->ldr.NodeModuleLink);
1430 memcpy( buffer, nt_name->Buffer + 4 /* \??\ prefix */, nt_name->Length - 4 * sizeof(WCHAR) );
1431 buffer[nt_name->Length/sizeof(WCHAR) - 4] = 0;
1432 if ((p = wcsrchr( buffer, '\\' ))) p++;
1433 else p = buffer;
1434 RtlInitUnicodeString( &wm->ldr.FullDllName, buffer );
1435 RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
1437 if (!is_dll_native_subsystem( &wm->ldr, nt, p ))
1439 if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
1440 wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1441 if (nt->OptionalHeader.AddressOfEntryPoint)
1442 wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1445 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1446 &wm->ldr.InLoadOrderLinks);
1447 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1448 &wm->ldr.InMemoryOrderLinks);
1449 /* wait until init is called for inserting into InInitializationOrderModuleList */
1451 if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
1453 ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1454 WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1455 NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1457 return wm;
1461 /*************************************************************************
1462 * alloc_thread_tls
1464 * Allocate the per-thread structure for module TLS storage.
1466 static NTSTATUS alloc_thread_tls(void)
1468 void **pointers;
1469 UINT i, size;
1471 if (!tls_module_count) return STATUS_SUCCESS;
1473 if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
1474 tls_module_count * sizeof(*pointers) )))
1475 return STATUS_NO_MEMORY;
1477 for (i = 0; i < tls_module_count; i++)
1479 const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1481 if (!dir) continue;
1482 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1483 if (!size && !dir->SizeOfZeroFill) continue;
1485 if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
1487 while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
1488 RtlFreeHeap( GetProcessHeap(), 0, pointers );
1489 return STATUS_NO_MEMORY;
1491 memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
1492 memset( (char *)pointers[i] + size, 0, dir->SizeOfZeroFill );
1494 TRACE( "thread %04x slot %u: %u/%u bytes at %p\n",
1495 GetCurrentThreadId(), i, size, dir->SizeOfZeroFill, pointers[i] );
1497 NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1498 #ifdef __x86_64__ /* macOS-specific hack */
1499 if (NtCurrentTeb()->Reserved5[0])
1500 ((TEB *)NtCurrentTeb()->Reserved5[0])->ThreadLocalStoragePointer = pointers;
1501 #endif
1502 return STATUS_SUCCESS;
1506 /*************************************************************************
1507 * call_tls_callbacks
1509 static void call_tls_callbacks( HMODULE module, UINT reason )
1511 const IMAGE_TLS_DIRECTORY *dir;
1512 const PIMAGE_TLS_CALLBACK *callback;
1513 ULONG dirsize;
1515 dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
1516 if (!dir || !dir->AddressOfCallBacks) return;
1518 for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1520 TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1521 *callback, module, reason_names[reason] );
1522 __TRY
1524 call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1526 __EXCEPT_ALL
1528 TRACE_(relay)("\1exception %08x in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1529 GetExceptionCode(), callback, module, reason_names[reason] );
1530 return;
1532 __ENDTRY
1533 TRACE_(relay)("\1Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1534 *callback, module, reason_names[reason] );
1538 /*************************************************************************
1539 * MODULE_InitDLL
1541 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1543 WCHAR mod_name[64];
1544 NTSTATUS status = STATUS_SUCCESS;
1545 DLLENTRYPROC entry = wm->ldr.EntryPoint;
1546 void *module = wm->ldr.DllBase;
1547 BOOL retv = FALSE;
1549 /* Skip calls for modules loaded with special load flags */
1551 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1552 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, reason );
1553 if (wm->ldr.Flags & LDR_WINE_INTERNAL && reason == DLL_PROCESS_ATTACH)
1554 unix_funcs->init_builtin_dll( wm->ldr.DllBase );
1555 if (!entry) return STATUS_SUCCESS;
1557 if (TRACE_ON(relay))
1559 size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1560 memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
1561 mod_name[len / sizeof(WCHAR)] = 0;
1562 TRACE_(relay)("\1Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1563 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved );
1565 else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
1566 reason_names[reason], lpReserved );
1568 __TRY
1570 retv = call_dll_entry_point( entry, module, reason, lpReserved );
1571 if (!retv)
1572 status = STATUS_DLL_INIT_FAILED;
1574 __EXCEPT_ALL
1576 status = GetExceptionCode();
1577 TRACE_(relay)("\1exception %08x in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1578 status, entry, module, reason_names[reason], lpReserved );
1580 __ENDTRY
1582 /* The state of the module list may have changed due to the call
1583 to the dll. We cannot assume that this module has not been
1584 deleted. */
1585 if (TRACE_ON(relay))
1586 TRACE_(relay)("\1Ret PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1587 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved, retv );
1588 else
1589 TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1591 return status;
1595 /*************************************************************************
1596 * process_attach
1598 * Send the process attach notification to all DLLs the given module
1599 * depends on (recursively). This is somewhat complicated due to the fact that
1601 * - we have to respect the module dependencies, i.e. modules implicitly
1602 * referenced by another module have to be initialized before the module
1603 * itself can be initialized
1605 * - the initialization routine of a DLL can itself call LoadLibrary,
1606 * thereby introducing a whole new set of dependencies (even involving
1607 * the 'old' modules) at any time during the whole process
1609 * (Note that this routine can be recursively entered not only directly
1610 * from itself, but also via LoadLibrary from one of the called initialization
1611 * routines.)
1613 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1614 * the process *detach* notifications to be sent in the correct order.
1615 * This must not only take into account module dependencies, but also
1616 * 'hidden' dependencies created by modules calling LoadLibrary in their
1617 * attach notification routine.
1619 * The strategy is rather simple: we move a WINE_MODREF to the head of the
1620 * list after the attach notification has returned. This implies that the
1621 * detach notifications are called in the reverse of the sequence the attach
1622 * notifications *returned*.
1624 * The loader_section must be locked while calling this function.
1626 static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
1628 NTSTATUS status = STATUS_SUCCESS;
1629 LDR_DATA_TABLE_ENTRY *mod;
1630 ULONG_PTR cookie;
1631 WINE_MODREF *wm;
1633 if (process_detaching) return status;
1635 mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
1636 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
1638 /* prevent infinite recursion in case of cyclical dependencies */
1639 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
1640 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1641 return status;
1643 TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1645 /* Tag current MODREF to prevent recursive loop */
1646 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1647 if (lpReserved) wm->ldr.LoadCount = -1; /* pin it if imported by the main exe */
1648 if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1650 /* Recursively attach all DLLs this one depends on */
1651 status = walk_node_dependencies( node, lpReserved, process_attach );
1653 if (!wm->ldr.InInitializationOrderLinks.Flink)
1654 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1655 &wm->ldr.InInitializationOrderLinks);
1657 /* Call DLL entry point */
1658 if (status == STATUS_SUCCESS)
1660 WINE_MODREF *prev = current_modref;
1661 current_modref = wm;
1663 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1664 status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
1665 if (status == STATUS_SUCCESS)
1667 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1669 else
1671 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1672 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );
1674 /* point to the name so LdrInitializeThunk can print it */
1675 last_failed_modref = wm;
1676 WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
1678 current_modref = prev;
1681 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1682 /* Remove recursion flag */
1683 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1685 TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1686 return status;
1690 /*************************************************************************
1691 * process_detach
1693 * Send DLL process detach notifications. See the comment about calling
1694 * sequence at process_attach.
1696 static void process_detach(void)
1698 PLIST_ENTRY mark, entry;
1699 PLDR_DATA_TABLE_ENTRY mod;
1701 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1704 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1706 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1707 InInitializationOrderLinks);
1708 /* Check whether to detach this DLL */
1709 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1710 continue;
1711 if ( mod->LoadCount && !process_detaching )
1712 continue;
1714 /* Call detach notification */
1715 mod->Flags &= ~LDR_PROCESS_ATTACHED;
1716 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1717 DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1718 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1720 /* Restart at head of WINE_MODREF list, as entries might have
1721 been added and/or removed while performing the call ... */
1722 break;
1724 } while (entry != mark);
1727 /*************************************************************************
1728 * thread_attach
1730 * Send DLL thread attach notifications. These are sent in the
1731 * reverse sequence of process detach notification.
1732 * The loader_section must be locked while calling this function.
1734 static void thread_attach(void)
1736 PLIST_ENTRY mark, entry;
1737 PLDR_DATA_TABLE_ENTRY mod;
1739 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1740 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1742 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1743 InInitializationOrderLinks);
1744 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1745 continue;
1746 if ( mod->Flags & LDR_NO_DLL_CALLS )
1747 continue;
1749 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1753 /******************************************************************
1754 * LdrDisableThreadCalloutsForDll (NTDLL.@)
1757 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1759 WINE_MODREF *wm;
1760 NTSTATUS ret = STATUS_SUCCESS;
1762 RtlEnterCriticalSection( &loader_section );
1764 wm = get_modref( hModule );
1765 if (!wm || wm->ldr.TlsIndex != -1)
1766 ret = STATUS_DLL_NOT_FOUND;
1767 else
1768 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1770 RtlLeaveCriticalSection( &loader_section );
1772 return ret;
1775 /******************************************************************
1776 * LdrFindEntryForAddress (NTDLL.@)
1778 * The loader_section must be locked while calling this function
1780 NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY *pmod )
1782 PLIST_ENTRY mark, entry;
1783 PLDR_DATA_TABLE_ENTRY mod;
1785 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1786 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1788 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
1789 if (mod->DllBase <= addr &&
1790 (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage)
1792 *pmod = mod;
1793 return STATUS_SUCCESS;
1796 return STATUS_NO_MORE_ENTRIES;
1799 /******************************************************************
1800 * LdrEnumerateLoadedModules (NTDLL.@)
1802 NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
1804 LIST_ENTRY *mark, *entry;
1805 LDR_DATA_TABLE_ENTRY *mod;
1806 BOOLEAN stop = FALSE;
1808 TRACE( "(%p, %p, %p)\n", unknown, callback, context );
1810 if (unknown || !callback)
1811 return STATUS_INVALID_PARAMETER;
1813 RtlEnterCriticalSection( &loader_section );
1815 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1816 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1818 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
1819 callback( mod, context, &stop );
1820 if (stop) break;
1823 RtlLeaveCriticalSection( &loader_section );
1824 return STATUS_SUCCESS;
1827 /******************************************************************
1828 * LdrRegisterDllNotification (NTDLL.@)
1830 NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
1831 void *context, void **cookie)
1833 struct ldr_notification *notify;
1835 TRACE( "(%x, %p, %p, %p)\n", flags, callback, context, cookie );
1837 if (!callback || !cookie)
1838 return STATUS_INVALID_PARAMETER;
1840 if (flags)
1841 FIXME( "ignoring flags %x\n", flags );
1843 notify = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*notify) );
1844 if (!notify) return STATUS_NO_MEMORY;
1845 notify->callback = callback;
1846 notify->context = context;
1848 RtlEnterCriticalSection( &loader_section );
1849 list_add_tail( &ldr_notifications, &notify->entry );
1850 RtlLeaveCriticalSection( &loader_section );
1852 *cookie = notify;
1853 return STATUS_SUCCESS;
1856 /******************************************************************
1857 * LdrUnregisterDllNotification (NTDLL.@)
1859 NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
1861 struct ldr_notification *notify = cookie;
1863 TRACE( "(%p)\n", cookie );
1865 if (!notify) return STATUS_INVALID_PARAMETER;
1867 RtlEnterCriticalSection( &loader_section );
1868 list_remove( &notify->entry );
1869 RtlLeaveCriticalSection( &loader_section );
1871 RtlFreeHeap( GetProcessHeap(), 0, notify );
1872 return STATUS_SUCCESS;
1875 /******************************************************************
1876 * LdrLockLoaderLock (NTDLL.@)
1878 * Note: some flags are not implemented.
1879 * Flag 0x01 is used to raise exceptions on errors.
1881 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1883 if (flags & ~0x2) FIXME( "flags %x not supported\n", flags );
1885 if (result) *result = 0;
1886 if (magic) *magic = 0;
1887 if (flags & ~0x3) return STATUS_INVALID_PARAMETER_1;
1888 if (!result && (flags & 0x2)) return STATUS_INVALID_PARAMETER_2;
1889 if (!magic) return STATUS_INVALID_PARAMETER_3;
1891 if (flags & 0x2)
1893 if (!RtlTryEnterCriticalSection( &loader_section ))
1895 *result = 2;
1896 return STATUS_SUCCESS;
1898 *result = 1;
1900 else
1902 RtlEnterCriticalSection( &loader_section );
1903 if (result) *result = 1;
1905 *magic = GetCurrentThreadId();
1906 return STATUS_SUCCESS;
1910 /******************************************************************
1911 * LdrUnlockLoaderUnlock (NTDLL.@)
1913 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
1915 if (magic)
1917 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
1918 RtlLeaveCriticalSection( &loader_section );
1920 return STATUS_SUCCESS;
1924 /******************************************************************
1925 * LdrGetProcedureAddress (NTDLL.@)
1927 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
1928 ULONG ord, PVOID *address)
1930 IMAGE_EXPORT_DIRECTORY *exports;
1931 DWORD exp_size;
1932 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
1934 RtlEnterCriticalSection( &loader_section );
1936 /* check if the module itself is invalid to return the proper error */
1937 if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
1938 else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
1939 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
1941 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL )
1942 : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL );
1943 if (proc)
1945 *address = proc;
1946 ret = STATUS_SUCCESS;
1950 RtlLeaveCriticalSection( &loader_section );
1951 return ret;
1955 /***********************************************************************
1956 * set_security_cookie
1958 * Create a random security cookie for buffer overflow protection. Make
1959 * sure it does not accidentally match the default cookie value.
1961 static void set_security_cookie( void *module, SIZE_T len )
1963 static ULONG seed;
1964 IMAGE_LOAD_CONFIG_DIRECTORY *loadcfg;
1965 ULONG loadcfg_size;
1966 ULONG_PTR *cookie;
1968 loadcfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &loadcfg_size );
1969 if (!loadcfg) return;
1970 if (loadcfg_size < offsetof(IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie) + sizeof(loadcfg->SecurityCookie)) return;
1971 if (!loadcfg->SecurityCookie) return;
1972 if (loadcfg->SecurityCookie < (ULONG_PTR)module ||
1973 loadcfg->SecurityCookie > (ULONG_PTR)module + len - sizeof(ULONG_PTR))
1975 WARN( "security cookie %p outside of image %p-%p\n",
1976 (void *)loadcfg->SecurityCookie, module, (char *)module + len );
1977 return;
1980 cookie = (ULONG_PTR *)loadcfg->SecurityCookie;
1981 TRACE( "initializing security cookie %p\n", cookie );
1983 if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
1984 for (;;)
1986 if (*cookie == DEFAULT_SECURITY_COOKIE_16)
1987 *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
1988 else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
1989 *cookie = RtlRandom( &seed );
1990 #ifdef DEFAULT_SECURITY_COOKIE_64
1991 else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
1993 *cookie = RtlRandom( &seed );
1994 /* fill up, but keep the highest word clear */
1995 *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
1997 #endif
1998 else
1999 break;
2003 static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
2005 char *base;
2006 IMAGE_BASE_RELOCATION *rel, *end;
2007 const IMAGE_DATA_DIRECTORY *relocs;
2008 const IMAGE_SECTION_HEADER *sec;
2009 INT_PTR delta;
2010 ULONG protect_old[96], i;
2012 base = (char *)nt->OptionalHeader.ImageBase;
2013 if (module == base) return STATUS_SUCCESS; /* nothing to do */
2015 /* no relocations are performed on non page-aligned binaries */
2016 if (nt->OptionalHeader.SectionAlignment < page_size)
2017 return STATUS_SUCCESS;
2019 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) && NtCurrentTeb()->Peb->ImageBaseAddress)
2020 return STATUS_SUCCESS;
2022 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
2024 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
2026 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
2027 base, module );
2028 return STATUS_CONFLICTING_ADDRESSES;
2031 if (!relocs->Size) return STATUS_SUCCESS;
2032 if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;
2034 if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
2035 return STATUS_INVALID_IMAGE_FORMAT;
2037 sec = (const IMAGE_SECTION_HEADER *)((const char *)&nt->OptionalHeader +
2038 nt->FileHeader.SizeOfOptionalHeader);
2039 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2041 void *addr = get_rva( module, sec[i].VirtualAddress );
2042 SIZE_T size = sec[i].SizeOfRawData;
2043 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2044 &size, PAGE_READWRITE, &protect_old[i] );
2047 TRACE( "relocating from %p-%p to %p-%p\n",
2048 base, base + len, module, (char *)module + len );
2050 rel = get_rva( module, relocs->VirtualAddress );
2051 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
2052 delta = (char *)module - base;
2054 while (rel < end - 1 && rel->SizeOfBlock)
2056 if (rel->VirtualAddress >= len)
2058 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
2059 return STATUS_ACCESS_VIOLATION;
2061 rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
2062 (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
2063 (USHORT *)(rel + 1), delta );
2064 if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
2067 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2069 void *addr = get_rva( module, sec[i].VirtualAddress );
2070 SIZE_T size = sec[i].SizeOfRawData;
2071 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2072 &size, protect_old[i], &protect_old[i] );
2075 return STATUS_SUCCESS;
2079 /*************************************************************************
2080 * build_module
2082 * Build the module data for a mapped dll.
2084 static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
2085 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2086 DWORD flags, BOOL system, WINE_MODREF **pwm )
2088 static const char builtin_signature[] = "Wine builtin DLL";
2089 char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1);
2090 BOOL is_builtin;
2091 IMAGE_NT_HEADERS *nt;
2092 WINE_MODREF *wm;
2093 NTSTATUS status;
2094 SIZE_T map_size;
2096 if (!(nt = RtlImageNtHeader( *module ))) return STATUS_INVALID_IMAGE_FORMAT;
2098 map_size = (nt->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
2099 if ((status = perform_relocations( *module, nt, map_size ))) return status;
2101 is_builtin = ((char *)nt - signature >= sizeof(builtin_signature) &&
2102 !memcmp( signature, builtin_signature, sizeof(builtin_signature) ));
2104 /* create the MODREF */
2106 if (!(wm = alloc_module( *module, nt_name, is_builtin ))) return STATUS_NO_MEMORY;
2108 if (id) wm->id = *id;
2109 if (image_info->LoaderFlags) wm->ldr.Flags |= LDR_COR_IMAGE;
2110 if (image_info->u.s.ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
2111 wm->system = system;
2113 set_security_cookie( *module, map_size );
2115 /* fixup imports */
2117 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
2118 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
2119 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE))
2121 if (wm->ldr.Flags & LDR_COR_ILONLY)
2122 status = fixup_imports_ilonly( wm, load_path, &wm->ldr.EntryPoint );
2123 else
2124 status = fixup_imports( wm, load_path );
2125 if (status != STATUS_SUCCESS)
2127 /* the module has only be inserted in the load & memory order lists */
2128 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
2129 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
2131 /* FIXME: there are several more dangling references
2132 * left. Including dlls loaded by this dll before the
2133 * failed one. Unrolling is rather difficult with the
2134 * current structure and we can leave them lying
2135 * around with no problems, so we don't care.
2136 * As these might reference our wm, we don't free it.
2138 *module = NULL;
2139 return status;
2143 TRACE( "loaded %s %p %p\n", debugstr_us(nt_name), wm, *module );
2145 if (is_builtin)
2147 if (TRACE_ON(relay)) RELAY_SetupDLL( *module );
2149 else
2151 if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( *module );
2154 TRACE_(loaddll)( "Loaded %s at %p: %s\n", debugstr_w(wm->ldr.FullDllName.Buffer), *module,
2155 is_builtin ? "builtin" : "native" );
2157 wm->ldr.LoadCount = 1;
2158 *pwm = wm;
2159 *module = NULL;
2160 return STATUS_SUCCESS;
2164 /*************************************************************************
2165 * build_ntdll_module
2167 * Build the module data for the initially-loaded ntdll.
2169 static void build_ntdll_module(void)
2171 MEMORY_BASIC_INFORMATION meminfo;
2172 UNICODE_STRING nt_name;
2173 WINE_MODREF *wm;
2175 RtlInitUnicodeString( &nt_name, L"\\??\\C:\\windows\\system32\\ntdll.dll" );
2176 NtQueryVirtualMemory( GetCurrentProcess(), build_ntdll_module, MemoryBasicInformation,
2177 &meminfo, sizeof(meminfo), NULL );
2178 wm = alloc_module( meminfo.AllocationBase, &nt_name, TRUE );
2179 assert( wm );
2180 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
2181 node_ntdll = wm->ldr.DdagNode;
2182 if (TRACE_ON(relay)) RELAY_SetupDLL( meminfo.AllocationBase );
2186 #ifdef _WIN64
2187 /* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
2188 static BOOL convert_to_pe64( HMODULE module, const SECTION_IMAGE_INFORMATION *info )
2190 static const ULONG copy_dirs[] = { IMAGE_DIRECTORY_ENTRY_RESOURCE,
2191 IMAGE_DIRECTORY_ENTRY_SECURITY,
2192 IMAGE_DIRECTORY_ENTRY_BASERELOC,
2193 IMAGE_DIRECTORY_ENTRY_DEBUG,
2194 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR };
2195 IMAGE_OPTIONAL_HEADER32 hdr32 = { IMAGE_NT_OPTIONAL_HDR32_MAGIC };
2196 IMAGE_OPTIONAL_HEADER64 hdr64 = { IMAGE_NT_OPTIONAL_HDR64_MAGIC };
2197 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2198 SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
2199 IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER *)((char *)&nt->OptionalHeader + hdr_size);
2200 SIZE_T size = min( nt->OptionalHeader.SizeOfHeaders, nt->OptionalHeader.SizeOfImage );
2201 void *addr = module;
2202 ULONG i, old_prot;
2204 if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return TRUE; /* already 64-bit */
2205 if (NtCurrentTeb()->WowTebOffset) return TRUE; /* no need to convert */
2206 if (!info->ImageContainsCode) return TRUE; /* no need to convert */
2208 TRACE( "%p\n", module );
2210 if (NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &old_prot ))
2211 return FALSE;
2213 if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
2215 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2216 return FALSE;
2219 memcpy( &hdr32, &nt->OptionalHeader, hdr_size );
2220 memcpy( &hdr64, &hdr32, offsetof( IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve ));
2221 hdr64.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2222 hdr64.AddressOfEntryPoint = 0;
2223 hdr64.ImageBase = hdr32.ImageBase;
2224 hdr64.SizeOfStackReserve = hdr32.SizeOfStackReserve;
2225 hdr64.SizeOfStackCommit = hdr32.SizeOfStackCommit;
2226 hdr64.SizeOfHeapReserve = hdr32.SizeOfHeapReserve;
2227 hdr64.SizeOfHeapCommit = hdr32.SizeOfHeapCommit;
2228 hdr64.LoaderFlags = hdr32.LoaderFlags;
2229 hdr64.NumberOfRvaAndSizes = hdr32.NumberOfRvaAndSizes;
2230 for (i = 0; i < ARRAY_SIZE( copy_dirs ); i++)
2231 hdr64.DataDirectory[copy_dirs[i]] = hdr32.DataDirectory[copy_dirs[i]];
2233 memmove( nt + 1, sec, nt->FileHeader.NumberOfSections * sizeof(*sec) );
2234 nt->FileHeader.SizeOfOptionalHeader = sizeof(hdr64);
2235 nt->OptionalHeader = hdr64;
2236 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2237 return TRUE;
2240 /* check COM header for ILONLY flag, ignoring runtime version */
2241 static BOOL get_cor_header( HANDLE file, const SECTION_IMAGE_INFORMATION *info, IMAGE_COR20_HEADER *cor )
2243 IMAGE_DOS_HEADER mz;
2244 IMAGE_NT_HEADERS32 nt;
2245 IO_STATUS_BLOCK io;
2246 LARGE_INTEGER offset;
2247 IMAGE_SECTION_HEADER sec[96];
2248 unsigned int i, count;
2249 DWORD va, size;
2251 offset.QuadPart = 0;
2252 if (NtReadFile( file, 0, NULL, NULL, &io, &mz, sizeof(mz), &offset, NULL )) return FALSE;
2253 if (io.Information != sizeof(mz)) return FALSE;
2254 if (mz.e_magic != IMAGE_DOS_SIGNATURE) return FALSE;
2255 offset.QuadPart = mz.e_lfanew;
2256 if (NtReadFile( file, 0, NULL, NULL, &io, &nt, sizeof(nt), &offset, NULL )) return FALSE;
2257 if (io.Information != sizeof(nt)) return FALSE;
2258 if (nt.Signature != IMAGE_NT_SIGNATURE) return FALSE;
2259 if (nt.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return FALSE;
2260 va = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress;
2261 size = nt.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].Size;
2262 if (!va || size < sizeof(*cor)) return FALSE;
2263 offset.QuadPart += offsetof( IMAGE_NT_HEADERS32, OptionalHeader ) + nt.FileHeader.SizeOfOptionalHeader;
2264 count = min( 96, nt.FileHeader.NumberOfSections );
2265 if (NtReadFile( file, 0, NULL, NULL, &io, &sec, count * sizeof(*sec), &offset, NULL )) return FALSE;
2266 if (io.Information != count * sizeof(*sec)) return FALSE;
2267 for (i = 0; i < count; i++)
2269 if (va < sec[i].VirtualAddress) continue;
2270 if (sec[i].Misc.VirtualSize && va - sec[i].VirtualAddress >= sec[i].Misc.VirtualSize) continue;
2271 offset.QuadPart = sec->PointerToRawData + va - sec[i].VirtualAddress;
2272 if (NtReadFile( file, 0, NULL, NULL, &io, cor, sizeof(*cor), &offset, NULL )) return FALSE;
2273 return (io.Information == sizeof(*cor));
2275 return FALSE;
2277 #endif
2279 /* On WoW64 setups, an image mapping can also be created for the other 32/64 CPU */
2280 /* but it cannot necessarily be loaded as a dll, so we need some additional checks */
2281 static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2283 #ifdef __i386__
2284 return info->Machine == IMAGE_FILE_MACHINE_I386;
2285 #elif defined(__arm__)
2286 return info->Machine == IMAGE_FILE_MACHINE_ARM ||
2287 info->Machine == IMAGE_FILE_MACHINE_THUMB ||
2288 info->Machine == IMAGE_FILE_MACHINE_ARMNT;
2289 #elif defined(_WIN64) /* support 32-bit IL-only images on 64-bit */
2290 #ifdef __x86_64__
2291 if (info->Machine == IMAGE_FILE_MACHINE_AMD64) return TRUE;
2292 #else
2293 if (info->Machine == IMAGE_FILE_MACHINE_ARM64) return TRUE;
2294 #endif
2295 if (NtCurrentTeb()->WowTebOffset) return TRUE;
2296 if (!info->ImageContainsCode) return TRUE;
2297 if (!(info->u.s.ComPlusNativeReady))
2299 IMAGE_COR20_HEADER cor_header;
2300 if (!get_cor_header( file, info, &cor_header )) return FALSE;
2301 if (!(cor_header.Flags & COMIMAGE_FLAGS_ILONLY)) return FALSE;
2303 return TRUE;
2304 #else
2305 return FALSE; /* no wow64 support on other platforms */
2306 #endif
2310 /******************************************************************
2311 * get_module_path_end
2313 * Returns the end of the directory component of the module path.
2315 static inline const WCHAR *get_module_path_end( const WCHAR *module )
2317 const WCHAR *p;
2318 const WCHAR *mod_end = module;
2320 if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
2321 if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2322 if (mod_end == module + 2 && module[1] == ':') mod_end++;
2323 if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
2324 return mod_end;
2328 /******************************************************************
2329 * append_path
2331 * Append a counted string to the load path. Helper for get_dll_load_path.
2333 static inline WCHAR *append_path( WCHAR *p, const WCHAR *str, int len )
2335 if (len == -1) len = wcslen(str);
2336 if (!len) return p;
2337 memcpy( p, str, len * sizeof(WCHAR) );
2338 p[len] = ';';
2339 return p + len + 1;
2343 /******************************************************************
2344 * get_dll_load_path
2346 static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2348 const WCHAR *mod_end = module;
2349 UNICODE_STRING name, value;
2350 WCHAR *p, *ret;
2351 int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2353 if (module)
2355 mod_end = get_module_path_end( module );
2356 len += (mod_end - module) + 1;
2359 RtlInitUnicodeString( &name, L"PATH" );
2360 value.Length = 0;
2361 value.MaximumLength = 0;
2362 value.Buffer = NULL;
2363 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2364 path_len = value.Length;
2366 if (dll_dir) len += wcslen( dll_dir ) + 1;
2367 else len += 2; /* current directory */
2368 if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2369 return STATUS_NO_MEMORY;
2371 p = append_path( p, module, mod_end - module );
2372 if (dll_dir) p = append_path( p, dll_dir, -1 );
2373 else if (!safe_mode) p = append_path( p, L".", -1 );
2374 p = append_path( p, system_path, -1 );
2375 if (!dll_dir && safe_mode) p = append_path( p, L".", -1 );
2377 value.Buffer = p;
2378 value.MaximumLength = path_len;
2380 while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2382 WCHAR *new_ptr;
2384 /* grow the buffer and retry */
2385 path_len = value.Length;
2386 if (!(new_ptr = RtlReAllocateHeap( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
2388 RtlFreeHeap( GetProcessHeap(), 0, ret );
2389 return STATUS_NO_MEMORY;
2391 value.Buffer = new_ptr + (value.Buffer - ret);
2392 value.MaximumLength = path_len;
2393 ret = new_ptr;
2395 value.Buffer[value.Length / sizeof(WCHAR)] = 0;
2396 *path = ret;
2397 return STATUS_SUCCESS;
2401 /******************************************************************
2402 * get_dll_load_path_search_flags
2404 static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCHAR **path )
2406 const WCHAR *image = NULL, *mod_end, *image_end;
2407 struct dll_dir_entry *dir;
2408 WCHAR *p, *ret;
2409 int len = 1;
2411 if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
2412 flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
2413 LOAD_LIBRARY_SEARCH_USER_DIRS |
2414 LOAD_LIBRARY_SEARCH_SYSTEM32);
2416 if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
2418 DWORD type = RtlDetermineDosPathNameType_U( module );
2419 if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2420 return STATUS_INVALID_PARAMETER;
2421 mod_end = get_module_path_end( module );
2422 len += (mod_end - module) + 1;
2424 else module = NULL;
2426 if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
2428 image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
2429 image_end = get_module_path_end( image );
2430 len += (image_end - image) + 1;
2433 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2435 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2436 len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2437 if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
2440 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2442 if ((p = ret = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2444 if (module) p = append_path( p, module, mod_end - module );
2445 if (image) p = append_path( p, image, image_end - image );
2446 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2448 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2449 p = append_path( p, dir->dir + 4 /* \??\ */, -1 );
2450 p = append_path( p, dll_directory.Buffer, dll_directory.Length / sizeof(WCHAR) );
2452 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2453 else
2455 if (p > ret) p--;
2456 *p = 0;
2459 *path = ret;
2460 return STATUS_SUCCESS;
2464 /***********************************************************************
2465 * open_dll_file
2467 * Open a file for a new dll. Helper for find_dll_file.
2469 static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2470 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2472 FILE_BASIC_INFORMATION info;
2473 OBJECT_ATTRIBUTES attr;
2474 IO_STATUS_BLOCK io;
2475 LARGE_INTEGER size;
2476 FILE_OBJECTID_BUFFER fid;
2477 NTSTATUS status;
2478 HANDLE handle;
2480 if ((*pwm = find_fullname_module( nt_name ))) return STATUS_SUCCESS;
2482 attr.Length = sizeof(attr);
2483 attr.RootDirectory = 0;
2484 attr.Attributes = OBJ_CASE_INSENSITIVE;
2485 attr.ObjectName = nt_name;
2486 attr.SecurityDescriptor = NULL;
2487 attr.SecurityQualityOfService = NULL;
2488 if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
2489 FILE_SHARE_READ | FILE_SHARE_DELETE,
2490 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
2492 if (status != STATUS_OBJECT_PATH_NOT_FOUND &&
2493 status != STATUS_OBJECT_NAME_NOT_FOUND &&
2494 !NtQueryAttributesFile( &attr, &info ))
2496 /* if the file exists but failed to open, report the error */
2497 return status;
2499 /* otherwise continue searching */
2500 return STATUS_DLL_NOT_FOUND;
2503 if (!NtFsControlFile( handle, 0, NULL, NULL, &io, FSCTL_GET_OBJECT_ID, NULL, 0, &fid, sizeof(fid) ))
2505 memcpy( id, fid.ObjectId, sizeof(*id) );
2506 if ((*pwm = find_fileid_module( id )))
2508 TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2509 (*pwm)->ldr.DllBase, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2510 NtClose( handle );
2511 return STATUS_SUCCESS;
2515 size.QuadPart = 0;
2516 status = NtCreateSection( mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2517 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
2518 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
2519 if (!status)
2521 NtQuerySection( *mapping, SectionImageInformation, image_info, sizeof(*image_info), NULL );
2522 if (!is_valid_binary( handle, image_info ))
2524 TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->Machine );
2525 status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2526 NtClose( *mapping );
2527 *mapping = NULL;
2530 NtClose( handle );
2531 return status;
2535 /******************************************************************************
2536 * find_existing_module
2538 * Find an existing module that is the same mapping as the new module.
2540 static WINE_MODREF *find_existing_module( HMODULE module )
2542 WINE_MODREF *wm;
2543 LIST_ENTRY *mark, *entry;
2544 LDR_DATA_TABLE_ENTRY *mod;
2545 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2547 if ((wm = get_modref( module ))) return wm;
2549 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
2550 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2552 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
2553 if (mod->TimeDateStamp != nt->FileHeader.TimeDateStamp) continue;
2554 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
2555 if (wm->CheckSum != nt->OptionalHeader.CheckSum) continue;
2556 if (NtAreMappedFilesTheSame( mod->DllBase, module ) != STATUS_SUCCESS) continue;
2557 return CONTAINING_RECORD( mod, WINE_MODREF, ldr );
2559 return NULL;
2563 /******************************************************************************
2564 * load_native_dll (internal)
2566 static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, HANDLE mapping,
2567 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2568 DWORD flags, BOOL system, WINE_MODREF** pwm )
2570 void *module = NULL;
2571 SIZE_T len = 0;
2572 NTSTATUS status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, NULL, &len,
2573 ViewShare, 0, PAGE_EXECUTE_READ );
2575 if (status == STATUS_IMAGE_NOT_AT_BASE) status = STATUS_SUCCESS;
2576 if (status) return status;
2578 if ((*pwm = find_existing_module( module ))) /* already loaded */
2580 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2581 TRACE( "found %s for %s at %p, count=%d\n",
2582 debugstr_us(&(*pwm)->ldr.FullDllName), debugstr_us(nt_name),
2583 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
2584 if (module != (*pwm)->ldr.DllBase) NtUnmapViewOfSection( NtCurrentProcess(), module );
2585 return STATUS_SUCCESS;
2587 #ifdef _WIN64
2588 if (!convert_to_pe64( module, image_info )) status = STATUS_INVALID_IMAGE_FORMAT;
2589 #endif
2590 if (!status) status = build_module( load_path, nt_name, &module, image_info, id, flags, system, pwm );
2591 if (status && module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2592 return status;
2596 /***********************************************************************
2597 * load_so_dll
2599 static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2600 DWORD flags, WINE_MODREF **pwm )
2602 void *module;
2603 NTSTATUS status;
2604 WINE_MODREF *wm;
2605 UNICODE_STRING win_name = *nt_name;
2607 TRACE( "trying %s as so lib\n", debugstr_us(&win_name) );
2608 if ((status = unix_funcs->load_so_dll( &win_name, &module )))
2610 WARN( "failed to load .so lib %s\n", debugstr_us(nt_name) );
2611 if (status == STATUS_INVALID_IMAGE_FORMAT) status = STATUS_INVALID_IMAGE_NOT_MZ;
2612 return status;
2615 if ((wm = get_modref( module ))) /* already loaded */
2617 TRACE( "Found %s at %p for builtin %s\n",
2618 debugstr_w(wm->ldr.FullDllName.Buffer), wm->ldr.DllBase, debugstr_us(nt_name) );
2619 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2621 else
2623 SECTION_IMAGE_INFORMATION image_info = { 0 };
2625 if ((status = build_module( load_path, &win_name, &module, &image_info, NULL, flags, FALSE, &wm )))
2627 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2628 return status;
2630 TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_us(nt_name), module );
2632 *pwm = wm;
2633 return STATUS_SUCCESS;
2637 /*************************************************************************
2638 * build_main_module
2640 * Build the module data for the main image.
2642 static WINE_MODREF *build_main_module(void)
2644 SECTION_IMAGE_INFORMATION info;
2645 UNICODE_STRING nt_name;
2646 WINE_MODREF *wm;
2647 NTSTATUS status;
2648 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
2649 void *module = NtCurrentTeb()->Peb->ImageBaseAddress;
2651 default_load_path = params->DllPath.Buffer;
2652 if (!default_load_path)
2653 get_dll_load_path( params->ImagePathName.Buffer, NULL, dll_safe_mode, &default_load_path );
2655 NtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info), NULL );
2656 if (info.ImageCharacteristics & IMAGE_FILE_DLL)
2658 MESSAGE( "wine: %s is a dll, not an executable\n", debugstr_us(&params->ImagePathName) );
2659 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
2661 #ifdef _WIN64
2662 if (!convert_to_pe64( module, &info ))
2664 status = STATUS_INVALID_IMAGE_FORMAT;
2665 goto failed;
2667 #endif
2668 status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
2669 if (status) goto failed;
2670 status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, FALSE, &wm );
2671 RtlFreeUnicodeString( &nt_name );
2672 if (!status) return wm;
2673 failed:
2674 MESSAGE( "wine: failed to create main module for %s, status %x\n",
2675 debugstr_us(&params->ImagePathName), status );
2676 NtTerminateProcess( GetCurrentProcess(), status );
2677 return NULL; /* unreached */
2681 /***********************************************************************
2682 * build_dlldata_path
2684 * Helper for find_actctx_dll.
2686 static NTSTATUS build_dlldata_path( LPCWSTR libname, ACTCTX_SECTION_KEYED_DATA *data, LPWSTR *fullname )
2688 struct dllredirect_data *dlldata = data->lpData;
2689 char *base = data->lpSectionBase;
2690 SIZE_T total = dlldata->total_len + (wcslen(libname) + 1) * sizeof(WCHAR);
2691 WCHAR *p, *buffer;
2692 NTSTATUS status = STATUS_SUCCESS;
2693 ULONG i;
2695 if (!(p = buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
2696 for (i = 0; i < dlldata->paths_count; i++)
2698 memcpy( p, base + dlldata->paths[i].offset, dlldata->paths[i].len );
2699 p += dlldata->paths[i].len / sizeof(WCHAR);
2701 if (p == buffer || p[-1] == '\\') wcscpy( p, libname );
2702 else *p = 0;
2704 if (dlldata->flags & DLL_REDIRECT_PATH_EXPAND)
2706 RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), NULL, 0, &total );
2707 if ((*fullname = RtlAllocateHeap( GetProcessHeap(), 0, total * sizeof(WCHAR) )))
2708 RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), *fullname, total, NULL );
2709 else
2710 status = STATUS_NO_MEMORY;
2712 RtlFreeHeap( GetProcessHeap(), 0, buffer );
2714 else *fullname = buffer;
2716 return status;
2720 /***********************************************************************
2721 * find_actctx_dll
2723 * Find the full path (if any) of the dll from the activation context.
2725 static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
2727 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
2729 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info = NULL;
2730 ACTCTX_SECTION_KEYED_DATA data;
2731 struct dllredirect_data *dlldata;
2732 UNICODE_STRING nameW;
2733 NTSTATUS status;
2734 SIZE_T needed, size = 1024;
2735 WCHAR *p;
2737 RtlInitUnicodeString( &nameW, libname );
2738 data.cbSize = sizeof(data);
2739 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2740 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
2741 &nameW, &data );
2742 if (status != STATUS_SUCCESS) return status;
2744 if (data.ulLength < offsetof( struct dllredirect_data, paths[0] ))
2746 status = STATUS_SXS_KEY_NOT_FOUND;
2747 goto done;
2749 dlldata = data.lpData;
2750 if (!(dlldata->flags & DLL_REDIRECT_PATH_OMITS_ASSEMBLY_ROOT))
2752 status = build_dlldata_path( libname, &data, fullname );
2753 goto done;
2756 for (;;)
2758 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2760 status = STATUS_NO_MEMORY;
2761 goto done;
2763 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
2764 AssemblyDetailedInformationInActivationContext,
2765 info, size, &needed );
2766 if (status == STATUS_SUCCESS) break;
2767 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
2768 RtlFreeHeap( GetProcessHeap(), 0, info );
2769 size = needed;
2770 /* restart with larger buffer */
2773 if (!info->lpAssemblyManifestPath)
2775 status = STATUS_SXS_KEY_NOT_FOUND;
2776 goto done;
2779 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2781 DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2782 p++;
2783 len = wcslen( p );
2784 if (!dirlen || len <= dirlen ||
2785 RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2786 wcsicmp( p + dirlen, L".manifest" ))
2788 /* manifest name does not match directory name, so it's not a global
2789 * windows/winsxs manifest; use the manifest directory name instead */
2790 dirlen = p - info->lpAssemblyManifestPath;
2791 needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
2792 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2794 status = STATUS_NO_MEMORY;
2795 goto done;
2797 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
2798 p += dirlen;
2799 wcscpy( p, libname );
2800 goto done;
2804 if (!info->lpAssemblyDirectoryName)
2806 status = STATUS_SXS_KEY_NOT_FOUND;
2807 goto done;
2810 needed = (wcslen(windows_dir) * sizeof(WCHAR) +
2811 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
2813 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2815 status = STATUS_NO_MEMORY;
2816 goto done;
2818 wcscpy( p, windows_dir );
2819 p += wcslen(p);
2820 memcpy( p, winsxsW, sizeof(winsxsW) );
2821 p += ARRAY_SIZE( winsxsW );
2822 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
2823 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2824 *p++ = '\\';
2825 wcscpy( p, libname );
2826 done:
2827 RtlFreeHeap( GetProcessHeap(), 0, info );
2828 RtlReleaseActivationContext( data.hActCtx );
2829 return status;
2834 /******************************************************************************
2835 * find_apiset_dll
2837 static NTSTATUS find_apiset_dll( const WCHAR *name, WCHAR **fullname )
2839 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
2840 const API_SET_NAMESPACE_ENTRY *entry;
2841 UNICODE_STRING str;
2842 ULONG len;
2844 if (get_apiset_entry( map, name, wcslen(name), &entry )) return STATUS_APISET_NOT_PRESENT;
2845 if (get_apiset_target( map, entry, NULL, &str )) return STATUS_DLL_NOT_FOUND;
2847 len = wcslen( system_dir ) + str.Length / sizeof(WCHAR);
2848 if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
2849 return STATUS_NO_MEMORY;
2850 wcscpy( *fullname, system_dir );
2851 memcpy( *fullname + wcslen( system_dir ), str.Buffer, str.Length );
2852 (*fullname)[len] = 0;
2853 return STATUS_SUCCESS;
2857 /***********************************************************************
2858 * get_env_var
2860 static NTSTATUS get_env_var( const WCHAR *name, SIZE_T extra, UNICODE_STRING *ret )
2862 NTSTATUS status;
2863 SIZE_T len, size = 1024 + extra;
2865 for (;;)
2867 ret->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) );
2868 status = RtlQueryEnvironmentVariable( NULL, name, wcslen(name),
2869 ret->Buffer, size - extra - 1, &len );
2870 if (!status)
2872 ret->Buffer[len] = 0;
2873 ret->Length = len * sizeof(WCHAR);
2874 ret->MaximumLength = size * sizeof(WCHAR);
2875 return status;
2877 RtlFreeHeap( GetProcessHeap(), 0, ret->Buffer );
2878 if (status != STATUS_BUFFER_TOO_SMALL)
2880 ret->Buffer = NULL;
2881 return status;
2883 size = len + 1 + extra;
2888 /***********************************************************************
2889 * find_builtin_without_file
2891 * Find a builtin dll when the corresponding file cannot be found in the prefix.
2892 * This is used during prefix bootstrap.
2894 static NTSTATUS find_builtin_without_file( const WCHAR *name, UNICODE_STRING *new_name,
2895 WINE_MODREF **pwm, HANDLE *mapping,
2896 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2898 const WCHAR *ext;
2899 WCHAR dllpath[32];
2900 DWORD i, len;
2901 NTSTATUS status = STATUS_DLL_NOT_FOUND;
2902 BOOL found_image = FALSE;
2904 if (contains_path( name )) return status;
2906 if (!is_prefix_bootstrap)
2908 /* 16-bit files can't be loaded from the prefix */
2909 if (!name[1] || wcscmp( name + wcslen(name) - 2, L"16" )) return status;
2912 if (!get_env_var( L"WINEBUILDDIR", 20 + 2 * wcslen(name), new_name ))
2914 len = new_name->Length;
2915 RtlAppendUnicodeToString( new_name, L"\\dlls\\" );
2916 RtlAppendUnicodeToString( new_name, name );
2917 if ((ext = wcsrchr( name, '.' )) && !wcscmp( ext, L".dll" )) new_name->Length -= 4 * sizeof(WCHAR);
2918 RtlAppendUnicodeToString( new_name, L"\\" );
2919 RtlAppendUnicodeToString( new_name, name );
2920 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2921 if (status != STATUS_DLL_NOT_FOUND) goto done;
2923 new_name->Length = len;
2924 RtlAppendUnicodeToString( new_name, L"\\programs\\" );
2925 RtlAppendUnicodeToString( new_name, name );
2926 RtlAppendUnicodeToString( new_name, L"\\" );
2927 RtlAppendUnicodeToString( new_name, name );
2928 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2929 if (status != STATUS_DLL_NOT_FOUND) goto done;
2930 RtlFreeUnicodeString( new_name );
2933 for (i = 0; ; i++)
2935 swprintf( dllpath, ARRAY_SIZE(dllpath), L"WINEDLLDIR%u", i );
2936 if (get_env_var( dllpath, wcslen(pe_dir) + wcslen(name) + 1, new_name )) break;
2937 len = new_name->Length;
2938 RtlAppendUnicodeToString( new_name, pe_dir );
2939 RtlAppendUnicodeToString( new_name, L"\\" );
2940 RtlAppendUnicodeToString( new_name, name );
2941 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2942 if (status != STATUS_DLL_NOT_FOUND) goto done;
2943 new_name->Length = len;
2944 RtlAppendUnicodeToString( new_name, L"\\" );
2945 RtlAppendUnicodeToString( new_name, name );
2946 status = open_dll_file( new_name, pwm, mapping, image_info, id );
2947 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
2948 else if (status != STATUS_DLL_NOT_FOUND) goto done;
2949 RtlFreeUnicodeString( new_name );
2951 if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
2953 done:
2954 RtlFreeUnicodeString( new_name );
2955 if (!status)
2957 new_name->Length = (4 + wcslen(system_dir) + wcslen(name)) * sizeof(WCHAR);
2958 new_name->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, new_name->Length + sizeof(WCHAR) );
2959 wcscpy( new_name->Buffer, L"\\??\\" );
2960 wcscat( new_name->Buffer, system_dir );
2961 wcscat( new_name->Buffer, name );
2963 return status;
2967 /***********************************************************************
2968 * search_dll_file
2970 * Search for dll in the specified paths.
2972 static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
2973 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
2974 struct file_id *id )
2976 WCHAR *name;
2977 BOOL found_image = FALSE;
2978 NTSTATUS status = STATUS_DLL_NOT_FOUND;
2979 ULONG len;
2981 if (!paths) paths = default_load_path;
2982 len = wcslen( paths );
2984 if (len < wcslen( system_dir )) len = wcslen( system_dir );
2985 len += wcslen( search ) + 2;
2987 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2988 return STATUS_NO_MEMORY;
2990 while (*paths)
2992 LPCWSTR ptr = paths;
2994 while (*ptr && *ptr != ';') ptr++;
2995 len = ptr - paths;
2996 if (*ptr == ';') ptr++;
2997 memcpy( name, paths, len * sizeof(WCHAR) );
2998 if (len && name[len - 1] != '\\') name[len++] = '\\';
2999 wcscpy( name + len, search );
3001 nt_name->Buffer = NULL;
3002 if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;
3004 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3005 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) found_image = TRUE;
3006 else if (status != STATUS_DLL_NOT_FOUND) goto done;
3007 RtlFreeUnicodeString( nt_name );
3008 paths = ptr;
3011 if (found_image) status = STATUS_IMAGE_MACHINE_TYPE_MISMATCH;
3013 done:
3014 RtlFreeHeap( GetProcessHeap(), 0, name );
3015 return status;
3018 /***********************************************************************
3019 * find_dll_file
3021 * Find the file (or already loaded module) for a given dll name.
3023 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNICODE_STRING *nt_name,
3024 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
3025 struct file_id *id )
3027 WCHAR *fullname = NULL;
3028 NTSTATUS status;
3029 ULONG wow64_old_value = 0;
3031 *pwm = NULL;
3033 /* Win 7/2008R2 and up seem to re-enable WoW64 FS redirection when loading libraries */
3034 RtlWow64EnableFsRedirectionEx( 0, &wow64_old_value );
3036 nt_name->Buffer = NULL;
3038 if (!contains_path( libname ))
3040 status = find_apiset_dll( libname, &fullname );
3041 if (status == STATUS_DLL_NOT_FOUND) goto done;
3043 if (status) status = find_actctx_dll( libname, &fullname );
3045 if (status == STATUS_SUCCESS)
3047 TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
3048 libname = fullname;
3050 else
3052 if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
3053 if ((*pwm = find_basename_module( libname )) != NULL)
3055 status = STATUS_SUCCESS;
3056 goto done;
3061 if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
3063 status = search_dll_file( load_path, libname, nt_name, pwm, mapping, image_info, id );
3064 if (status == STATUS_DLL_NOT_FOUND)
3065 status = find_builtin_without_file( libname, nt_name, pwm, mapping, image_info, id );
3067 else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
3068 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3070 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH) status = STATUS_INVALID_IMAGE_FORMAT;
3072 done:
3073 RtlFreeHeap( GetProcessHeap(), 0, fullname );
3074 if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
3075 return status;
3079 /***********************************************************************
3080 * load_dll (internal)
3082 * Load a PE style module according to the load order.
3083 * The loader_section must be locked while calling this function.
3085 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system )
3087 UNICODE_STRING nt_name;
3088 struct file_id id;
3089 HANDLE mapping = 0;
3090 SECTION_IMAGE_INFORMATION image_info;
3091 NTSTATUS nts = STATUS_DLL_NOT_FOUND;
3092 ULONG64 prev;
3094 TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
3096 if (system && system_dll_path.Buffer)
3097 nts = search_dll_file( system_dll_path.Buffer, libname, &nt_name, pwm, &mapping, &image_info, &id );
3099 if (nts)
3101 nts = find_dll_file( load_path, libname, &nt_name, pwm, &mapping, &image_info, &id );
3102 system = FALSE;
3105 if (*pwm) /* found already loaded module */
3107 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
3109 TRACE("Found %s for %s at %p, count=%d\n",
3110 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
3111 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
3112 RtlFreeUnicodeString( &nt_name );
3113 return STATUS_SUCCESS;
3116 if (nts && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
3118 if (NtCurrentTeb64())
3120 prev = NtCurrentTeb64()->Tib.ArbitraryUserPointer;
3121 NtCurrentTeb64()->Tib.ArbitraryUserPointer = (ULONG_PTR)(nt_name.Buffer + 4);
3123 else
3125 prev = (ULONG_PTR)NtCurrentTeb()->Tib.ArbitraryUserPointer;
3126 NtCurrentTeb()->Tib.ArbitraryUserPointer = nt_name.Buffer + 4;
3129 switch (nts)
3131 case STATUS_INVALID_IMAGE_NOT_MZ: /* not in PE format, maybe it's a .so file */
3132 nts = load_so_dll( load_path, &nt_name, flags, pwm );
3133 break;
3135 case STATUS_SUCCESS: /* valid PE file */
3136 nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, system, pwm );
3137 break;
3140 if (NtCurrentTeb64())
3141 NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev;
3142 else
3143 NtCurrentTeb()->Tib.ArbitraryUserPointer = (void *)(ULONG_PTR)prev;
3145 done:
3146 if (nts == STATUS_SUCCESS)
3147 TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.DllBase);
3148 else
3149 WARN("Failed to load module %s; status=%x\n", debugstr_w(libname), nts);
3151 if (mapping) NtClose( mapping );
3152 RtlFreeUnicodeString( &nt_name );
3153 return nts;
3157 /***********************************************************************
3158 * __wine_ctrl_routine
3160 NTSTATUS WINAPI __wine_ctrl_routine( void *arg )
3162 DWORD ret = 0;
3164 if (pCtrlRoutine && NtCurrentTeb()->Peb->ProcessParameters->ConsoleHandle) ret = pCtrlRoutine( arg );
3165 RtlExitUserThread( ret );
3168 /******************************************************************
3169 * LdrLoadDll (NTDLL.@)
3171 NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
3172 const UNICODE_STRING *libname, HMODULE* hModule)
3174 WINE_MODREF *wm;
3175 NTSTATUS nts;
3176 WCHAR *dllname = append_dll_ext( libname->Buffer );
3178 RtlEnterCriticalSection( &loader_section );
3180 nts = load_dll( path_name, dllname ? dllname : libname->Buffer, flags, &wm, FALSE );
3182 if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
3184 nts = process_attach( wm->ldr.DdagNode, NULL );
3185 if (nts != STATUS_SUCCESS)
3187 LdrUnloadDll(wm->ldr.DllBase);
3188 wm = NULL;
3191 *hModule = (wm) ? wm->ldr.DllBase : NULL;
3193 RtlLeaveCriticalSection( &loader_section );
3194 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3195 return nts;
3199 /******************************************************************
3200 * LdrGetDllFullName (NTDLL.@)
3202 NTSTATUS WINAPI LdrGetDllFullName( HMODULE module, UNICODE_STRING *name )
3204 WINE_MODREF *wm;
3205 NTSTATUS status;
3207 TRACE( "module %p, name %p.\n", module, name );
3209 if (!module) module = NtCurrentTeb()->Peb->ImageBaseAddress;
3211 RtlEnterCriticalSection( &loader_section );
3212 wm = get_modref( module );
3213 if (wm)
3215 RtlCopyUnicodeString( name, &wm->ldr.FullDllName );
3216 if (name->MaximumLength < wm->ldr.FullDllName.Length + sizeof(WCHAR)) status = STATUS_BUFFER_TOO_SMALL;
3217 else status = STATUS_SUCCESS;
3218 } else status = STATUS_DLL_NOT_FOUND;
3219 RtlLeaveCriticalSection( &loader_section );
3221 return status;
3225 /******************************************************************
3226 * LdrGetDllHandleEx (NTDLL.@)
3228 NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics,
3229 const UNICODE_STRING *name, HMODULE *base )
3231 static const ULONG supported_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
3232 | LDR_GET_DLL_HANDLE_EX_FLAG_PIN;
3233 static const ULONG valid_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
3234 | LDR_GET_DLL_HANDLE_EX_FLAG_PIN | 4;
3235 SECTION_IMAGE_INFORMATION image_info;
3236 UNICODE_STRING nt_name;
3237 struct file_id id;
3238 NTSTATUS status;
3239 WINE_MODREF *wm;
3240 WCHAR *dllname;
3241 HANDLE mapping;
3243 TRACE( "flags %#x, load_path %p, dll_characteristics %p, name %p, base %p.\n",
3244 flags, load_path, dll_characteristics, name, base );
3246 if (flags & ~valid_flags) return STATUS_INVALID_PARAMETER;
3248 if ((flags & (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
3249 == (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
3250 return STATUS_INVALID_PARAMETER;
3252 if (flags & ~supported_flags) FIXME( "Unsupported flags %#x.\n", flags );
3253 if (dll_characteristics) FIXME( "dll_characteristics unsupported.\n" );
3255 dllname = append_dll_ext( name->Buffer );
3257 RtlEnterCriticalSection( &loader_section );
3259 status = find_dll_file( load_path, dllname ? dllname : name->Buffer,
3260 &nt_name, &wm, &mapping, &image_info, &id );
3262 if (wm) *base = wm->ldr.DllBase;
3263 else
3265 if (status == STATUS_SUCCESS) NtClose( mapping );
3266 status = STATUS_DLL_NOT_FOUND;
3268 RtlFreeUnicodeString( &nt_name );
3270 if (!status)
3272 if (flags & LDR_GET_DLL_HANDLE_EX_FLAG_PIN)
3273 LdrAddRefDll( LDR_ADDREF_DLL_PIN, *base );
3274 else if (!(flags & LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
3275 LdrAddRefDll( 0, *base );
3278 RtlLeaveCriticalSection( &loader_section );
3279 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3280 TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
3281 return status;
3285 /******************************************************************
3286 * LdrGetDllHandle (NTDLL.@)
3288 NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
3290 return LdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, load_path, NULL, name, base );
3294 /******************************************************************
3295 * LdrAddRefDll (NTDLL.@)
3297 NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
3299 NTSTATUS ret = STATUS_SUCCESS;
3300 WINE_MODREF *wm;
3302 if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %x not implemented\n", module, flags );
3304 RtlEnterCriticalSection( &loader_section );
3306 if ((wm = get_modref( module )))
3308 if (flags & LDR_ADDREF_DLL_PIN)
3309 wm->ldr.LoadCount = -1;
3310 else
3311 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
3312 TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3314 else ret = STATUS_INVALID_PARAMETER;
3316 RtlLeaveCriticalSection( &loader_section );
3317 return ret;
3321 /***********************************************************************
3322 * LdrProcessRelocationBlock (NTDLL.@)
3324 * Apply relocations to a given page of a mapped PE image.
3326 IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
3327 USHORT *relocs, INT_PTR delta )
3329 while (count--)
3331 USHORT offset = *relocs & 0xfff;
3332 int type = *relocs >> 12;
3333 switch(type)
3335 case IMAGE_REL_BASED_ABSOLUTE:
3336 break;
3337 case IMAGE_REL_BASED_HIGH:
3338 *(short *)((char *)page + offset) += HIWORD(delta);
3339 break;
3340 case IMAGE_REL_BASED_LOW:
3341 *(short *)((char *)page + offset) += LOWORD(delta);
3342 break;
3343 case IMAGE_REL_BASED_HIGHLOW:
3344 *(int *)((char *)page + offset) += delta;
3345 break;
3346 #ifdef _WIN64
3347 case IMAGE_REL_BASED_DIR64:
3348 *(INT_PTR *)((char *)page + offset) += delta;
3349 break;
3350 #elif defined(__arm__)
3351 case IMAGE_REL_BASED_THUMB_MOV32:
3353 DWORD *inst = (DWORD *)((char *)page + offset);
3354 WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) +
3355 ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff);
3356 WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) +
3357 ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff);
3358 DWORD imm = MAKELONG( lo, hi ) + delta;
3360 lo = LOWORD( imm );
3361 hi = HIWORD( imm );
3363 if ((inst[0] & 0x8000fbf0) != 0x0000f240 || (inst[1] & 0x8000fbf0) != 0x0000f2c0)
3364 ERR("wrong Thumb2 instruction @%p %08x:%08x, expected MOVW/MOVT\n",
3365 inst, inst[0], inst[1] );
3367 inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) +
3368 ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000);
3369 inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) +
3370 ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000);
3371 break;
3373 #endif
3374 default:
3375 FIXME("Unknown/unsupported fixup type %x.\n", type);
3376 return NULL;
3378 relocs++;
3380 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
3384 /******************************************************************
3385 * LdrQueryProcessModuleInformation
3388 NTSTATUS WINAPI LdrQueryProcessModuleInformation(RTL_PROCESS_MODULES *smi,
3389 ULONG buf_size, ULONG* req_size)
3391 RTL_PROCESS_MODULE_INFORMATION *sm = &smi->Modules[0];
3392 ULONG size = sizeof(ULONG);
3393 NTSTATUS nts = STATUS_SUCCESS;
3394 ANSI_STRING str;
3395 char* ptr;
3396 PLIST_ENTRY mark, entry;
3397 LDR_DATA_TABLE_ENTRY *mod;
3398 WORD id = 0;
3400 smi->ModulesCount = 0;
3402 RtlEnterCriticalSection( &loader_section );
3403 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3404 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3406 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3407 size += sizeof(*sm);
3408 if (size <= buf_size)
3410 sm->Section = 0; /* FIXME */
3411 sm->MappedBaseAddress = mod->DllBase;
3412 sm->ImageBaseAddress = mod->DllBase;
3413 sm->ImageSize = mod->SizeOfImage;
3414 sm->Flags = mod->Flags;
3415 sm->LoadOrderIndex = id++;
3416 sm->InitOrderIndex = 0; /* FIXME */
3417 sm->LoadCount = mod->LoadCount;
3418 str.Length = 0;
3419 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
3420 str.Buffer = (char*)sm->Name;
3421 RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
3422 ptr = strrchr(str.Buffer, '\\');
3423 sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3425 smi->ModulesCount++;
3426 sm++;
3428 else nts = STATUS_INFO_LENGTH_MISMATCH;
3430 RtlLeaveCriticalSection( &loader_section );
3432 if (req_size) *req_size = size;
3434 return nts;
3438 static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, LONG *value )
3440 NTSTATUS status;
3441 UNICODE_STRING str;
3442 ULONG size;
3443 WCHAR buffer[64];
3444 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3446 RtlInitUnicodeString( &str, name );
3448 size = sizeof(buffer) - sizeof(WCHAR);
3449 if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
3450 return status;
3452 if (info->Type != REG_DWORD)
3454 buffer[size / sizeof(WCHAR)] = 0;
3455 *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3457 else memcpy( value, info->Data, sizeof(*value) );
3458 return status;
3461 static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
3462 void *data, ULONG in_size, ULONG *out_size )
3464 NTSTATUS status;
3465 UNICODE_STRING str;
3466 ULONG size;
3467 char *buffer;
3468 KEY_VALUE_PARTIAL_INFORMATION *info;
3469 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
3471 RtlInitUnicodeString( &str, name );
3473 size = info_size + in_size;
3474 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
3475 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3476 status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
3477 if (!status || status == STATUS_BUFFER_OVERFLOW)
3479 if (out_size) *out_size = info->DataLength;
3480 if (data && !status) memcpy( data, info->Data, info->DataLength );
3482 RtlFreeHeap( GetProcessHeap(), 0, buffer );
3483 return status;
3487 /******************************************************************
3488 * LdrQueryImageFileExecutionOptions (NTDLL.@)
3490 NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
3491 void *data, ULONG in_size, ULONG *out_size )
3493 static const WCHAR optionsW[] = {'M','a','c','h','i','n','e','\\',
3494 'S','o','f','t','w','a','r','e','\\',
3495 'M','i','c','r','o','s','o','f','t','\\',
3496 'W','i','n','d','o','w','s',' ','N','T','\\',
3497 'C','u','r','r','e','n','t','V','e','r','s','i','o','n','\\',
3498 'I','m','a','g','e',' ','F','i','l','e',' ',
3499 'E','x','e','c','u','t','i','o','n',' ','O','p','t','i','o','n','s','\\'};
3500 WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3501 OBJECT_ATTRIBUTES attr;
3502 UNICODE_STRING name_str;
3503 HANDLE hkey;
3504 NTSTATUS status;
3505 ULONG len;
3506 WCHAR *p;
3508 attr.Length = sizeof(attr);
3509 attr.RootDirectory = 0;
3510 attr.ObjectName = &name_str;
3511 attr.Attributes = OBJ_CASE_INSENSITIVE;
3512 attr.SecurityDescriptor = NULL;
3513 attr.SecurityQualityOfService = NULL;
3515 p = key->Buffer + key->Length / sizeof(WCHAR);
3516 while (p > key->Buffer && p[-1] != '\\') p--;
3517 len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
3518 name_str.Buffer = path;
3519 name_str.Length = sizeof(optionsW) + len;
3520 name_str.MaximumLength = name_str.Length;
3521 memcpy( path, optionsW, sizeof(optionsW) );
3522 memcpy( path + ARRAY_SIZE( optionsW ), p, len );
3523 if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
3525 if (type == REG_DWORD)
3527 if (out_size) *out_size = sizeof(ULONG);
3528 if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
3529 else status = STATUS_BUFFER_OVERFLOW;
3531 else status = query_string_option( hkey, value, type, data, in_size, out_size );
3533 NtClose( hkey );
3534 return status;
3538 /******************************************************************
3539 * RtlDllShutdownInProgress (NTDLL.@)
3541 BOOLEAN WINAPI RtlDllShutdownInProgress(void)
3543 return process_detaching;
3546 /****************************************************************************
3547 * LdrResolveDelayLoadedAPI (NTDLL.@)
3549 void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3550 PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
3551 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3552 IMAGE_THUNK_DATA* addr, ULONG flags )
3554 IMAGE_THUNK_DATA *pIAT, *pINT;
3555 DELAYLOAD_INFO delayinfo;
3556 UNICODE_STRING mod;
3557 const CHAR* name;
3558 HMODULE *phmod;
3559 NTSTATUS nts;
3560 FARPROC fp;
3561 DWORD id;
3563 TRACE( "(%p, %p, %p, %p, %p, 0x%08x)\n", base, desc, dllhook, syshook, addr, flags );
3565 phmod = get_rva(base, desc->ModuleHandleRVA);
3566 pIAT = get_rva(base, desc->ImportAddressTableRVA);
3567 pINT = get_rva(base, desc->ImportNameTableRVA);
3568 name = get_rva(base, desc->DllNameRVA);
3569 id = addr - pIAT;
3571 if (!*phmod)
3573 if (!RtlCreateUnicodeStringFromAsciiz(&mod, name))
3575 nts = STATUS_NO_MEMORY;
3576 goto fail;
3578 nts = LdrLoadDll(NULL, 0, &mod, phmod);
3579 RtlFreeUnicodeString(&mod);
3580 if (nts) goto fail;
3583 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3584 nts = LdrGetProcedureAddress(*phmod, NULL, LOWORD(pINT[id].u1.Ordinal), (void**)&fp);
3585 else
3587 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3588 ANSI_STRING fnc;
3590 RtlInitAnsiString(&fnc, (char*)iibn->Name);
3591 nts = LdrGetProcedureAddress(*phmod, &fnc, 0, (void**)&fp);
3593 if (!nts)
3595 pIAT[id].u1.Function = (ULONG_PTR)fp;
3596 return fp;
3599 fail:
3600 delayinfo.Size = sizeof(delayinfo);
3601 delayinfo.DelayloadDescriptor = desc;
3602 delayinfo.ThunkAddress = addr;
3603 delayinfo.TargetDllName = name;
3604 delayinfo.TargetApiDescriptor.ImportDescribedByName = !IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal);
3605 delayinfo.TargetApiDescriptor.Description.Ordinal = LOWORD(pINT[id].u1.Ordinal);
3606 delayinfo.TargetModuleBase = *phmod;
3607 delayinfo.Unused = NULL;
3608 delayinfo.LastError = nts;
3610 if (dllhook)
3611 return dllhook(4, &delayinfo);
3613 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3615 DWORD_PTR ord = LOWORD(pINT[id].u1.Ordinal);
3616 return syshook(name, (const char *)ord);
3618 else
3620 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3621 return syshook(name, (const char *)iibn->Name);
3625 /******************************************************************
3626 * LdrShutdownProcess (NTDLL.@)
3629 void WINAPI LdrShutdownProcess(void)
3631 BOOL detaching = process_detaching;
3633 TRACE("()\n");
3635 process_detaching = TRUE;
3636 if (!detaching)
3637 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3639 process_detach();
3643 /******************************************************************
3644 * RtlExitUserProcess (NTDLL.@)
3646 void WINAPI RtlExitUserProcess( DWORD status )
3648 RtlEnterCriticalSection( &loader_section );
3649 RtlAcquirePebLock();
3650 NtTerminateProcess( 0, status );
3651 LdrShutdownProcess();
3652 for (;;) NtTerminateProcess( GetCurrentProcess(), status );
3655 /******************************************************************
3656 * LdrShutdownThread (NTDLL.@)
3659 void WINAPI LdrShutdownThread(void)
3661 PLIST_ENTRY mark, entry;
3662 LDR_DATA_TABLE_ENTRY *mod;
3663 WINE_MODREF *wm;
3664 UINT i;
3665 void **pointers;
3667 TRACE("()\n");
3669 /* don't do any detach calls if process is exiting */
3670 if (process_detaching) return;
3672 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3674 RtlEnterCriticalSection( &loader_section );
3675 wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3677 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3678 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3680 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
3681 InInitializationOrderLinks);
3682 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3683 continue;
3684 if ( mod->Flags & LDR_NO_DLL_CALLS )
3685 continue;
3687 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
3688 DLL_THREAD_DETACH, NULL );
3691 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );
3693 RtlAcquirePebLock();
3694 if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3695 if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
3697 for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
3698 RtlFreeHeap( GetProcessHeap(), 0, pointers );
3700 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
3701 NtCurrentTeb()->FlsSlots = NULL;
3702 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3703 NtCurrentTeb()->TlsExpansionSlots = NULL;
3704 RtlReleasePebLock();
3706 RtlLeaveCriticalSection( &loader_section );
3707 /* don't call DbgUiGetThreadDebugObject as some apps hook it and terminate if called */
3708 if (NtCurrentTeb()->DbgSsReserved[1]) NtClose( NtCurrentTeb()->DbgSsReserved[1] );
3709 RtlFreeThreadActivationContextStack();
3713 /***********************************************************************
3714 * free_modref
3717 static void free_modref( WINE_MODREF *wm )
3719 SINGLE_LIST_ENTRY *entry;
3720 LDR_DEPENDENCY *dep;
3722 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
3723 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
3724 if (wm->ldr.InInitializationOrderLinks.Flink)
3725 RemoveEntryList(&wm->ldr.InInitializationOrderLinks);
3727 while ((entry = wm->ldr.DdagNode->Dependencies.Tail))
3729 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
3730 assert( dep->dependency_from == wm->ldr.DdagNode );
3731 remove_module_dependency( dep );
3734 while ((entry = wm->ldr.DdagNode->IncomingDependencies.Tail))
3736 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_from_entry );
3737 assert( dep->dependency_to == wm->ldr.DdagNode );
3738 remove_module_dependency( dep );
3741 RemoveEntryList(&wm->ldr.NodeModuleLink);
3742 if (IsListEmpty(&wm->ldr.DdagNode->Modules))
3743 RtlFreeHeap( GetProcessHeap(), 0, wm->ldr.DdagNode );
3745 TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
3746 if (!TRACE_ON(module))
3747 TRACE_(loaddll)("Unloaded module %s : %s\n",
3748 debugstr_w(wm->ldr.FullDllName.Buffer),
3749 (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );
3751 free_tls_slot( &wm->ldr );
3752 RtlReleaseActivationContext( wm->ldr.ActivationContext );
3753 NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
3754 if (cached_modref == wm) cached_modref = NULL;
3755 RtlFreeUnicodeString( &wm->ldr.FullDllName );
3756 RtlFreeHeap( GetProcessHeap(), 0, wm );
3759 /***********************************************************************
3760 * MODULE_FlushModrefs
3762 * Remove all unused modrefs and call the internal unloading routines
3763 * for the library type.
3765 * The loader_section must be locked while calling this function.
3767 static void MODULE_FlushModrefs(void)
3769 PLIST_ENTRY mark, entry, prev;
3770 LDR_DATA_TABLE_ENTRY *mod;
3771 WINE_MODREF*wm;
3773 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3774 for (entry = mark->Blink; entry != mark; entry = prev)
3776 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
3777 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3778 prev = entry->Blink;
3779 if (!mod->LoadCount) free_modref( wm );
3782 /* check load order list too for modules that haven't been initialized yet */
3783 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3784 for (entry = mark->Blink; entry != mark; entry = prev)
3786 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3787 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3788 prev = entry->Blink;
3789 if (!mod->LoadCount) free_modref( wm );
3793 /***********************************************************************
3794 * MODULE_DecRefCount
3796 * The loader_section must be locked while calling this function.
3798 static NTSTATUS MODULE_DecRefCount( LDR_DDAG_NODE *node, void *context )
3800 LDR_DATA_TABLE_ENTRY *mod;
3801 WINE_MODREF *wm;
3803 mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
3804 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
3806 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
3807 return STATUS_SUCCESS;
3809 if ( wm->ldr.LoadCount <= 0 )
3810 return STATUS_SUCCESS;
3812 --wm->ldr.LoadCount;
3813 TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3815 if ( wm->ldr.LoadCount == 0 )
3817 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
3818 walk_node_dependencies( node, context, MODULE_DecRefCount );
3819 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
3820 module_push_unload_trace( wm );
3822 return STATUS_SUCCESS;
3825 /******************************************************************
3826 * LdrUnloadDll (NTDLL.@)
3830 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
3832 WINE_MODREF *wm;
3833 NTSTATUS retv = STATUS_SUCCESS;
3835 if (process_detaching) return retv;
3837 TRACE("(%p)\n", hModule);
3839 RtlEnterCriticalSection( &loader_section );
3841 free_lib_count++;
3842 if ((wm = get_modref( hModule )) != NULL)
3844 TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
3846 /* Recursively decrement reference counts */
3847 MODULE_DecRefCount( wm->ldr.DdagNode, NULL );
3849 /* Call process detach notifications */
3850 if ( free_lib_count <= 1 )
3852 process_detach();
3853 MODULE_FlushModrefs();
3856 TRACE("END\n");
3858 else
3859 retv = STATUS_DLL_NOT_FOUND;
3861 free_lib_count--;
3863 RtlLeaveCriticalSection( &loader_section );
3865 return retv;
3868 /***********************************************************************
3869 * RtlImageNtHeader (NTDLL.@)
3871 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
3873 IMAGE_NT_HEADERS *ret;
3875 __TRY
3877 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
3879 ret = NULL;
3880 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
3882 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
3883 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
3886 __EXCEPT_PAGE_FAULT
3888 return NULL;
3890 __ENDTRY
3891 return ret;
3894 /***********************************************************************
3895 * process_breakpoint
3897 * Trigger a debug breakpoint if the process is being debugged.
3899 static void process_breakpoint(void)
3901 DWORD_PTR port = 0;
3903 NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort, &port, sizeof(port), NULL );
3904 if (!port) return;
3906 __TRY
3908 DbgBreakPoint();
3910 __EXCEPT_ALL
3912 /* do nothing */
3914 __ENDTRY
3918 /***********************************************************************
3919 * load_global_options
3921 static void load_global_options(void)
3923 OBJECT_ATTRIBUTES attr;
3924 UNICODE_STRING name_str, val_str;
3925 HANDLE hkey;
3927 RtlInitUnicodeString( &name_str, L"WINEBOOTSTRAPMODE" );
3928 val_str.MaximumLength = 0;
3929 is_prefix_bootstrap = RtlQueryEnvironmentVariable_U( NULL, &name_str, &val_str ) != STATUS_VARIABLE_NOT_FOUND;
3931 attr.Length = sizeof(attr);
3932 attr.RootDirectory = 0;
3933 attr.ObjectName = &name_str;
3934 attr.Attributes = OBJ_CASE_INSENSITIVE;
3935 attr.SecurityDescriptor = NULL;
3936 attr.SecurityQualityOfService = NULL;
3937 RtlInitUnicodeString( &name_str, L"Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
3939 if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
3941 query_dword_option( hkey, L"SafeProcessSearchMode", &path_safe_mode );
3942 query_dword_option( hkey, L"SafeDllSearchMode", &dll_safe_mode );
3943 NtClose( hkey );
3949 #ifdef _WIN64
3951 static void (WINAPI *pWow64LdrpInitialize)( CONTEXT *ctx );
3953 void (WINAPI *pWow64PrepareForException)( EXCEPTION_RECORD *rec, CONTEXT *context ) = NULL;
3955 static void init_wow64( CONTEXT *context )
3957 if (!imports_fixup_done)
3959 HMODULE wow64;
3960 WINE_MODREF *wm;
3961 NTSTATUS status;
3962 static const WCHAR wow64_path[] = L"C:\\windows\\system32\\wow64.dll";
3964 if ((status = load_dll( NULL, wow64_path, 0, &wm, FALSE )))
3966 ERR( "could not load %s, status %x\n", debugstr_w(wow64_path), status );
3967 NtTerminateProcess( GetCurrentProcess(), status );
3969 wow64 = wm->ldr.DllBase;
3970 #define GET_PTR(name) \
3971 if (!(p ## name = RtlFindExportedRoutineByName( wow64, #name ))) ERR( "failed to load %s\n", #name )
3973 GET_PTR( Wow64LdrpInitialize );
3974 GET_PTR( Wow64PrepareForException );
3975 #undef GET_PTR
3976 imports_fixup_done = TRUE;
3979 RtlLeaveCriticalSection( &loader_section );
3980 pWow64LdrpInitialize( context );
3984 #else
3986 void *Wow64Transition = NULL;
3988 static void map_wow64cpu(void)
3990 SIZE_T size = 0;
3991 OBJECT_ATTRIBUTES attr;
3992 UNICODE_STRING string;
3993 HANDLE file, section;
3994 IO_STATUS_BLOCK io;
3995 NTSTATUS status;
3997 RtlInitUnicodeString( &string, L"\\??\\C:\\windows\\sysnative\\wow64cpu.dll" );
3998 InitializeObjectAttributes( &attr, &string, 0, NULL, NULL );
3999 if ((status = NtOpenFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ,
4000 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
4002 WARN("failed to open wow64cpu, status %#x\n", status);
4003 return;
4005 if (!NtCreateSection( &section, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
4006 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
4007 NULL, NULL, PAGE_EXECUTE_READ, SEC_COMMIT, file ))
4009 NtMapViewOfSection( section, NtCurrentProcess(), &Wow64Transition, 0,
4010 0, NULL, &size, ViewShare, 0, PAGE_EXECUTE_READ );
4011 NtClose( section );
4013 NtClose( file );
4016 static void init_wow64( CONTEXT *context )
4018 PEB *peb = NtCurrentTeb()->Peb;
4019 PEB64 *peb64 = UlongToPtr( NtCurrentTeb64()->Peb );
4021 if (Wow64Transition) return; /* already initialized */
4023 peb64->OSMajorVersion = peb->OSMajorVersion;
4024 peb64->OSMinorVersion = peb->OSMinorVersion;
4025 peb64->OSBuildNumber = peb->OSBuildNumber;
4026 peb64->OSPlatformId = peb->OSPlatformId;
4028 #define SET_INIT_BLOCK(func) LdrSystemDllInitBlock.p ## func = PtrToUlong( &func )
4029 SET_INIT_BLOCK( KiUserApcDispatcher );
4030 SET_INIT_BLOCK( KiUserExceptionDispatcher );
4031 SET_INIT_BLOCK( LdrInitializeThunk );
4032 SET_INIT_BLOCK( LdrSystemDllInitBlock );
4033 SET_INIT_BLOCK( RtlUserThreadStart );
4034 SET_INIT_BLOCK( KiUserCallbackDispatcher );
4035 /* SET_INIT_BLOCK( RtlpQueryProcessDebugInformationRemote ); */
4036 /* SET_INIT_BLOCK( RtlpFreezeTimeBias ); */
4037 /* LdrSystemDllInitBlock.ntdll_handle */
4038 #undef SET_INIT_BLOCK
4040 map_wow64cpu();
4042 #endif
4045 /* release some address space once dlls are loaded*/
4046 static void release_address_space(void)
4048 #ifndef _WIN64
4049 void *addr = (void *)1;
4050 SIZE_T size = 0;
4052 NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
4053 #endif
4056 /******************************************************************
4057 * LdrInitializeThunk (NTDLL.@)
4059 * Attach to all the loaded dlls.
4060 * If this is the first time, perform the full process initialization.
4062 void WINAPI LdrInitializeThunk( CONTEXT *context, ULONG_PTR unknown2, ULONG_PTR unknown3, ULONG_PTR unknown4 )
4064 static int attach_done;
4065 NTSTATUS status;
4066 ULONG_PTR cookie;
4067 WINE_MODREF *wm;
4068 void **entry;
4070 #ifdef __i386__
4071 entry = (void **)&context->Eax;
4072 #elif defined(__x86_64__)
4073 entry = (void **)&context->Rcx;
4074 #elif defined(__arm__)
4075 entry = (void **)&context->R0;
4076 #elif defined(__aarch64__)
4077 entry = (void **)&context->u.s.X0;
4078 #endif
4080 if (process_detaching) NtTerminateThread( GetCurrentThread(), 0 );
4082 RtlEnterCriticalSection( &loader_section );
4084 if (!imports_fixup_done)
4086 ANSI_STRING func_name;
4087 WINE_MODREF *kernel32;
4088 PEB *peb = NtCurrentTeb()->Peb;
4090 peb->LdrData = &ldr;
4091 peb->FastPebLock = &peb_lock;
4092 peb->TlsBitmap = &tls_bitmap;
4093 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
4094 peb->LoaderLock = &loader_section;
4095 peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL );
4097 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
4098 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
4099 sizeof(peb->TlsExpansionBitmapBits) * 8 );
4100 RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
4102 init_user_process_params();
4103 load_global_options();
4104 version_init();
4106 get_env_var( L"WINESYSTEMDLLPATH", 0, &system_dll_path );
4108 wm = build_main_module();
4109 wm->ldr.LoadCount = -1;
4111 build_ntdll_module();
4113 if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
4115 if ((status = load_dll( NULL, L"kernel32.dll", 0, &kernel32, FALSE )) != STATUS_SUCCESS)
4117 MESSAGE( "wine: could not load kernel32.dll, status %x\n", status );
4118 NtTerminateProcess( GetCurrentProcess(), status );
4120 kernel32_handle = kernel32->ldr.DllBase;
4121 node_kernel32 = kernel32->ldr.DdagNode;
4122 RtlInitAnsiString( &func_name, "BaseThreadInitThunk" );
4123 if ((status = LdrGetProcedureAddress( kernel32_handle, &func_name,
4124 0, (void **)&pBaseThreadInitThunk )) != STATUS_SUCCESS)
4126 MESSAGE( "wine: could not find BaseThreadInitThunk in kernel32.dll, status %x\n", status );
4127 NtTerminateProcess( GetCurrentProcess(), status );
4129 RtlInitAnsiString( &func_name, "CtrlRoutine" );
4130 LdrGetProcedureAddress( kernel32_handle, &func_name, 0, (void **)&pCtrlRoutine );
4132 locale_init();
4133 actctx_init();
4134 if (wm->ldr.Flags & LDR_COR_ILONLY)
4135 status = fixup_imports_ilonly( wm, NULL, entry );
4136 else
4137 status = fixup_imports( wm, NULL );
4139 if (status)
4141 ERR( "Importing dlls for %s failed, status %x\n",
4142 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4143 NtTerminateProcess( GetCurrentProcess(), status );
4145 imports_fixup_done = TRUE;
4147 else wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
4149 #ifdef _WIN64
4150 if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
4151 #endif
4153 RtlAcquirePebLock();
4154 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
4155 RtlReleasePebLock();
4157 NtCurrentTeb()->FlsSlots = fls_alloc_data();
4159 if (!attach_done) /* first time around */
4161 attach_done = 1;
4162 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4164 ERR( "TLS init failed when loading %s, status %x\n",
4165 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4166 NtTerminateProcess( GetCurrentProcess(), status );
4168 wm->ldr.Flags |= LDR_PROCESS_ATTACHED; /* don't try to attach again */
4169 if (wm->ldr.ActivationContext)
4170 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
4172 if ((status = process_attach( node_ntdll, context ))
4173 || (status = process_attach( node_kernel32, context )))
4175 ERR( "Initializing system dll for %s failed, status %x\n",
4176 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4177 NtTerminateProcess( GetCurrentProcess(), status );
4180 if ((status = walk_node_dependencies( wm->ldr.DdagNode, context, process_attach )))
4182 if (last_failed_modref)
4183 ERR( "%s failed to initialize, aborting\n",
4184 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
4185 ERR( "Initializing dlls for %s failed, status %x\n",
4186 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4187 NtTerminateProcess( GetCurrentProcess(), status );
4189 release_address_space();
4190 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
4191 if (wm->ldr.Flags & LDR_WINE_INTERNAL) unix_funcs->init_builtin_dll( wm->ldr.DllBase );
4192 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
4193 process_breakpoint();
4195 else
4197 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4198 NtTerminateThread( GetCurrentThread(), status );
4199 thread_attach();
4200 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH );
4203 RtlLeaveCriticalSection( &loader_section );
4204 signal_start_thread( context );
4208 /***********************************************************************
4209 * RtlImageDirectoryEntryToData (NTDLL.@)
4211 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
4213 const IMAGE_NT_HEADERS *nt;
4214 DWORD addr;
4216 if ((ULONG_PTR)module & 1) image = FALSE; /* mapped as data file */
4217 module = (HMODULE)((ULONG_PTR)module & ~3);
4218 if (!(nt = RtlImageNtHeader( module ))) return NULL;
4219 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
4221 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
4223 if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4224 if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4225 *size = nt64->OptionalHeader.DataDirectory[dir].Size;
4226 if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4228 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
4230 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
4232 if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4233 if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4234 *size = nt32->OptionalHeader.DataDirectory[dir].Size;
4235 if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4237 else return NULL;
4239 /* not mapped as image, need to find the section containing the virtual address */
4240 return RtlImageRvaToVa( nt, module, addr, NULL );
4244 /***********************************************************************
4245 * RtlImageRvaToSection (NTDLL.@)
4247 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
4248 HMODULE module, DWORD rva )
4250 int i;
4251 const IMAGE_SECTION_HEADER *sec;
4253 sec = (const IMAGE_SECTION_HEADER*)((const char*)&nt->OptionalHeader +
4254 nt->FileHeader.SizeOfOptionalHeader);
4255 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
4257 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4258 return (PIMAGE_SECTION_HEADER)sec;
4260 return NULL;
4264 /***********************************************************************
4265 * RtlImageRvaToVa (NTDLL.@)
4267 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
4268 DWORD rva, IMAGE_SECTION_HEADER **section )
4270 IMAGE_SECTION_HEADER *sec;
4272 if (section && *section) /* try this section first */
4274 sec = *section;
4275 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4276 goto found;
4278 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
4279 found:
4280 if (section) *section = sec;
4281 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
4285 /***********************************************************************
4286 * RtlPcToFileHeader (NTDLL.@)
4288 PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
4290 LDR_DATA_TABLE_ENTRY *module;
4291 PVOID ret = NULL;
4293 RtlEnterCriticalSection( &loader_section );
4294 if (!LdrFindEntryForAddress( pc, &module )) ret = module->DllBase;
4295 RtlLeaveCriticalSection( &loader_section );
4296 *address = ret;
4297 return ret;
4301 /****************************************************************************
4302 * LdrGetDllDirectory (NTDLL.@)
4304 NTSTATUS WINAPI LdrGetDllDirectory( UNICODE_STRING *dir )
4306 NTSTATUS status = STATUS_SUCCESS;
4308 RtlEnterCriticalSection( &dlldir_section );
4309 dir->Length = dll_directory.Length + sizeof(WCHAR);
4310 if (dir->MaximumLength >= dir->Length) RtlCopyUnicodeString( dir, &dll_directory );
4311 else
4313 status = STATUS_BUFFER_TOO_SMALL;
4314 if (dir->MaximumLength) dir->Buffer[0] = 0;
4316 RtlLeaveCriticalSection( &dlldir_section );
4317 return status;
4321 /****************************************************************************
4322 * LdrSetDllDirectory (NTDLL.@)
4324 NTSTATUS WINAPI LdrSetDllDirectory( const UNICODE_STRING *dir )
4326 NTSTATUS status = STATUS_SUCCESS;
4327 UNICODE_STRING new;
4329 if (!dir->Buffer) RtlInitUnicodeString( &new, NULL );
4330 else if ((status = RtlDuplicateUnicodeString( 1, dir, &new ))) return status;
4332 RtlEnterCriticalSection( &dlldir_section );
4333 RtlFreeUnicodeString( &dll_directory );
4334 dll_directory = new;
4335 RtlLeaveCriticalSection( &dlldir_section );
4336 return status;
4340 /****************************************************************************
4341 * LdrAddDllDirectory (NTDLL.@)
4343 NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
4345 FILE_BASIC_INFORMATION info;
4346 UNICODE_STRING nt_name;
4347 NTSTATUS status;
4348 OBJECT_ATTRIBUTES attr;
4349 DWORD len;
4350 struct dll_dir_entry *ptr;
4351 DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );
4353 if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
4354 return STATUS_INVALID_PARAMETER;
4356 status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );
4357 if (status) return status;
4358 len = nt_name.Length / sizeof(WCHAR);
4359 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] ))))
4360 return STATUS_NO_MEMORY;
4361 memcpy( ptr->dir, nt_name.Buffer, len * sizeof(WCHAR) );
4363 attr.Length = sizeof(attr);
4364 attr.RootDirectory = 0;
4365 attr.Attributes = OBJ_CASE_INSENSITIVE;
4366 attr.ObjectName = &nt_name;
4367 attr.SecurityDescriptor = NULL;
4368 attr.SecurityQualityOfService = NULL;
4369 status = NtQueryAttributesFile( &attr, &info );
4370 RtlFreeUnicodeString( &nt_name );
4372 if (!status)
4374 TRACE( "%s\n", debugstr_w( ptr->dir ));
4375 RtlEnterCriticalSection( &dlldir_section );
4376 list_add_head( &dll_dir_list, &ptr->entry );
4377 RtlLeaveCriticalSection( &dlldir_section );
4378 *cookie = ptr;
4380 else RtlFreeHeap( GetProcessHeap(), 0, ptr );
4381 return status;
4385 /****************************************************************************
4386 * LdrRemoveDllDirectory (NTDLL.@)
4388 NTSTATUS WINAPI LdrRemoveDllDirectory( void *cookie )
4390 struct dll_dir_entry *ptr = cookie;
4392 TRACE( "%s\n", debugstr_w( ptr->dir ));
4394 RtlEnterCriticalSection( &dlldir_section );
4395 list_remove( &ptr->entry );
4396 RtlFreeHeap( GetProcessHeap(), 0, ptr );
4397 RtlLeaveCriticalSection( &dlldir_section );
4398 return STATUS_SUCCESS;
4402 /*************************************************************************
4403 * LdrSetDefaultDllDirectories (NTDLL.@)
4405 NTSTATUS WINAPI LdrSetDefaultDllDirectories( ULONG flags )
4407 /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
4408 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4409 LOAD_LIBRARY_SEARCH_USER_DIRS |
4410 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4411 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4413 if (!flags || (flags & ~load_library_search_flags)) return STATUS_INVALID_PARAMETER;
4414 default_search_flags = flags;
4415 return STATUS_SUCCESS;
4419 /******************************************************************
4420 * LdrGetDllPath (NTDLL.@)
4422 NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *unknown )
4424 NTSTATUS status;
4425 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
4426 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4427 LOAD_LIBRARY_SEARCH_USER_DIRS |
4428 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4429 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4431 if (flags & LOAD_WITH_ALTERED_SEARCH_PATH)
4433 if (flags & load_library_search_flags) return STATUS_INVALID_PARAMETER;
4434 if (default_search_flags) flags |= default_search_flags | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
4436 else if (!(flags & load_library_search_flags)) flags |= default_search_flags;
4438 RtlEnterCriticalSection( &dlldir_section );
4440 if (flags & load_library_search_flags)
4442 status = get_dll_load_path_search_flags( module, flags, path );
4444 else
4446 const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL;
4447 if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH) || !wcschr( module, L'\\' ))
4448 module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4449 status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
4452 RtlLeaveCriticalSection( &dlldir_section );
4453 *unknown = NULL;
4454 return status;
4458 /*************************************************************************
4459 * RtlSetSearchPathMode (NTDLL.@)
4461 NTSTATUS WINAPI RtlSetSearchPathMode( ULONG flags )
4463 int val;
4465 switch (flags)
4467 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE:
4468 val = 1;
4469 break;
4470 case BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE:
4471 val = 0;
4472 break;
4473 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT:
4474 InterlockedExchange( &path_safe_mode, 2 );
4475 return STATUS_SUCCESS;
4476 default:
4477 return STATUS_INVALID_PARAMETER;
4480 for (;;)
4482 LONG prev = path_safe_mode;
4483 if (prev == 2) break; /* permanently set */
4484 if (InterlockedCompareExchange( &path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4486 return STATUS_ACCESS_DENIED;
4490 /******************************************************************
4491 * RtlGetExePath (NTDLL.@)
4493 NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
4495 const WCHAR *dlldir = L".";
4496 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4498 /* same check as NeedCurrentDirectoryForExePathW */
4499 if (!wcschr( name, '\\' ))
4501 UNICODE_STRING name, value = { 0 };
4503 RtlInitUnicodeString( &name, L"NoDefaultCurrentDirectoryInExePath" );
4504 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4505 dlldir = L"";
4507 return get_dll_load_path( module, dlldir, FALSE, path );
4511 /******************************************************************
4512 * RtlGetSearchPath (NTDLL.@)
4514 NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
4516 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4517 return get_dll_load_path( module, NULL, path_safe_mode, path );
4521 /******************************************************************
4522 * RtlReleasePath (NTDLL.@)
4524 void WINAPI RtlReleasePath( PWSTR path )
4526 RtlFreeHeap( GetProcessHeap(), 0, path );
4530 /*********************************************************************
4531 * ApiSetQueryApiSetPresence (NTDLL.@)
4533 NTSTATUS WINAPI ApiSetQueryApiSetPresence( const UNICODE_STRING *name, BOOLEAN *present )
4535 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
4536 const API_SET_NAMESPACE_ENTRY *entry;
4537 UNICODE_STRING str;
4539 *present = (!get_apiset_entry( map, name->Buffer, name->Length / sizeof(WCHAR), &entry ) &&
4540 !get_apiset_target( map, entry, NULL, &str ));
4541 return STATUS_SUCCESS;
4545 /*********************************************************************
4546 * ApiSetQueryApiSetPresenceEx (NTDLL.@)
4548 NTSTATUS WINAPI ApiSetQueryApiSetPresenceEx( const UNICODE_STRING *name, BOOLEAN *in_schema, BOOLEAN *present )
4550 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
4551 const API_SET_NAMESPACE_ENTRY *entry;
4552 NTSTATUS status;
4553 UNICODE_STRING str;
4554 ULONG i, len = name->Length / sizeof(WCHAR);
4556 /* extension not allowed */
4557 for (i = 0; i < len; i++) if (name->Buffer[i] == '.') return STATUS_INVALID_PARAMETER;
4559 status = get_apiset_entry( map, name->Buffer, len, &entry );
4560 if (status == STATUS_APISET_NOT_PRESENT)
4562 *in_schema = *present = FALSE;
4563 return STATUS_SUCCESS;
4565 if (status) return status;
4567 /* the name must match exactly */
4568 *in_schema = (entry->NameLength == name->Length &&
4569 !wcsnicmp( (WCHAR *)((char *)map + entry->NameOffset), name->Buffer, len ));
4570 *present = *in_schema && !get_apiset_target( map, entry, NULL, &str );
4571 return STATUS_SUCCESS;
4575 /******************************************************************
4576 * DllMain (NTDLL.@)
4578 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4580 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
4581 return TRUE;
4585 static NTSTATUS CDECL load_so_dll_fallback( UNICODE_STRING *nt_name, void **module )
4587 return STATUS_INVALID_IMAGE_FORMAT;
4590 static void CDECL init_builtin_dll_fallback( void *module )
4594 static NTSTATUS CDECL unwind_builtin_dll_fallback( ULONG type, struct _DISPATCHER_CONTEXT *dispatch,
4595 CONTEXT *context )
4597 return STATUS_UNSUCCESSFUL;
4600 static LONGLONG WINAPI RtlGetSystemTimePrecise_fallback(void)
4602 LARGE_INTEGER now;
4603 NtQuerySystemTime( &now );
4604 return now.QuadPart;
4607 static const struct unix_funcs unix_fallbacks =
4609 load_so_dll_fallback,
4610 init_builtin_dll_fallback,
4611 unwind_builtin_dll_fallback,
4612 RtlGetSystemTimePrecise_fallback,
4615 const struct unix_funcs *unix_funcs = &unix_fallbacks;
4617 /***********************************************************************
4618 * __wine_set_unix_funcs
4620 NTSTATUS CDECL __wine_set_unix_funcs( int version, const struct unix_funcs *funcs )
4622 if (version != NTDLL_UNIXLIB_VERSION) return STATUS_REVISION_MISMATCH;
4623 unix_funcs = funcs;
4624 return STATUS_SUCCESS;