include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / ntdll / loader.c
blobbad1492e138d0f77e6f08a6deaad8efee68b6a56
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 #include "windef.h"
29 #include "winnt.h"
30 #include "winioctl.h"
31 #include "winternl.h"
32 #include "delayloadhandler.h"
34 #include "wine/exception.h"
35 #include "wine/debug.h"
36 #include "wine/list.h"
37 #include "ntdll_misc.h"
38 #include "ddk/ntddk.h"
39 #include "ddk/wdm.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(module);
42 WINE_DECLARE_DEBUG_CHANNEL(relay);
43 WINE_DECLARE_DEBUG_CHANNEL(snoop);
44 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
45 WINE_DECLARE_DEBUG_CHANNEL(imports);
47 #ifdef _WIN64
48 #define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
49 #endif
50 #define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
51 #define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
53 #ifdef __i386__
54 static const WCHAR pe_dir[] = L"\\i386-windows";
55 #elif defined __x86_64__
56 static const WCHAR pe_dir[] = L"\\x86_64-windows";
57 #elif defined __arm__
58 static const WCHAR pe_dir[] = L"\\arm-windows";
59 #elif defined __aarch64__
60 static const WCHAR pe_dir[] = L"\\aarch64-windows";
61 #else
62 static const WCHAR pe_dir[] = L"";
63 #endif
65 /* we don't want to include winuser.h */
66 #define RT_MANIFEST ((ULONG_PTR)24)
67 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
69 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
70 typedef void (CALLBACK *LDRENUMPROC)(LDR_DATA_TABLE_ENTRY *, void *, BOOLEAN *);
72 void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) = NULL;
73 NTSTATUS (WINAPI *__wine_unix_call_dispatcher)( unixlib_handle_t, unsigned int, void * ) = NULL;
75 static DWORD (WINAPI *pCtrlRoutine)(void *);
77 SYSTEM_DLL_INIT_BLOCK LdrSystemDllInitBlock = { 0xf0 };
79 void *__wine_syscall_dispatcher = NULL;
80 unixlib_handle_t __wine_unixlib_handle = 0;
82 /* windows directory */
83 const WCHAR windows_dir[] = L"C:\\windows";
84 /* system directory with trailing backslash */
85 const WCHAR system_dir[] = L"C:\\windows\\system32\\";
87 /* system search path */
88 static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows";
90 static BOOL is_prefix_bootstrap; /* are we bootstrapping the prefix? */
91 static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */
92 static BOOL process_detaching = FALSE; /* set on process detach to avoid deadlocks with thread detach */
93 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
94 static LONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
95 static LONG dll_safe_mode = 1; /* dll search mode */
96 static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
97 static UNICODE_STRING system_dll_path; /* path to search for system dependency dlls */
98 static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
99 static WCHAR *default_load_path; /* default dll search path */
101 struct dll_dir_entry
103 struct list entry;
104 WCHAR dir[1];
107 static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from LdrAddDllDirectory */
109 struct ldr_notification
111 struct list entry;
112 PLDR_DLL_NOTIFICATION_FUNCTION callback;
113 void *context;
116 static struct list ldr_notifications = LIST_INIT( ldr_notifications );
118 static const char * const reason_names[] =
120 "PROCESS_DETACH",
121 "PROCESS_ATTACH",
122 "THREAD_ATTACH",
123 "THREAD_DETACH",
126 struct file_id
128 BYTE ObjectId[16];
131 /* internal representation of loaded modules */
132 typedef struct _wine_modref
134 LDR_DATA_TABLE_ENTRY ldr;
135 struct file_id id;
136 ULONG CheckSum;
137 BOOL system;
138 } WINE_MODREF;
140 static UINT tls_module_count; /* number of modules with TLS directory */
141 static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
142 static LIST_ENTRY tls_links = { &tls_links, &tls_links };
144 static RTL_CRITICAL_SECTION loader_section;
145 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
147 0, 0, &loader_section,
148 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
149 0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
151 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
153 static CRITICAL_SECTION dlldir_section;
154 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
156 0, 0, &dlldir_section,
157 { &dlldir_critsect_debug.ProcessLocksList, &dlldir_critsect_debug.ProcessLocksList },
158 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
160 static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 };
162 static RTL_CRITICAL_SECTION peb_lock;
163 static RTL_CRITICAL_SECTION_DEBUG peb_critsect_debug =
165 0, 0, &peb_lock,
166 { &peb_critsect_debug.ProcessLocksList, &peb_critsect_debug.ProcessLocksList },
167 0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
169 static RTL_CRITICAL_SECTION peb_lock = { &peb_critsect_debug, -1, 0, 0, 0, 0 };
171 static PEB_LDR_DATA ldr =
173 sizeof(ldr), TRUE, NULL,
174 { &ldr.InLoadOrderModuleList, &ldr.InLoadOrderModuleList },
175 { &ldr.InMemoryOrderModuleList, &ldr.InMemoryOrderModuleList },
176 { &ldr.InInitializationOrderModuleList, &ldr.InInitializationOrderModuleList }
179 static RTL_BITMAP tls_bitmap;
180 static RTL_BITMAP tls_expansion_bitmap;
182 static WINE_MODREF *cached_modref;
183 static WINE_MODREF *current_modref;
184 static WINE_MODREF *last_failed_modref;
186 static LDR_DDAG_NODE *node_ntdll, *node_kernel32;
188 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system );
189 static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved );
190 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
191 DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
192 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
193 DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
195 /* convert PE image VirtualAddress to Real Address */
196 static inline void *get_rva( HMODULE module, DWORD va )
198 return (void *)((char *)module + va);
201 /* check whether the file name contains a path */
202 static inline BOOL contains_path( LPCWSTR name )
204 return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
207 #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
209 typedef struct _RTL_UNLOAD_EVENT_TRACE
211 void *BaseAddress;
212 SIZE_T SizeOfImage;
213 ULONG Sequence;
214 ULONG TimeDateStamp;
215 ULONG CheckSum;
216 WCHAR ImageName[32];
217 } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;
219 static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER];
220 static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr;
221 static unsigned int unload_trace_seq;
223 static void module_push_unload_trace( const WINE_MODREF *wm )
225 RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq];
226 const LDR_DATA_TABLE_ENTRY *ldr = &wm->ldr;
227 unsigned int len = min(sizeof(ptr->ImageName) - sizeof(WCHAR), ldr->BaseDllName.Length);
229 ptr->BaseAddress = ldr->DllBase;
230 ptr->SizeOfImage = ldr->SizeOfImage;
231 ptr->Sequence = unload_trace_seq;
232 ptr->TimeDateStamp = ldr->TimeDateStamp;
233 ptr->CheckSum = wm->CheckSum;
234 memcpy(ptr->ImageName, ldr->BaseDllName.Buffer, len);
235 ptr->ImageName[len / sizeof(*ptr->ImageName)] = 0;
237 unload_trace_seq = (unload_trace_seq + 1) % ARRAY_SIZE(unload_traces);
238 unload_trace_ptr = unload_traces;
241 #ifdef __arm64ec__
243 static void update_hybrid_pointer( void *module, const IMAGE_SECTION_HEADER *sec, UINT rva, void *ptr )
245 if (!rva) return;
247 if (rva < sec->VirtualAddress || rva >= sec->VirtualAddress + sec->Misc.VirtualSize)
248 ERR( "rva %x outside of section %s (%lx-%lx)\n", rva,
249 sec->Name, sec->VirtualAddress, sec->VirtualAddress + sec->Misc.VirtualSize );
250 else
251 *(void **)get_rva( module, rva ) = ptr;
254 static void update_hybrid_metadata( void *module, IMAGE_NT_HEADERS *nt,
255 const IMAGE_ARM64EC_METADATA *metadata )
257 DWORD i, protect_old;
258 const IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
260 /* assume that all pointers are in the same section */
262 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
264 if ((sec->VirtualAddress <= metadata->__os_arm64x_dispatch_call) &&
265 (sec->VirtualAddress + sec->Misc.VirtualSize > metadata->__os_arm64x_dispatch_call))
267 void *base = get_rva( module, sec->VirtualAddress );
268 SIZE_T size = sec->Misc.VirtualSize;
270 NtProtectVirtualMemory( NtCurrentProcess(), &base, &size, PAGE_READWRITE, &protect_old );
272 #define SET_FUNC(func,val) update_hybrid_pointer( module, sec, metadata->func, val )
273 SET_FUNC( __os_arm64x_dispatch_call, __os_arm64x_check_call );
274 SET_FUNC( __os_arm64x_dispatch_call_no_redirect, __os_arm64x_dispatch_call_no_redirect );
275 SET_FUNC( __os_arm64x_dispatch_fptr, __os_arm64x_dispatch_fptr );
276 SET_FUNC( __os_arm64x_dispatch_icall, __os_arm64x_check_icall );
277 SET_FUNC( __os_arm64x_dispatch_icall_cfg, __os_arm64x_check_icall_cfg );
278 SET_FUNC( __os_arm64x_dispatch_ret, __os_arm64x_dispatch_ret );
279 SET_FUNC( __os_arm64x_helper0, __os_arm64x_helper0 );
280 SET_FUNC( __os_arm64x_helper1, __os_arm64x_helper1 );
281 SET_FUNC( __os_arm64x_helper2, __os_arm64x_helper2 );
282 SET_FUNC( __os_arm64x_helper3, __os_arm64x_helper3 );
283 SET_FUNC( __os_arm64x_helper4, __os_arm64x_helper4 );
284 SET_FUNC( __os_arm64x_helper5, __os_arm64x_helper5 );
285 SET_FUNC( __os_arm64x_helper6, __os_arm64x_helper6 );
286 SET_FUNC( __os_arm64x_helper7, __os_arm64x_helper7 );
287 SET_FUNC( __os_arm64x_helper8, __os_arm64x_helper8 );
288 SET_FUNC( GetX64InformationFunctionPointer, __os_arm64x_get_x64_information );
289 SET_FUNC( SetX64InformationFunctionPointer, __os_arm64x_set_x64_information );
290 #undef SET_FUNC
292 NtProtectVirtualMemory( NtCurrentProcess(), &base, &size, protect_old, &protect_old );
293 return;
296 ERR( "module %p no section found for %lx\n", module, metadata->__os_arm64x_dispatch_call );
299 #endif
301 /*********************************************************************
302 * RtlGetUnloadEventTrace [NTDLL.@]
304 RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
306 return unload_traces;
309 /*********************************************************************
310 * RtlGetUnloadEventTraceEx [NTDLL.@]
312 void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
314 static ULONG element_size = sizeof(*unload_traces);
315 static ULONG element_count = ARRAY_SIZE(unload_traces);
317 *size = &element_size;
318 *count = &element_count;
319 *trace = &unload_trace_ptr;
322 /*************************************************************************
323 * call_dll_entry_point
325 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
326 * their entry point, so we need a small asm wrapper. Testing indicates
327 * that only modifying esi leads to a crash, so use this one to backup
328 * ebp while running the dll entry proc.
330 #if defined(__i386__)
331 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
332 __ASM_GLOBAL_FUNC(call_dll_entry_point,
333 "pushl %ebp\n\t"
334 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
335 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
336 "movl %esp,%ebp\n\t"
337 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
338 "pushl %ebx\n\t"
339 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
340 "pushl %esi\n\t"
341 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
342 "pushl %edi\n\t"
343 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
344 "movl %ebp,%esi\n\t"
345 __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
346 "pushl 20(%ebp)\n\t"
347 "pushl 16(%ebp)\n\t"
348 "pushl 12(%ebp)\n\t"
349 "movl 8(%ebp),%eax\n\t"
350 "call *%eax\n\t"
351 "movl %esi,%ebp\n\t"
352 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
353 "leal -12(%ebp),%esp\n\t"
354 "popl %edi\n\t"
355 __ASM_CFI(".cfi_same_value %edi\n\t")
356 "popl %esi\n\t"
357 __ASM_CFI(".cfi_same_value %esi\n\t")
358 "popl %ebx\n\t"
359 __ASM_CFI(".cfi_same_value %ebx\n\t")
360 "popl %ebp\n\t"
361 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
362 __ASM_CFI(".cfi_same_value %ebp\n\t")
363 "ret" )
364 #elif defined(__x86_64__) && !defined(__arm64ec__)
365 extern BOOL CDECL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
366 /* Some apps modify rbx in TLS entry point. */
367 __ASM_GLOBAL_FUNC(call_dll_entry_point,
368 "pushq %rbx\n\t"
369 __ASM_SEH(".seh_pushreg %rbx\n\t")
370 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
371 __ASM_CFI(".cfi_rel_offset %rbx,0\n\t")
372 "subq $48,%rsp\n\t"
373 __ASM_SEH(".seh_stackalloc 48\n\t")
374 __ASM_SEH(".seh_endprologue\n\t")
375 __ASM_CFI(".cfi_adjust_cfa_offset 48\n\t")
376 "mov %rcx,%r10\n\t"
377 "mov %rdx,%rcx\n\t"
378 "mov %r8d,%edx\n\t"
379 "mov %r9,%r8\n\t"
380 "call *%r10\n\t"
381 "addq $48,%rsp\n\t"
382 __ASM_CFI(".cfi_adjust_cfa_offset -48\n\t")
383 "popq %rbx\n\t"
384 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
385 __ASM_CFI(".cfi_same_value %rbx\n\t")
386 "ret" )
387 #else
388 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
389 UINT reason, void *reserved )
391 return proc( module, reason, reserved );
393 #endif
396 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
397 /*************************************************************************
398 * stub_entry_point
400 * Entry point for stub functions.
402 static void WINAPI stub_entry_point( const char *dll, const char *name, void *ret_addr )
404 EXCEPTION_RECORD rec;
406 rec.ExceptionCode = EXCEPTION_WINE_STUB;
407 rec.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
408 rec.ExceptionRecord = NULL;
409 rec.ExceptionAddress = ret_addr;
410 rec.NumberParameters = 2;
411 rec.ExceptionInformation[0] = (ULONG_PTR)dll;
412 rec.ExceptionInformation[1] = (ULONG_PTR)name;
413 for (;;) RtlRaiseException( &rec );
417 #include "pshpack1.h"
418 #ifdef __i386__
419 struct stub
421 BYTE pushl1; /* pushl $name */
422 const char *name;
423 BYTE pushl2; /* pushl $dll */
424 const char *dll;
425 BYTE call; /* call stub_entry_point */
426 DWORD entry;
428 #elif defined(__arm__)
429 struct stub
431 DWORD ldr_r0; /* ldr r0, $dll */
432 DWORD ldr_r1; /* ldr r1, $name */
433 DWORD mov_r2_lr; /* mov r2, lr */
434 DWORD ldr_pc_pc; /* ldr pc, [pc, #4] */
435 const char *dll;
436 const char *name;
437 const void* entry;
439 #elif defined(__aarch64__)
440 struct stub
442 DWORD ldr_x0; /* ldr x0, $dll */
443 DWORD ldr_x1; /* ldr x1, $name */
444 DWORD mov_x2_lr; /* mov x2, lr */
445 DWORD ldr_x16; /* ldr x16, $entry */
446 DWORD br_x16; /* br x16 */
447 const char *dll;
448 const char *name;
449 const void *entry;
451 #else
452 struct stub
454 BYTE movq_rdi[2]; /* movq $dll,%rdi */
455 const char *dll;
456 BYTE movq_rsi[2]; /* movq $name,%rsi */
457 const char *name;
458 BYTE movq_rsp_rdx[4]; /* movq (%rsp),%rdx */
459 BYTE movq_rax[2]; /* movq $entry, %rax */
460 const void* entry;
461 BYTE jmpq_rax[2]; /* jmp %rax */
463 #endif
464 #include "poppack.h"
466 /*************************************************************************
467 * allocate_stub
469 * Allocate a stub entry point.
471 static ULONG_PTR allocate_stub( const char *dll, const char *name )
473 #define MAX_SIZE 65536
474 static struct stub *stubs;
475 static unsigned int nb_stubs;
476 struct stub *stub;
478 if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
480 if (!stubs)
482 SIZE_T size = MAX_SIZE;
483 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
484 MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
485 return 0xdeadbeef;
487 stub = &stubs[nb_stubs++];
488 #ifdef __i386__
489 stub->pushl1 = 0x68; /* pushl $name */
490 stub->name = name;
491 stub->pushl2 = 0x68; /* pushl $dll */
492 stub->dll = dll;
493 stub->call = 0xe8; /* call stub_entry_point */
494 stub->entry = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
495 #elif defined(__arm__)
496 stub->ldr_r0 = 0xe59f0008; /* ldr r0, [pc, #8] ($dll) */
497 stub->ldr_r1 = 0xe59f1008; /* ldr r1, [pc, #8] ($name) */
498 stub->mov_r2_lr = 0xe1a0200e; /* mov r2, lr */
499 stub->ldr_pc_pc = 0xe59ff004; /* ldr pc, [pc, #4] */
500 stub->dll = dll;
501 stub->name = name;
502 stub->entry = stub_entry_point;
503 #elif defined(__aarch64__)
504 stub->ldr_x0 = 0x580000a0; /* ldr x0, #20 ($dll) */
505 stub->ldr_x1 = 0x580000c1; /* ldr x1, #24 ($name) */
506 stub->mov_x2_lr = 0xaa1e03e2; /* mov x2, lr */
507 stub->ldr_x16 = 0x580000d0; /* ldr x16, #24 ($entry) */
508 stub->br_x16 = 0xd61f0200; /* br x16 */
509 stub->dll = dll;
510 stub->name = name;
511 stub->entry = stub_entry_point;
512 #else
513 stub->movq_rdi[0] = 0x48; /* movq $dll,%rcx */
514 stub->movq_rdi[1] = 0xb9;
515 stub->dll = dll;
516 stub->movq_rsi[0] = 0x48; /* movq $name,%rdx */
517 stub->movq_rsi[1] = 0xba;
518 stub->name = name;
519 stub->movq_rsp_rdx[0] = 0x4c; /* movq (%rsp),%r8 */
520 stub->movq_rsp_rdx[1] = 0x8b;
521 stub->movq_rsp_rdx[2] = 0x04;
522 stub->movq_rsp_rdx[3] = 0x24;
523 stub->movq_rax[0] = 0x48; /* movq $entry, %rax */
524 stub->movq_rax[1] = 0xb8;
525 stub->entry = stub_entry_point;
526 stub->jmpq_rax[0] = 0xff; /* jmp %rax */
527 stub->jmpq_rax[1] = 0xe0;
528 #endif
529 return (ULONG_PTR)stub;
532 #else /* __i386__ */
533 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
534 #endif /* __i386__ */
536 /* call ldr notifications */
537 static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
539 struct ldr_notification *notify, *notify_next;
540 LDR_DLL_NOTIFICATION_DATA data;
542 data.Loaded.Flags = 0;
543 data.Loaded.FullDllName = &module->FullDllName;
544 data.Loaded.BaseDllName = &module->BaseDllName;
545 data.Loaded.DllBase = module->DllBase;
546 data.Loaded.SizeOfImage = module->SizeOfImage;
548 LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
550 TRACE_(relay)("\1Call LDR notification callback (proc=%p,reason=%lu,data=%p,context=%p)\n",
551 notify->callback, reason, &data, notify->context );
553 notify->callback(reason, &data, notify->context);
555 TRACE_(relay)("\1Ret LDR notification callback (proc=%p,reason=%lu,data=%p,context=%p)\n",
556 notify->callback, reason, &data, notify->context );
560 /*************************************************************************
561 * get_modref
563 * Looks for the referenced HMODULE in the current process
564 * The loader_section must be locked while calling this function.
566 static WINE_MODREF *get_modref( HMODULE hmod )
568 PLIST_ENTRY mark, entry;
569 PLDR_DATA_TABLE_ENTRY mod;
571 if (cached_modref && cached_modref->ldr.DllBase == hmod) return cached_modref;
573 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
574 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
576 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
577 if (mod->DllBase == hmod)
578 return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
580 return NULL;
584 /**********************************************************************
585 * find_basename_module
587 * Find a module from its base name.
588 * The loader_section must be locked while calling this function
590 static WINE_MODREF *find_basename_module( LPCWSTR name )
592 PLIST_ENTRY mark, entry;
593 UNICODE_STRING name_str;
595 RtlInitUnicodeString( &name_str, name );
597 if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
598 return cached_modref;
600 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
601 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
603 WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.InLoadOrderLinks);
604 if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && !mod->system)
606 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
607 return cached_modref;
610 return NULL;
614 /**********************************************************************
615 * find_fullname_module
617 * Find a module from its full path name.
618 * The loader_section must be locked while calling this function
620 static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
622 PLIST_ENTRY mark, entry;
623 UNICODE_STRING name = *nt_name;
625 if (name.Length <= 4 * sizeof(WCHAR)) return NULL;
626 name.Length -= 4 * sizeof(WCHAR); /* for \??\ prefix */
627 name.Buffer += 4;
629 if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE ))
630 return cached_modref;
632 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
633 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
635 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
636 if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
638 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
639 return cached_modref;
642 return NULL;
646 /**********************************************************************
647 * find_fileid_module
649 * Find a module from its file id.
650 * The loader_section must be locked while calling this function
652 static WINE_MODREF *find_fileid_module( const struct file_id *id )
654 LIST_ENTRY *mark, *entry;
656 if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref;
658 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
659 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
661 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
662 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
664 if (!memcmp( &wm->id, id, sizeof(*id) ))
666 cached_modref = wm;
667 return wm;
670 return NULL;
674 /******************************************************************************
675 * get_apiset_entry
677 static NTSTATUS get_apiset_entry( const API_SET_NAMESPACE *map, const WCHAR *name, ULONG len,
678 const API_SET_NAMESPACE_ENTRY **entry )
680 const API_SET_HASH_ENTRY *hash_entry;
681 ULONG hash, i, hash_len;
682 int min, max;
684 if (len <= 4) return STATUS_INVALID_PARAMETER;
685 if (wcsnicmp( name, L"api-", 4 ) && wcsnicmp( name, L"ext-", 4 )) return STATUS_INVALID_PARAMETER;
686 if (!map) return STATUS_APISET_NOT_PRESENT;
688 for (i = hash_len = 0; i < len; i++)
690 if (name[i] == '.') break;
691 if (name[i] == '-') hash_len = i;
693 for (i = hash = 0; i < hash_len; i++)
694 hash = hash * map->HashFactor + ((name[i] >= 'A' && name[i] <= 'Z') ? name[i] + 32 : name[i]);
696 hash_entry = (API_SET_HASH_ENTRY *)((char *)map + map->HashOffset);
697 min = 0;
698 max = map->Count - 1;
699 while (min <= max)
701 int pos = (min + max) / 2;
702 if (hash_entry[pos].Hash < hash) min = pos + 1;
703 else if (hash_entry[pos].Hash > hash) max = pos - 1;
704 else
706 *entry = (API_SET_NAMESPACE_ENTRY *)((char *)map + map->EntryOffset) + hash_entry[pos].Index;
707 if ((*entry)->HashedLength != hash_len * sizeof(WCHAR)) break;
708 if (wcsnicmp( (WCHAR *)((char *)map + (*entry)->NameOffset), name, hash_len )) break;
709 return STATUS_SUCCESS;
712 return STATUS_APISET_NOT_PRESENT;
716 /******************************************************************************
717 * get_apiset_target
719 static NTSTATUS get_apiset_target( const API_SET_NAMESPACE *map, const API_SET_NAMESPACE_ENTRY *entry,
720 const WCHAR *host, UNICODE_STRING *ret )
722 const API_SET_VALUE_ENTRY *value = (API_SET_VALUE_ENTRY *)((char *)map + entry->ValueOffset);
723 ULONG i, len;
725 if (!entry->ValueCount) return STATUS_DLL_NOT_FOUND;
726 if (host)
728 /* look for specific host in entries 1..n, entry 0 is the default */
729 for (i = 1; i < entry->ValueCount; i++)
731 len = value[i].NameLength / sizeof(WCHAR);
732 if (!wcsnicmp( host, (WCHAR *)((char *)map + value[i].NameOffset), len ) && !host[len])
734 value += i;
735 break;
739 if (!value->ValueOffset) return STATUS_DLL_NOT_FOUND;
740 ret->Buffer = (WCHAR *)((char *)map + value->ValueOffset);
741 ret->Length = value->ValueLength;
742 return STATUS_SUCCESS;
746 /**********************************************************************
747 * build_import_name
749 static NTSTATUS build_import_name( WCHAR buffer[256], const char *import, int len )
751 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
752 const API_SET_NAMESPACE_ENTRY *entry;
753 const WCHAR *host = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
754 UNICODE_STRING str;
756 while (len && import[len-1] == ' ') len--; /* remove trailing spaces */
757 if (len + sizeof(".dll") > 256) return STATUS_DLL_NOT_FOUND;
758 ascii_to_unicode( buffer, import, len );
759 buffer[len] = 0;
760 if (!wcschr( buffer, '.' )) wcscpy( buffer + len, L".dll" );
762 if (get_apiset_entry( map, buffer, wcslen(buffer), &entry )) return STATUS_SUCCESS;
764 if (get_apiset_target( map, entry, host, &str )) return STATUS_DLL_NOT_FOUND;
765 if (str.Length >= 256 * sizeof(WCHAR)) return STATUS_DLL_NOT_FOUND;
767 TRACE( "found %s for %s\n", debugstr_us(&str), debugstr_w(buffer));
768 memcpy( buffer, str.Buffer, str.Length );
769 buffer[str.Length / sizeof(WCHAR)] = 0;
770 return STATUS_SUCCESS;
774 /**********************************************************************
775 * append_dll_ext
777 static WCHAR *append_dll_ext( const WCHAR *name )
779 const WCHAR *ext = wcsrchr( name, '.' );
781 if (!ext || wcschr( ext, '/' ) || wcschr( ext, '\\'))
783 WCHAR *ret = RtlAllocateHeap( GetProcessHeap(), 0,
784 wcslen(name) * sizeof(WCHAR) + sizeof(L".dll") );
785 if (!ret) return NULL;
786 wcscpy( ret, name );
787 wcscat( ret, L".dll" );
788 return ret;
790 return NULL;
794 /***********************************************************************
795 * is_import_dll_system
797 static BOOL is_import_dll_system( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_IMPORT_DESCRIPTOR *import )
799 const char *name = get_rva( mod->DllBase, import->Name );
801 return !_stricmp( name, "ntdll.dll" ) || !_stricmp( name, "kernel32.dll" );
804 /**********************************************************************
805 * insert_single_list_tail
807 static void insert_single_list_after( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *prev, SINGLE_LIST_ENTRY *entry )
809 if (!list->Tail)
811 assert( !prev );
812 entry->Next = entry;
813 list->Tail = entry;
814 return;
816 if (!prev)
818 /* Insert at head. */
819 entry->Next = list->Tail->Next;
820 list->Tail->Next = entry;
821 return;
823 entry->Next = prev->Next;
824 prev->Next = entry;
825 if (prev == list->Tail) list->Tail = entry;
828 /**********************************************************************
829 * remove_single_list_entry
831 static void remove_single_list_entry( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *entry )
833 SINGLE_LIST_ENTRY *prev;
835 assert( list->Tail );
837 if (entry->Next == entry)
839 assert( list->Tail == entry );
840 list->Tail = NULL;
841 return;
844 prev = list->Tail->Next;
845 while (prev->Next != entry && prev != list->Tail)
846 prev = prev->Next;
847 assert( prev->Next == entry );
848 prev->Next = entry->Next;
849 if (list->Tail == entry) list->Tail = prev;
850 entry->Next = NULL;
853 /**********************************************************************
854 * add_module_dependency_after
856 static BOOL add_module_dependency_after( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to,
857 SINGLE_LIST_ENTRY *dep_after )
859 LDR_DEPENDENCY *dep;
861 if (!(dep = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*dep) ))) return FALSE;
863 dep->dependency_from = from;
864 insert_single_list_after( &from->Dependencies, dep_after, &dep->dependency_to_entry );
865 dep->dependency_to = to;
866 insert_single_list_after( &to->IncomingDependencies, NULL, &dep->dependency_from_entry );
868 return TRUE;
871 /**********************************************************************
872 * add_module_dependency
874 static BOOL add_module_dependency( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to )
876 return add_module_dependency_after( from, to, from->Dependencies.Tail );
879 /**********************************************************************
880 * remove_module_dependency
882 static void remove_module_dependency( LDR_DEPENDENCY *dep )
884 remove_single_list_entry( &dep->dependency_to->IncomingDependencies, &dep->dependency_from_entry );
885 remove_single_list_entry( &dep->dependency_from->Dependencies, &dep->dependency_to_entry );
886 RtlFreeHeap( GetProcessHeap(), 0, dep );
889 /**********************************************************************
890 * walk_node_dependencies
892 static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context,
893 NTSTATUS (*callback)( LDR_DDAG_NODE *, void * ))
895 SINGLE_LIST_ENTRY *entry;
896 LDR_DEPENDENCY *dep;
897 NTSTATUS status;
899 if (!(entry = node->Dependencies.Tail)) return STATUS_SUCCESS;
903 entry = entry->Next;
904 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
905 assert( dep->dependency_from == node );
906 if ((status = callback( dep->dependency_to, context ))) break;
907 } while (entry != node->Dependencies.Tail);
909 return status;
912 /*************************************************************************
913 * find_forwarded_export
915 * Find the final function pointer for a forwarded function.
916 * The loader_section must be locked while calling this function.
918 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
920 const IMAGE_EXPORT_DIRECTORY *exports;
921 DWORD exp_size;
922 WINE_MODREF *wm;
923 WCHAR mod_name[256];
924 const char *end = strrchr(forward, '.');
925 FARPROC proc = NULL;
927 if (!end) return NULL;
928 if (build_import_name( mod_name, forward, end - forward )) return NULL;
930 if (!(wm = find_basename_module( mod_name )))
932 WINE_MODREF *imp = get_modref( module );
933 TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
934 if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS &&
935 !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
937 if (!imports_fixup_done && current_modref)
939 add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode );
941 else if (process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS)
943 LdrUnloadDll( wm->ldr.DllBase );
944 wm = NULL;
948 if (!wm)
950 ERR( "module not found for forward '%s' used by %s\n",
951 forward, debugstr_w(imp->ldr.FullDllName.Buffer) );
952 return NULL;
955 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
956 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
958 const char *name = end + 1;
960 if (*name == '#') { /* ordinal */
961 proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size,
962 atoi(name+1) - exports->Base, load_path );
963 } else
964 proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path );
967 if (!proc)
969 ERR("function not found for forward '%s' used by %s."
970 " If you are using builtin %s, try using the native one instead.\n",
971 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
972 debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
974 return proc;
978 /*************************************************************************
979 * find_ordinal_export
981 * Find an exported function by ordinal.
982 * The exports base must have been subtracted from the ordinal already.
983 * The loader_section must be locked while calling this function.
985 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
986 DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
988 FARPROC proc;
989 const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
991 if (ordinal >= exports->NumberOfFunctions)
993 TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base );
994 return NULL;
996 if (!functions[ordinal]) return NULL;
998 proc = get_rva( module, functions[ordinal] );
1000 /* if the address falls into the export dir, it's a forward */
1001 if (((const char *)proc >= (const char *)exports) &&
1002 ((const char *)proc < (const char *)exports + exp_size))
1003 return find_forwarded_export( module, (const char *)proc, load_path );
1005 if (TRACE_ON(snoop))
1007 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
1008 proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
1010 if (TRACE_ON(relay))
1012 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
1013 proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
1015 return proc;
1019 /*************************************************************************
1020 * find_name_in_exports
1022 * Helper for find_named_export.
1024 static int find_name_in_exports( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, const char *name )
1026 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
1027 const DWORD *names = get_rva( module, exports->AddressOfNames );
1028 int min = 0, max = exports->NumberOfNames - 1;
1030 while (min <= max)
1032 int res, pos = (min + max) / 2;
1033 char *ename = get_rva( module, names[pos] );
1034 if (!(res = strcmp( ename, name ))) return ordinals[pos];
1035 if (res > 0) max = pos - 1;
1036 else min = pos + 1;
1038 return -1;
1042 /*************************************************************************
1043 * find_named_export
1045 * Find an exported function by name.
1046 * The loader_section must be locked while calling this function.
1048 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
1049 DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
1051 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
1052 const DWORD *names = get_rva( module, exports->AddressOfNames );
1053 int ordinal;
1055 /* first check the hint */
1056 if (hint >= 0 && hint < exports->NumberOfNames)
1058 char *ename = get_rva( module, names[hint] );
1059 if (!strcmp( ename, name ))
1060 return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
1063 /* then do a binary search */
1064 if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
1065 return find_ordinal_export( module, exports, exp_size, ordinal, load_path );
1070 /*************************************************************************
1071 * RtlFindExportedRoutineByName
1073 void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
1075 const IMAGE_EXPORT_DIRECTORY *exports;
1076 const DWORD *functions;
1077 DWORD exp_size;
1078 int ordinal;
1079 void *proc;
1081 exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
1082 if (!exports || exp_size < sizeof(*exports)) return NULL;
1084 if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
1085 if (ordinal >= exports->NumberOfFunctions) return NULL;
1086 functions = get_rva( module, exports->AddressOfFunctions );
1087 if (!functions[ordinal]) return NULL;
1088 proc = get_rva( module, functions[ordinal] );
1089 /* if the address falls into the export dir, it's a forward */
1090 if (((const char *)proc >= (const char *)exports) &&
1091 ((const char *)proc < (const char *)exports + exp_size))
1092 return NULL;
1093 return proc;
1097 /*************************************************************************
1098 * import_dll
1100 * Import the dll specified by the given import descriptor.
1101 * The loader_section must be locked while calling this function.
1103 static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
1105 BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL);
1106 NTSTATUS status;
1107 WINE_MODREF *wmImp;
1108 HMODULE imp_mod;
1109 const IMAGE_EXPORT_DIRECTORY *exports;
1110 DWORD exp_size;
1111 const IMAGE_THUNK_DATA *import_list;
1112 IMAGE_THUNK_DATA *thunk_list;
1113 WCHAR buffer[256];
1114 const char *name = get_rva( module, descr->Name );
1115 DWORD len = strlen(name);
1116 PVOID protect_base;
1117 SIZE_T protect_size = 0;
1118 DWORD protect_old;
1120 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
1121 if (descr->OriginalFirstThunk)
1122 import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );
1123 else
1124 import_list = thunk_list;
1126 if (!import_list->u1.Ordinal)
1128 WARN( "Skipping unused import %s\n", name );
1129 *pwm = NULL;
1130 return TRUE;
1133 status = build_import_name( buffer, name, len );
1134 if (!status) status = load_dll( load_path, buffer, 0, &wmImp, system );
1136 if (status)
1138 if (status == STATUS_DLL_NOT_FOUND)
1139 ERR("Library %s (which is needed by %s) not found\n",
1140 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
1141 else
1142 ERR("Loading library %s (which is needed by %s) failed (error %lx).\n",
1143 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
1144 return FALSE;
1147 /* unprotect the import address table since it can be located in
1148 * readonly section */
1149 while (import_list[protect_size].u1.Ordinal) protect_size++;
1150 protect_base = thunk_list;
1151 protect_size *= sizeof(*thunk_list);
1152 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
1153 &protect_size, PAGE_READWRITE, &protect_old );
1155 imp_mod = wmImp->ldr.DllBase;
1156 exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
1158 if (!exports)
1160 /* set all imported function to deadbeef */
1161 while (import_list->u1.Ordinal)
1163 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
1165 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
1166 WARN("No implementation for %s.%d", name, ordinal );
1167 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1169 else
1171 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1172 WARN("No implementation for %s.%s", name, pe_name->Name );
1173 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1175 WARN(" imported from %s, allocating stub %p\n",
1176 debugstr_w(current_modref->ldr.FullDllName.Buffer),
1177 (void *)thunk_list->u1.Function );
1178 import_list++;
1179 thunk_list++;
1181 goto done;
1184 while (import_list->u1.Ordinal)
1186 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
1188 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
1190 thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
1191 ordinal - exports->Base, load_path );
1192 if (!thunk_list->u1.Function)
1194 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1195 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
1196 name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
1197 (void *)thunk_list->u1.Function );
1199 TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
1201 else /* import by name */
1203 IMAGE_IMPORT_BY_NAME *pe_name;
1204 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1205 thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
1206 (const char*)pe_name->Name,
1207 pe_name->Hint, load_path );
1208 if (!thunk_list->u1.Function)
1210 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1211 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
1212 name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
1213 (void *)thunk_list->u1.Function );
1215 TRACE_(imports)("--- %s %s.%d = %p\n",
1216 pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
1218 import_list++;
1219 thunk_list++;
1222 done:
1223 /* restore old protection of the import address table */
1224 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
1225 *pwm = wmImp;
1226 return TRUE;
1230 /***********************************************************************
1231 * create_module_activation_context
1233 static NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module )
1235 NTSTATUS status;
1236 LDR_RESOURCE_INFO info;
1237 const IMAGE_RESOURCE_DATA_ENTRY *entry;
1239 info.Type = RT_MANIFEST;
1240 info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
1241 info.Language = 0;
1242 if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry )))
1244 ACTCTXW ctx;
1245 ctx.cbSize = sizeof(ctx);
1246 ctx.lpSource = NULL;
1247 ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
1248 ctx.hModule = module->DllBase;
1249 ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
1250 status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
1252 return status;
1256 /*************************************************************************
1257 * is_dll_native_subsystem
1259 * Check if dll is a proper native driver.
1260 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
1261 * while being perfectly normal DLLs. This heuristic should catch such breakages.
1263 static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
1265 const IMAGE_IMPORT_DESCRIPTOR *imports;
1266 DWORD i, size;
1268 if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
1269 if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
1270 if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
1272 if ((imports = RtlImageDirectoryEntryToData( mod->DllBase, TRUE,
1273 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1275 for (i = 0; imports[i].Name; i++)
1276 if (is_import_dll_system( mod, &imports[i] ))
1278 TRACE( "%s imports system dll, assuming not native\n", debugstr_w(filename) );
1279 return FALSE;
1282 return TRUE;
1285 /*************************************************************************
1286 * alloc_tls_slot
1288 * Allocate a TLS slot for a newly-loaded module.
1289 * The loader_section must be locked while calling this function.
1291 static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1293 const IMAGE_TLS_DIRECTORY *dir;
1294 ULONG i, size;
1295 void *new_ptr;
1296 LIST_ENTRY *entry;
1298 if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
1299 return FALSE;
1301 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1302 if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return FALSE;
1304 for (i = 0; i < tls_module_count; i++)
1306 if (!tls_dirs[i].StartAddressOfRawData && !tls_dirs[i].EndAddressOfRawData &&
1307 !tls_dirs[i].SizeOfZeroFill && !tls_dirs[i].AddressOfCallBacks)
1308 break;
1311 TRACE( "module %p data %p-%p zerofill %lu index %p callback %p flags %lx -> slot %lu\n", mod->DllBase,
1312 (void *)dir->StartAddressOfRawData, (void *)dir->EndAddressOfRawData, dir->SizeOfZeroFill,
1313 (void *)dir->AddressOfIndex, (void *)dir->AddressOfCallBacks, dir->Characteristics, i );
1315 if (i == tls_module_count)
1317 UINT new_count = max( 32, tls_module_count * 2 );
1319 if (!tls_dirs)
1320 new_ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*tls_dirs) );
1321 else
1322 new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
1323 new_count * sizeof(*tls_dirs) );
1324 if (!new_ptr) return FALSE;
1326 /* resize the pointer block in all running threads */
1327 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1329 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1330 void **old = teb->ThreadLocalStoragePointer;
1331 void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
1333 if (!new) return FALSE;
1334 if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
1335 teb->ThreadLocalStoragePointer = new;
1336 #ifdef __x86_64__ /* macOS-specific hack */
1337 if (teb->Instrumentation[0]) ((TEB *)teb->Instrumentation[0])->ThreadLocalStoragePointer = new;
1338 #endif
1339 TRACE( "thread %04lx tls block %p -> %p\n", HandleToULong(teb->ClientId.UniqueThread), old, new );
1340 /* FIXME: can't free old block here, should be freed at thread exit */
1343 tls_dirs = new_ptr;
1344 tls_module_count = new_count;
1347 /* allocate the data block in all running threads */
1348 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1350 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1352 if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
1353 memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
1354 memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
1356 TRACE( "thread %04lx slot %lu: %lu/%lu bytes at %p\n",
1357 HandleToULong(teb->ClientId.UniqueThread), i, size, dir->SizeOfZeroFill, new_ptr );
1359 RtlFreeHeap( GetProcessHeap(), 0,
1360 InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1363 *(DWORD *)dir->AddressOfIndex = i;
1364 tls_dirs[i] = *dir;
1365 return TRUE;
1369 /*************************************************************************
1370 * free_tls_slot
1372 * Free the module TLS slot on unload.
1373 * The loader_section must be locked while calling this function.
1375 static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1377 const IMAGE_TLS_DIRECTORY *dir;
1378 ULONG i, size;
1380 if (mod->TlsIndex != -1)
1381 return;
1382 if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
1383 return;
1385 i = *(ULONG*)dir->AddressOfIndex;
1386 assert( i < tls_module_count );
1387 memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1391 /****************************************************************
1392 * fixup_imports_ilonly
1394 * Fixup imports for an IL-only module. All we do is import mscoree.
1395 * The loader_section must be locked while calling this function.
1397 static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
1399 NTSTATUS status;
1400 void *proc;
1401 const char *name;
1402 WINE_MODREF *prev, *imp;
1404 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1405 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1407 prev = current_modref;
1408 current_modref = wm;
1409 assert( !wm->ldr.DdagNode->Dependencies.Tail );
1410 if (!(status = load_dll( load_path, L"mscoree.dll", 0, &imp, FALSE ))
1411 && !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
1412 status = STATUS_NO_MEMORY;
1413 current_modref = prev;
1414 if (status)
1416 ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
1417 debugstr_w(wm->ldr.BaseDllName.Buffer) );
1418 return status;
1421 TRACE( "loaded mscoree for %s\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
1423 name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
1424 if (!(proc = RtlFindExportedRoutineByName( imp->ldr.DllBase, name ))) return STATUS_PROCEDURE_NOT_FOUND;
1425 *entry = proc;
1426 return STATUS_SUCCESS;
1430 /****************************************************************
1431 * fixup_imports
1433 * Fixup all imports of a given module.
1434 * The loader_section must be locked while calling this function.
1436 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
1438 const IMAGE_IMPORT_DESCRIPTOR *imports;
1439 SINGLE_LIST_ENTRY *dep_after;
1440 WINE_MODREF *prev, *imp;
1441 int i, nb_imports;
1442 DWORD size;
1443 NTSTATUS status;
1444 ULONG_PTR cookie;
1446 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1447 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1449 if (alloc_tls_slot( &wm->ldr )) wm->ldr.TlsIndex = -1;
1451 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
1452 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1453 return STATUS_SUCCESS;
1455 nb_imports = 0;
1456 while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
1458 if (!nb_imports) return STATUS_SUCCESS; /* no imports */
1460 if (!create_module_activation_context( &wm->ldr ))
1461 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1463 /* load the imported modules. They are automatically
1464 * added to the modref list of the process.
1466 prev = current_modref;
1467 current_modref = wm;
1468 status = STATUS_SUCCESS;
1469 for (i = 0; i < nb_imports; i++)
1471 dep_after = wm->ldr.DdagNode->Dependencies.Tail;
1472 if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp ))
1473 status = STATUS_DLL_NOT_FOUND;
1474 else if (imp && imp->ldr.DdagNode != node_ntdll && imp->ldr.DdagNode != node_kernel32)
1475 add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, dep_after );
1477 current_modref = prev;
1478 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1479 return status;
1483 /*************************************************************************
1484 * alloc_module
1486 * Allocate a WINE_MODREF structure and add it to the process list
1487 * The loader_section must be locked while calling this function.
1489 static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1491 WCHAR *buffer;
1492 WINE_MODREF *wm;
1493 const WCHAR *p;
1494 const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1496 if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1498 wm->ldr.DllBase = hModule;
1499 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
1500 wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1501 wm->ldr.TlsIndex = 0;
1502 wm->ldr.LoadCount = 1;
1503 wm->CheckSum = nt->OptionalHeader.CheckSum;
1504 wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp;
1506 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) )))
1508 RtlFreeHeap( GetProcessHeap(), 0, wm );
1509 return NULL;
1512 if (!(wm->ldr.DdagNode = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm->ldr.DdagNode) )))
1514 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1515 RtlFreeHeap( GetProcessHeap(), 0, wm );
1516 return NULL;
1518 InitializeListHead(&wm->ldr.DdagNode->Modules);
1519 InsertTailList(&wm->ldr.DdagNode->Modules, &wm->ldr.NodeModuleLink);
1521 if (nt_name->Length >= 8 * sizeof(WCHAR) && !wcsncmp(nt_name->Buffer + 4, L"UNC\\", 4))
1523 buffer[0] = '\\';
1524 memcpy( buffer + 1, nt_name->Buffer + 7 /* \??\UNC prefix */, nt_name->Length - 7 * sizeof(WCHAR) );
1525 buffer[nt_name->Length/sizeof(WCHAR) - 6] = 0;
1527 else
1529 memcpy( buffer, nt_name->Buffer + 4 /* \??\ prefix */, nt_name->Length - 4 * sizeof(WCHAR) );
1530 buffer[nt_name->Length/sizeof(WCHAR) - 4] = 0;
1532 if ((p = wcsrchr( buffer, '\\' ))) p++;
1533 else p = buffer;
1534 RtlInitUnicodeString( &wm->ldr.FullDllName, buffer );
1535 RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
1537 if (!is_dll_native_subsystem( &wm->ldr, nt, p ))
1539 if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
1540 wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1541 if (nt->OptionalHeader.AddressOfEntryPoint)
1542 wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1545 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1546 &wm->ldr.InLoadOrderLinks);
1547 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1548 &wm->ldr.InMemoryOrderLinks);
1549 /* wait until init is called for inserting into InInitializationOrderModuleList */
1551 if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
1553 ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1554 WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1555 NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1557 return wm;
1561 /*************************************************************************
1562 * alloc_thread_tls
1564 * Allocate the per-thread structure for module TLS storage.
1566 static NTSTATUS alloc_thread_tls(void)
1568 void **pointers;
1569 UINT i, size;
1571 if (!tls_module_count) return STATUS_SUCCESS;
1573 if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
1574 tls_module_count * sizeof(*pointers) )))
1575 return STATUS_NO_MEMORY;
1577 for (i = 0; i < tls_module_count; i++)
1579 const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1581 if (!dir) continue;
1582 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1583 if (!size && !dir->SizeOfZeroFill) continue;
1585 if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
1587 while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
1588 RtlFreeHeap( GetProcessHeap(), 0, pointers );
1589 return STATUS_NO_MEMORY;
1591 memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
1592 memset( (char *)pointers[i] + size, 0, dir->SizeOfZeroFill );
1594 TRACE( "slot %u: %u/%lu bytes at %p\n", i, size, dir->SizeOfZeroFill, pointers[i] );
1596 NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1597 #ifdef __x86_64__ /* macOS-specific hack */
1598 if (NtCurrentTeb()->Instrumentation[0])
1599 ((TEB *)NtCurrentTeb()->Instrumentation[0])->ThreadLocalStoragePointer = pointers;
1600 #endif
1601 return STATUS_SUCCESS;
1605 /*************************************************************************
1606 * call_tls_callbacks
1608 static void call_tls_callbacks( HMODULE module, UINT reason )
1610 const IMAGE_TLS_DIRECTORY *dir;
1611 const PIMAGE_TLS_CALLBACK *callback;
1612 ULONG dirsize;
1614 dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
1615 if (!dir || !dir->AddressOfCallBacks) return;
1617 for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1619 TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1620 *callback, module, reason_names[reason] );
1621 __TRY
1623 call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1625 __EXCEPT_ALL
1627 TRACE_(relay)("\1exception %08lx in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1628 GetExceptionCode(), callback, module, reason_names[reason] );
1629 return;
1631 __ENDTRY
1632 TRACE_(relay)("\1Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1633 *callback, module, reason_names[reason] );
1637 /*************************************************************************
1638 * MODULE_InitDLL
1640 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1642 WCHAR mod_name[64];
1643 NTSTATUS status = STATUS_SUCCESS;
1644 DLLENTRYPROC entry = wm->ldr.EntryPoint;
1645 void *module = wm->ldr.DllBase;
1646 BOOL retv = FALSE;
1648 /* Skip calls for modules loaded with special load flags */
1650 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1651 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, reason );
1652 if (!entry) return STATUS_SUCCESS;
1654 if (TRACE_ON(relay))
1656 size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1657 memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
1658 mod_name[len / sizeof(WCHAR)] = 0;
1659 TRACE_(relay)("\1Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1660 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved );
1662 else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
1663 reason_names[reason], lpReserved );
1665 __TRY
1667 retv = call_dll_entry_point( entry, module, reason, lpReserved );
1668 if (!retv)
1669 status = STATUS_DLL_INIT_FAILED;
1671 __EXCEPT_ALL
1673 status = GetExceptionCode();
1674 TRACE_(relay)("\1exception %08lx in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1675 status, entry, module, reason_names[reason], lpReserved );
1677 __ENDTRY
1679 /* The state of the module list may have changed due to the call
1680 to the dll. We cannot assume that this module has not been
1681 deleted. */
1682 if (TRACE_ON(relay))
1683 TRACE_(relay)("\1Ret PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1684 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved, retv );
1685 else
1686 TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1688 return status;
1692 /*************************************************************************
1693 * process_attach
1695 * Send the process attach notification to all DLLs the given module
1696 * depends on (recursively). This is somewhat complicated due to the fact that
1698 * - we have to respect the module dependencies, i.e. modules implicitly
1699 * referenced by another module have to be initialized before the module
1700 * itself can be initialized
1702 * - the initialization routine of a DLL can itself call LoadLibrary,
1703 * thereby introducing a whole new set of dependencies (even involving
1704 * the 'old' modules) at any time during the whole process
1706 * (Note that this routine can be recursively entered not only directly
1707 * from itself, but also via LoadLibrary from one of the called initialization
1708 * routines.)
1710 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1711 * the process *detach* notifications to be sent in the correct order.
1712 * This must not only take into account module dependencies, but also
1713 * 'hidden' dependencies created by modules calling LoadLibrary in their
1714 * attach notification routine.
1716 * The strategy is rather simple: we move a WINE_MODREF to the head of the
1717 * list after the attach notification has returned. This implies that the
1718 * detach notifications are called in the reverse of the sequence the attach
1719 * notifications *returned*.
1721 * The loader_section must be locked while calling this function.
1723 static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
1725 NTSTATUS status = STATUS_SUCCESS;
1726 LDR_DATA_TABLE_ENTRY *mod;
1727 ULONG_PTR cookie;
1728 WINE_MODREF *wm;
1730 if (process_detaching) return status;
1732 mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
1733 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
1735 /* prevent infinite recursion in case of cyclical dependencies */
1736 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
1737 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1738 return status;
1740 TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1742 /* Tag current MODREF to prevent recursive loop */
1743 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1744 if (lpReserved) wm->ldr.LoadCount = -1; /* pin it if imported by the main exe */
1745 if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1747 /* Recursively attach all DLLs this one depends on */
1748 status = walk_node_dependencies( node, lpReserved, process_attach );
1750 if (!wm->ldr.InInitializationOrderLinks.Flink)
1751 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1752 &wm->ldr.InInitializationOrderLinks);
1754 /* Call DLL entry point */
1755 if (status == STATUS_SUCCESS)
1757 WINE_MODREF *prev = current_modref;
1758 current_modref = wm;
1760 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1761 status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
1762 if (status == STATUS_SUCCESS)
1764 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1766 else
1768 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1769 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );
1771 /* point to the name so LdrInitializeThunk can print it */
1772 last_failed_modref = wm;
1773 WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
1775 current_modref = prev;
1778 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1779 /* Remove recursion flag */
1780 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1782 TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1783 return status;
1787 /*************************************************************************
1788 * process_detach
1790 * Send DLL process detach notifications. See the comment about calling
1791 * sequence at process_attach.
1793 static void process_detach(void)
1795 PLIST_ENTRY mark, entry;
1796 PLDR_DATA_TABLE_ENTRY mod;
1798 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1801 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1803 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1804 InInitializationOrderLinks);
1805 /* Check whether to detach this DLL */
1806 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1807 continue;
1808 if ( mod->LoadCount && !process_detaching )
1809 continue;
1811 /* Call detach notification */
1812 mod->Flags &= ~LDR_PROCESS_ATTACHED;
1813 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1814 DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1815 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1817 /* Restart at head of WINE_MODREF list, as entries might have
1818 been added and/or removed while performing the call ... */
1819 break;
1821 } while (entry != mark);
1824 /*************************************************************************
1825 * thread_attach
1827 * Send DLL thread attach notifications. These are sent in the
1828 * reverse sequence of process detach notification.
1829 * The loader_section must be locked while calling this function.
1831 static void thread_attach(void)
1833 PLIST_ENTRY mark, entry;
1834 PLDR_DATA_TABLE_ENTRY mod;
1836 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1837 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1839 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1840 InInitializationOrderLinks);
1841 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1842 continue;
1843 if ( mod->Flags & LDR_NO_DLL_CALLS )
1844 continue;
1846 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1850 /******************************************************************
1851 * LdrDisableThreadCalloutsForDll (NTDLL.@)
1854 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1856 WINE_MODREF *wm;
1857 NTSTATUS ret = STATUS_SUCCESS;
1859 RtlEnterCriticalSection( &loader_section );
1861 wm = get_modref( hModule );
1862 if (!wm || wm->ldr.TlsIndex == -1)
1863 ret = STATUS_DLL_NOT_FOUND;
1864 else
1865 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1867 RtlLeaveCriticalSection( &loader_section );
1869 return ret;
1872 /******************************************************************
1873 * LdrFindEntryForAddress (NTDLL.@)
1875 * The loader_section must be locked while calling this function
1877 NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY *pmod )
1879 PLIST_ENTRY mark, entry;
1880 PLDR_DATA_TABLE_ENTRY mod;
1882 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1883 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1885 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
1886 if (mod->DllBase <= addr &&
1887 (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage)
1889 *pmod = mod;
1890 return STATUS_SUCCESS;
1893 return STATUS_NO_MORE_ENTRIES;
1896 /******************************************************************
1897 * LdrEnumerateLoadedModules (NTDLL.@)
1899 NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
1901 LIST_ENTRY *mark, *entry;
1902 LDR_DATA_TABLE_ENTRY *mod;
1903 BOOLEAN stop = FALSE;
1905 TRACE( "(%p, %p, %p)\n", unknown, callback, context );
1907 if (unknown || !callback)
1908 return STATUS_INVALID_PARAMETER;
1910 RtlEnterCriticalSection( &loader_section );
1912 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1913 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1915 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
1916 callback( mod, context, &stop );
1917 if (stop) break;
1920 RtlLeaveCriticalSection( &loader_section );
1921 return STATUS_SUCCESS;
1924 /******************************************************************
1925 * LdrRegisterDllNotification (NTDLL.@)
1927 NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
1928 void *context, void **cookie)
1930 struct ldr_notification *notify;
1932 TRACE( "(%lx, %p, %p, %p)\n", flags, callback, context, cookie );
1934 if (!callback || !cookie)
1935 return STATUS_INVALID_PARAMETER;
1937 if (flags)
1938 FIXME( "ignoring flags %lx\n", flags );
1940 notify = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*notify) );
1941 if (!notify) return STATUS_NO_MEMORY;
1942 notify->callback = callback;
1943 notify->context = context;
1945 RtlEnterCriticalSection( &loader_section );
1946 list_add_tail( &ldr_notifications, &notify->entry );
1947 RtlLeaveCriticalSection( &loader_section );
1949 *cookie = notify;
1950 return STATUS_SUCCESS;
1953 /******************************************************************
1954 * LdrUnregisterDllNotification (NTDLL.@)
1956 NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
1958 struct ldr_notification *notify = cookie;
1960 TRACE( "(%p)\n", cookie );
1962 if (!notify) return STATUS_INVALID_PARAMETER;
1964 RtlEnterCriticalSection( &loader_section );
1965 list_remove( &notify->entry );
1966 RtlLeaveCriticalSection( &loader_section );
1968 RtlFreeHeap( GetProcessHeap(), 0, notify );
1969 return STATUS_SUCCESS;
1972 /******************************************************************
1973 * LdrLockLoaderLock (NTDLL.@)
1975 * Note: some flags are not implemented.
1976 * Flag 0x01 is used to raise exceptions on errors.
1978 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1980 if (flags & ~0x2) FIXME( "flags %lx not supported\n", flags );
1982 if (result) *result = 0;
1983 if (magic) *magic = 0;
1984 if (flags & ~0x3) return STATUS_INVALID_PARAMETER_1;
1985 if (!result && (flags & 0x2)) return STATUS_INVALID_PARAMETER_2;
1986 if (!magic) return STATUS_INVALID_PARAMETER_3;
1988 if (flags & 0x2)
1990 if (!RtlTryEnterCriticalSection( &loader_section ))
1992 *result = 2;
1993 return STATUS_SUCCESS;
1995 *result = 1;
1997 else
1999 RtlEnterCriticalSection( &loader_section );
2000 if (result) *result = 1;
2002 *magic = GetCurrentThreadId();
2003 return STATUS_SUCCESS;
2007 /******************************************************************
2008 * LdrUnlockLoaderUnlock (NTDLL.@)
2010 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
2012 if (magic)
2014 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
2015 RtlLeaveCriticalSection( &loader_section );
2017 return STATUS_SUCCESS;
2021 /******************************************************************
2022 * LdrGetProcedureAddress (NTDLL.@)
2024 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
2025 ULONG ord, PVOID *address)
2027 IMAGE_EXPORT_DIRECTORY *exports;
2028 WINE_MODREF *wm;
2029 DWORD exp_size;
2030 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
2032 RtlEnterCriticalSection( &loader_section );
2034 /* check if the module itself is invalid to return the proper error */
2035 if (!(wm = get_modref( module ))) ret = STATUS_DLL_NOT_FOUND;
2036 else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
2037 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
2039 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL )
2040 : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL );
2041 if (proc)
2043 *address = proc;
2044 ret = STATUS_SUCCESS;
2046 else
2048 WARN( "%s (ordinal %lu) not found in %s\n", debugstr_a(name ? name->Buffer : NULL),
2049 ord, debugstr_us(&wm->ldr.FullDllName) );
2053 RtlLeaveCriticalSection( &loader_section );
2054 return ret;
2058 /***********************************************************************
2059 * set_security_cookie
2061 * Create a random security cookie for buffer overflow protection. Make
2062 * sure it does not accidentally match the default cookie value.
2064 static void set_security_cookie( ULONG_PTR *cookie )
2066 static ULONG seed;
2068 TRACE( "initializing security cookie %p\n", cookie );
2070 if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
2071 for (;;)
2073 if (*cookie == DEFAULT_SECURITY_COOKIE_16)
2074 *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
2075 else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
2076 *cookie = RtlRandom( &seed );
2077 #ifdef DEFAULT_SECURITY_COOKIE_64
2078 else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
2080 *cookie = RtlRandom( &seed );
2081 /* fill up, but keep the highest word clear */
2082 *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
2084 #endif
2085 else
2086 break;
2091 /***********************************************************************
2092 * update_load_config
2094 static void update_load_config( void *module )
2096 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2097 IMAGE_LOAD_CONFIG_DIRECTORY *cfg;
2098 ULONG size;
2100 cfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size );
2101 if (!cfg) return;
2102 size = min( size, cfg->Size );
2103 if (size > offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie ) &&
2104 cfg->SecurityCookie > (ULONG_PTR)module &&
2105 cfg->SecurityCookie < (ULONG_PTR)module + nt->OptionalHeader.SizeOfImage)
2107 set_security_cookie( (ULONG_PTR *)cfg->SecurityCookie );
2109 #ifdef __arm64ec__
2110 if (size > offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer ) &&
2111 cfg->CHPEMetadataPointer > (ULONG_PTR)module &&
2112 cfg->CHPEMetadataPointer < (ULONG_PTR)module + nt->OptionalHeader.SizeOfImage)
2114 update_hybrid_metadata( module, nt, (void *)cfg->CHPEMetadataPointer );
2116 #endif
2120 static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
2122 char *base;
2123 IMAGE_BASE_RELOCATION *rel, *end;
2124 const IMAGE_DATA_DIRECTORY *relocs;
2125 const IMAGE_SECTION_HEADER *sec;
2126 INT_PTR delta;
2127 ULONG protect_old[96], i;
2129 base = (char *)nt->OptionalHeader.ImageBase;
2130 if (module == base) return STATUS_SUCCESS; /* nothing to do */
2132 /* no relocations are performed on non page-aligned binaries */
2133 if (nt->OptionalHeader.SectionAlignment < page_size)
2134 return STATUS_SUCCESS;
2136 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
2137 module != NtCurrentTeb()->Peb->ImageBaseAddress)
2138 return STATUS_SUCCESS;
2140 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
2142 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
2144 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
2145 base, module );
2146 return STATUS_CONFLICTING_ADDRESSES;
2149 if (!relocs->Size) return STATUS_SUCCESS;
2150 if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;
2152 if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
2153 return STATUS_INVALID_IMAGE_FORMAT;
2155 sec = IMAGE_FIRST_SECTION( nt );
2156 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2158 void *addr = get_rva( module, sec[i].VirtualAddress );
2159 SIZE_T size = sec[i].SizeOfRawData;
2160 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2161 &size, PAGE_READWRITE, &protect_old[i] );
2164 TRACE( "relocating from %p-%p to %p-%p\n",
2165 base, base + len, module, (char *)module + len );
2167 rel = get_rva( module, relocs->VirtualAddress );
2168 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
2169 delta = (char *)module - base;
2171 while (rel < end - 1 && rel->SizeOfBlock)
2173 if (rel->VirtualAddress >= len)
2175 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
2176 return STATUS_ACCESS_VIOLATION;
2178 rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
2179 (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
2180 (USHORT *)(rel + 1), delta );
2181 if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
2184 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2186 void *addr = get_rva( module, sec[i].VirtualAddress );
2187 SIZE_T size = sec[i].SizeOfRawData;
2188 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2189 &size, protect_old[i], &protect_old[i] );
2192 return STATUS_SUCCESS;
2196 /*************************************************************************
2197 * build_module
2199 * Build the module data for a mapped dll.
2201 static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
2202 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2203 DWORD flags, BOOL system, WINE_MODREF **pwm )
2205 static const char builtin_signature[] = "Wine builtin DLL";
2206 char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1);
2207 BOOL is_builtin;
2208 IMAGE_NT_HEADERS *nt;
2209 WINE_MODREF *wm;
2210 NTSTATUS status;
2211 SIZE_T map_size;
2213 if (!(nt = RtlImageNtHeader( *module ))) return STATUS_INVALID_IMAGE_FORMAT;
2215 map_size = (nt->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
2216 if ((status = perform_relocations( *module, nt, map_size ))) return status;
2218 is_builtin = ((char *)nt - signature >= sizeof(builtin_signature) &&
2219 !memcmp( signature, builtin_signature, sizeof(builtin_signature) ));
2221 /* create the MODREF */
2223 if (!(wm = alloc_module( *module, nt_name, is_builtin ))) return STATUS_NO_MEMORY;
2225 if (id) wm->id = *id;
2226 if (image_info->LoaderFlags) wm->ldr.Flags |= LDR_COR_IMAGE;
2227 if (image_info->ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
2228 wm->system = system;
2230 update_load_config( *module );
2232 /* fixup imports */
2234 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
2235 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
2236 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE))
2238 if (wm->ldr.Flags & LDR_COR_ILONLY)
2239 status = fixup_imports_ilonly( wm, load_path, &wm->ldr.EntryPoint );
2240 else
2241 status = fixup_imports( wm, load_path );
2242 if (status != STATUS_SUCCESS)
2244 /* the module has only be inserted in the load & memory order lists */
2245 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
2246 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
2248 /* FIXME: there are several more dangling references
2249 * left. Including dlls loaded by this dll before the
2250 * failed one. Unrolling is rather difficult with the
2251 * current structure and we can leave them lying
2252 * around with no problems, so we don't care.
2253 * As these might reference our wm, we don't free it.
2255 *module = NULL;
2256 return status;
2260 TRACE( "loaded %s %p %p\n", debugstr_us(nt_name), wm, *module );
2262 if (is_builtin)
2264 if (TRACE_ON(relay)) RELAY_SetupDLL( *module );
2266 else
2268 if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( *module );
2271 TRACE_(loaddll)( "Loaded %s at %p: %s\n", debugstr_w(wm->ldr.FullDllName.Buffer), *module,
2272 is_builtin ? "builtin" : "native" );
2274 wm->ldr.LoadCount = 1;
2275 *pwm = wm;
2276 *module = NULL;
2277 return STATUS_SUCCESS;
2281 /*************************************************************************
2282 * build_ntdll_module
2284 * Build the module data for the initially-loaded ntdll.
2286 static void build_ntdll_module(void)
2288 UNICODE_STRING nt_name = RTL_CONSTANT_STRING( L"\\??\\C:\\windows\\system32\\ntdll.dll" );
2289 MEMORY_BASIC_INFORMATION meminfo;
2290 WINE_MODREF *wm;
2291 void *module;
2293 NtQueryVirtualMemory( GetCurrentProcess(), LdrInitializeThunk, MemoryBasicInformation,
2294 &meminfo, sizeof(meminfo), NULL );
2295 module = meminfo.AllocationBase;
2296 wm = alloc_module( module, &nt_name, TRUE );
2297 assert( wm );
2298 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
2299 node_ntdll = wm->ldr.DdagNode;
2300 if (TRACE_ON(relay)) RELAY_SetupDLL( module );
2304 #ifdef _WIN64
2305 /* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
2306 static BOOL convert_to_pe64( HMODULE module, const SECTION_IMAGE_INFORMATION *info )
2308 static const ULONG copy_dirs[] = { IMAGE_DIRECTORY_ENTRY_RESOURCE,
2309 IMAGE_DIRECTORY_ENTRY_SECURITY,
2310 IMAGE_DIRECTORY_ENTRY_BASERELOC,
2311 IMAGE_DIRECTORY_ENTRY_DEBUG,
2312 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR };
2313 IMAGE_OPTIONAL_HEADER32 hdr32 = { IMAGE_NT_OPTIONAL_HDR32_MAGIC };
2314 IMAGE_OPTIONAL_HEADER64 hdr64 = { IMAGE_NT_OPTIONAL_HDR64_MAGIC };
2315 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2316 IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
2317 SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
2318 SIZE_T size = min( nt->OptionalHeader.SizeOfHeaders, nt->OptionalHeader.SizeOfImage );
2319 void *addr = module;
2320 ULONG i, old_prot;
2322 if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return TRUE; /* already 64-bit */
2323 if (NtCurrentTeb()->WowTebOffset) return TRUE; /* no need to convert */
2324 if (!info->ImageContainsCode) return TRUE; /* no need to convert */
2326 TRACE( "%p\n", module );
2328 if (NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &old_prot ))
2329 return FALSE;
2331 if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
2333 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2334 return FALSE;
2337 memcpy( &hdr32, &nt->OptionalHeader, hdr_size );
2338 memcpy( &hdr64, &hdr32, offsetof( IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve ));
2339 hdr64.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2340 hdr64.AddressOfEntryPoint = 0;
2341 hdr64.ImageBase = hdr32.ImageBase;
2342 hdr64.SizeOfStackReserve = hdr32.SizeOfStackReserve;
2343 hdr64.SizeOfStackCommit = hdr32.SizeOfStackCommit;
2344 hdr64.SizeOfHeapReserve = hdr32.SizeOfHeapReserve;
2345 hdr64.SizeOfHeapCommit = hdr32.SizeOfHeapCommit;
2346 hdr64.LoaderFlags = hdr32.LoaderFlags;
2347 hdr64.NumberOfRvaAndSizes = hdr32.NumberOfRvaAndSizes;
2348 for (i = 0; i < ARRAY_SIZE( copy_dirs ); i++)
2349 hdr64.DataDirectory[copy_dirs[i]] = hdr32.DataDirectory[copy_dirs[i]];
2351 memmove( nt + 1, sec, nt->FileHeader.NumberOfSections * sizeof(*sec) );
2352 nt->FileHeader.SizeOfOptionalHeader = sizeof(hdr64);
2353 nt->OptionalHeader = hdr64;
2354 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2355 return TRUE;
2358 /* read data out of a PE image directory */
2359 static ULONG read_image_directory( HANDLE file, const SECTION_IMAGE_INFORMATION *info,
2360 ULONG dir, void *buffer, ULONG maxlen, USHORT *magic )
2362 IMAGE_DOS_HEADER mz;
2363 IO_STATUS_BLOCK io;
2364 LARGE_INTEGER offset;
2365 IMAGE_SECTION_HEADER sec[96];
2366 unsigned int i, count;
2367 DWORD va, size;
2368 union
2370 IMAGE_NT_HEADERS32 nt32;
2371 IMAGE_NT_HEADERS64 nt64;
2372 } nt;
2374 offset.QuadPart = 0;
2375 if (NtReadFile( file, 0, NULL, NULL, &io, &mz, sizeof(mz), &offset, NULL )) return 0;
2376 if (io.Information != sizeof(mz)) return 0;
2377 if (mz.e_magic != IMAGE_DOS_SIGNATURE) return 0;
2378 offset.QuadPart = mz.e_lfanew;
2379 if (NtReadFile( file, 0, NULL, NULL, &io, &nt, sizeof(nt), &offset, NULL )) return 0;
2380 if (io.Information != sizeof(nt)) return 0;
2381 if (nt.nt32.Signature != IMAGE_NT_SIGNATURE) return 0;
2382 *magic = nt.nt32.OptionalHeader.Magic;
2383 switch (nt.nt32.OptionalHeader.Magic)
2385 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
2386 va = nt.nt32.OptionalHeader.DataDirectory[dir].VirtualAddress;
2387 size = nt.nt32.OptionalHeader.DataDirectory[dir].Size;
2388 break;
2389 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
2390 va = nt.nt64.OptionalHeader.DataDirectory[dir].VirtualAddress;
2391 size = nt.nt64.OptionalHeader.DataDirectory[dir].Size;
2392 break;
2393 default:
2394 return 0;
2396 if (!va) return 0;
2397 offset.QuadPart += offsetof( IMAGE_NT_HEADERS32, OptionalHeader ) + nt.nt32.FileHeader.SizeOfOptionalHeader;
2398 count = min( 96, nt.nt32.FileHeader.NumberOfSections );
2399 if (NtReadFile( file, 0, NULL, NULL, &io, &sec, count * sizeof(*sec), &offset, NULL )) return 0;
2400 if (io.Information != count * sizeof(*sec)) return 0;
2401 for (i = 0; i < count; i++)
2403 if (va < sec[i].VirtualAddress) continue;
2404 if (sec[i].Misc.VirtualSize && va - sec[i].VirtualAddress >= sec[i].Misc.VirtualSize) continue;
2405 offset.QuadPart = sec[i].PointerToRawData + va - sec[i].VirtualAddress;
2406 if (NtReadFile( file, 0, NULL, NULL, &io, buffer, min( maxlen, size ), &offset, NULL )) return 0;
2407 return io.Information;
2409 return 0;
2412 /* check COM header for ILONLY flag, ignoring runtime version */
2413 static BOOL is_com_ilonly( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2415 USHORT magic;
2416 IMAGE_COR20_HEADER cor_header;
2417 ULONG len = read_image_directory( file, info, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
2418 &cor_header, sizeof(cor_header), &magic );
2420 if (len != sizeof(cor_header)) return FALSE;
2421 if (magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return FALSE;
2422 return !!(cor_header.Flags & COMIMAGE_FLAGS_ILONLY);
2425 /* check LOAD_CONFIG header for CHPE metadata */
2426 static BOOL has_chpe_metadata( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2428 USHORT magic;
2429 IMAGE_LOAD_CONFIG_DIRECTORY64 loadcfg;
2430 ULONG len = read_image_directory( file, info, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
2431 &loadcfg, sizeof(loadcfg), &magic );
2433 if (!len) return FALSE;
2434 if (magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) return FALSE;
2435 len = min( len, loadcfg.Size );
2436 if (len <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY64, CHPEMetadataPointer )) return FALSE;
2437 return !!loadcfg.CHPEMetadataPointer;
2440 /* On WoW64 setups, an image mapping can also be created for the other 32/64 CPU */
2441 /* but it cannot necessarily be loaded as a dll, so we need some additional checks */
2442 static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2444 if (info->Machine == current_machine) return TRUE;
2445 if (NtCurrentTeb()->WowTebOffset) return TRUE;
2446 /* support ARM64EC binaries on x86-64 */
2447 if (current_machine == IMAGE_FILE_MACHINE_AMD64 && has_chpe_metadata( file, info )) return TRUE;
2448 /* support 32-bit IL-only images on 64-bit */
2449 if (!info->ImageContainsCode) return TRUE;
2450 if (info->ComPlusNativeReady) return TRUE;
2451 return is_com_ilonly( file, info );
2454 #else /* _WIN64 */
2456 static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2458 return (info->Machine == current_machine);
2461 #endif /* _WIN64 */
2464 /******************************************************************
2465 * get_module_path_end
2467 * Returns the end of the directory component of the module path.
2469 static inline const WCHAR *get_module_path_end( const WCHAR *module )
2471 const WCHAR *p;
2472 const WCHAR *mod_end = module;
2474 if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
2475 if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2476 if (mod_end == module + 2 && module[1] == ':') mod_end++;
2477 if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
2478 return mod_end;
2482 /******************************************************************
2483 * append_path
2485 * Append a counted string to the load path. Helper for get_dll_load_path.
2487 static inline WCHAR *append_path( WCHAR *p, const WCHAR *str, int len )
2489 if (len == -1) len = wcslen(str);
2490 if (!len) return p;
2491 memcpy( p, str, len * sizeof(WCHAR) );
2492 p[len] = ';';
2493 return p + len + 1;
2497 /******************************************************************
2498 * get_dll_load_path
2500 static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2502 const WCHAR *mod_end = module;
2503 UNICODE_STRING name = RTL_CONSTANT_STRING( L"PATH" ), value;
2504 WCHAR *p, *ret;
2505 int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2507 if (module)
2509 mod_end = get_module_path_end( module );
2510 len += (mod_end - module) + 1;
2513 value.Length = 0;
2514 value.MaximumLength = 0;
2515 value.Buffer = NULL;
2516 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2517 path_len = value.Length;
2519 if (dll_dir) len += wcslen( dll_dir ) + 1;
2520 else len += 2; /* current directory */
2521 if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2522 return STATUS_NO_MEMORY;
2524 p = append_path( p, module, mod_end - module );
2525 if (dll_dir) p = append_path( p, dll_dir, -1 );
2526 else if (!safe_mode) p = append_path( p, L".", -1 );
2527 p = append_path( p, system_path, -1 );
2528 if (!dll_dir && safe_mode) p = append_path( p, L".", -1 );
2530 value.Buffer = p;
2531 value.MaximumLength = path_len;
2533 while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2535 WCHAR *new_ptr;
2537 /* grow the buffer and retry */
2538 path_len = value.Length;
2539 if (!(new_ptr = RtlReAllocateHeap( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
2541 RtlFreeHeap( GetProcessHeap(), 0, ret );
2542 return STATUS_NO_MEMORY;
2544 value.Buffer = new_ptr + (value.Buffer - ret);
2545 value.MaximumLength = path_len;
2546 ret = new_ptr;
2548 value.Buffer[value.Length / sizeof(WCHAR)] = 0;
2549 *path = ret;
2550 return STATUS_SUCCESS;
2554 /******************************************************************
2555 * get_dll_load_path_search_flags
2557 static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCHAR **path )
2559 const WCHAR *image = NULL, *mod_end, *image_end;
2560 struct dll_dir_entry *dir;
2561 WCHAR *p, *ret;
2562 int len = 1;
2564 if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
2565 flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
2566 LOAD_LIBRARY_SEARCH_USER_DIRS |
2567 LOAD_LIBRARY_SEARCH_SYSTEM32);
2569 if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
2571 DWORD type = RtlDetermineDosPathNameType_U( module );
2572 if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2573 return STATUS_INVALID_PARAMETER;
2574 mod_end = get_module_path_end( module );
2575 len += (mod_end - module) + 1;
2577 else module = NULL;
2579 if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
2581 image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
2582 image_end = get_module_path_end( image );
2583 len += (image_end - image) + 1;
2586 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2588 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2589 len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2590 if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
2593 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2595 if ((p = ret = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2597 if (module) p = append_path( p, module, mod_end - module );
2598 if (image) p = append_path( p, image, image_end - image );
2599 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2601 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2602 p = append_path( p, dir->dir + 4 /* \??\ */, -1 );
2603 p = append_path( p, dll_directory.Buffer, dll_directory.Length / sizeof(WCHAR) );
2605 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2606 else
2608 if (p > ret) p--;
2609 *p = 0;
2612 *path = ret;
2613 return STATUS_SUCCESS;
2617 /***********************************************************************
2618 * open_dll_file
2620 * Open a file for a new dll. Helper for find_dll_file.
2622 static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2623 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2625 FILE_BASIC_INFORMATION info;
2626 OBJECT_ATTRIBUTES attr;
2627 IO_STATUS_BLOCK io;
2628 LARGE_INTEGER size;
2629 FILE_OBJECTID_BUFFER fid;
2630 NTSTATUS status;
2631 HANDLE handle;
2633 if ((*pwm = find_fullname_module( nt_name ))) return STATUS_SUCCESS;
2635 attr.Length = sizeof(attr);
2636 attr.RootDirectory = 0;
2637 attr.Attributes = OBJ_CASE_INSENSITIVE;
2638 attr.ObjectName = nt_name;
2639 attr.SecurityDescriptor = NULL;
2640 attr.SecurityQualityOfService = NULL;
2641 if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
2642 FILE_SHARE_READ | FILE_SHARE_DELETE,
2643 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
2645 if (status != STATUS_OBJECT_PATH_NOT_FOUND &&
2646 status != STATUS_OBJECT_NAME_NOT_FOUND &&
2647 !NtQueryAttributesFile( &attr, &info ))
2649 /* if the file exists but failed to open, report the error */
2650 return status;
2652 /* otherwise continue searching */
2653 return STATUS_DLL_NOT_FOUND;
2656 if (!NtFsControlFile( handle, 0, NULL, NULL, &io, FSCTL_GET_OBJECT_ID, NULL, 0, &fid, sizeof(fid) ))
2658 memcpy( id, fid.ObjectId, sizeof(*id) );
2659 if ((*pwm = find_fileid_module( id )))
2661 TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2662 (*pwm)->ldr.DllBase, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2663 NtClose( handle );
2664 return STATUS_SUCCESS;
2668 size.QuadPart = 0;
2669 status = NtCreateSection( mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2670 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
2671 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
2672 if (!status)
2674 NtQuerySection( *mapping, SectionImageInformation, image_info, sizeof(*image_info), NULL );
2675 if (!is_valid_binary( handle, image_info ))
2677 TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->Machine );
2678 status = STATUS_NOT_SUPPORTED;
2679 NtClose( *mapping );
2680 *mapping = NULL;
2683 NtClose( handle );
2684 return status;
2688 /******************************************************************************
2689 * find_existing_module
2691 * Find an existing module that is the same mapping as the new module.
2693 static WINE_MODREF *find_existing_module( HMODULE module )
2695 WINE_MODREF *wm;
2696 LIST_ENTRY *mark, *entry;
2697 LDR_DATA_TABLE_ENTRY *mod;
2698 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2700 if ((wm = get_modref( module ))) return wm;
2702 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
2703 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2705 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
2706 if (mod->TimeDateStamp != nt->FileHeader.TimeDateStamp) continue;
2707 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
2708 if (wm->CheckSum != nt->OptionalHeader.CheckSum) continue;
2709 if (NtAreMappedFilesTheSame( mod->DllBase, module ) != STATUS_SUCCESS) continue;
2710 return CONTAINING_RECORD( mod, WINE_MODREF, ldr );
2712 return NULL;
2716 /******************************************************************************
2717 * load_native_dll (internal)
2719 static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, HANDLE mapping,
2720 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2721 DWORD flags, BOOL system, WINE_MODREF** pwm )
2723 void *module = NULL;
2724 SIZE_T len = 0;
2725 NTSTATUS status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, NULL, &len,
2726 ViewShare, 0, PAGE_EXECUTE_READ );
2728 if (!NT_SUCCESS(status)) return status;
2730 if ((*pwm = find_existing_module( module ))) /* already loaded */
2732 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2733 TRACE( "found %s for %s at %p, count=%d\n",
2734 debugstr_us(&(*pwm)->ldr.FullDllName), debugstr_us(nt_name),
2735 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
2736 if (module != (*pwm)->ldr.DllBase) NtUnmapViewOfSection( NtCurrentProcess(), module );
2737 return STATUS_SUCCESS;
2739 #ifdef _WIN64
2740 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH && !convert_to_pe64( module, image_info ))
2741 status = STATUS_INVALID_IMAGE_FORMAT;
2742 #endif
2743 if (NT_SUCCESS(status)) status = build_module( load_path, nt_name, &module, image_info, id, flags, system, pwm );
2744 if (status && module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2745 return status;
2749 /***********************************************************************
2750 * load_so_dll
2752 static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2753 DWORD flags, WINE_MODREF **pwm )
2755 void *module;
2756 NTSTATUS status;
2757 WINE_MODREF *wm;
2758 struct load_so_dll_params params = { *nt_name, &module };
2760 TRACE( "trying %s as so lib\n", debugstr_us(nt_name) );
2761 if ((status = WINE_UNIX_CALL( unix_load_so_dll, &params )))
2763 WARN( "failed to load .so lib %s\n", debugstr_us(nt_name) );
2764 if (status == STATUS_INVALID_IMAGE_FORMAT) status = STATUS_INVALID_IMAGE_NOT_MZ;
2765 return status;
2768 if ((wm = get_modref( module ))) /* already loaded */
2770 TRACE( "Found %s at %p for builtin %s\n",
2771 debugstr_w(wm->ldr.FullDllName.Buffer), wm->ldr.DllBase, debugstr_us(nt_name) );
2772 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2774 else
2776 SECTION_IMAGE_INFORMATION image_info = { 0 };
2778 if ((status = build_module( load_path, &params.nt_name, &module, &image_info, NULL, flags, FALSE, &wm )))
2780 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2781 return status;
2783 TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_us(nt_name), module );
2785 *pwm = wm;
2786 return STATUS_SUCCESS;
2790 /*************************************************************************
2791 * build_main_module
2793 * Build the module data for the main image.
2795 static WINE_MODREF *build_main_module(void)
2797 SECTION_IMAGE_INFORMATION info;
2798 UNICODE_STRING nt_name;
2799 WINE_MODREF *wm;
2800 NTSTATUS status;
2801 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
2802 void *module = NtCurrentTeb()->Peb->ImageBaseAddress;
2804 default_load_path = params->DllPath.Buffer;
2805 if (!default_load_path)
2806 get_dll_load_path( params->ImagePathName.Buffer, NULL, dll_safe_mode, &default_load_path );
2808 NtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info), NULL );
2809 if (info.ImageCharacteristics & IMAGE_FILE_DLL)
2811 MESSAGE( "wine: %s is a dll, not an executable\n", debugstr_us(&params->ImagePathName) );
2812 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
2814 #ifdef _WIN64
2815 if (!convert_to_pe64( module, &info ))
2817 status = STATUS_INVALID_IMAGE_FORMAT;
2818 goto failed;
2820 #endif
2821 status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
2822 if (status) goto failed;
2823 status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, FALSE, &wm );
2824 if (status) goto failed;
2825 RtlFreeUnicodeString( &nt_name );
2826 wm->ldr.LoadCount = -1;
2827 return wm;
2828 failed:
2829 MESSAGE( "wine: failed to create main module for %s, status %lx\n",
2830 debugstr_us(&params->ImagePathName), status );
2831 NtTerminateProcess( GetCurrentProcess(), status );
2832 return NULL; /* unreached */
2836 /***********************************************************************
2837 * build_dlldata_path
2839 * Helper for find_actctx_dll.
2841 static NTSTATUS build_dlldata_path( LPCWSTR libname, ACTCTX_SECTION_KEYED_DATA *data, LPWSTR *fullname )
2843 ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *dlldata = data->lpData;
2844 ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT *path;
2845 char *base = data->lpSectionBase;
2846 SIZE_T total = dlldata->TotalPathLength + (wcslen(libname) + 1) * sizeof(WCHAR);
2847 WCHAR *p, *buffer;
2848 NTSTATUS status = STATUS_SUCCESS;
2849 ULONG i;
2851 if (!(p = buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
2852 path = (ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_SEGMENT *)(dlldata + 1);
2853 for (i = 0; i < dlldata->PathSegmentCount; i++)
2855 memcpy( p, base + path[i].Offset, path[i].Length );
2856 p += path[i].Length / sizeof(WCHAR);
2858 if (p == buffer || p[-1] == '\\') wcscpy( p, libname );
2859 else *p = 0;
2861 if (dlldata->Flags & ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_EXPAND)
2863 RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), NULL, 0, &total );
2864 if ((*fullname = RtlAllocateHeap( GetProcessHeap(), 0, total * sizeof(WCHAR) )))
2865 RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), *fullname, total, NULL );
2866 else
2867 status = STATUS_NO_MEMORY;
2869 RtlFreeHeap( GetProcessHeap(), 0, buffer );
2871 else *fullname = buffer;
2873 return status;
2877 /***********************************************************************
2878 * find_actctx_dll
2880 * Find the full path (if any) of the dll from the activation context.
2882 static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
2884 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
2886 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info = NULL;
2887 ACTCTX_SECTION_KEYED_DATA data;
2888 ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *dlldata;
2889 UNICODE_STRING nameW;
2890 NTSTATUS status;
2891 SIZE_T needed, size = 1024;
2892 WCHAR *p;
2894 RtlInitUnicodeString( &nameW, libname );
2895 data.cbSize = sizeof(data);
2896 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2897 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
2898 &nameW, &data );
2899 if (status != STATUS_SUCCESS) return status;
2901 if (data.ulLength < sizeof(*dlldata))
2903 status = STATUS_SXS_KEY_NOT_FOUND;
2904 goto done;
2906 dlldata = data.lpData;
2907 if (!(dlldata->Flags & ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION_PATH_OMITS_ASSEMBLY_ROOT))
2909 status = build_dlldata_path( libname, &data, fullname );
2910 goto done;
2913 for (;;)
2915 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2917 status = STATUS_NO_MEMORY;
2918 goto done;
2920 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
2921 AssemblyDetailedInformationInActivationContext,
2922 info, size, &needed );
2923 if (status == STATUS_SUCCESS) break;
2924 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
2925 RtlFreeHeap( GetProcessHeap(), 0, info );
2926 size = needed;
2927 /* restart with larger buffer */
2930 if (!info->lpAssemblyManifestPath)
2932 status = STATUS_SXS_KEY_NOT_FOUND;
2933 goto done;
2936 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2938 DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2939 p++;
2940 len = wcslen( p );
2941 if (!dirlen || len <= dirlen ||
2942 RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2943 wcsicmp( p + dirlen, L".manifest" ))
2945 /* manifest name does not match directory name, so it's not a global
2946 * windows/winsxs manifest; use the manifest directory name instead */
2947 dirlen = p - info->lpAssemblyManifestPath;
2948 needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
2949 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2951 status = STATUS_NO_MEMORY;
2952 goto done;
2954 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
2955 p += dirlen;
2956 wcscpy( p, libname );
2957 goto done;
2961 if (!info->lpAssemblyDirectoryName)
2963 status = STATUS_SXS_KEY_NOT_FOUND;
2964 goto done;
2967 needed = (wcslen(windows_dir) * sizeof(WCHAR) +
2968 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
2970 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2972 status = STATUS_NO_MEMORY;
2973 goto done;
2975 wcscpy( p, windows_dir );
2976 p += wcslen(p);
2977 memcpy( p, winsxsW, sizeof(winsxsW) );
2978 p += ARRAY_SIZE( winsxsW );
2979 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
2980 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2981 *p++ = '\\';
2982 wcscpy( p, libname );
2983 done:
2984 RtlFreeHeap( GetProcessHeap(), 0, info );
2985 RtlReleaseActivationContext( data.hActCtx );
2986 return status;
2991 /******************************************************************************
2992 * find_apiset_dll
2994 static NTSTATUS find_apiset_dll( const WCHAR *name, WCHAR **fullname )
2996 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
2997 const API_SET_NAMESPACE_ENTRY *entry;
2998 UNICODE_STRING str;
2999 ULONG len;
3001 if (get_apiset_entry( map, name, wcslen(name), &entry )) return STATUS_APISET_NOT_PRESENT;
3002 if (get_apiset_target( map, entry, NULL, &str )) return STATUS_DLL_NOT_FOUND;
3004 len = wcslen( system_dir ) + str.Length / sizeof(WCHAR);
3005 if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
3006 return STATUS_NO_MEMORY;
3007 wcscpy( *fullname, system_dir );
3008 memcpy( *fullname + wcslen( system_dir ), str.Buffer, str.Length );
3009 (*fullname)[len] = 0;
3010 return STATUS_SUCCESS;
3014 /***********************************************************************
3015 * get_env_var
3017 static NTSTATUS get_env_var( const WCHAR *name, SIZE_T extra, UNICODE_STRING *ret )
3019 NTSTATUS status;
3020 SIZE_T len, size = 1024 + extra;
3022 for (;;)
3024 ret->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) );
3025 status = RtlQueryEnvironmentVariable( NULL, name, wcslen(name),
3026 ret->Buffer, size - extra - 1, &len );
3027 if (!status)
3029 ret->Buffer[len] = 0;
3030 ret->Length = len * sizeof(WCHAR);
3031 ret->MaximumLength = size * sizeof(WCHAR);
3032 return status;
3034 RtlFreeHeap( GetProcessHeap(), 0, ret->Buffer );
3035 if (status != STATUS_BUFFER_TOO_SMALL)
3037 ret->Buffer = NULL;
3038 return status;
3040 size = len + 1 + extra;
3045 /***********************************************************************
3046 * find_builtin_without_file
3048 * Find a builtin dll when the corresponding file cannot be found in the prefix.
3049 * This is used during prefix bootstrap.
3051 static NTSTATUS find_builtin_without_file( const WCHAR *name, UNICODE_STRING *new_name,
3052 WINE_MODREF **pwm, HANDLE *mapping,
3053 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
3055 const WCHAR *ext;
3056 WCHAR dllpath[32];
3057 DWORD i, len;
3058 NTSTATUS status = STATUS_DLL_NOT_FOUND;
3059 BOOL found_image = FALSE;
3061 if (contains_path( name )) return status;
3063 if (!is_prefix_bootstrap)
3065 /* 16-bit files can't be loaded from the prefix */
3066 if (!name[1] || wcscmp( name + wcslen(name) - 2, L"16" )) return status;
3069 if (!get_env_var( L"WINEBUILDDIR", 20 + 2 * wcslen(name) + wcslen(pe_dir), new_name ))
3071 len = new_name->Length;
3072 RtlAppendUnicodeToString( new_name, L"\\dlls\\" );
3073 RtlAppendUnicodeToString( new_name, name );
3074 if ((ext = wcsrchr( name, '.' )) && !wcscmp( ext, L".dll" )) new_name->Length -= 4 * sizeof(WCHAR);
3075 RtlAppendUnicodeToString( new_name, pe_dir );
3076 RtlAppendUnicodeToString( new_name, L"\\" );
3077 RtlAppendUnicodeToString( new_name, name );
3078 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3079 if (status != STATUS_DLL_NOT_FOUND) goto done;
3081 new_name->Length = len;
3082 RtlAppendUnicodeToString( new_name, L"\\programs\\" );
3083 RtlAppendUnicodeToString( new_name, name );
3084 RtlAppendUnicodeToString( new_name, pe_dir );
3085 RtlAppendUnicodeToString( new_name, L"\\" );
3086 RtlAppendUnicodeToString( new_name, name );
3087 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3088 if (status != STATUS_DLL_NOT_FOUND) goto done;
3089 RtlFreeUnicodeString( new_name );
3092 for (i = 0; ; i++)
3094 swprintf( dllpath, ARRAY_SIZE(dllpath), L"WINEDLLDIR%u", i );
3095 if (get_env_var( dllpath, wcslen(pe_dir) + wcslen(name) + 1, new_name )) break;
3096 len = new_name->Length;
3097 RtlAppendUnicodeToString( new_name, pe_dir );
3098 RtlAppendUnicodeToString( new_name, L"\\" );
3099 RtlAppendUnicodeToString( new_name, name );
3100 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3101 if (status != STATUS_DLL_NOT_FOUND) goto done;
3102 new_name->Length = len;
3103 RtlAppendUnicodeToString( new_name, L"\\" );
3104 RtlAppendUnicodeToString( new_name, name );
3105 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3106 if (status == STATUS_NOT_SUPPORTED) found_image = TRUE;
3107 else if (status != STATUS_DLL_NOT_FOUND) goto done;
3108 RtlFreeUnicodeString( new_name );
3110 if (found_image) status = STATUS_NOT_SUPPORTED;
3112 done:
3113 RtlFreeUnicodeString( new_name );
3114 if (!status)
3116 new_name->Length = (4 + wcslen(system_dir) + wcslen(name)) * sizeof(WCHAR);
3117 new_name->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, new_name->Length + sizeof(WCHAR) );
3118 wcscpy( new_name->Buffer, L"\\??\\" );
3119 wcscat( new_name->Buffer, system_dir );
3120 wcscat( new_name->Buffer, name );
3122 return status;
3126 /***********************************************************************
3127 * search_dll_file
3129 * Search for dll in the specified paths.
3131 static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
3132 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
3133 struct file_id *id )
3135 WCHAR *name;
3136 BOOL found_image = FALSE;
3137 NTSTATUS status = STATUS_DLL_NOT_FOUND;
3138 ULONG len;
3140 if (!paths) paths = default_load_path;
3141 len = wcslen( paths );
3143 if (len < wcslen( system_dir )) len = wcslen( system_dir );
3144 len += wcslen( search ) + 2;
3146 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
3147 return STATUS_NO_MEMORY;
3149 while (*paths)
3151 LPCWSTR ptr = paths;
3153 while (*ptr && *ptr != ';') ptr++;
3154 len = ptr - paths;
3155 if (*ptr == ';') ptr++;
3156 memcpy( name, paths, len * sizeof(WCHAR) );
3157 if (len && name[len - 1] != '\\') name[len++] = '\\';
3158 wcscpy( name + len, search );
3160 nt_name->Buffer = NULL;
3161 if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;
3163 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3164 if (status == STATUS_NOT_SUPPORTED) found_image = TRUE;
3165 else if (status != STATUS_DLL_NOT_FOUND) goto done;
3166 RtlFreeUnicodeString( nt_name );
3167 paths = ptr;
3170 if (found_image) status = STATUS_NOT_SUPPORTED;
3172 done:
3173 RtlFreeHeap( GetProcessHeap(), 0, name );
3174 return status;
3177 /***********************************************************************
3178 * find_dll_file
3180 * Find the file (or already loaded module) for a given dll name.
3182 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNICODE_STRING *nt_name,
3183 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
3184 struct file_id *id )
3186 WCHAR *fullname = NULL;
3187 NTSTATUS status;
3188 ULONG wow64_old_value = 0;
3190 *pwm = NULL;
3192 /* Win 7/2008R2 and up seem to re-enable WoW64 FS redirection when loading libraries */
3193 RtlWow64EnableFsRedirectionEx( 0, &wow64_old_value );
3195 nt_name->Buffer = NULL;
3197 if (!contains_path( libname ))
3199 status = find_apiset_dll( libname, &fullname );
3200 if (status == STATUS_DLL_NOT_FOUND) goto done;
3202 if (status) status = find_actctx_dll( libname, &fullname );
3204 if (status == STATUS_SUCCESS)
3206 TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
3207 libname = fullname;
3209 else
3211 if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
3212 if ((*pwm = find_basename_module( libname )) != NULL)
3214 status = STATUS_SUCCESS;
3215 goto done;
3220 if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
3222 status = search_dll_file( load_path, libname, nt_name, pwm, mapping, image_info, id );
3223 if (status == STATUS_DLL_NOT_FOUND)
3224 status = find_builtin_without_file( libname, nt_name, pwm, mapping, image_info, id );
3226 else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
3227 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3229 if (status == STATUS_NOT_SUPPORTED) status = STATUS_INVALID_IMAGE_FORMAT;
3231 done:
3232 RtlFreeHeap( GetProcessHeap(), 0, fullname );
3233 if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
3234 return status;
3238 /***********************************************************************
3239 * load_dll (internal)
3241 * Load a PE style module according to the load order.
3242 * The loader_section must be locked while calling this function.
3244 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system )
3246 UNICODE_STRING nt_name;
3247 struct file_id id;
3248 HANDLE mapping = 0;
3249 SECTION_IMAGE_INFORMATION image_info;
3250 NTSTATUS nts = STATUS_DLL_NOT_FOUND;
3251 void *prev;
3253 TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
3255 if (system && system_dll_path.Buffer)
3256 nts = search_dll_file( system_dll_path.Buffer, libname, &nt_name, pwm, &mapping, &image_info, &id );
3258 if (nts)
3260 nts = find_dll_file( load_path, libname, &nt_name, pwm, &mapping, &image_info, &id );
3261 system = FALSE;
3264 if (*pwm) /* found already loaded module */
3266 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
3268 TRACE("Found %s for %s at %p, count=%d\n",
3269 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
3270 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
3271 RtlFreeUnicodeString( &nt_name );
3272 return STATUS_SUCCESS;
3275 if (nts && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
3277 prev = NtCurrentTeb()->Tib.ArbitraryUserPointer;
3278 NtCurrentTeb()->Tib.ArbitraryUserPointer = nt_name.Buffer + 4;
3280 switch (nts)
3282 case STATUS_INVALID_IMAGE_NOT_MZ: /* not in PE format, maybe it's a .so file */
3283 if (__wine_unixlib_handle) nts = load_so_dll( load_path, &nt_name, flags, pwm );
3284 break;
3286 case STATUS_SUCCESS: /* valid PE file */
3287 nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, system, pwm );
3288 break;
3291 NtCurrentTeb()->Tib.ArbitraryUserPointer = prev;
3293 done:
3294 if (nts == STATUS_SUCCESS)
3295 TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.DllBase);
3296 else
3297 WARN("Failed to load module %s; status=%lx\n", debugstr_w(libname), nts);
3299 if (mapping) NtClose( mapping );
3300 RtlFreeUnicodeString( &nt_name );
3301 return nts;
3305 /***********************************************************************
3306 * __wine_ctrl_routine
3308 NTSTATUS WINAPI __wine_ctrl_routine( void *arg )
3310 DWORD ret = pCtrlRoutine ? pCtrlRoutine( arg ) : 0;
3311 RtlExitUserThread( ret );
3315 /***********************************************************************
3316 * __wine_unix_spawnvp
3318 NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait )
3320 struct wine_spawnvp_params params = { (char **)argv, wait };
3322 return WINE_UNIX_CALL( unix_wine_spawnvp, &params );
3326 /***********************************************************************
3327 * wine_server_call
3329 unsigned int CDECL wine_server_call( void *req_ptr )
3331 return WINE_UNIX_CALL( unix_wine_server_call, req_ptr );
3335 /***********************************************************************
3336 * wine_server_fd_to_handle
3338 NTSTATUS CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes,
3339 HANDLE *handle )
3341 struct wine_server_fd_to_handle_params params = { fd, access, attributes, handle };
3343 return WINE_UNIX_CALL( unix_wine_server_fd_to_handle, &params );
3347 /***********************************************************************
3348 * wine_server_handle_to_fd (NTDLL.@)
3350 NTSTATUS CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd,
3351 unsigned int *options )
3353 struct wine_server_handle_to_fd_params params = { handle, access, unix_fd, options };
3355 return WINE_UNIX_CALL( unix_wine_server_handle_to_fd, &params );
3358 /******************************************************************
3359 * LdrLoadDll (NTDLL.@)
3361 NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
3362 const UNICODE_STRING *libname, HMODULE* hModule)
3364 WINE_MODREF *wm;
3365 NTSTATUS nts;
3366 WCHAR *dllname = append_dll_ext( libname->Buffer );
3368 RtlEnterCriticalSection( &loader_section );
3370 nts = load_dll( path_name, dllname ? dllname : libname->Buffer, flags, &wm, FALSE );
3372 if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
3374 nts = process_attach( wm->ldr.DdagNode, NULL );
3375 if (nts != STATUS_SUCCESS)
3377 LdrUnloadDll(wm->ldr.DllBase);
3378 wm = NULL;
3381 *hModule = (wm) ? wm->ldr.DllBase : NULL;
3383 RtlLeaveCriticalSection( &loader_section );
3384 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3385 return nts;
3389 /******************************************************************
3390 * LdrGetDllFullName (NTDLL.@)
3392 NTSTATUS WINAPI LdrGetDllFullName( HMODULE module, UNICODE_STRING *name )
3394 WINE_MODREF *wm;
3395 NTSTATUS status;
3397 TRACE( "module %p, name %p.\n", module, name );
3399 if (!module) module = NtCurrentTeb()->Peb->ImageBaseAddress;
3401 RtlEnterCriticalSection( &loader_section );
3402 wm = get_modref( module );
3403 if (wm)
3405 RtlCopyUnicodeString( name, &wm->ldr.FullDllName );
3406 if (name->MaximumLength < wm->ldr.FullDllName.Length + sizeof(WCHAR)) status = STATUS_BUFFER_TOO_SMALL;
3407 else status = STATUS_SUCCESS;
3408 } else status = STATUS_DLL_NOT_FOUND;
3409 RtlLeaveCriticalSection( &loader_section );
3411 return status;
3415 /******************************************************************
3416 * LdrGetDllHandleEx (NTDLL.@)
3418 NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics,
3419 const UNICODE_STRING *name, HMODULE *base )
3421 static const ULONG supported_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
3422 | LDR_GET_DLL_HANDLE_EX_FLAG_PIN;
3423 static const ULONG valid_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
3424 | LDR_GET_DLL_HANDLE_EX_FLAG_PIN | 4;
3425 SECTION_IMAGE_INFORMATION image_info;
3426 UNICODE_STRING nt_name;
3427 struct file_id id;
3428 NTSTATUS status;
3429 WINE_MODREF *wm;
3430 WCHAR *dllname;
3431 HANDLE mapping;
3433 TRACE( "flags %#lx, load_path %p, dll_characteristics %p, name %p, base %p.\n",
3434 flags, load_path, dll_characteristics, name, base );
3436 if (flags & ~valid_flags) return STATUS_INVALID_PARAMETER;
3438 if ((flags & (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
3439 == (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
3440 return STATUS_INVALID_PARAMETER;
3442 if (flags & ~supported_flags) FIXME( "Unsupported flags %#lx.\n", flags );
3443 if (dll_characteristics) FIXME( "dll_characteristics unsupported.\n" );
3445 dllname = append_dll_ext( name->Buffer );
3447 RtlEnterCriticalSection( &loader_section );
3449 status = find_dll_file( load_path, dllname ? dllname : name->Buffer,
3450 &nt_name, &wm, &mapping, &image_info, &id );
3452 if (wm) *base = wm->ldr.DllBase;
3453 else
3455 if (status == STATUS_SUCCESS) NtClose( mapping );
3456 status = STATUS_DLL_NOT_FOUND;
3458 RtlFreeUnicodeString( &nt_name );
3460 if (!status)
3462 if (flags & LDR_GET_DLL_HANDLE_EX_FLAG_PIN)
3463 LdrAddRefDll( LDR_ADDREF_DLL_PIN, *base );
3464 else if (!(flags & LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
3465 LdrAddRefDll( 0, *base );
3468 RtlLeaveCriticalSection( &loader_section );
3469 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3470 TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
3471 return status;
3475 /******************************************************************
3476 * LdrGetDllHandle (NTDLL.@)
3478 NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
3480 return LdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, load_path, NULL, name, base );
3484 /******************************************************************
3485 * LdrAddRefDll (NTDLL.@)
3487 NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
3489 NTSTATUS ret = STATUS_SUCCESS;
3490 WINE_MODREF *wm;
3492 if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %lx not implemented\n", module, flags );
3494 RtlEnterCriticalSection( &loader_section );
3496 if ((wm = get_modref( module )))
3498 if (flags & LDR_ADDREF_DLL_PIN)
3499 wm->ldr.LoadCount = -1;
3500 else
3501 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
3502 TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3504 else ret = STATUS_INVALID_PARAMETER;
3506 RtlLeaveCriticalSection( &loader_section );
3507 return ret;
3511 /***********************************************************************
3512 * LdrProcessRelocationBlock (NTDLL.@)
3514 * Apply relocations to a given page of a mapped PE image.
3516 IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
3517 USHORT *relocs, INT_PTR delta )
3519 while (count--)
3521 USHORT offset = *relocs & 0xfff;
3522 int type = *relocs >> 12;
3523 switch(type)
3525 case IMAGE_REL_BASED_ABSOLUTE:
3526 break;
3527 case IMAGE_REL_BASED_HIGH:
3528 *(short *)((char *)page + offset) += HIWORD(delta);
3529 break;
3530 case IMAGE_REL_BASED_LOW:
3531 *(short *)((char *)page + offset) += LOWORD(delta);
3532 break;
3533 case IMAGE_REL_BASED_HIGHLOW:
3534 *(int *)((char *)page + offset) += delta;
3535 break;
3536 #ifdef _WIN64
3537 case IMAGE_REL_BASED_DIR64:
3538 *(INT_PTR *)((char *)page + offset) += delta;
3539 break;
3540 #elif defined(__arm__)
3541 case IMAGE_REL_BASED_THUMB_MOV32:
3543 UINT *inst = (UINT *)((char *)page + offset);
3544 WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) +
3545 ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff);
3546 WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) +
3547 ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff);
3548 DWORD imm = MAKELONG( lo, hi ) + delta;
3550 lo = LOWORD( imm );
3551 hi = HIWORD( imm );
3553 if ((inst[0] & 0x8000fbf0) != 0x0000f240 || (inst[1] & 0x8000fbf0) != 0x0000f2c0)
3554 ERR("wrong Thumb2 instruction @%p %08x:%08x, expected MOVW/MOVT\n",
3555 inst, inst[0], inst[1] );
3557 inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) +
3558 ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000);
3559 inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) +
3560 ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000);
3561 break;
3563 #endif
3564 default:
3565 FIXME("Unknown/unsupported fixup type %x.\n", type);
3566 return NULL;
3568 relocs++;
3570 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
3574 /******************************************************************
3575 * LdrQueryProcessModuleInformation
3578 NTSTATUS WINAPI LdrQueryProcessModuleInformation(RTL_PROCESS_MODULES *smi,
3579 ULONG buf_size, ULONG* req_size)
3581 RTL_PROCESS_MODULE_INFORMATION *sm = &smi->Modules[0];
3582 ULONG size = sizeof(ULONG);
3583 NTSTATUS nts = STATUS_SUCCESS;
3584 ANSI_STRING str;
3585 char* ptr;
3586 PLIST_ENTRY mark, entry;
3587 LDR_DATA_TABLE_ENTRY *mod;
3588 WORD id = 0;
3590 smi->ModulesCount = 0;
3592 RtlEnterCriticalSection( &loader_section );
3593 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3594 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3596 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3597 size += sizeof(*sm);
3598 if (size <= buf_size)
3600 sm->Section = 0; /* FIXME */
3601 sm->MappedBaseAddress = mod->DllBase;
3602 sm->ImageBaseAddress = mod->DllBase;
3603 sm->ImageSize = mod->SizeOfImage;
3604 sm->Flags = mod->Flags;
3605 sm->LoadOrderIndex = id++;
3606 sm->InitOrderIndex = 0; /* FIXME */
3607 sm->LoadCount = mod->LoadCount;
3608 str.Length = 0;
3609 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
3610 str.Buffer = (char*)sm->Name;
3611 RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
3612 ptr = strrchr(str.Buffer, '\\');
3613 sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3615 smi->ModulesCount++;
3616 sm++;
3618 else nts = STATUS_INFO_LENGTH_MISMATCH;
3620 RtlLeaveCriticalSection( &loader_section );
3622 if (req_size) *req_size = size;
3624 return nts;
3628 static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, LONG *value )
3630 NTSTATUS status;
3631 UNICODE_STRING str;
3632 ULONG size;
3633 WCHAR buffer[64];
3634 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3636 RtlInitUnicodeString( &str, name );
3638 size = sizeof(buffer) - sizeof(WCHAR);
3639 if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
3640 return status;
3642 if (info->Type != REG_DWORD)
3644 buffer[size / sizeof(WCHAR)] = 0;
3645 *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3647 else memcpy( value, info->Data, sizeof(*value) );
3648 return status;
3651 static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
3652 void *data, ULONG in_size, ULONG *out_size )
3654 NTSTATUS status;
3655 UNICODE_STRING str;
3656 ULONG size;
3657 char *buffer;
3658 KEY_VALUE_PARTIAL_INFORMATION *info;
3659 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
3661 RtlInitUnicodeString( &str, name );
3663 size = info_size + in_size;
3664 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
3665 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3666 status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
3667 if (!status || status == STATUS_BUFFER_OVERFLOW)
3669 if (out_size) *out_size = info->DataLength;
3670 if (data && !status) memcpy( data, info->Data, info->DataLength );
3672 RtlFreeHeap( GetProcessHeap(), 0, buffer );
3673 return status;
3677 /******************************************************************
3678 * LdrQueryImageFileExecutionOptions (NTDLL.@)
3680 NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
3681 void *data, ULONG in_size, ULONG *out_size )
3683 static const WCHAR optionsW[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\";
3684 WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3685 OBJECT_ATTRIBUTES attr;
3686 UNICODE_STRING name_str;
3687 HANDLE hkey;
3688 NTSTATUS status;
3689 ULONG len;
3690 WCHAR *p;
3692 attr.Length = sizeof(attr);
3693 attr.RootDirectory = 0;
3694 attr.ObjectName = &name_str;
3695 attr.Attributes = OBJ_CASE_INSENSITIVE;
3696 attr.SecurityDescriptor = NULL;
3697 attr.SecurityQualityOfService = NULL;
3699 p = key->Buffer + key->Length / sizeof(WCHAR);
3700 while (p > key->Buffer && p[-1] != '\\') p--;
3701 len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
3702 name_str.Buffer = path;
3703 name_str.Length = sizeof(optionsW) - sizeof(WCHAR) + len;
3704 name_str.MaximumLength = name_str.Length;
3705 memcpy( path, optionsW, sizeof(optionsW) );
3706 memcpy( path + ARRAY_SIZE( optionsW ) - 1, p, len );
3707 if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
3709 if (type == REG_DWORD)
3711 if (out_size) *out_size = sizeof(ULONG);
3712 if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
3713 else status = STATUS_BUFFER_OVERFLOW;
3715 else status = query_string_option( hkey, value, type, data, in_size, out_size );
3717 NtClose( hkey );
3718 return status;
3722 /******************************************************************
3723 * RtlDllShutdownInProgress (NTDLL.@)
3725 BOOLEAN WINAPI RtlDllShutdownInProgress(void)
3727 return process_detaching;
3730 /****************************************************************************
3731 * LdrResolveDelayLoadedAPI (NTDLL.@)
3733 void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3734 PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
3735 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3736 IMAGE_THUNK_DATA* addr, ULONG flags )
3738 IMAGE_THUNK_DATA *pIAT, *pINT;
3739 DELAYLOAD_INFO delayinfo;
3740 UNICODE_STRING mod;
3741 const CHAR* name;
3742 HMODULE *phmod;
3743 NTSTATUS nts;
3744 FARPROC fp;
3745 DWORD id;
3747 TRACE( "(%p, %p, %p, %p, %p, 0x%08lx)\n", base, desc, dllhook, syshook, addr, flags );
3749 phmod = get_rva(base, desc->ModuleHandleRVA);
3750 pIAT = get_rva(base, desc->ImportAddressTableRVA);
3751 pINT = get_rva(base, desc->ImportNameTableRVA);
3752 name = get_rva(base, desc->DllNameRVA);
3753 id = addr - pIAT;
3755 if (!*phmod)
3757 if (!RtlCreateUnicodeStringFromAsciiz(&mod, name))
3759 nts = STATUS_NO_MEMORY;
3760 goto fail;
3762 nts = LdrLoadDll(NULL, 0, &mod, phmod);
3763 RtlFreeUnicodeString(&mod);
3764 if (nts) goto fail;
3767 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3768 nts = LdrGetProcedureAddress(*phmod, NULL, LOWORD(pINT[id].u1.Ordinal), (void**)&fp);
3769 else
3771 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3772 ANSI_STRING fnc;
3774 RtlInitAnsiString(&fnc, (char*)iibn->Name);
3775 nts = LdrGetProcedureAddress(*phmod, &fnc, 0, (void**)&fp);
3777 if (!nts)
3779 pIAT[id].u1.Function = (ULONG_PTR)fp;
3780 return fp;
3783 fail:
3784 delayinfo.Size = sizeof(delayinfo);
3785 delayinfo.DelayloadDescriptor = desc;
3786 delayinfo.ThunkAddress = addr;
3787 delayinfo.TargetDllName = name;
3788 delayinfo.TargetApiDescriptor.ImportDescribedByName = !IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal);
3789 delayinfo.TargetApiDescriptor.Description.Ordinal = LOWORD(pINT[id].u1.Ordinal);
3790 delayinfo.TargetModuleBase = *phmod;
3791 delayinfo.Unused = NULL;
3792 delayinfo.LastError = nts;
3794 if (dllhook)
3795 return dllhook(4, &delayinfo);
3797 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3799 DWORD_PTR ord = LOWORD(pINT[id].u1.Ordinal);
3800 return syshook(name, (const char *)ord);
3802 else
3804 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3805 return syshook(name, (const char *)iibn->Name);
3809 /******************************************************************
3810 * LdrShutdownProcess (NTDLL.@)
3813 void WINAPI LdrShutdownProcess(void)
3815 BOOL detaching = process_detaching;
3817 TRACE("()\n");
3819 process_detaching = TRUE;
3820 if (!detaching)
3821 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3823 process_detach();
3827 /******************************************************************
3828 * RtlExitUserProcess (NTDLL.@)
3830 void WINAPI RtlExitUserProcess( DWORD status )
3832 RtlEnterCriticalSection( &loader_section );
3833 RtlAcquirePebLock();
3834 NtTerminateProcess( 0, status );
3835 LdrShutdownProcess();
3836 for (;;) NtTerminateProcess( GetCurrentProcess(), status );
3839 /******************************************************************
3840 * LdrShutdownThread (NTDLL.@)
3843 void WINAPI LdrShutdownThread(void)
3845 PLIST_ENTRY mark, entry;
3846 LDR_DATA_TABLE_ENTRY *mod;
3847 WINE_MODREF *wm;
3848 UINT i;
3849 void **pointers;
3851 TRACE("()\n");
3853 /* don't do any detach calls if process is exiting */
3854 if (process_detaching) return;
3856 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3858 RtlEnterCriticalSection( &loader_section );
3859 wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3861 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3862 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3864 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
3865 InInitializationOrderLinks);
3866 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3867 continue;
3868 if ( mod->Flags & LDR_NO_DLL_CALLS )
3869 continue;
3871 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
3872 DLL_THREAD_DETACH, NULL );
3875 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );
3877 RtlAcquirePebLock();
3878 if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3879 if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
3881 for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
3882 RtlFreeHeap( GetProcessHeap(), 0, pointers );
3884 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
3885 NtCurrentTeb()->FlsSlots = NULL;
3886 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3887 NtCurrentTeb()->TlsExpansionSlots = NULL;
3888 RtlReleasePebLock();
3890 RtlLeaveCriticalSection( &loader_section );
3891 /* don't call DbgUiGetThreadDebugObject as some apps hook it and terminate if called */
3892 if (NtCurrentTeb()->DbgSsReserved[1]) NtClose( NtCurrentTeb()->DbgSsReserved[1] );
3893 RtlFreeThreadActivationContextStack();
3895 heap_thread_detach();
3899 /***********************************************************************
3900 * free_modref
3903 static void free_modref( WINE_MODREF *wm )
3905 SINGLE_LIST_ENTRY *entry;
3906 LDR_DEPENDENCY *dep;
3908 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
3909 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
3910 if (wm->ldr.InInitializationOrderLinks.Flink)
3911 RemoveEntryList(&wm->ldr.InInitializationOrderLinks);
3913 while ((entry = wm->ldr.DdagNode->Dependencies.Tail))
3915 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
3916 assert( dep->dependency_from == wm->ldr.DdagNode );
3917 remove_module_dependency( dep );
3920 while ((entry = wm->ldr.DdagNode->IncomingDependencies.Tail))
3922 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_from_entry );
3923 assert( dep->dependency_to == wm->ldr.DdagNode );
3924 remove_module_dependency( dep );
3927 RemoveEntryList(&wm->ldr.NodeModuleLink);
3928 if (IsListEmpty(&wm->ldr.DdagNode->Modules))
3929 RtlFreeHeap( GetProcessHeap(), 0, wm->ldr.DdagNode );
3931 TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
3932 if (!TRACE_ON(module))
3933 TRACE_(loaddll)("Unloaded module %s : %s\n",
3934 debugstr_w(wm->ldr.FullDllName.Buffer),
3935 (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );
3937 free_tls_slot( &wm->ldr );
3938 RtlReleaseActivationContext( wm->ldr.ActivationContext );
3939 NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
3940 if (cached_modref == wm) cached_modref = NULL;
3941 RtlFreeUnicodeString( &wm->ldr.FullDllName );
3942 RtlFreeHeap( GetProcessHeap(), 0, wm );
3945 /***********************************************************************
3946 * MODULE_FlushModrefs
3948 * Remove all unused modrefs and call the internal unloading routines
3949 * for the library type.
3951 * The loader_section must be locked while calling this function.
3953 static void MODULE_FlushModrefs(void)
3955 PLIST_ENTRY mark, entry, prev;
3956 LDR_DATA_TABLE_ENTRY *mod;
3957 WINE_MODREF*wm;
3959 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3960 for (entry = mark->Blink; entry != mark; entry = prev)
3962 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
3963 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3964 prev = entry->Blink;
3965 if (!mod->LoadCount) free_modref( wm );
3968 /* check load order list too for modules that haven't been initialized yet */
3969 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3970 for (entry = mark->Blink; entry != mark; entry = prev)
3972 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3973 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3974 prev = entry->Blink;
3975 if (!mod->LoadCount) free_modref( wm );
3979 /***********************************************************************
3980 * MODULE_DecRefCount
3982 * The loader_section must be locked while calling this function.
3984 static NTSTATUS MODULE_DecRefCount( LDR_DDAG_NODE *node, void *context )
3986 LDR_DATA_TABLE_ENTRY *mod;
3987 WINE_MODREF *wm;
3989 mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
3990 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
3992 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
3993 return STATUS_SUCCESS;
3995 if ( wm->ldr.LoadCount <= 0 )
3996 return STATUS_SUCCESS;
3998 --wm->ldr.LoadCount;
3999 TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
4001 if ( wm->ldr.LoadCount == 0 )
4003 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
4004 walk_node_dependencies( node, context, MODULE_DecRefCount );
4005 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
4006 module_push_unload_trace( wm );
4008 return STATUS_SUCCESS;
4011 /******************************************************************
4012 * LdrUnloadDll (NTDLL.@)
4016 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
4018 WINE_MODREF *wm;
4019 NTSTATUS retv = STATUS_SUCCESS;
4021 if (process_detaching) return retv;
4023 TRACE("(%p)\n", hModule);
4025 RtlEnterCriticalSection( &loader_section );
4027 free_lib_count++;
4028 if ((wm = get_modref( hModule )) != NULL)
4030 TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
4032 /* Recursively decrement reference counts */
4033 MODULE_DecRefCount( wm->ldr.DdagNode, NULL );
4035 /* Call process detach notifications */
4036 if ( free_lib_count <= 1 )
4038 process_detach();
4039 MODULE_FlushModrefs();
4042 TRACE("END\n");
4044 else
4045 retv = STATUS_DLL_NOT_FOUND;
4047 free_lib_count--;
4049 RtlLeaveCriticalSection( &loader_section );
4051 return retv;
4054 /***********************************************************************
4055 * RtlImageNtHeader (NTDLL.@)
4057 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
4059 IMAGE_NT_HEADERS *ret;
4061 __TRY
4063 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
4065 ret = NULL;
4066 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
4068 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
4069 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
4072 __EXCEPT_PAGE_FAULT
4074 return NULL;
4076 __ENDTRY
4077 return ret;
4080 /***********************************************************************
4081 * load_global_options
4083 static void load_global_options(void)
4085 OBJECT_ATTRIBUTES attr;
4086 UNICODE_STRING bootstrap_mode_str = RTL_CONSTANT_STRING( L"WINEBOOTSTRAPMODE" );
4087 UNICODE_STRING session_manager_str =
4088 RTL_CONSTANT_STRING( L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
4089 UNICODE_STRING val_str;
4090 HANDLE hkey;
4092 val_str.MaximumLength = 0;
4093 is_prefix_bootstrap =
4094 RtlQueryEnvironmentVariable_U( NULL, &bootstrap_mode_str, &val_str ) != STATUS_VARIABLE_NOT_FOUND;
4096 attr.Length = sizeof(attr);
4097 attr.RootDirectory = 0;
4098 attr.ObjectName = &session_manager_str;
4099 attr.Attributes = OBJ_CASE_INSENSITIVE;
4100 attr.SecurityDescriptor = NULL;
4101 attr.SecurityQualityOfService = NULL;
4103 if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
4105 query_dword_option( hkey, L"SafeProcessSearchMode", &path_safe_mode );
4106 query_dword_option( hkey, L"SafeDllSearchMode", &dll_safe_mode );
4107 NtClose( hkey );
4111 static BOOL needs_elevation(void)
4113 ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION run_level;
4115 if (!RtlQueryInformationActivationContext( 0, NULL, NULL, RunlevelInformationInActivationContext,
4116 &run_level, sizeof(run_level), NULL ))
4118 TRACE( "image requested run level %#x\n", run_level.RunLevel );
4119 if (run_level.RunLevel == ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE
4120 || run_level.RunLevel == ACTCTX_RUN_LEVEL_REQUIRE_ADMIN)
4121 return TRUE;
4123 return FALSE;
4126 static void elevate_token(void)
4128 PROCESS_ACCESS_TOKEN token;
4129 TOKEN_ELEVATION_TYPE type;
4130 TOKEN_LINKED_TOKEN linked;
4132 NtQueryInformationToken( GetCurrentThreadEffectiveToken(),
4133 TokenElevationType, &type, sizeof(type), NULL );
4135 if (type == TokenElevationTypeFull) return;
4137 NtQueryInformationToken( GetCurrentThreadEffectiveToken(),
4138 TokenLinkedToken, &linked, sizeof(linked), NULL );
4139 NtDuplicateToken( linked.LinkedToken, 0, NULL, FALSE, TokenPrimary, &token.Token );
4141 token.Thread = NULL;
4142 NtSetInformationProcess( GetCurrentProcess(), ProcessAccessToken, &token, sizeof(token) );
4143 NtClose( token.Token );
4144 NtClose( linked.LinkedToken );
4147 #ifdef __arm64ec__
4149 static void load_arm64ec_module(void)
4151 ULONG buffer[16];
4152 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
4153 UNICODE_STRING nameW = RTL_CONSTANT_STRING( L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\amd64" );
4154 WCHAR module[64] = L"C:\\windows\\system32\\xtajit64.dll";
4155 OBJECT_ATTRIBUTES attr;
4156 WINE_MODREF *wm;
4157 NTSTATUS status;
4158 HANDLE key;
4160 InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
4161 if (!NtOpenKey( &key, KEY_READ | KEY_WOW64_64KEY, &attr ))
4163 UNICODE_STRING valueW = RTL_CONSTANT_STRING( L"" );
4164 ULONG dirlen = wcslen( L"C:\\windows\\system32\\" );
4165 ULONG size = sizeof(buffer);
4167 if (!NtQueryValueKey( key, &valueW, KeyValuePartialInformation, buffer, size, &size ) && info->Type == REG_SZ)
4169 size = sizeof(module) - (dirlen + 1) * sizeof(WCHAR);
4170 memcpy( module + dirlen, info->Data, min( info->DataLength, size ));
4172 NtClose( key );
4175 if ((status = load_dll( NULL, module, 0, &wm, FALSE )) ||
4176 (status = arm64ec_process_init( wm->ldr.DllBase )))
4178 ERR( "could not load %s, status %lx\n", debugstr_w(module), status );
4179 NtTerminateProcess( GetCurrentProcess(), status );
4183 #endif
4185 #ifdef _WIN64
4187 static void build_wow64_main_module(void)
4189 UNICODE_STRING nt_name;
4190 WINE_MODREF *wm;
4191 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
4192 void *module = NtCurrentTeb()->Peb->ImageBaseAddress;
4194 RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
4195 wm = alloc_module( module, &nt_name, FALSE );
4196 assert( wm );
4197 wm->ldr.LoadCount = -1;
4198 RtlFreeUnicodeString( &nt_name );
4201 static void (WINAPI *pWow64LdrpInitialize)( CONTEXT *ctx );
4203 void (WINAPI *pWow64PrepareForException)( EXCEPTION_RECORD *rec, CONTEXT *context ) = NULL;
4205 static void init_wow64( CONTEXT *context )
4207 if (!imports_fixup_done)
4209 HMODULE wow64;
4210 WINE_MODREF *wm;
4211 NTSTATUS status;
4212 static const WCHAR wow64_path[] = L"C:\\windows\\system32\\wow64.dll";
4214 build_wow64_main_module();
4215 build_ntdll_module();
4217 if ((status = load_dll( NULL, wow64_path, 0, &wm, FALSE )))
4219 ERR( "could not load %s, status %lx\n", debugstr_w(wow64_path), status );
4220 NtTerminateProcess( GetCurrentProcess(), status );
4222 wow64 = wm->ldr.DllBase;
4223 #define GET_PTR(name) \
4224 if (!(p ## name = RtlFindExportedRoutineByName( wow64, #name ))) ERR( "failed to load %s\n", #name )
4226 GET_PTR( Wow64LdrpInitialize );
4227 GET_PTR( Wow64PrepareForException );
4228 #undef GET_PTR
4229 imports_fixup_done = TRUE;
4232 RtlAcquirePebLock();
4233 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
4234 RtlReleasePebLock();
4236 RtlLeaveCriticalSection( &loader_section );
4237 pWow64LdrpInitialize( context );
4241 #else
4243 void *Wow64Transition = NULL;
4245 static void map_wow64cpu(void)
4247 SIZE_T size = 0;
4248 OBJECT_ATTRIBUTES attr;
4249 UNICODE_STRING string = RTL_CONSTANT_STRING( L"\\??\\C:\\windows\\sysnative\\wow64cpu.dll" );
4250 HANDLE file, section;
4251 IO_STATUS_BLOCK io;
4252 NTSTATUS status;
4254 InitializeObjectAttributes( &attr, &string, 0, NULL, NULL );
4255 if ((status = NtOpenFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ,
4256 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
4258 WARN("failed to open wow64cpu, status %#lx\n", status);
4259 return;
4261 if (!NtCreateSection( &section, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
4262 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
4263 NULL, NULL, PAGE_EXECUTE_READ, SEC_COMMIT, file ))
4265 NtMapViewOfSection( section, NtCurrentProcess(), &Wow64Transition, 0,
4266 0, NULL, &size, ViewShare, 0, PAGE_EXECUTE_READ );
4267 NtClose( section );
4269 NtClose( file );
4272 static void init_wow64( CONTEXT *context )
4274 PEB *peb = NtCurrentTeb()->Peb;
4275 PEB64 *peb64 = UlongToPtr( NtCurrentTeb64()->Peb );
4277 if (Wow64Transition) return; /* already initialized */
4279 peb64->OSMajorVersion = peb->OSMajorVersion;
4280 peb64->OSMinorVersion = peb->OSMinorVersion;
4281 peb64->OSBuildNumber = peb->OSBuildNumber;
4282 peb64->OSPlatformId = peb->OSPlatformId;
4284 #define SET_INIT_BLOCK(func) LdrSystemDllInitBlock.p ## func = PtrToUlong( &func )
4285 SET_INIT_BLOCK( KiUserApcDispatcher );
4286 SET_INIT_BLOCK( KiUserExceptionDispatcher );
4287 SET_INIT_BLOCK( LdrInitializeThunk );
4288 SET_INIT_BLOCK( LdrSystemDllInitBlock );
4289 SET_INIT_BLOCK( RtlUserThreadStart );
4290 SET_INIT_BLOCK( KiUserCallbackDispatcher );
4291 /* SET_INIT_BLOCK( RtlpQueryProcessDebugInformationRemote ); */
4292 /* SET_INIT_BLOCK( RtlpFreezeTimeBias ); */
4293 /* LdrSystemDllInitBlock.ntdll_handle */
4294 #undef SET_INIT_BLOCK
4296 map_wow64cpu();
4298 #endif
4301 /* release some address space once dlls are loaded*/
4302 static void release_address_space(void)
4304 #ifndef _WIN64
4305 void *addr = (void *)1;
4306 SIZE_T size = 0;
4308 NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
4309 #endif
4312 /******************************************************************
4313 * loader_init
4315 * Attach to all the loaded dlls.
4316 * If this is the first time, perform the full process initialization.
4318 void loader_init( CONTEXT *context, void **entry )
4320 static int attach_done;
4321 NTSTATUS status;
4322 ULONG_PTR cookie, port = 0;
4323 WINE_MODREF *wm;
4325 if (process_detaching) NtTerminateThread( GetCurrentThread(), 0 );
4327 RtlEnterCriticalSection( &loader_section );
4329 if (!imports_fixup_done)
4331 ANSI_STRING ctrl_routine = RTL_CONSTANT_STRING( "CtrlRoutine" );
4332 WINE_MODREF *kernel32;
4333 PEB *peb = NtCurrentTeb()->Peb;
4335 peb->LdrData = &ldr;
4336 peb->FastPebLock = &peb_lock;
4337 peb->TlsBitmap = &tls_bitmap;
4338 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
4339 peb->LoaderLock = &loader_section;
4340 peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL );
4342 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
4343 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
4344 sizeof(peb->TlsExpansionBitmapBits) * 8 );
4345 /* TLS index 0 is always reserved, and wow64 reserves extra TLS entries */
4346 RtlSetBits( peb->TlsBitmap, 0, NtCurrentTeb()->WowTebOffset ? WOW64_TLS_MAX_NUMBER : 1 );
4347 RtlSetBits( peb->TlsBitmap, NTDLL_TLS_ERRNO, 1 );
4349 init_user_process_params();
4350 load_global_options();
4351 version_init();
4353 if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
4355 wm = build_main_module();
4356 build_ntdll_module();
4357 #ifdef __arm64ec__
4358 load_arm64ec_module();
4359 update_load_config( wm->ldr.DllBase );
4360 #endif
4362 if ((status = load_dll( NULL, L"kernel32.dll", 0, &kernel32, FALSE )) != STATUS_SUCCESS)
4364 MESSAGE( "wine: could not load kernel32.dll, status %lx\n", status );
4365 NtTerminateProcess( GetCurrentProcess(), status );
4367 node_kernel32 = kernel32->ldr.DdagNode;
4368 pBaseThreadInitThunk = RtlFindExportedRoutineByName( kernel32->ldr.DllBase, "BaseThreadInitThunk" );
4369 LdrGetProcedureAddress( kernel32->ldr.DllBase, &ctrl_routine, 0, (void **)&pCtrlRoutine );
4371 actctx_init();
4372 locale_init();
4373 if (needs_elevation())
4374 elevate_token();
4375 get_env_var( L"WINESYSTEMDLLPATH", 0, &system_dll_path );
4376 if (wm->ldr.Flags & LDR_COR_ILONLY)
4377 status = fixup_imports_ilonly( wm, NULL, entry );
4378 else
4379 status = fixup_imports( wm, NULL );
4381 if (status)
4383 ERR( "Importing dlls for %s failed, status %lx\n",
4384 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4385 NtTerminateProcess( GetCurrentProcess(), status );
4387 imports_fixup_done = TRUE;
4389 else
4391 #ifdef _WIN64
4392 if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
4393 #endif
4394 #ifdef __arm64ec__
4395 arm64ec_thread_init();
4396 #endif
4397 wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
4400 RtlAcquirePebLock();
4401 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
4402 RtlReleasePebLock();
4404 NtCurrentTeb()->FlsSlots = fls_alloc_data();
4406 if (!attach_done) /* first time around */
4408 attach_done = 1;
4409 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4411 ERR( "TLS init failed when loading %s, status %lx\n",
4412 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4413 NtTerminateProcess( GetCurrentProcess(), status );
4415 wm->ldr.Flags |= LDR_PROCESS_ATTACHED; /* don't try to attach again */
4416 if (wm->ldr.ActivationContext)
4417 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
4419 if ((status = process_attach( node_ntdll, context ))
4420 || (status = process_attach( node_kernel32, context )))
4422 ERR( "Initializing system dll for %s failed, status %lx\n",
4423 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4424 NtTerminateProcess( GetCurrentProcess(), status );
4427 if ((status = walk_node_dependencies( wm->ldr.DdagNode, context, process_attach )))
4429 if (last_failed_modref)
4430 ERR( "%s failed to initialize, aborting\n",
4431 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
4432 ERR( "Initializing dlls for %s failed, status %lx\n",
4433 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4434 NtTerminateProcess( GetCurrentProcess(), status );
4436 release_address_space();
4437 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
4438 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
4440 NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort, &port, sizeof(port), NULL );
4441 if (port) process_breakpoint();
4443 else
4445 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4446 NtTerminateThread( GetCurrentThread(), status );
4447 thread_attach();
4448 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH );
4451 RtlLeaveCriticalSection( &loader_section );
4455 /***********************************************************************
4456 * RtlImageDirectoryEntryToData (NTDLL.@)
4458 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
4460 const IMAGE_NT_HEADERS *nt;
4461 DWORD addr;
4463 if ((ULONG_PTR)module & 1) image = FALSE; /* mapped as data file */
4464 module = (HMODULE)((ULONG_PTR)module & ~3);
4465 if (!(nt = RtlImageNtHeader( module ))) return NULL;
4466 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
4468 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
4470 if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4471 if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4472 *size = nt64->OptionalHeader.DataDirectory[dir].Size;
4473 if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4475 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
4477 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
4479 if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4480 if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4481 *size = nt32->OptionalHeader.DataDirectory[dir].Size;
4482 if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4484 else return NULL;
4486 /* not mapped as image, need to find the section containing the virtual address */
4487 return RtlImageRvaToVa( nt, module, addr, NULL );
4491 /***********************************************************************
4492 * RtlImageRvaToSection (NTDLL.@)
4494 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
4495 HMODULE module, DWORD rva )
4497 int i;
4498 const IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
4500 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
4502 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4503 return (PIMAGE_SECTION_HEADER)sec;
4505 return NULL;
4509 /***********************************************************************
4510 * RtlImageRvaToVa (NTDLL.@)
4512 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
4513 DWORD rva, IMAGE_SECTION_HEADER **section )
4515 IMAGE_SECTION_HEADER *sec;
4517 if (section && *section) /* try this section first */
4519 sec = *section;
4520 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4521 goto found;
4523 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
4524 found:
4525 if (section) *section = sec;
4526 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
4530 /***********************************************************************
4531 * RtlAddressInSectionTable (NTDLL.@)
4533 PVOID WINAPI RtlAddressInSectionTable( const IMAGE_NT_HEADERS *nt, HMODULE module,
4534 DWORD rva )
4536 return RtlImageRvaToVa( nt, module, rva, NULL );
4539 /***********************************************************************
4540 * RtlPcToFileHeader (NTDLL.@)
4542 PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
4544 LDR_DATA_TABLE_ENTRY *module;
4545 PVOID ret = NULL;
4547 RtlEnterCriticalSection( &loader_section );
4548 if (!LdrFindEntryForAddress( pc, &module )) ret = module->DllBase;
4549 RtlLeaveCriticalSection( &loader_section );
4550 *address = ret;
4551 return ret;
4555 /****************************************************************************
4556 * LdrGetDllDirectory (NTDLL.@)
4558 NTSTATUS WINAPI LdrGetDllDirectory( UNICODE_STRING *dir )
4560 NTSTATUS status = STATUS_SUCCESS;
4562 RtlEnterCriticalSection( &dlldir_section );
4563 dir->Length = dll_directory.Length + sizeof(WCHAR);
4564 if (dir->MaximumLength >= dir->Length) RtlCopyUnicodeString( dir, &dll_directory );
4565 else
4567 status = STATUS_BUFFER_TOO_SMALL;
4568 if (dir->MaximumLength) dir->Buffer[0] = 0;
4570 RtlLeaveCriticalSection( &dlldir_section );
4571 return status;
4575 /****************************************************************************
4576 * LdrSetDllDirectory (NTDLL.@)
4578 NTSTATUS WINAPI LdrSetDllDirectory( const UNICODE_STRING *dir )
4580 NTSTATUS status = STATUS_SUCCESS;
4581 UNICODE_STRING new;
4583 if (!dir->Buffer) RtlInitUnicodeString( &new, NULL );
4584 else if ((status = RtlDuplicateUnicodeString( 1, dir, &new ))) return status;
4586 RtlEnterCriticalSection( &dlldir_section );
4587 RtlFreeUnicodeString( &dll_directory );
4588 dll_directory = new;
4589 RtlLeaveCriticalSection( &dlldir_section );
4590 return status;
4594 /****************************************************************************
4595 * LdrAddDllDirectory (NTDLL.@)
4597 NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
4599 FILE_BASIC_INFORMATION info;
4600 UNICODE_STRING nt_name;
4601 NTSTATUS status;
4602 OBJECT_ATTRIBUTES attr;
4603 DWORD len;
4604 struct dll_dir_entry *ptr;
4605 DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );
4607 if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
4608 return STATUS_INVALID_PARAMETER;
4610 status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );
4611 if (status) return status;
4612 len = nt_name.Length / sizeof(WCHAR);
4613 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] ))))
4614 return STATUS_NO_MEMORY;
4615 memcpy( ptr->dir, nt_name.Buffer, len * sizeof(WCHAR) );
4617 attr.Length = sizeof(attr);
4618 attr.RootDirectory = 0;
4619 attr.Attributes = OBJ_CASE_INSENSITIVE;
4620 attr.ObjectName = &nt_name;
4621 attr.SecurityDescriptor = NULL;
4622 attr.SecurityQualityOfService = NULL;
4623 status = NtQueryAttributesFile( &attr, &info );
4624 RtlFreeUnicodeString( &nt_name );
4626 if (!status)
4628 TRACE( "%s\n", debugstr_w( ptr->dir ));
4629 RtlEnterCriticalSection( &dlldir_section );
4630 list_add_head( &dll_dir_list, &ptr->entry );
4631 RtlLeaveCriticalSection( &dlldir_section );
4632 *cookie = ptr;
4634 else RtlFreeHeap( GetProcessHeap(), 0, ptr );
4635 return status;
4639 /****************************************************************************
4640 * LdrRemoveDllDirectory (NTDLL.@)
4642 NTSTATUS WINAPI LdrRemoveDllDirectory( void *cookie )
4644 struct dll_dir_entry *ptr = cookie;
4646 TRACE( "%s\n", debugstr_w( ptr->dir ));
4648 RtlEnterCriticalSection( &dlldir_section );
4649 list_remove( &ptr->entry );
4650 RtlFreeHeap( GetProcessHeap(), 0, ptr );
4651 RtlLeaveCriticalSection( &dlldir_section );
4652 return STATUS_SUCCESS;
4656 /*************************************************************************
4657 * LdrSetDefaultDllDirectories (NTDLL.@)
4659 NTSTATUS WINAPI LdrSetDefaultDllDirectories( ULONG flags )
4661 /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
4662 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4663 LOAD_LIBRARY_SEARCH_USER_DIRS |
4664 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4665 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4667 if (!flags || (flags & ~load_library_search_flags)) return STATUS_INVALID_PARAMETER;
4668 default_search_flags = flags;
4669 return STATUS_SUCCESS;
4673 /******************************************************************
4674 * LdrGetDllPath (NTDLL.@)
4676 NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *unknown )
4678 NTSTATUS status;
4679 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
4680 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4681 LOAD_LIBRARY_SEARCH_USER_DIRS |
4682 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4683 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4685 if (flags & LOAD_WITH_ALTERED_SEARCH_PATH)
4687 if (flags & load_library_search_flags) return STATUS_INVALID_PARAMETER;
4688 if (default_search_flags) flags |= default_search_flags | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
4690 else if (!(flags & load_library_search_flags)) flags |= default_search_flags;
4692 RtlEnterCriticalSection( &dlldir_section );
4694 if (flags & load_library_search_flags)
4696 status = get_dll_load_path_search_flags( module, flags, path );
4698 else
4700 const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL;
4701 if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH) || !wcschr( module, L'\\' ))
4702 module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4703 status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
4706 RtlLeaveCriticalSection( &dlldir_section );
4707 *unknown = NULL;
4708 return status;
4712 /*************************************************************************
4713 * RtlSetSearchPathMode (NTDLL.@)
4715 NTSTATUS WINAPI RtlSetSearchPathMode( ULONG flags )
4717 int val;
4719 switch (flags)
4721 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE:
4722 val = 1;
4723 break;
4724 case BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE:
4725 val = 0;
4726 break;
4727 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT:
4728 InterlockedExchange( &path_safe_mode, 2 );
4729 return STATUS_SUCCESS;
4730 default:
4731 return STATUS_INVALID_PARAMETER;
4734 for (;;)
4736 LONG prev = path_safe_mode;
4737 if (prev == 2) break; /* permanently set */
4738 if (InterlockedCompareExchange( &path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4740 return STATUS_ACCESS_DENIED;
4744 /******************************************************************
4745 * RtlGetExePath (NTDLL.@)
4747 NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
4749 const WCHAR *dlldir = L".";
4750 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4752 /* same check as NeedCurrentDirectoryForExePathW */
4753 if (!wcschr( name, '\\' ))
4755 UNICODE_STRING name = RTL_CONSTANT_STRING( L"NoDefaultCurrentDirectoryInExePath" ), value = { 0 };
4757 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4758 dlldir = L"";
4760 return get_dll_load_path( module, dlldir, FALSE, path );
4764 /******************************************************************
4765 * RtlGetSearchPath (NTDLL.@)
4767 NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
4769 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4770 return get_dll_load_path( module, NULL, path_safe_mode, path );
4774 /******************************************************************
4775 * RtlReleasePath (NTDLL.@)
4777 void WINAPI RtlReleasePath( PWSTR path )
4779 RtlFreeHeap( GetProcessHeap(), 0, path );
4783 /*********************************************************************
4784 * ApiSetQueryApiSetPresence (NTDLL.@)
4786 NTSTATUS WINAPI ApiSetQueryApiSetPresence( const UNICODE_STRING *name, BOOLEAN *present )
4788 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
4789 const API_SET_NAMESPACE_ENTRY *entry;
4790 UNICODE_STRING str;
4792 *present = (!get_apiset_entry( map, name->Buffer, name->Length / sizeof(WCHAR), &entry ) &&
4793 !get_apiset_target( map, entry, NULL, &str ));
4794 return STATUS_SUCCESS;
4798 /*********************************************************************
4799 * ApiSetQueryApiSetPresenceEx (NTDLL.@)
4801 NTSTATUS WINAPI ApiSetQueryApiSetPresenceEx( const UNICODE_STRING *name, BOOLEAN *in_schema, BOOLEAN *present )
4803 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
4804 const API_SET_NAMESPACE_ENTRY *entry;
4805 NTSTATUS status;
4806 UNICODE_STRING str;
4807 ULONG i, len = name->Length / sizeof(WCHAR);
4809 /* extension not allowed */
4810 for (i = 0; i < len; i++) if (name->Buffer[i] == '.') return STATUS_INVALID_PARAMETER;
4812 status = get_apiset_entry( map, name->Buffer, len, &entry );
4813 if (status == STATUS_APISET_NOT_PRESENT)
4815 *in_schema = *present = FALSE;
4816 return STATUS_SUCCESS;
4818 if (status) return status;
4820 /* the name must match exactly */
4821 *in_schema = (entry->NameLength == name->Length &&
4822 !wcsnicmp( (WCHAR *)((char *)map + entry->NameOffset), name->Buffer, len ));
4823 *present = *in_schema && !get_apiset_target( map, entry, NULL, &str );
4824 return STATUS_SUCCESS;
4828 /******************************************************************
4829 * DllMain (NTDLL.@)
4831 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4833 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
4834 return TRUE;