ntdll: Only build the main module and ntdll once on Wow64.
[wine.git] / dlls / ntdll / loader.c
blob4fc8af2662e194223857c5906db48794f82b9a97
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/wdm.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(module);
41 WINE_DECLARE_DEBUG_CHANNEL(relay);
42 WINE_DECLARE_DEBUG_CHANNEL(snoop);
43 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
44 WINE_DECLARE_DEBUG_CHANNEL(imports);
46 #ifdef _WIN64
47 #define DEFAULT_SECURITY_COOKIE_64 (((ULONGLONG)0x00002b99 << 32) | 0x2ddfa232)
48 #endif
49 #define DEFAULT_SECURITY_COOKIE_32 0xbb40e64e
50 #define DEFAULT_SECURITY_COOKIE_16 (DEFAULT_SECURITY_COOKIE_32 >> 16)
52 #ifdef __i386__
53 static const WCHAR pe_dir[] = L"\\i386-windows";
54 static const USHORT current_machine = IMAGE_FILE_MACHINE_I386;
55 #elif defined __x86_64__
56 static const WCHAR pe_dir[] = L"\\x86_64-windows";
57 static const USHORT current_machine = IMAGE_FILE_MACHINE_AMD64;
58 #elif defined __arm__
59 static const WCHAR pe_dir[] = L"\\arm-windows";
60 static const USHORT current_machine = IMAGE_FILE_MACHINE_ARMNT;
61 #elif defined __aarch64__
62 static const WCHAR pe_dir[] = L"\\aarch64-windows";
63 static const USHORT current_machine = IMAGE_FILE_MACHINE_ARM64;
64 #else
65 static const WCHAR pe_dir[] = L"";
66 static const USHORT current_machine = IMAGE_FILE_MACHINE_UNKNOWN;
67 #endif
69 /* we don't want to include winuser.h */
70 #define RT_MANIFEST ((ULONG_PTR)24)
71 #define ISOLATIONAWARE_MANIFEST_RESOURCE_ID ((ULONG_PTR)2)
73 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
74 typedef void (CALLBACK *LDRENUMPROC)(LDR_DATA_TABLE_ENTRY *, void *, BOOLEAN *);
76 void (FASTCALL *pBaseThreadInitThunk)(DWORD,LPTHREAD_START_ROUTINE,void *) = NULL;
77 NTSTATUS (WINAPI *__wine_unix_call_dispatcher)( unixlib_handle_t, unsigned int, void * ) = __wine_unix_call;
79 static DWORD (WINAPI *pCtrlRoutine)(void *);
81 SYSTEM_DLL_INIT_BLOCK LdrSystemDllInitBlock = { 0xf0 };
83 void *__wine_syscall_dispatcher = NULL;
84 unixlib_handle_t __wine_unixlib_handle = 0;
86 /* windows directory */
87 const WCHAR windows_dir[] = L"C:\\windows";
88 /* system directory with trailing backslash */
89 const WCHAR system_dir[] = L"C:\\windows\\system32\\";
91 /* system search path */
92 static const WCHAR system_path[] = L"C:\\windows\\system32;C:\\windows\\system;C:\\windows";
94 static BOOL is_prefix_bootstrap; /* are we bootstrapping the prefix? */
95 static BOOL imports_fixup_done = FALSE; /* set once the imports have been fixed up, before attaching them */
96 static BOOL process_detaching = FALSE; /* set on process detach to avoid deadlocks with thread detach */
97 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
98 static LONG path_safe_mode; /* path mode set by RtlSetSearchPathMode */
99 static LONG dll_safe_mode = 1; /* dll search mode */
100 static UNICODE_STRING dll_directory; /* extra path for LdrSetDllDirectory */
101 static UNICODE_STRING system_dll_path; /* path to search for system dependency dlls */
102 static DWORD default_search_flags; /* default flags set by LdrSetDefaultDllDirectories */
103 static WCHAR *default_load_path; /* default dll search path */
105 struct dll_dir_entry
107 struct list entry;
108 WCHAR dir[1];
111 static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from LdrAddDllDirectory */
113 struct ldr_notification
115 struct list entry;
116 PLDR_DLL_NOTIFICATION_FUNCTION callback;
117 void *context;
120 static struct list ldr_notifications = LIST_INIT( ldr_notifications );
122 static const char * const reason_names[] =
124 "PROCESS_DETACH",
125 "PROCESS_ATTACH",
126 "THREAD_ATTACH",
127 "THREAD_DETACH",
130 struct file_id
132 BYTE ObjectId[16];
135 /* internal representation of loaded modules */
136 typedef struct _wine_modref
138 LDR_DATA_TABLE_ENTRY ldr;
139 struct file_id id;
140 ULONG CheckSum;
141 BOOL system;
142 } WINE_MODREF;
144 static UINT tls_module_count; /* number of modules with TLS directory */
145 static IMAGE_TLS_DIRECTORY *tls_dirs; /* array of TLS directories */
146 LIST_ENTRY tls_links = { &tls_links, &tls_links };
148 static RTL_CRITICAL_SECTION loader_section;
149 static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
151 0, 0, &loader_section,
152 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
153 0, 0, { (DWORD_PTR)(__FILE__ ": loader_section") }
155 static RTL_CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
157 static CRITICAL_SECTION dlldir_section;
158 static CRITICAL_SECTION_DEBUG dlldir_critsect_debug =
160 0, 0, &dlldir_section,
161 { &dlldir_critsect_debug.ProcessLocksList, &dlldir_critsect_debug.ProcessLocksList },
162 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
164 static CRITICAL_SECTION dlldir_section = { &dlldir_critsect_debug, -1, 0, 0, 0, 0 };
166 static RTL_CRITICAL_SECTION peb_lock;
167 static RTL_CRITICAL_SECTION_DEBUG peb_critsect_debug =
169 0, 0, &peb_lock,
170 { &peb_critsect_debug.ProcessLocksList, &peb_critsect_debug.ProcessLocksList },
171 0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
173 static RTL_CRITICAL_SECTION peb_lock = { &peb_critsect_debug, -1, 0, 0, 0, 0 };
175 static PEB_LDR_DATA ldr =
177 sizeof(ldr), TRUE, NULL,
178 { &ldr.InLoadOrderModuleList, &ldr.InLoadOrderModuleList },
179 { &ldr.InMemoryOrderModuleList, &ldr.InMemoryOrderModuleList },
180 { &ldr.InInitializationOrderModuleList, &ldr.InInitializationOrderModuleList }
183 static RTL_BITMAP tls_bitmap;
184 static RTL_BITMAP tls_expansion_bitmap;
186 static WINE_MODREF *cached_modref;
187 static WINE_MODREF *current_modref;
188 static WINE_MODREF *last_failed_modref;
190 static LDR_DDAG_NODE *node_ntdll, *node_kernel32;
192 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system );
193 static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved );
194 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
195 DWORD exp_size, DWORD ordinal, LPCWSTR load_path );
196 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
197 DWORD exp_size, const char *name, int hint, LPCWSTR load_path );
199 /* convert PE image VirtualAddress to Real Address */
200 static inline void *get_rva( HMODULE module, DWORD va )
202 return (void *)((char *)module + va);
205 /* check whether the file name contains a path */
206 static inline BOOL contains_path( LPCWSTR name )
208 return ((*name && (name[1] == ':')) || wcschr(name, '/') || wcschr(name, '\\'));
211 #define RTL_UNLOAD_EVENT_TRACE_NUMBER 64
213 typedef struct _RTL_UNLOAD_EVENT_TRACE
215 void *BaseAddress;
216 SIZE_T SizeOfImage;
217 ULONG Sequence;
218 ULONG TimeDateStamp;
219 ULONG CheckSum;
220 WCHAR ImageName[32];
221 } RTL_UNLOAD_EVENT_TRACE, *PRTL_UNLOAD_EVENT_TRACE;
223 static RTL_UNLOAD_EVENT_TRACE unload_traces[RTL_UNLOAD_EVENT_TRACE_NUMBER];
224 static RTL_UNLOAD_EVENT_TRACE *unload_trace_ptr;
225 static unsigned int unload_trace_seq;
227 static void module_push_unload_trace( const WINE_MODREF *wm )
229 RTL_UNLOAD_EVENT_TRACE *ptr = &unload_traces[unload_trace_seq];
230 const LDR_DATA_TABLE_ENTRY *ldr = &wm->ldr;
231 unsigned int len = min(sizeof(ptr->ImageName) - sizeof(WCHAR), ldr->BaseDllName.Length);
233 ptr->BaseAddress = ldr->DllBase;
234 ptr->SizeOfImage = ldr->SizeOfImage;
235 ptr->Sequence = unload_trace_seq;
236 ptr->TimeDateStamp = ldr->TimeDateStamp;
237 ptr->CheckSum = wm->CheckSum;
238 memcpy(ptr->ImageName, ldr->BaseDllName.Buffer, len);
239 ptr->ImageName[len / sizeof(*ptr->ImageName)] = 0;
241 unload_trace_seq = (unload_trace_seq + 1) % ARRAY_SIZE(unload_traces);
242 unload_trace_ptr = unload_traces;
245 #ifdef __arm64ec__
247 static void update_hybrid_metadata( void *module, IMAGE_NT_HEADERS *nt,
248 const IMAGE_ARM64EC_METADATA *metadata )
250 DWORD i, protect_old;
251 const IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
253 if (metadata->Version != 1)
255 ERR( "unknown version %lu\n", metadata->Version );
256 return;
259 /* assume that all pointers are in the same section */
261 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
263 if ((sec->VirtualAddress <= metadata->__os_arm64x_dispatch_call) &&
264 (sec->VirtualAddress + sec->Misc.VirtualSize > metadata->__os_arm64x_dispatch_call))
266 void *base = get_rva( module, sec->VirtualAddress );
267 SIZE_T size = sec->Misc.VirtualSize;
269 NtProtectVirtualMemory( NtCurrentProcess(), &base, &size, PAGE_READWRITE, &protect_old );
271 #define SET_FUNC(func,val) *(void **)get_rva( module, metadata->func ) = val
272 SET_FUNC( __os_arm64x_dispatch_call, __os_arm64x_check_call );
273 SET_FUNC( __os_arm64x_dispatch_call_no_redirect, __os_arm64x_dispatch_call_no_redirect );
274 SET_FUNC( __os_arm64x_dispatch_fptr, __os_arm64x_dispatch_fptr );
275 SET_FUNC( __os_arm64x_dispatch_icall, __os_arm64x_check_icall );
276 SET_FUNC( __os_arm64x_dispatch_icall_cfg, __os_arm64x_check_icall_cfg );
277 SET_FUNC( __os_arm64x_dispatch_ret, __os_arm64x_dispatch_ret );
278 SET_FUNC( GetX64InformationFunctionPointer, __os_arm64x_get_x64_information );
279 SET_FUNC( SetX64InformationFunctionPointer, __os_arm64x_set_x64_information );
280 #undef SET_FUNC
282 NtProtectVirtualMemory( NtCurrentProcess(), &base, &size, protect_old, &protect_old );
283 return;
286 ERR( "module %p no section found for %lx\n", module, metadata->__os_arm64x_dispatch_call );
289 #endif
291 /*********************************************************************
292 * RtlGetUnloadEventTrace [NTDLL.@]
294 RTL_UNLOAD_EVENT_TRACE * WINAPI RtlGetUnloadEventTrace(void)
296 return unload_traces;
299 /*********************************************************************
300 * RtlGetUnloadEventTraceEx [NTDLL.@]
302 void WINAPI RtlGetUnloadEventTraceEx(ULONG **size, ULONG **count, void **trace)
304 static ULONG element_size = sizeof(*unload_traces);
305 static ULONG element_count = ARRAY_SIZE(unload_traces);
307 *size = &element_size;
308 *count = &element_count;
309 *trace = &unload_trace_ptr;
312 /*************************************************************************
313 * call_dll_entry_point
315 * Some brain-damaged dlls (ir32_32.dll for instance) modify ebx in
316 * their entry point, so we need a small asm wrapper. Testing indicates
317 * that only modifying esi leads to a crash, so use this one to backup
318 * ebp while running the dll entry proc.
320 #if defined(__i386__)
321 extern BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
322 __ASM_GLOBAL_FUNC(call_dll_entry_point,
323 "pushl %ebp\n\t"
324 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
325 __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
326 "movl %esp,%ebp\n\t"
327 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
328 "pushl %ebx\n\t"
329 __ASM_CFI(".cfi_rel_offset %ebx,-4\n\t")
330 "pushl %esi\n\t"
331 __ASM_CFI(".cfi_rel_offset %esi,-8\n\t")
332 "pushl %edi\n\t"
333 __ASM_CFI(".cfi_rel_offset %edi,-12\n\t")
334 "movl %ebp,%esi\n\t"
335 __ASM_CFI(".cfi_def_cfa_register %esi\n\t")
336 "pushl 20(%ebp)\n\t"
337 "pushl 16(%ebp)\n\t"
338 "pushl 12(%ebp)\n\t"
339 "movl 8(%ebp),%eax\n\t"
340 "call *%eax\n\t"
341 "movl %esi,%ebp\n\t"
342 __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
343 "leal -12(%ebp),%esp\n\t"
344 "popl %edi\n\t"
345 __ASM_CFI(".cfi_same_value %edi\n\t")
346 "popl %esi\n\t"
347 __ASM_CFI(".cfi_same_value %esi\n\t")
348 "popl %ebx\n\t"
349 __ASM_CFI(".cfi_same_value %ebx\n\t")
350 "popl %ebp\n\t"
351 __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
352 __ASM_CFI(".cfi_same_value %ebp\n\t")
353 "ret" )
354 #elif defined(__x86_64__) && !defined(__arm64ec__)
355 extern BOOL CDECL call_dll_entry_point( DLLENTRYPROC proc, void *module, UINT reason, void *reserved );
356 /* Some apps modify rbx in TLS entry point. */
357 __ASM_GLOBAL_FUNC(call_dll_entry_point,
358 "pushq %rbx\n\t"
359 __ASM_SEH(".seh_pushreg %rbx\n\t")
360 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
361 __ASM_CFI(".cfi_rel_offset %rbx,0\n\t")
362 "subq $48,%rsp\n\t"
363 __ASM_SEH(".seh_stackalloc 48\n\t")
364 __ASM_SEH(".seh_endprologue\n\t")
365 __ASM_CFI(".cfi_adjust_cfa_offset 48\n\t")
366 "mov %rcx,%r10\n\t"
367 "mov %rdx,%rcx\n\t"
368 "mov %r8d,%edx\n\t"
369 "mov %r9,%r8\n\t"
370 "call *%r10\n\t"
371 "addq $48,%rsp\n\t"
372 __ASM_CFI(".cfi_adjust_cfa_offset -48\n\t")
373 "popq %rbx\n\t"
374 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
375 __ASM_CFI(".cfi_same_value %rbx\n\t")
376 "ret" )
377 #else
378 static inline BOOL call_dll_entry_point( DLLENTRYPROC proc, void *module,
379 UINT reason, void *reserved )
381 return proc( module, reason, reserved );
383 #endif
386 #if defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
387 /*************************************************************************
388 * stub_entry_point
390 * Entry point for stub functions.
392 static void WINAPI stub_entry_point( const char *dll, const char *name, void *ret_addr )
394 EXCEPTION_RECORD rec;
396 rec.ExceptionCode = EXCEPTION_WINE_STUB;
397 rec.ExceptionFlags = EH_NONCONTINUABLE;
398 rec.ExceptionRecord = NULL;
399 rec.ExceptionAddress = ret_addr;
400 rec.NumberParameters = 2;
401 rec.ExceptionInformation[0] = (ULONG_PTR)dll;
402 rec.ExceptionInformation[1] = (ULONG_PTR)name;
403 for (;;) RtlRaiseException( &rec );
407 #include "pshpack1.h"
408 #ifdef __i386__
409 struct stub
411 BYTE pushl1; /* pushl $name */
412 const char *name;
413 BYTE pushl2; /* pushl $dll */
414 const char *dll;
415 BYTE call; /* call stub_entry_point */
416 DWORD entry;
418 #elif defined(__arm__)
419 struct stub
421 DWORD ldr_r0; /* ldr r0, $dll */
422 DWORD ldr_r1; /* ldr r1, $name */
423 DWORD mov_r2_lr; /* mov r2, lr */
424 DWORD ldr_pc_pc; /* ldr pc, [pc, #4] */
425 const char *dll;
426 const char *name;
427 const void* entry;
429 #elif defined(__aarch64__) || defined(__arm64ec__)
430 struct stub
432 DWORD ldr_x0; /* ldr x0, $dll */
433 DWORD ldr_x1; /* ldr x1, $name */
434 DWORD mov_x2_lr; /* mov x2, lr */
435 DWORD ldr_x16; /* ldr x16, $entry */
436 DWORD br_x16; /* br x16 */
437 const char *dll;
438 const char *name;
439 const void *entry;
441 #else
442 struct stub
444 BYTE movq_rdi[2]; /* movq $dll,%rdi */
445 const char *dll;
446 BYTE movq_rsi[2]; /* movq $name,%rsi */
447 const char *name;
448 BYTE movq_rsp_rdx[4]; /* movq (%rsp),%rdx */
449 BYTE movq_rax[2]; /* movq $entry, %rax */
450 const void* entry;
451 BYTE jmpq_rax[2]; /* jmp %rax */
453 #endif
454 #include "poppack.h"
456 /*************************************************************************
457 * allocate_stub
459 * Allocate a stub entry point.
461 static ULONG_PTR allocate_stub( const char *dll, const char *name )
463 #define MAX_SIZE 65536
464 static struct stub *stubs;
465 static unsigned int nb_stubs;
466 struct stub *stub;
468 if (nb_stubs >= MAX_SIZE / sizeof(*stub)) return 0xdeadbeef;
470 if (!stubs)
472 SIZE_T size = MAX_SIZE;
473 if (NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&stubs, 0, &size,
474 MEM_COMMIT, PAGE_EXECUTE_READWRITE ) != STATUS_SUCCESS)
475 return 0xdeadbeef;
477 stub = &stubs[nb_stubs++];
478 #ifdef __i386__
479 stub->pushl1 = 0x68; /* pushl $name */
480 stub->name = name;
481 stub->pushl2 = 0x68; /* pushl $dll */
482 stub->dll = dll;
483 stub->call = 0xe8; /* call stub_entry_point */
484 stub->entry = (BYTE *)stub_entry_point - (BYTE *)(&stub->entry + 1);
485 #elif defined(__arm__)
486 stub->ldr_r0 = 0xe59f0008; /* ldr r0, [pc, #8] ($dll) */
487 stub->ldr_r1 = 0xe59f1008; /* ldr r1, [pc, #8] ($name) */
488 stub->mov_r2_lr = 0xe1a0200e; /* mov r2, lr */
489 stub->ldr_pc_pc = 0xe59ff004; /* ldr pc, [pc, #4] */
490 stub->dll = dll;
491 stub->name = name;
492 stub->entry = stub_entry_point;
493 #elif defined(__aarch64__) || defined(__arm64ec__)
494 stub->ldr_x0 = 0x580000a0; /* ldr x0, #20 ($dll) */
495 stub->ldr_x1 = 0x580000c1; /* ldr x1, #24 ($name) */
496 stub->mov_x2_lr = 0xaa1e03e2; /* mov x2, lr */
497 stub->ldr_x16 = 0x580000d0; /* ldr x16, #24 ($entry) */
498 stub->br_x16 = 0xd61f0200; /* br x16 */
499 stub->dll = dll;
500 stub->name = name;
501 stub->entry = stub_entry_point;
502 #else
503 stub->movq_rdi[0] = 0x48; /* movq $dll,%rcx */
504 stub->movq_rdi[1] = 0xb9;
505 stub->dll = dll;
506 stub->movq_rsi[0] = 0x48; /* movq $name,%rdx */
507 stub->movq_rsi[1] = 0xba;
508 stub->name = name;
509 stub->movq_rsp_rdx[0] = 0x4c; /* movq (%rsp),%r8 */
510 stub->movq_rsp_rdx[1] = 0x8b;
511 stub->movq_rsp_rdx[2] = 0x04;
512 stub->movq_rsp_rdx[3] = 0x24;
513 stub->movq_rax[0] = 0x48; /* movq $entry, %rax */
514 stub->movq_rax[1] = 0xb8;
515 stub->entry = stub_entry_point;
516 stub->jmpq_rax[0] = 0xff; /* jmp %rax */
517 stub->jmpq_rax[1] = 0xe0;
518 #endif
519 return (ULONG_PTR)stub;
522 #else /* __i386__ */
523 static inline ULONG_PTR allocate_stub( const char *dll, const char *name ) { return 0xdeadbeef; }
524 #endif /* __i386__ */
526 /* call ldr notifications */
527 static void call_ldr_notifications( ULONG reason, LDR_DATA_TABLE_ENTRY *module )
529 struct ldr_notification *notify, *notify_next;
530 LDR_DLL_NOTIFICATION_DATA data;
532 data.Loaded.Flags = 0;
533 data.Loaded.FullDllName = &module->FullDllName;
534 data.Loaded.BaseDllName = &module->BaseDllName;
535 data.Loaded.DllBase = module->DllBase;
536 data.Loaded.SizeOfImage = module->SizeOfImage;
538 LIST_FOR_EACH_ENTRY_SAFE( notify, notify_next, &ldr_notifications, struct ldr_notification, entry )
540 TRACE_(relay)("\1Call LDR notification callback (proc=%p,reason=%lu,data=%p,context=%p)\n",
541 notify->callback, reason, &data, notify->context );
543 notify->callback(reason, &data, notify->context);
545 TRACE_(relay)("\1Ret LDR notification callback (proc=%p,reason=%lu,data=%p,context=%p)\n",
546 notify->callback, reason, &data, notify->context );
550 /*************************************************************************
551 * get_modref
553 * Looks for the referenced HMODULE in the current process
554 * The loader_section must be locked while calling this function.
556 static WINE_MODREF *get_modref( HMODULE hmod )
558 PLIST_ENTRY mark, entry;
559 PLDR_DATA_TABLE_ENTRY mod;
561 if (cached_modref && cached_modref->ldr.DllBase == hmod) return cached_modref;
563 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
564 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
566 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
567 if (mod->DllBase == hmod)
568 return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
570 return NULL;
574 /**********************************************************************
575 * find_basename_module
577 * Find a module from its base name.
578 * The loader_section must be locked while calling this function
580 static WINE_MODREF *find_basename_module( LPCWSTR name )
582 PLIST_ENTRY mark, entry;
583 UNICODE_STRING name_str;
585 RtlInitUnicodeString( &name_str, name );
587 if (cached_modref && RtlEqualUnicodeString( &name_str, &cached_modref->ldr.BaseDllName, TRUE ))
588 return cached_modref;
590 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
591 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
593 WINE_MODREF *mod = CONTAINING_RECORD(entry, WINE_MODREF, ldr.InLoadOrderLinks);
594 if (RtlEqualUnicodeString( &name_str, &mod->ldr.BaseDllName, TRUE ) && !mod->system)
596 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
597 return cached_modref;
600 return NULL;
604 /**********************************************************************
605 * find_fullname_module
607 * Find a module from its full path name.
608 * The loader_section must be locked while calling this function
610 static WINE_MODREF *find_fullname_module( const UNICODE_STRING *nt_name )
612 PLIST_ENTRY mark, entry;
613 UNICODE_STRING name = *nt_name;
615 if (name.Length <= 4 * sizeof(WCHAR)) return NULL;
616 name.Length -= 4 * sizeof(WCHAR); /* for \??\ prefix */
617 name.Buffer += 4;
619 if (cached_modref && RtlEqualUnicodeString( &name, &cached_modref->ldr.FullDllName, TRUE ))
620 return cached_modref;
622 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
623 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
625 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
626 if (RtlEqualUnicodeString( &name, &mod->FullDllName, TRUE ))
628 cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
629 return cached_modref;
632 return NULL;
636 /**********************************************************************
637 * find_fileid_module
639 * Find a module from its file id.
640 * The loader_section must be locked while calling this function
642 static WINE_MODREF *find_fileid_module( const struct file_id *id )
644 LIST_ENTRY *mark, *entry;
646 if (cached_modref && !memcmp( &cached_modref->id, id, sizeof(*id) )) return cached_modref;
648 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
649 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
651 LDR_DATA_TABLE_ENTRY *mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks );
652 WINE_MODREF *wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
654 if (!memcmp( &wm->id, id, sizeof(*id) ))
656 cached_modref = wm;
657 return wm;
660 return NULL;
664 /******************************************************************************
665 * get_apiset_entry
667 static NTSTATUS get_apiset_entry( const API_SET_NAMESPACE *map, const WCHAR *name, ULONG len,
668 const API_SET_NAMESPACE_ENTRY **entry )
670 const API_SET_HASH_ENTRY *hash_entry;
671 ULONG hash, i, hash_len;
672 int min, max;
674 if (len <= 4) return STATUS_INVALID_PARAMETER;
675 if (wcsnicmp( name, L"api-", 4 ) && wcsnicmp( name, L"ext-", 4 )) return STATUS_INVALID_PARAMETER;
676 if (!map) return STATUS_APISET_NOT_PRESENT;
678 for (i = hash_len = 0; i < len; i++)
680 if (name[i] == '.') break;
681 if (name[i] == '-') hash_len = i;
683 for (i = hash = 0; i < hash_len; i++)
684 hash = hash * map->HashFactor + ((name[i] >= 'A' && name[i] <= 'Z') ? name[i] + 32 : name[i]);
686 hash_entry = (API_SET_HASH_ENTRY *)((char *)map + map->HashOffset);
687 min = 0;
688 max = map->Count - 1;
689 while (min <= max)
691 int pos = (min + max) / 2;
692 if (hash_entry[pos].Hash < hash) min = pos + 1;
693 else if (hash_entry[pos].Hash > hash) max = pos - 1;
694 else
696 *entry = (API_SET_NAMESPACE_ENTRY *)((char *)map + map->EntryOffset) + hash_entry[pos].Index;
697 if ((*entry)->HashedLength != hash_len * sizeof(WCHAR)) break;
698 if (wcsnicmp( (WCHAR *)((char *)map + (*entry)->NameOffset), name, hash_len )) break;
699 return STATUS_SUCCESS;
702 return STATUS_APISET_NOT_PRESENT;
706 /******************************************************************************
707 * get_apiset_target
709 static NTSTATUS get_apiset_target( const API_SET_NAMESPACE *map, const API_SET_NAMESPACE_ENTRY *entry,
710 const WCHAR *host, UNICODE_STRING *ret )
712 const API_SET_VALUE_ENTRY *value = (API_SET_VALUE_ENTRY *)((char *)map + entry->ValueOffset);
713 ULONG i, len;
715 if (!entry->ValueCount) return STATUS_DLL_NOT_FOUND;
716 if (host)
718 /* look for specific host in entries 1..n, entry 0 is the default */
719 for (i = 1; i < entry->ValueCount; i++)
721 len = value[i].NameLength / sizeof(WCHAR);
722 if (!wcsnicmp( host, (WCHAR *)((char *)map + value[i].NameOffset), len ) && !host[len])
724 value += i;
725 break;
729 if (!value->ValueOffset) return STATUS_DLL_NOT_FOUND;
730 ret->Buffer = (WCHAR *)((char *)map + value->ValueOffset);
731 ret->Length = value->ValueLength;
732 return STATUS_SUCCESS;
736 /**********************************************************************
737 * build_import_name
739 static NTSTATUS build_import_name( WCHAR buffer[256], const char *import, int len )
741 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
742 const API_SET_NAMESPACE_ENTRY *entry;
743 const WCHAR *host = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
744 UNICODE_STRING str;
746 while (len && import[len-1] == ' ') len--; /* remove trailing spaces */
747 if (len + sizeof(".dll") > 256) return STATUS_DLL_NOT_FOUND;
748 ascii_to_unicode( buffer, import, len );
749 buffer[len] = 0;
750 if (!wcschr( buffer, '.' )) wcscpy( buffer + len, L".dll" );
752 if (get_apiset_entry( map, buffer, wcslen(buffer), &entry )) return STATUS_SUCCESS;
754 if (get_apiset_target( map, entry, host, &str )) return STATUS_DLL_NOT_FOUND;
755 if (str.Length >= 256 * sizeof(WCHAR)) return STATUS_DLL_NOT_FOUND;
757 TRACE( "found %s for %s\n", debugstr_us(&str), debugstr_w(buffer));
758 memcpy( buffer, str.Buffer, str.Length );
759 buffer[str.Length / sizeof(WCHAR)] = 0;
760 return STATUS_SUCCESS;
764 /**********************************************************************
765 * append_dll_ext
767 static WCHAR *append_dll_ext( const WCHAR *name )
769 const WCHAR *ext = wcsrchr( name, '.' );
771 if (!ext || wcschr( ext, '/' ) || wcschr( ext, '\\'))
773 WCHAR *ret = RtlAllocateHeap( GetProcessHeap(), 0,
774 wcslen(name) * sizeof(WCHAR) + sizeof(L".dll") );
775 if (!ret) return NULL;
776 wcscpy( ret, name );
777 wcscat( ret, L".dll" );
778 return ret;
780 return NULL;
784 /***********************************************************************
785 * is_import_dll_system
787 static BOOL is_import_dll_system( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_IMPORT_DESCRIPTOR *import )
789 const char *name = get_rva( mod->DllBase, import->Name );
791 return !_stricmp( name, "ntdll.dll" ) || !_stricmp( name, "kernel32.dll" );
794 /**********************************************************************
795 * insert_single_list_tail
797 static void insert_single_list_after( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *prev, SINGLE_LIST_ENTRY *entry )
799 if (!list->Tail)
801 assert( !prev );
802 entry->Next = entry;
803 list->Tail = entry;
804 return;
806 if (!prev)
808 /* Insert at head. */
809 entry->Next = list->Tail->Next;
810 list->Tail->Next = entry;
811 return;
813 entry->Next = prev->Next;
814 prev->Next = entry;
815 if (prev == list->Tail) list->Tail = entry;
818 /**********************************************************************
819 * remove_single_list_entry
821 static void remove_single_list_entry( LDRP_CSLIST *list, SINGLE_LIST_ENTRY *entry )
823 SINGLE_LIST_ENTRY *prev;
825 assert( list->Tail );
827 if (entry->Next == entry)
829 assert( list->Tail == entry );
830 list->Tail = NULL;
831 return;
834 prev = list->Tail->Next;
835 while (prev->Next != entry && prev != list->Tail)
836 prev = prev->Next;
837 assert( prev->Next == entry );
838 prev->Next = entry->Next;
839 if (list->Tail == entry) list->Tail = prev;
840 entry->Next = NULL;
843 /**********************************************************************
844 * add_module_dependency_after
846 static BOOL add_module_dependency_after( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to,
847 SINGLE_LIST_ENTRY *dep_after )
849 LDR_DEPENDENCY *dep;
851 if (!(dep = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*dep) ))) return FALSE;
853 dep->dependency_from = from;
854 insert_single_list_after( &from->Dependencies, dep_after, &dep->dependency_to_entry );
855 dep->dependency_to = to;
856 insert_single_list_after( &to->IncomingDependencies, NULL, &dep->dependency_from_entry );
858 return TRUE;
861 /**********************************************************************
862 * add_module_dependency
864 static BOOL add_module_dependency( LDR_DDAG_NODE *from, LDR_DDAG_NODE *to )
866 return add_module_dependency_after( from, to, from->Dependencies.Tail );
869 /**********************************************************************
870 * remove_module_dependency
872 static void remove_module_dependency( LDR_DEPENDENCY *dep )
874 remove_single_list_entry( &dep->dependency_to->IncomingDependencies, &dep->dependency_from_entry );
875 remove_single_list_entry( &dep->dependency_from->Dependencies, &dep->dependency_to_entry );
876 RtlFreeHeap( GetProcessHeap(), 0, dep );
879 /**********************************************************************
880 * walk_node_dependencies
882 static NTSTATUS walk_node_dependencies( LDR_DDAG_NODE *node, void *context,
883 NTSTATUS (*callback)( LDR_DDAG_NODE *, void * ))
885 SINGLE_LIST_ENTRY *entry;
886 LDR_DEPENDENCY *dep;
887 NTSTATUS status;
889 if (!(entry = node->Dependencies.Tail)) return STATUS_SUCCESS;
893 entry = entry->Next;
894 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
895 assert( dep->dependency_from == node );
896 if ((status = callback( dep->dependency_to, context ))) break;
897 } while (entry != node->Dependencies.Tail);
899 return status;
902 /*************************************************************************
903 * find_forwarded_export
905 * Find the final function pointer for a forwarded function.
906 * The loader_section must be locked while calling this function.
908 static FARPROC find_forwarded_export( HMODULE module, const char *forward, LPCWSTR load_path )
910 const IMAGE_EXPORT_DIRECTORY *exports;
911 DWORD exp_size;
912 WINE_MODREF *wm;
913 WCHAR mod_name[256];
914 const char *end = strrchr(forward, '.');
915 FARPROC proc = NULL;
917 if (!end) return NULL;
918 if (build_import_name( mod_name, forward, end - forward )) return NULL;
920 if (!(wm = find_basename_module( mod_name )))
922 WINE_MODREF *imp = get_modref( module );
923 TRACE( "delay loading %s for '%s'\n", debugstr_w(mod_name), forward );
924 if (load_dll( load_path, mod_name, 0, &wm, imp->system ) == STATUS_SUCCESS &&
925 !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
927 if (!imports_fixup_done && current_modref)
929 add_module_dependency( current_modref->ldr.DdagNode, wm->ldr.DdagNode );
931 else if (process_attach( wm->ldr.DdagNode, NULL ) != STATUS_SUCCESS)
933 LdrUnloadDll( wm->ldr.DllBase );
934 wm = NULL;
938 if (!wm)
940 ERR( "module not found for forward '%s' used by %s\n",
941 forward, debugstr_w(imp->ldr.FullDllName.Buffer) );
942 return NULL;
945 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
946 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
948 const char *name = end + 1;
950 if (*name == '#') { /* ordinal */
951 proc = find_ordinal_export( wm->ldr.DllBase, exports, exp_size,
952 atoi(name+1) - exports->Base, load_path );
953 } else
954 proc = find_named_export( wm->ldr.DllBase, exports, exp_size, name, -1, load_path );
957 if (!proc)
959 ERR("function not found for forward '%s' used by %s."
960 " If you are using builtin %s, try using the native one instead.\n",
961 forward, debugstr_w(get_modref(module)->ldr.FullDllName.Buffer),
962 debugstr_w(get_modref(module)->ldr.BaseDllName.Buffer) );
964 return proc;
968 /*************************************************************************
969 * find_ordinal_export
971 * Find an exported function by ordinal.
972 * The exports base must have been subtracted from the ordinal already.
973 * The loader_section must be locked while calling this function.
975 static FARPROC find_ordinal_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
976 DWORD exp_size, DWORD ordinal, LPCWSTR load_path )
978 FARPROC proc;
979 const DWORD *functions = get_rva( module, exports->AddressOfFunctions );
981 if (ordinal >= exports->NumberOfFunctions)
983 TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base );
984 return NULL;
986 if (!functions[ordinal]) return NULL;
988 proc = get_rva( module, functions[ordinal] );
990 /* if the address falls into the export dir, it's a forward */
991 if (((const char *)proc >= (const char *)exports) &&
992 ((const char *)proc < (const char *)exports + exp_size))
993 return find_forwarded_export( module, (const char *)proc, load_path );
995 if (TRACE_ON(snoop))
997 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
998 proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
1000 if (TRACE_ON(relay))
1002 const WCHAR *user = current_modref ? current_modref->ldr.BaseDllName.Buffer : NULL;
1003 proc = RELAY_GetProcAddress( module, exports, exp_size, proc, ordinal, user );
1005 return proc;
1009 /*************************************************************************
1010 * find_name_in_exports
1012 * Helper for find_named_export.
1014 static int find_name_in_exports( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports, const char *name )
1016 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
1017 const DWORD *names = get_rva( module, exports->AddressOfNames );
1018 int min = 0, max = exports->NumberOfNames - 1;
1020 while (min <= max)
1022 int res, pos = (min + max) / 2;
1023 char *ename = get_rva( module, names[pos] );
1024 if (!(res = strcmp( ename, name ))) return ordinals[pos];
1025 if (res > 0) max = pos - 1;
1026 else min = pos + 1;
1028 return -1;
1032 /*************************************************************************
1033 * find_named_export
1035 * Find an exported function by name.
1036 * The loader_section must be locked while calling this function.
1038 static FARPROC find_named_export( HMODULE module, const IMAGE_EXPORT_DIRECTORY *exports,
1039 DWORD exp_size, const char *name, int hint, LPCWSTR load_path )
1041 const WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
1042 const DWORD *names = get_rva( module, exports->AddressOfNames );
1043 int ordinal;
1045 /* first check the hint */
1046 if (hint >= 0 && hint < exports->NumberOfNames)
1048 char *ename = get_rva( module, names[hint] );
1049 if (!strcmp( ename, name ))
1050 return find_ordinal_export( module, exports, exp_size, ordinals[hint], load_path );
1053 /* then do a binary search */
1054 if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
1055 return find_ordinal_export( module, exports, exp_size, ordinal, load_path );
1060 /*************************************************************************
1061 * RtlFindExportedRoutineByName
1063 void * WINAPI RtlFindExportedRoutineByName( HMODULE module, const char *name )
1065 const IMAGE_EXPORT_DIRECTORY *exports;
1066 const DWORD *functions;
1067 DWORD exp_size;
1068 int ordinal;
1069 void *proc;
1071 exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
1072 if (!exports || exp_size < sizeof(*exports)) return NULL;
1074 if ((ordinal = find_name_in_exports( module, exports, name )) == -1) return NULL;
1075 if (ordinal >= exports->NumberOfFunctions) return NULL;
1076 functions = get_rva( module, exports->AddressOfFunctions );
1077 if (!functions[ordinal]) return NULL;
1078 proc = get_rva( module, functions[ordinal] );
1079 /* if the address falls into the export dir, it's a forward */
1080 if (((const char *)proc >= (const char *)exports) &&
1081 ((const char *)proc < (const char *)exports + exp_size))
1082 return NULL;
1083 return proc;
1087 /*************************************************************************
1088 * import_dll
1090 * Import the dll specified by the given import descriptor.
1091 * The loader_section must be locked while calling this function.
1093 static BOOL import_dll( HMODULE module, const IMAGE_IMPORT_DESCRIPTOR *descr, LPCWSTR load_path, WINE_MODREF **pwm )
1095 BOOL system = current_modref->system || (current_modref->ldr.Flags & LDR_WINE_INTERNAL);
1096 NTSTATUS status;
1097 WINE_MODREF *wmImp;
1098 HMODULE imp_mod;
1099 const IMAGE_EXPORT_DIRECTORY *exports;
1100 DWORD exp_size;
1101 const IMAGE_THUNK_DATA *import_list;
1102 IMAGE_THUNK_DATA *thunk_list;
1103 WCHAR buffer[256];
1104 const char *name = get_rva( module, descr->Name );
1105 DWORD len = strlen(name);
1106 PVOID protect_base;
1107 SIZE_T protect_size = 0;
1108 DWORD protect_old;
1110 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
1111 if (descr->OriginalFirstThunk)
1112 import_list = get_rva( module, (DWORD)descr->OriginalFirstThunk );
1113 else
1114 import_list = thunk_list;
1116 if (!import_list->u1.Ordinal)
1118 WARN( "Skipping unused import %s\n", name );
1119 *pwm = NULL;
1120 return TRUE;
1123 status = build_import_name( buffer, name, len );
1124 if (!status) status = load_dll( load_path, buffer, 0, &wmImp, system );
1126 if (status)
1128 if (status == STATUS_DLL_NOT_FOUND)
1129 ERR("Library %s (which is needed by %s) not found\n",
1130 name, debugstr_w(current_modref->ldr.FullDllName.Buffer));
1131 else
1132 ERR("Loading library %s (which is needed by %s) failed (error %lx).\n",
1133 name, debugstr_w(current_modref->ldr.FullDllName.Buffer), status);
1134 return FALSE;
1137 /* unprotect the import address table since it can be located in
1138 * readonly section */
1139 while (import_list[protect_size].u1.Ordinal) protect_size++;
1140 protect_base = thunk_list;
1141 protect_size *= sizeof(*thunk_list);
1142 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base,
1143 &protect_size, PAGE_READWRITE, &protect_old );
1145 imp_mod = wmImp->ldr.DllBase;
1146 exports = RtlImageDirectoryEntryToData( imp_mod, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
1148 if (!exports)
1150 /* set all imported function to deadbeef */
1151 while (import_list->u1.Ordinal)
1153 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
1155 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
1156 WARN("No implementation for %s.%d", name, ordinal );
1157 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1159 else
1161 IMAGE_IMPORT_BY_NAME *pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1162 WARN("No implementation for %s.%s", name, pe_name->Name );
1163 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1165 WARN(" imported from %s, allocating stub %p\n",
1166 debugstr_w(current_modref->ldr.FullDllName.Buffer),
1167 (void *)thunk_list->u1.Function );
1168 import_list++;
1169 thunk_list++;
1171 goto done;
1174 while (import_list->u1.Ordinal)
1176 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
1178 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
1180 thunk_list->u1.Function = (ULONG_PTR)find_ordinal_export( imp_mod, exports, exp_size,
1181 ordinal - exports->Base, load_path );
1182 if (!thunk_list->u1.Function)
1184 thunk_list->u1.Function = allocate_stub( name, IntToPtr(ordinal) );
1185 WARN("No implementation for %s.%d imported from %s, setting to %p\n",
1186 name, ordinal, debugstr_w(current_modref->ldr.FullDllName.Buffer),
1187 (void *)thunk_list->u1.Function );
1189 TRACE_(imports)("--- Ordinal %s.%d = %p\n", name, ordinal, (void *)thunk_list->u1.Function );
1191 else /* import by name */
1193 IMAGE_IMPORT_BY_NAME *pe_name;
1194 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
1195 thunk_list->u1.Function = (ULONG_PTR)find_named_export( imp_mod, exports, exp_size,
1196 (const char*)pe_name->Name,
1197 pe_name->Hint, load_path );
1198 if (!thunk_list->u1.Function)
1200 thunk_list->u1.Function = allocate_stub( name, (const char*)pe_name->Name );
1201 WARN("No implementation for %s.%s imported from %s, setting to %p\n",
1202 name, pe_name->Name, debugstr_w(current_modref->ldr.FullDllName.Buffer),
1203 (void *)thunk_list->u1.Function );
1205 TRACE_(imports)("--- %s %s.%d = %p\n",
1206 pe_name->Name, name, pe_name->Hint, (void *)thunk_list->u1.Function);
1208 import_list++;
1209 thunk_list++;
1212 done:
1213 /* restore old protection of the import address table */
1214 NtProtectVirtualMemory( NtCurrentProcess(), &protect_base, &protect_size, protect_old, &protect_old );
1215 *pwm = wmImp;
1216 return TRUE;
1220 /***********************************************************************
1221 * create_module_activation_context
1223 static NTSTATUS create_module_activation_context( LDR_DATA_TABLE_ENTRY *module )
1225 NTSTATUS status;
1226 LDR_RESOURCE_INFO info;
1227 const IMAGE_RESOURCE_DATA_ENTRY *entry;
1229 info.Type = RT_MANIFEST;
1230 info.Name = ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
1231 info.Language = 0;
1232 if (!(status = LdrFindResource_U( module->DllBase, &info, 3, &entry )))
1234 ACTCTXW ctx;
1235 ctx.cbSize = sizeof(ctx);
1236 ctx.lpSource = NULL;
1237 ctx.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_HMODULE_VALID;
1238 ctx.hModule = module->DllBase;
1239 ctx.lpResourceName = (LPCWSTR)ISOLATIONAWARE_MANIFEST_RESOURCE_ID;
1240 status = RtlCreateActivationContext( &module->ActivationContext, &ctx );
1242 return status;
1246 /*************************************************************************
1247 * is_dll_native_subsystem
1249 * Check if dll is a proper native driver.
1250 * Some dlls (corpol.dll from IE6 for instance) are incorrectly marked as native
1251 * while being perfectly normal DLLs. This heuristic should catch such breakages.
1253 static BOOL is_dll_native_subsystem( LDR_DATA_TABLE_ENTRY *mod, const IMAGE_NT_HEADERS *nt, LPCWSTR filename )
1255 const IMAGE_IMPORT_DESCRIPTOR *imports;
1256 DWORD i, size;
1258 if (nt->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE) return FALSE;
1259 if (nt->OptionalHeader.SectionAlignment < page_size) return TRUE;
1260 if (mod->Flags & LDR_WINE_INTERNAL) return TRUE;
1262 if ((imports = RtlImageDirectoryEntryToData( mod->DllBase, TRUE,
1263 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1265 for (i = 0; imports[i].Name; i++)
1266 if (is_import_dll_system( mod, &imports[i] ))
1268 TRACE( "%s imports system dll, assuming not native\n", debugstr_w(filename) );
1269 return FALSE;
1272 return TRUE;
1275 /*************************************************************************
1276 * alloc_tls_slot
1278 * Allocate a TLS slot for a newly-loaded module.
1279 * The loader_section must be locked while calling this function.
1281 static BOOL alloc_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1283 const IMAGE_TLS_DIRECTORY *dir;
1284 ULONG i, size;
1285 void *new_ptr;
1286 LIST_ENTRY *entry;
1288 if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
1289 return FALSE;
1291 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1292 if (!size && !dir->SizeOfZeroFill && !dir->AddressOfCallBacks) return FALSE;
1294 for (i = 0; i < tls_module_count; i++)
1296 if (!tls_dirs[i].StartAddressOfRawData && !tls_dirs[i].EndAddressOfRawData &&
1297 !tls_dirs[i].SizeOfZeroFill && !tls_dirs[i].AddressOfCallBacks)
1298 break;
1301 TRACE( "module %p data %p-%p zerofill %lu index %p callback %p flags %lx -> slot %lu\n", mod->DllBase,
1302 (void *)dir->StartAddressOfRawData, (void *)dir->EndAddressOfRawData, dir->SizeOfZeroFill,
1303 (void *)dir->AddressOfIndex, (void *)dir->AddressOfCallBacks, dir->Characteristics, i );
1305 if (i == tls_module_count)
1307 UINT new_count = max( 32, tls_module_count * 2 );
1309 if (!tls_dirs)
1310 new_ptr = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*tls_dirs) );
1311 else
1312 new_ptr = RtlReAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, tls_dirs,
1313 new_count * sizeof(*tls_dirs) );
1314 if (!new_ptr) return FALSE;
1316 /* resize the pointer block in all running threads */
1317 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1319 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1320 void **old = teb->ThreadLocalStoragePointer;
1321 void **new = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, new_count * sizeof(*new));
1323 if (!new) return FALSE;
1324 if (old) memcpy( new, old, tls_module_count * sizeof(*new) );
1325 teb->ThreadLocalStoragePointer = new;
1326 #ifdef __x86_64__ /* macOS-specific hack */
1327 if (teb->Instrumentation[0]) ((TEB *)teb->Instrumentation[0])->ThreadLocalStoragePointer = new;
1328 #endif
1329 TRACE( "thread %04lx tls block %p -> %p\n", HandleToULong(teb->ClientId.UniqueThread), old, new );
1330 /* FIXME: can't free old block here, should be freed at thread exit */
1333 tls_dirs = new_ptr;
1334 tls_module_count = new_count;
1337 /* allocate the data block in all running threads */
1338 for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
1340 TEB *teb = CONTAINING_RECORD( entry, TEB, TlsLinks );
1342 if (!(new_ptr = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill ))) return -1;
1343 memcpy( new_ptr, (void *)dir->StartAddressOfRawData, size );
1344 memset( (char *)new_ptr + size, 0, dir->SizeOfZeroFill );
1346 TRACE( "thread %04lx slot %lu: %lu/%lu bytes at %p\n",
1347 HandleToULong(teb->ClientId.UniqueThread), i, size, dir->SizeOfZeroFill, new_ptr );
1349 RtlFreeHeap( GetProcessHeap(), 0,
1350 InterlockedExchangePointer( (void **)teb->ThreadLocalStoragePointer + i, new_ptr ));
1353 *(DWORD *)dir->AddressOfIndex = i;
1354 tls_dirs[i] = *dir;
1355 return TRUE;
1359 /*************************************************************************
1360 * free_tls_slot
1362 * Free the module TLS slot on unload.
1363 * The loader_section must be locked while calling this function.
1365 static void free_tls_slot( LDR_DATA_TABLE_ENTRY *mod )
1367 const IMAGE_TLS_DIRECTORY *dir;
1368 ULONG i, size;
1370 if (mod->TlsIndex != -1)
1371 return;
1372 if (!(dir = RtlImageDirectoryEntryToData( mod->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &size )))
1373 return;
1375 i = *(ULONG*)dir->AddressOfIndex;
1376 assert( i < tls_module_count );
1377 memset( &tls_dirs[i], 0, sizeof(tls_dirs[i]) );
1381 /****************************************************************
1382 * fixup_imports_ilonly
1384 * Fixup imports for an IL-only module. All we do is import mscoree.
1385 * The loader_section must be locked while calling this function.
1387 static NTSTATUS fixup_imports_ilonly( WINE_MODREF *wm, LPCWSTR load_path, void **entry )
1389 NTSTATUS status;
1390 void *proc;
1391 const char *name;
1392 WINE_MODREF *prev, *imp;
1394 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1395 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1397 prev = current_modref;
1398 current_modref = wm;
1399 assert( !wm->ldr.DdagNode->Dependencies.Tail );
1400 if (!(status = load_dll( load_path, L"mscoree.dll", 0, &imp, FALSE ))
1401 && !add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, NULL ))
1402 status = STATUS_NO_MEMORY;
1403 current_modref = prev;
1404 if (status)
1406 ERR( "mscoree.dll not found, IL-only binary %s cannot be loaded\n",
1407 debugstr_w(wm->ldr.BaseDllName.Buffer) );
1408 return status;
1411 TRACE( "loaded mscoree for %s\n", debugstr_w(wm->ldr.FullDllName.Buffer) );
1413 name = (wm->ldr.Flags & LDR_IMAGE_IS_DLL) ? "_CorDllMain" : "_CorExeMain";
1414 if (!(proc = RtlFindExportedRoutineByName( imp->ldr.DllBase, name ))) return STATUS_PROCEDURE_NOT_FOUND;
1415 *entry = proc;
1416 return STATUS_SUCCESS;
1420 /****************************************************************
1421 * fixup_imports
1423 * Fixup all imports of a given module.
1424 * The loader_section must be locked while calling this function.
1426 static NTSTATUS fixup_imports( WINE_MODREF *wm, LPCWSTR load_path )
1428 const IMAGE_IMPORT_DESCRIPTOR *imports;
1429 SINGLE_LIST_ENTRY *dep_after;
1430 WINE_MODREF *prev, *imp;
1431 int i, nb_imports;
1432 DWORD size;
1433 NTSTATUS status;
1434 ULONG_PTR cookie;
1436 if (!(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS)) return STATUS_SUCCESS; /* already done */
1437 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1439 if (alloc_tls_slot( &wm->ldr )) wm->ldr.TlsIndex = -1;
1441 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.DllBase, TRUE,
1442 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
1443 return STATUS_SUCCESS;
1445 nb_imports = 0;
1446 while (imports[nb_imports].Name && imports[nb_imports].FirstThunk) nb_imports++;
1448 if (!nb_imports) return STATUS_SUCCESS; /* no imports */
1450 if (!create_module_activation_context( &wm->ldr ))
1451 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1453 /* load the imported modules. They are automatically
1454 * added to the modref list of the process.
1456 prev = current_modref;
1457 current_modref = wm;
1458 status = STATUS_SUCCESS;
1459 for (i = 0; i < nb_imports; i++)
1461 dep_after = wm->ldr.DdagNode->Dependencies.Tail;
1462 if (!import_dll( wm->ldr.DllBase, &imports[i], load_path, &imp ))
1463 status = STATUS_DLL_NOT_FOUND;
1464 else if (imp && imp->ldr.DdagNode != node_ntdll && imp->ldr.DdagNode != node_kernel32)
1465 add_module_dependency_after( wm->ldr.DdagNode, imp->ldr.DdagNode, dep_after );
1467 current_modref = prev;
1468 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1469 return status;
1473 /*************************************************************************
1474 * alloc_module
1476 * Allocate a WINE_MODREF structure and add it to the process list
1477 * The loader_section must be locked while calling this function.
1479 static WINE_MODREF *alloc_module( HMODULE hModule, const UNICODE_STRING *nt_name, BOOL builtin )
1481 WCHAR *buffer;
1482 WINE_MODREF *wm;
1483 const WCHAR *p;
1484 const IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
1486 if (!(wm = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) ))) return NULL;
1488 wm->ldr.DllBase = hModule;
1489 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
1490 wm->ldr.Flags = LDR_DONT_RESOLVE_REFS | (builtin ? LDR_WINE_INTERNAL : 0);
1491 wm->ldr.TlsIndex = 0;
1492 wm->ldr.LoadCount = 1;
1493 wm->CheckSum = nt->OptionalHeader.CheckSum;
1494 wm->ldr.TimeDateStamp = nt->FileHeader.TimeDateStamp;
1496 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_name->Length - 3 * sizeof(WCHAR) )))
1498 RtlFreeHeap( GetProcessHeap(), 0, wm );
1499 return NULL;
1502 if (!(wm->ldr.DdagNode = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm->ldr.DdagNode) )))
1504 RtlFreeHeap( GetProcessHeap(), 0, buffer );
1505 RtlFreeHeap( GetProcessHeap(), 0, wm );
1506 return NULL;
1508 InitializeListHead(&wm->ldr.DdagNode->Modules);
1509 InsertTailList(&wm->ldr.DdagNode->Modules, &wm->ldr.NodeModuleLink);
1511 memcpy( buffer, nt_name->Buffer + 4 /* \??\ prefix */, nt_name->Length - 4 * sizeof(WCHAR) );
1512 buffer[nt_name->Length/sizeof(WCHAR) - 4] = 0;
1513 if ((p = wcsrchr( buffer, '\\' ))) p++;
1514 else p = buffer;
1515 RtlInitUnicodeString( &wm->ldr.FullDllName, buffer );
1516 RtlInitUnicodeString( &wm->ldr.BaseDllName, p );
1518 if (!is_dll_native_subsystem( &wm->ldr, nt, p ))
1520 if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
1521 wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
1522 if (nt->OptionalHeader.AddressOfEntryPoint)
1523 wm->ldr.EntryPoint = (char *)hModule + nt->OptionalHeader.AddressOfEntryPoint;
1526 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
1527 &wm->ldr.InLoadOrderLinks);
1528 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList,
1529 &wm->ldr.InMemoryOrderLinks);
1530 /* wait until init is called for inserting into InInitializationOrderModuleList */
1532 if (!(nt->OptionalHeader.DllCharacteristics & IMAGE_DLLCHARACTERISTICS_NX_COMPAT))
1534 ULONG flags = MEM_EXECUTE_OPTION_ENABLE;
1535 WARN( "disabling no-exec because of %s\n", debugstr_w(wm->ldr.BaseDllName.Buffer) );
1536 NtSetInformationProcess( GetCurrentProcess(), ProcessExecuteFlags, &flags, sizeof(flags) );
1538 return wm;
1542 /*************************************************************************
1543 * alloc_thread_tls
1545 * Allocate the per-thread structure for module TLS storage.
1547 static NTSTATUS alloc_thread_tls(void)
1549 void **pointers;
1550 UINT i, size;
1552 if (!tls_module_count) return STATUS_SUCCESS;
1554 if (!(pointers = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY,
1555 tls_module_count * sizeof(*pointers) )))
1556 return STATUS_NO_MEMORY;
1558 for (i = 0; i < tls_module_count; i++)
1560 const IMAGE_TLS_DIRECTORY *dir = &tls_dirs[i];
1562 if (!dir) continue;
1563 size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
1564 if (!size && !dir->SizeOfZeroFill) continue;
1566 if (!(pointers[i] = RtlAllocateHeap( GetProcessHeap(), 0, size + dir->SizeOfZeroFill )))
1568 while (i) RtlFreeHeap( GetProcessHeap(), 0, pointers[--i] );
1569 RtlFreeHeap( GetProcessHeap(), 0, pointers );
1570 return STATUS_NO_MEMORY;
1572 memcpy( pointers[i], (void *)dir->StartAddressOfRawData, size );
1573 memset( (char *)pointers[i] + size, 0, dir->SizeOfZeroFill );
1575 TRACE( "slot %u: %u/%lu bytes at %p\n", i, size, dir->SizeOfZeroFill, pointers[i] );
1577 NtCurrentTeb()->ThreadLocalStoragePointer = pointers;
1578 #ifdef __x86_64__ /* macOS-specific hack */
1579 if (NtCurrentTeb()->Instrumentation[0])
1580 ((TEB *)NtCurrentTeb()->Instrumentation[0])->ThreadLocalStoragePointer = pointers;
1581 #endif
1582 return STATUS_SUCCESS;
1586 /*************************************************************************
1587 * call_tls_callbacks
1589 static void call_tls_callbacks( HMODULE module, UINT reason )
1591 const IMAGE_TLS_DIRECTORY *dir;
1592 const PIMAGE_TLS_CALLBACK *callback;
1593 ULONG dirsize;
1595 dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
1596 if (!dir || !dir->AddressOfCallBacks) return;
1598 for (callback = (const PIMAGE_TLS_CALLBACK *)dir->AddressOfCallBacks; *callback; callback++)
1600 TRACE_(relay)("\1Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1601 *callback, module, reason_names[reason] );
1602 __TRY
1604 call_dll_entry_point( (DLLENTRYPROC)*callback, module, reason, NULL );
1606 __EXCEPT_ALL
1608 TRACE_(relay)("\1exception %08lx in TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1609 GetExceptionCode(), callback, module, reason_names[reason] );
1610 return;
1612 __ENDTRY
1613 TRACE_(relay)("\1Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
1614 *callback, module, reason_names[reason] );
1618 /*************************************************************************
1619 * MODULE_InitDLL
1621 static NTSTATUS MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
1623 WCHAR mod_name[64];
1624 NTSTATUS status = STATUS_SUCCESS;
1625 DLLENTRYPROC entry = wm->ldr.EntryPoint;
1626 void *module = wm->ldr.DllBase;
1627 BOOL retv = FALSE;
1629 /* Skip calls for modules loaded with special load flags */
1631 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return STATUS_SUCCESS;
1632 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, reason );
1633 if (!entry) return STATUS_SUCCESS;
1635 if (TRACE_ON(relay))
1637 size_t len = min( wm->ldr.BaseDllName.Length, sizeof(mod_name)-sizeof(WCHAR) );
1638 memcpy( mod_name, wm->ldr.BaseDllName.Buffer, len );
1639 mod_name[len / sizeof(WCHAR)] = 0;
1640 TRACE_(relay)("\1Call PE DLL (proc=%p,module=%p %s,reason=%s,res=%p)\n",
1641 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved );
1643 else TRACE("(%p %s,%s,%p) - CALL\n", module, debugstr_w(wm->ldr.BaseDllName.Buffer),
1644 reason_names[reason], lpReserved );
1646 __TRY
1648 retv = call_dll_entry_point( entry, module, reason, lpReserved );
1649 if (!retv)
1650 status = STATUS_DLL_INIT_FAILED;
1652 __EXCEPT_ALL
1654 status = GetExceptionCode();
1655 TRACE_(relay)("\1exception %08lx in PE entry point (proc=%p,module=%p,reason=%s,res=%p)\n",
1656 status, entry, module, reason_names[reason], lpReserved );
1658 __ENDTRY
1660 /* The state of the module list may have changed due to the call
1661 to the dll. We cannot assume that this module has not been
1662 deleted. */
1663 if (TRACE_ON(relay))
1664 TRACE_(relay)("\1Ret PE DLL (proc=%p,module=%p %s,reason=%s,res=%p) retval=%x\n",
1665 entry, module, debugstr_w(mod_name), reason_names[reason], lpReserved, retv );
1666 else
1667 TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
1669 return status;
1673 /*************************************************************************
1674 * process_attach
1676 * Send the process attach notification to all DLLs the given module
1677 * depends on (recursively). This is somewhat complicated due to the fact that
1679 * - we have to respect the module dependencies, i.e. modules implicitly
1680 * referenced by another module have to be initialized before the module
1681 * itself can be initialized
1683 * - the initialization routine of a DLL can itself call LoadLibrary,
1684 * thereby introducing a whole new set of dependencies (even involving
1685 * the 'old' modules) at any time during the whole process
1687 * (Note that this routine can be recursively entered not only directly
1688 * from itself, but also via LoadLibrary from one of the called initialization
1689 * routines.)
1691 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
1692 * the process *detach* notifications to be sent in the correct order.
1693 * This must not only take into account module dependencies, but also
1694 * 'hidden' dependencies created by modules calling LoadLibrary in their
1695 * attach notification routine.
1697 * The strategy is rather simple: we move a WINE_MODREF to the head of the
1698 * list after the attach notification has returned. This implies that the
1699 * detach notifications are called in the reverse of the sequence the attach
1700 * notifications *returned*.
1702 * The loader_section must be locked while calling this function.
1704 static NTSTATUS process_attach( LDR_DDAG_NODE *node, LPVOID lpReserved )
1706 NTSTATUS status = STATUS_SUCCESS;
1707 LDR_DATA_TABLE_ENTRY *mod;
1708 ULONG_PTR cookie;
1709 WINE_MODREF *wm;
1711 if (process_detaching) return status;
1713 mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
1714 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
1716 /* prevent infinite recursion in case of cyclical dependencies */
1717 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
1718 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
1719 return status;
1721 TRACE("(%s,%p) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1723 /* Tag current MODREF to prevent recursive loop */
1724 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
1725 if (lpReserved) wm->ldr.LoadCount = -1; /* pin it if imported by the main exe */
1726 if (wm->ldr.ActivationContext) RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
1728 /* Recursively attach all DLLs this one depends on */
1729 status = walk_node_dependencies( node, lpReserved, process_attach );
1731 if (!wm->ldr.InInitializationOrderLinks.Flink)
1732 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
1733 &wm->ldr.InInitializationOrderLinks);
1735 /* Call DLL entry point */
1736 if (status == STATUS_SUCCESS)
1738 WINE_MODREF *prev = current_modref;
1739 current_modref = wm;
1741 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_LOADED, &wm->ldr );
1742 status = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
1743 if (status == STATUS_SUCCESS)
1745 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
1747 else
1749 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
1750 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, &wm->ldr );
1752 /* point to the name so LdrInitializeThunk can print it */
1753 last_failed_modref = wm;
1754 WARN("Initialization of %s failed\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
1756 current_modref = prev;
1759 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
1760 /* Remove recursion flag */
1761 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
1763 TRACE("(%s,%p) - END\n", debugstr_w(wm->ldr.BaseDllName.Buffer), lpReserved );
1764 return status;
1768 /*************************************************************************
1769 * process_detach
1771 * Send DLL process detach notifications. See the comment about calling
1772 * sequence at process_attach.
1774 static void process_detach(void)
1776 PLIST_ENTRY mark, entry;
1777 PLDR_DATA_TABLE_ENTRY mod;
1779 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1782 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1784 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1785 InInitializationOrderLinks);
1786 /* Check whether to detach this DLL */
1787 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1788 continue;
1789 if ( mod->LoadCount && !process_detaching )
1790 continue;
1792 /* Call detach notification */
1793 mod->Flags &= ~LDR_PROCESS_ATTACHED;
1794 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1795 DLL_PROCESS_DETACH, ULongToPtr(process_detaching) );
1796 call_ldr_notifications( LDR_DLL_NOTIFICATION_REASON_UNLOADED, mod );
1798 /* Restart at head of WINE_MODREF list, as entries might have
1799 been added and/or removed while performing the call ... */
1800 break;
1802 } while (entry != mark);
1805 /*************************************************************************
1806 * thread_attach
1808 * Send DLL thread attach notifications. These are sent in the
1809 * reverse sequence of process detach notification.
1810 * The loader_section must be locked while calling this function.
1812 static void thread_attach(void)
1814 PLIST_ENTRY mark, entry;
1815 PLDR_DATA_TABLE_ENTRY mod;
1817 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1818 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1820 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
1821 InInitializationOrderLinks);
1822 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1823 continue;
1824 if ( mod->Flags & LDR_NO_DLL_CALLS )
1825 continue;
1827 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr), DLL_THREAD_ATTACH, NULL );
1831 /******************************************************************
1832 * LdrDisableThreadCalloutsForDll (NTDLL.@)
1835 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
1837 WINE_MODREF *wm;
1838 NTSTATUS ret = STATUS_SUCCESS;
1840 RtlEnterCriticalSection( &loader_section );
1842 wm = get_modref( hModule );
1843 if (!wm || wm->ldr.TlsIndex == -1)
1844 ret = STATUS_DLL_NOT_FOUND;
1845 else
1846 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
1848 RtlLeaveCriticalSection( &loader_section );
1850 return ret;
1853 /******************************************************************
1854 * LdrFindEntryForAddress (NTDLL.@)
1856 * The loader_section must be locked while calling this function
1858 NTSTATUS WINAPI LdrFindEntryForAddress( const void *addr, PLDR_DATA_TABLE_ENTRY *pmod )
1860 PLIST_ENTRY mark, entry;
1861 PLDR_DATA_TABLE_ENTRY mod;
1863 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1864 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1866 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
1867 if (mod->DllBase <= addr &&
1868 (const char *)addr < (char*)mod->DllBase + mod->SizeOfImage)
1870 *pmod = mod;
1871 return STATUS_SUCCESS;
1874 return STATUS_NO_MORE_ENTRIES;
1877 /******************************************************************
1878 * LdrEnumerateLoadedModules (NTDLL.@)
1880 NTSTATUS WINAPI LdrEnumerateLoadedModules( void *unknown, LDRENUMPROC callback, void *context )
1882 LIST_ENTRY *mark, *entry;
1883 LDR_DATA_TABLE_ENTRY *mod;
1884 BOOLEAN stop = FALSE;
1886 TRACE( "(%p, %p, %p)\n", unknown, callback, context );
1888 if (unknown || !callback)
1889 return STATUS_INVALID_PARAMETER;
1891 RtlEnterCriticalSection( &loader_section );
1893 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
1894 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1896 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
1897 callback( mod, context, &stop );
1898 if (stop) break;
1901 RtlLeaveCriticalSection( &loader_section );
1902 return STATUS_SUCCESS;
1905 /******************************************************************
1906 * LdrRegisterDllNotification (NTDLL.@)
1908 NTSTATUS WINAPI LdrRegisterDllNotification(ULONG flags, PLDR_DLL_NOTIFICATION_FUNCTION callback,
1909 void *context, void **cookie)
1911 struct ldr_notification *notify;
1913 TRACE( "(%lx, %p, %p, %p)\n", flags, callback, context, cookie );
1915 if (!callback || !cookie)
1916 return STATUS_INVALID_PARAMETER;
1918 if (flags)
1919 FIXME( "ignoring flags %lx\n", flags );
1921 notify = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*notify) );
1922 if (!notify) return STATUS_NO_MEMORY;
1923 notify->callback = callback;
1924 notify->context = context;
1926 RtlEnterCriticalSection( &loader_section );
1927 list_add_tail( &ldr_notifications, &notify->entry );
1928 RtlLeaveCriticalSection( &loader_section );
1930 *cookie = notify;
1931 return STATUS_SUCCESS;
1934 /******************************************************************
1935 * LdrUnregisterDllNotification (NTDLL.@)
1937 NTSTATUS WINAPI LdrUnregisterDllNotification( void *cookie )
1939 struct ldr_notification *notify = cookie;
1941 TRACE( "(%p)\n", cookie );
1943 if (!notify) return STATUS_INVALID_PARAMETER;
1945 RtlEnterCriticalSection( &loader_section );
1946 list_remove( &notify->entry );
1947 RtlLeaveCriticalSection( &loader_section );
1949 RtlFreeHeap( GetProcessHeap(), 0, notify );
1950 return STATUS_SUCCESS;
1953 /******************************************************************
1954 * LdrLockLoaderLock (NTDLL.@)
1956 * Note: some flags are not implemented.
1957 * Flag 0x01 is used to raise exceptions on errors.
1959 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG_PTR *magic )
1961 if (flags & ~0x2) FIXME( "flags %lx not supported\n", flags );
1963 if (result) *result = 0;
1964 if (magic) *magic = 0;
1965 if (flags & ~0x3) return STATUS_INVALID_PARAMETER_1;
1966 if (!result && (flags & 0x2)) return STATUS_INVALID_PARAMETER_2;
1967 if (!magic) return STATUS_INVALID_PARAMETER_3;
1969 if (flags & 0x2)
1971 if (!RtlTryEnterCriticalSection( &loader_section ))
1973 *result = 2;
1974 return STATUS_SUCCESS;
1976 *result = 1;
1978 else
1980 RtlEnterCriticalSection( &loader_section );
1981 if (result) *result = 1;
1983 *magic = GetCurrentThreadId();
1984 return STATUS_SUCCESS;
1988 /******************************************************************
1989 * LdrUnlockLoaderUnlock (NTDLL.@)
1991 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG_PTR magic )
1993 if (magic)
1995 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
1996 RtlLeaveCriticalSection( &loader_section );
1998 return STATUS_SUCCESS;
2002 /******************************************************************
2003 * LdrGetProcedureAddress (NTDLL.@)
2005 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, const ANSI_STRING *name,
2006 ULONG ord, PVOID *address)
2008 IMAGE_EXPORT_DIRECTORY *exports;
2009 WINE_MODREF *wm;
2010 DWORD exp_size;
2011 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
2013 RtlEnterCriticalSection( &loader_section );
2015 /* check if the module itself is invalid to return the proper error */
2016 if (!(wm = get_modref( module ))) ret = STATUS_DLL_NOT_FOUND;
2017 else if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
2018 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
2020 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1, NULL )
2021 : find_ordinal_export( module, exports, exp_size, ord - exports->Base, NULL );
2022 if (proc)
2024 *address = proc;
2025 ret = STATUS_SUCCESS;
2027 else
2029 WARN( "%s (ordinal %lu) not found in %s\n", debugstr_a(name ? name->Buffer : NULL),
2030 ord, debugstr_us(&wm->ldr.FullDllName) );
2034 RtlLeaveCriticalSection( &loader_section );
2035 return ret;
2039 /***********************************************************************
2040 * set_security_cookie
2042 * Create a random security cookie for buffer overflow protection. Make
2043 * sure it does not accidentally match the default cookie value.
2045 static void set_security_cookie( ULONG_PTR *cookie )
2047 static ULONG seed;
2049 TRACE( "initializing security cookie %p\n", cookie );
2051 if (!seed) seed = NtGetTickCount() ^ GetCurrentProcessId();
2052 for (;;)
2054 if (*cookie == DEFAULT_SECURITY_COOKIE_16)
2055 *cookie = RtlRandom( &seed ) >> 16; /* leave the high word clear */
2056 else if (*cookie == DEFAULT_SECURITY_COOKIE_32)
2057 *cookie = RtlRandom( &seed );
2058 #ifdef DEFAULT_SECURITY_COOKIE_64
2059 else if (*cookie == DEFAULT_SECURITY_COOKIE_64)
2061 *cookie = RtlRandom( &seed );
2062 /* fill up, but keep the highest word clear */
2063 *cookie ^= (ULONG_PTR)RtlRandom( &seed ) << 16;
2065 #endif
2066 else
2067 break;
2072 /***********************************************************************
2073 * update_load_config
2075 static void update_load_config( void *module )
2077 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2078 IMAGE_LOAD_CONFIG_DIRECTORY *cfg;
2079 ULONG size;
2081 cfg = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size );
2082 if (!cfg) return;
2083 size = min( size, cfg->Size );
2084 if (size > offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, SecurityCookie ) &&
2085 cfg->SecurityCookie > (ULONG_PTR)module &&
2086 cfg->SecurityCookie < (ULONG_PTR)module + nt->OptionalHeader.SizeOfImage)
2088 set_security_cookie( (ULONG_PTR *)cfg->SecurityCookie );
2090 #ifdef __arm64ec__
2091 if (size > offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer ) &&
2092 cfg->CHPEMetadataPointer > (ULONG_PTR)module &&
2093 cfg->CHPEMetadataPointer < (ULONG_PTR)module + nt->OptionalHeader.SizeOfImage)
2095 update_hybrid_metadata( module, nt, (void *)cfg->CHPEMetadataPointer );
2097 #endif
2101 static NTSTATUS perform_relocations( void *module, IMAGE_NT_HEADERS *nt, SIZE_T len )
2103 char *base;
2104 IMAGE_BASE_RELOCATION *rel, *end;
2105 const IMAGE_DATA_DIRECTORY *relocs;
2106 const IMAGE_SECTION_HEADER *sec;
2107 INT_PTR delta;
2108 ULONG protect_old[96], i;
2110 base = (char *)nt->OptionalHeader.ImageBase;
2111 if (module == base) return STATUS_SUCCESS; /* nothing to do */
2113 /* no relocations are performed on non page-aligned binaries */
2114 if (nt->OptionalHeader.SectionAlignment < page_size)
2115 return STATUS_SUCCESS;
2117 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL) &&
2118 module != NtCurrentTeb()->Peb->ImageBaseAddress)
2119 return STATUS_SUCCESS;
2121 relocs = &nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
2123 if (nt->FileHeader.Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
2125 WARN( "Need to relocate module from %p to %p, but there are no relocation records\n",
2126 base, module );
2127 return STATUS_CONFLICTING_ADDRESSES;
2130 if (!relocs->Size) return STATUS_SUCCESS;
2131 if (!relocs->VirtualAddress) return STATUS_CONFLICTING_ADDRESSES;
2133 if (nt->FileHeader.NumberOfSections > ARRAY_SIZE( protect_old ))
2134 return STATUS_INVALID_IMAGE_FORMAT;
2136 sec = IMAGE_FIRST_SECTION( nt );
2137 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2139 void *addr = get_rva( module, sec[i].VirtualAddress );
2140 SIZE_T size = sec[i].SizeOfRawData;
2141 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2142 &size, PAGE_READWRITE, &protect_old[i] );
2145 TRACE( "relocating from %p-%p to %p-%p\n",
2146 base, base + len, module, (char *)module + len );
2148 rel = get_rva( module, relocs->VirtualAddress );
2149 end = get_rva( module, relocs->VirtualAddress + relocs->Size );
2150 delta = (char *)module - base;
2152 while (rel < end - 1 && rel->SizeOfBlock)
2154 if (rel->VirtualAddress >= len)
2156 WARN( "invalid address %p in relocation %p\n", get_rva( module, rel->VirtualAddress ), rel );
2157 return STATUS_ACCESS_VIOLATION;
2159 rel = LdrProcessRelocationBlock( get_rva( module, rel->VirtualAddress ),
2160 (rel->SizeOfBlock - sizeof(*rel)) / sizeof(USHORT),
2161 (USHORT *)(rel + 1), delta );
2162 if (!rel) return STATUS_INVALID_IMAGE_FORMAT;
2165 for (i = 0; i < nt->FileHeader.NumberOfSections; i++)
2167 void *addr = get_rva( module, sec[i].VirtualAddress );
2168 SIZE_T size = sec[i].SizeOfRawData;
2169 NtProtectVirtualMemory( NtCurrentProcess(), &addr,
2170 &size, protect_old[i], &protect_old[i] );
2173 return STATUS_SUCCESS;
2177 /*************************************************************************
2178 * build_module
2180 * Build the module data for a mapped dll.
2182 static NTSTATUS build_module( LPCWSTR load_path, const UNICODE_STRING *nt_name, void **module,
2183 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2184 DWORD flags, BOOL system, WINE_MODREF **pwm )
2186 static const char builtin_signature[] = "Wine builtin DLL";
2187 char *signature = (char *)((IMAGE_DOS_HEADER *)*module + 1);
2188 BOOL is_builtin;
2189 IMAGE_NT_HEADERS *nt;
2190 WINE_MODREF *wm;
2191 NTSTATUS status;
2192 SIZE_T map_size;
2194 if (!(nt = RtlImageNtHeader( *module ))) return STATUS_INVALID_IMAGE_FORMAT;
2196 map_size = (nt->OptionalHeader.SizeOfImage + page_size - 1) & ~(page_size - 1);
2197 if ((status = perform_relocations( *module, nt, map_size ))) return status;
2199 is_builtin = ((char *)nt - signature >= sizeof(builtin_signature) &&
2200 !memcmp( signature, builtin_signature, sizeof(builtin_signature) ));
2202 /* create the MODREF */
2204 if (!(wm = alloc_module( *module, nt_name, is_builtin ))) return STATUS_NO_MEMORY;
2206 if (id) wm->id = *id;
2207 if (image_info->LoaderFlags) wm->ldr.Flags |= LDR_COR_IMAGE;
2208 if (image_info->ComPlusILOnly) wm->ldr.Flags |= LDR_COR_ILONLY;
2209 wm->system = system;
2211 update_load_config( *module );
2213 /* fixup imports */
2215 if (!(flags & DONT_RESOLVE_DLL_REFERENCES) &&
2216 ((nt->FileHeader.Characteristics & IMAGE_FILE_DLL) ||
2217 nt->OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_NATIVE))
2219 if (wm->ldr.Flags & LDR_COR_ILONLY)
2220 status = fixup_imports_ilonly( wm, load_path, &wm->ldr.EntryPoint );
2221 else
2222 status = fixup_imports( wm, load_path );
2223 if (status != STATUS_SUCCESS)
2225 /* the module has only be inserted in the load & memory order lists */
2226 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
2227 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
2229 /* FIXME: there are several more dangling references
2230 * left. Including dlls loaded by this dll before the
2231 * failed one. Unrolling is rather difficult with the
2232 * current structure and we can leave them lying
2233 * around with no problems, so we don't care.
2234 * As these might reference our wm, we don't free it.
2236 *module = NULL;
2237 return status;
2241 TRACE( "loaded %s %p %p\n", debugstr_us(nt_name), wm, *module );
2243 if (is_builtin)
2245 if (TRACE_ON(relay)) RELAY_SetupDLL( *module );
2247 else
2249 if ((wm->ldr.Flags & LDR_IMAGE_IS_DLL) && TRACE_ON(snoop)) SNOOP_SetupDLL( *module );
2252 TRACE_(loaddll)( "Loaded %s at %p: %s\n", debugstr_w(wm->ldr.FullDllName.Buffer), *module,
2253 is_builtin ? "builtin" : "native" );
2255 wm->ldr.LoadCount = 1;
2256 *pwm = wm;
2257 *module = NULL;
2258 return STATUS_SUCCESS;
2262 /*************************************************************************
2263 * build_ntdll_module
2265 * Build the module data for the initially-loaded ntdll.
2267 static void build_ntdll_module(void)
2269 UNICODE_STRING nt_name = RTL_CONSTANT_STRING( L"\\??\\C:\\windows\\system32\\ntdll.dll" );
2270 MEMORY_BASIC_INFORMATION meminfo;
2271 WINE_MODREF *wm;
2272 void *module;
2274 NtQueryVirtualMemory( GetCurrentProcess(), LdrInitializeThunk, MemoryBasicInformation,
2275 &meminfo, sizeof(meminfo), NULL );
2276 module = meminfo.AllocationBase;
2277 wm = alloc_module( module, &nt_name, TRUE );
2278 assert( wm );
2279 wm->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
2280 node_ntdll = wm->ldr.DdagNode;
2281 if (TRACE_ON(relay)) RELAY_SetupDLL( module );
2285 #ifdef _WIN64
2286 /* convert PE header to 64-bit when loading a 32-bit IL-only module into a 64-bit process */
2287 static BOOL convert_to_pe64( HMODULE module, const SECTION_IMAGE_INFORMATION *info )
2289 static const ULONG copy_dirs[] = { IMAGE_DIRECTORY_ENTRY_RESOURCE,
2290 IMAGE_DIRECTORY_ENTRY_SECURITY,
2291 IMAGE_DIRECTORY_ENTRY_BASERELOC,
2292 IMAGE_DIRECTORY_ENTRY_DEBUG,
2293 IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR };
2294 IMAGE_OPTIONAL_HEADER32 hdr32 = { IMAGE_NT_OPTIONAL_HDR32_MAGIC };
2295 IMAGE_OPTIONAL_HEADER64 hdr64 = { IMAGE_NT_OPTIONAL_HDR64_MAGIC };
2296 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2297 IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
2298 SIZE_T hdr_size = min( sizeof(hdr32), nt->FileHeader.SizeOfOptionalHeader );
2299 SIZE_T size = min( nt->OptionalHeader.SizeOfHeaders, nt->OptionalHeader.SizeOfImage );
2300 void *addr = module;
2301 ULONG i, old_prot;
2303 if (nt->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return TRUE; /* already 64-bit */
2304 if (NtCurrentTeb()->WowTebOffset) return TRUE; /* no need to convert */
2305 if (!info->ImageContainsCode) return TRUE; /* no need to convert */
2307 TRACE( "%p\n", module );
2309 if (NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, PAGE_READWRITE, &old_prot ))
2310 return FALSE;
2312 if ((char *)module + size < (char *)(nt + 1) + nt->FileHeader.NumberOfSections * sizeof(*sec))
2314 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2315 return FALSE;
2318 memcpy( &hdr32, &nt->OptionalHeader, hdr_size );
2319 memcpy( &hdr64, &hdr32, offsetof( IMAGE_OPTIONAL_HEADER64, SizeOfStackReserve ));
2320 hdr64.Magic = IMAGE_NT_OPTIONAL_HDR64_MAGIC;
2321 hdr64.AddressOfEntryPoint = 0;
2322 hdr64.ImageBase = hdr32.ImageBase;
2323 hdr64.SizeOfStackReserve = hdr32.SizeOfStackReserve;
2324 hdr64.SizeOfStackCommit = hdr32.SizeOfStackCommit;
2325 hdr64.SizeOfHeapReserve = hdr32.SizeOfHeapReserve;
2326 hdr64.SizeOfHeapCommit = hdr32.SizeOfHeapCommit;
2327 hdr64.LoaderFlags = hdr32.LoaderFlags;
2328 hdr64.NumberOfRvaAndSizes = hdr32.NumberOfRvaAndSizes;
2329 for (i = 0; i < ARRAY_SIZE( copy_dirs ); i++)
2330 hdr64.DataDirectory[copy_dirs[i]] = hdr32.DataDirectory[copy_dirs[i]];
2332 memmove( nt + 1, sec, nt->FileHeader.NumberOfSections * sizeof(*sec) );
2333 nt->FileHeader.SizeOfOptionalHeader = sizeof(hdr64);
2334 nt->OptionalHeader = hdr64;
2335 NtProtectVirtualMemory( NtCurrentProcess(), &addr, &size, old_prot, &old_prot );
2336 return TRUE;
2339 /* read data out of a PE image directory */
2340 static ULONG read_image_directory( HANDLE file, const SECTION_IMAGE_INFORMATION *info,
2341 ULONG dir, void *buffer, ULONG maxlen, USHORT *magic )
2343 IMAGE_DOS_HEADER mz;
2344 IO_STATUS_BLOCK io;
2345 LARGE_INTEGER offset;
2346 IMAGE_SECTION_HEADER sec[96];
2347 unsigned int i, count;
2348 DWORD va, size;
2349 union
2351 IMAGE_NT_HEADERS32 nt32;
2352 IMAGE_NT_HEADERS64 nt64;
2353 } nt;
2355 offset.QuadPart = 0;
2356 if (NtReadFile( file, 0, NULL, NULL, &io, &mz, sizeof(mz), &offset, NULL )) return 0;
2357 if (io.Information != sizeof(mz)) return 0;
2358 if (mz.e_magic != IMAGE_DOS_SIGNATURE) return 0;
2359 offset.QuadPart = mz.e_lfanew;
2360 if (NtReadFile( file, 0, NULL, NULL, &io, &nt, sizeof(nt), &offset, NULL )) return 0;
2361 if (io.Information != sizeof(nt)) return 0;
2362 if (nt.nt32.Signature != IMAGE_NT_SIGNATURE) return 0;
2363 *magic = nt.nt32.OptionalHeader.Magic;
2364 switch (nt.nt32.OptionalHeader.Magic)
2366 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
2367 va = nt.nt32.OptionalHeader.DataDirectory[dir].VirtualAddress;
2368 size = nt.nt32.OptionalHeader.DataDirectory[dir].Size;
2369 break;
2370 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
2371 va = nt.nt64.OptionalHeader.DataDirectory[dir].VirtualAddress;
2372 size = nt.nt64.OptionalHeader.DataDirectory[dir].Size;
2373 break;
2374 default:
2375 return 0;
2377 if (!va) return 0;
2378 offset.QuadPart += offsetof( IMAGE_NT_HEADERS32, OptionalHeader ) + nt.nt32.FileHeader.SizeOfOptionalHeader;
2379 count = min( 96, nt.nt32.FileHeader.NumberOfSections );
2380 if (NtReadFile( file, 0, NULL, NULL, &io, &sec, count * sizeof(*sec), &offset, NULL )) return 0;
2381 if (io.Information != count * sizeof(*sec)) return 0;
2382 for (i = 0; i < count; i++)
2384 if (va < sec[i].VirtualAddress) continue;
2385 if (sec[i].Misc.VirtualSize && va - sec[i].VirtualAddress >= sec[i].Misc.VirtualSize) continue;
2386 offset.QuadPart = sec[i].PointerToRawData + va - sec[i].VirtualAddress;
2387 if (NtReadFile( file, 0, NULL, NULL, &io, buffer, min( maxlen, size ), &offset, NULL )) return 0;
2388 return io.Information;
2390 return 0;
2393 /* check COM header for ILONLY flag, ignoring runtime version */
2394 static BOOL is_com_ilonly( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2396 USHORT magic;
2397 IMAGE_COR20_HEADER cor_header;
2398 ULONG len = read_image_directory( file, info, IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
2399 &cor_header, sizeof(cor_header), &magic );
2401 if (len != sizeof(cor_header)) return FALSE;
2402 if (magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) return FALSE;
2403 return !!(cor_header.Flags & COMIMAGE_FLAGS_ILONLY);
2406 /* check LOAD_CONFIG header for CHPE metadata */
2407 static BOOL has_chpe_metadata( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2409 USHORT magic;
2410 IMAGE_LOAD_CONFIG_DIRECTORY64 loadcfg;
2411 ULONG len = read_image_directory( file, info, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
2412 &loadcfg, sizeof(loadcfg), &magic );
2414 if (!len) return FALSE;
2415 if (magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC) return FALSE;
2416 len = min( len, loadcfg.Size );
2417 if (len <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY64, CHPEMetadataPointer )) return FALSE;
2418 return !!loadcfg.CHPEMetadataPointer;
2421 /* On WoW64 setups, an image mapping can also be created for the other 32/64 CPU */
2422 /* but it cannot necessarily be loaded as a dll, so we need some additional checks */
2423 static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2425 if (info->Machine == current_machine) return TRUE;
2426 if (NtCurrentTeb()->WowTebOffset) return TRUE;
2427 /* support ARM64EC binaries on x86-64 */
2428 if (current_machine == IMAGE_FILE_MACHINE_AMD64 && has_chpe_metadata( file, info )) return TRUE;
2429 /* support 32-bit IL-only images on 64-bit */
2430 if (!info->ImageContainsCode) return TRUE;
2431 if (info->ComPlusNativeReady) return TRUE;
2432 return is_com_ilonly( file, info );
2435 #else /* _WIN64 */
2437 static BOOL is_valid_binary( HANDLE file, const SECTION_IMAGE_INFORMATION *info )
2439 return (info->Machine == current_machine);
2442 #endif /* _WIN64 */
2445 /******************************************************************
2446 * get_module_path_end
2448 * Returns the end of the directory component of the module path.
2450 static inline const WCHAR *get_module_path_end( const WCHAR *module )
2452 const WCHAR *p;
2453 const WCHAR *mod_end = module;
2455 if ((p = wcsrchr( mod_end, '\\' ))) mod_end = p;
2456 if ((p = wcsrchr( mod_end, '/' ))) mod_end = p;
2457 if (mod_end == module + 2 && module[1] == ':') mod_end++;
2458 if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
2459 return mod_end;
2463 /******************************************************************
2464 * append_path
2466 * Append a counted string to the load path. Helper for get_dll_load_path.
2468 static inline WCHAR *append_path( WCHAR *p, const WCHAR *str, int len )
2470 if (len == -1) len = wcslen(str);
2471 if (!len) return p;
2472 memcpy( p, str, len * sizeof(WCHAR) );
2473 p[len] = ';';
2474 return p + len + 1;
2478 /******************************************************************
2479 * get_dll_load_path
2481 static NTSTATUS get_dll_load_path( LPCWSTR module, LPCWSTR dll_dir, ULONG safe_mode, WCHAR **path )
2483 const WCHAR *mod_end = module;
2484 UNICODE_STRING name = RTL_CONSTANT_STRING( L"PATH" ), value;
2485 WCHAR *p, *ret;
2486 int len = ARRAY_SIZE(system_path) + 1, path_len = 0;
2488 if (module)
2490 mod_end = get_module_path_end( module );
2491 len += (mod_end - module) + 1;
2494 value.Length = 0;
2495 value.MaximumLength = 0;
2496 value.Buffer = NULL;
2497 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2498 path_len = value.Length;
2500 if (dll_dir) len += wcslen( dll_dir ) + 1;
2501 else len += 2; /* current directory */
2502 if (!(p = ret = RtlAllocateHeap( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
2503 return STATUS_NO_MEMORY;
2505 p = append_path( p, module, mod_end - module );
2506 if (dll_dir) p = append_path( p, dll_dir, -1 );
2507 else if (!safe_mode) p = append_path( p, L".", -1 );
2508 p = append_path( p, system_path, -1 );
2509 if (!dll_dir && safe_mode) p = append_path( p, L".", -1 );
2511 value.Buffer = p;
2512 value.MaximumLength = path_len;
2514 while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
2516 WCHAR *new_ptr;
2518 /* grow the buffer and retry */
2519 path_len = value.Length;
2520 if (!(new_ptr = RtlReAllocateHeap( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
2522 RtlFreeHeap( GetProcessHeap(), 0, ret );
2523 return STATUS_NO_MEMORY;
2525 value.Buffer = new_ptr + (value.Buffer - ret);
2526 value.MaximumLength = path_len;
2527 ret = new_ptr;
2529 value.Buffer[value.Length / sizeof(WCHAR)] = 0;
2530 *path = ret;
2531 return STATUS_SUCCESS;
2535 /******************************************************************
2536 * get_dll_load_path_search_flags
2538 static NTSTATUS get_dll_load_path_search_flags( LPCWSTR module, DWORD flags, WCHAR **path )
2540 const WCHAR *image = NULL, *mod_end, *image_end;
2541 struct dll_dir_entry *dir;
2542 WCHAR *p, *ret;
2543 int len = 1;
2545 if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
2546 flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
2547 LOAD_LIBRARY_SEARCH_USER_DIRS |
2548 LOAD_LIBRARY_SEARCH_SYSTEM32);
2550 if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
2552 DWORD type = RtlDetermineDosPathNameType_U( module );
2553 if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH && type != DEVICE_PATH)
2554 return STATUS_INVALID_PARAMETER;
2555 mod_end = get_module_path_end( module );
2556 len += (mod_end - module) + 1;
2558 else module = NULL;
2560 if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
2562 image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
2563 image_end = get_module_path_end( image );
2564 len += (image_end - image) + 1;
2567 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2569 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2570 len += wcslen( dir->dir + 4 /* \??\ */ ) + 1;
2571 if (dll_directory.Length) len += dll_directory.Length / sizeof(WCHAR) + 1;
2574 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += wcslen( system_dir );
2576 if ((p = ret = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
2578 if (module) p = append_path( p, module, mod_end - module );
2579 if (image) p = append_path( p, image, image_end - image );
2580 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
2582 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
2583 p = append_path( p, dir->dir + 4 /* \??\ */, -1 );
2584 p = append_path( p, dll_directory.Buffer, dll_directory.Length / sizeof(WCHAR) );
2586 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) wcscpy( p, system_dir );
2587 else
2589 if (p > ret) p--;
2590 *p = 0;
2593 *path = ret;
2594 return STATUS_SUCCESS;
2598 /***********************************************************************
2599 * open_dll_file
2601 * Open a file for a new dll. Helper for find_dll_file.
2603 static NTSTATUS open_dll_file( UNICODE_STRING *nt_name, WINE_MODREF **pwm, HANDLE *mapping,
2604 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
2606 FILE_BASIC_INFORMATION info;
2607 OBJECT_ATTRIBUTES attr;
2608 IO_STATUS_BLOCK io;
2609 LARGE_INTEGER size;
2610 FILE_OBJECTID_BUFFER fid;
2611 NTSTATUS status;
2612 HANDLE handle;
2614 if ((*pwm = find_fullname_module( nt_name ))) return STATUS_SUCCESS;
2616 attr.Length = sizeof(attr);
2617 attr.RootDirectory = 0;
2618 attr.Attributes = OBJ_CASE_INSENSITIVE;
2619 attr.ObjectName = nt_name;
2620 attr.SecurityDescriptor = NULL;
2621 attr.SecurityQualityOfService = NULL;
2622 if ((status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
2623 FILE_SHARE_READ | FILE_SHARE_DELETE,
2624 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
2626 if (status != STATUS_OBJECT_PATH_NOT_FOUND &&
2627 status != STATUS_OBJECT_NAME_NOT_FOUND &&
2628 !NtQueryAttributesFile( &attr, &info ))
2630 /* if the file exists but failed to open, report the error */
2631 return status;
2633 /* otherwise continue searching */
2634 return STATUS_DLL_NOT_FOUND;
2637 if (!NtFsControlFile( handle, 0, NULL, NULL, &io, FSCTL_GET_OBJECT_ID, NULL, 0, &fid, sizeof(fid) ))
2639 memcpy( id, fid.ObjectId, sizeof(*id) );
2640 if ((*pwm = find_fileid_module( id )))
2642 TRACE( "%s is the same file as existing module %p %s\n", debugstr_w( nt_name->Buffer ),
2643 (*pwm)->ldr.DllBase, debugstr_w( (*pwm)->ldr.FullDllName.Buffer ));
2644 NtClose( handle );
2645 return STATUS_SUCCESS;
2649 size.QuadPart = 0;
2650 status = NtCreateSection( mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
2651 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
2652 NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, handle );
2653 if (!status)
2655 NtQuerySection( *mapping, SectionImageInformation, image_info, sizeof(*image_info), NULL );
2656 if (!is_valid_binary( handle, image_info ))
2658 TRACE( "%s is for arch %x, continuing search\n", debugstr_us(nt_name), image_info->Machine );
2659 status = STATUS_NOT_SUPPORTED;
2660 NtClose( *mapping );
2661 *mapping = NULL;
2664 NtClose( handle );
2665 return status;
2669 /******************************************************************************
2670 * find_existing_module
2672 * Find an existing module that is the same mapping as the new module.
2674 static WINE_MODREF *find_existing_module( HMODULE module )
2676 WINE_MODREF *wm;
2677 LIST_ENTRY *mark, *entry;
2678 LDR_DATA_TABLE_ENTRY *mod;
2679 IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
2681 if ((wm = get_modref( module ))) return wm;
2683 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
2684 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
2686 mod = CONTAINING_RECORD( entry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks );
2687 if (mod->TimeDateStamp != nt->FileHeader.TimeDateStamp) continue;
2688 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
2689 if (wm->CheckSum != nt->OptionalHeader.CheckSum) continue;
2690 if (NtAreMappedFilesTheSame( mod->DllBase, module ) != STATUS_SUCCESS) continue;
2691 return CONTAINING_RECORD( mod, WINE_MODREF, ldr );
2693 return NULL;
2697 /******************************************************************************
2698 * load_native_dll (internal)
2700 static NTSTATUS load_native_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name, HANDLE mapping,
2701 const SECTION_IMAGE_INFORMATION *image_info, const struct file_id *id,
2702 DWORD flags, BOOL system, WINE_MODREF** pwm )
2704 void *module = NULL;
2705 SIZE_T len = 0;
2706 NTSTATUS status = NtMapViewOfSection( mapping, NtCurrentProcess(), &module, 0, 0, NULL, &len,
2707 ViewShare, 0, PAGE_EXECUTE_READ );
2709 if (!NT_SUCCESS(status)) return status;
2711 if ((*pwm = find_existing_module( module ))) /* already loaded */
2713 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
2714 TRACE( "found %s for %s at %p, count=%d\n",
2715 debugstr_us(&(*pwm)->ldr.FullDllName), debugstr_us(nt_name),
2716 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
2717 if (module != (*pwm)->ldr.DllBase) NtUnmapViewOfSection( NtCurrentProcess(), module );
2718 return STATUS_SUCCESS;
2720 #ifdef _WIN64
2721 if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH && !convert_to_pe64( module, image_info ))
2722 status = STATUS_INVALID_IMAGE_FORMAT;
2723 #endif
2724 if (NT_SUCCESS(status)) status = build_module( load_path, nt_name, &module, image_info, id, flags, system, pwm );
2725 if (status && module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2726 return status;
2730 /***********************************************************************
2731 * load_so_dll
2733 static NTSTATUS load_so_dll( LPCWSTR load_path, const UNICODE_STRING *nt_name,
2734 DWORD flags, WINE_MODREF **pwm )
2736 void *module;
2737 NTSTATUS status;
2738 WINE_MODREF *wm;
2739 struct load_so_dll_params params = { *nt_name, &module };
2741 TRACE( "trying %s as so lib\n", debugstr_us(nt_name) );
2742 if ((status = WINE_UNIX_CALL( unix_load_so_dll, &params )))
2744 WARN( "failed to load .so lib %s\n", debugstr_us(nt_name) );
2745 if (status == STATUS_INVALID_IMAGE_FORMAT) status = STATUS_INVALID_IMAGE_NOT_MZ;
2746 return status;
2749 if ((wm = get_modref( module ))) /* already loaded */
2751 TRACE( "Found %s at %p for builtin %s\n",
2752 debugstr_w(wm->ldr.FullDllName.Buffer), wm->ldr.DllBase, debugstr_us(nt_name) );
2753 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
2755 else
2757 SECTION_IMAGE_INFORMATION image_info = { 0 };
2759 if ((status = build_module( load_path, &params.nt_name, &module, &image_info, NULL, flags, FALSE, &wm )))
2761 if (module) NtUnmapViewOfSection( NtCurrentProcess(), module );
2762 return status;
2764 TRACE_(loaddll)( "Loaded %s at %p: builtin\n", debugstr_us(nt_name), module );
2766 *pwm = wm;
2767 return STATUS_SUCCESS;
2771 /*************************************************************************
2772 * build_main_module
2774 * Build the module data for the main image.
2776 static WINE_MODREF *build_main_module(void)
2778 SECTION_IMAGE_INFORMATION info;
2779 UNICODE_STRING nt_name;
2780 WINE_MODREF *wm;
2781 NTSTATUS status;
2782 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
2783 void *module = NtCurrentTeb()->Peb->ImageBaseAddress;
2785 default_load_path = params->DllPath.Buffer;
2786 if (!default_load_path)
2787 get_dll_load_path( params->ImagePathName.Buffer, NULL, dll_safe_mode, &default_load_path );
2789 NtQueryInformationProcess( GetCurrentProcess(), ProcessImageInformation, &info, sizeof(info), NULL );
2790 if (info.ImageCharacteristics & IMAGE_FILE_DLL)
2792 MESSAGE( "wine: %s is a dll, not an executable\n", debugstr_us(&params->ImagePathName) );
2793 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
2795 #ifdef _WIN64
2796 if (!convert_to_pe64( module, &info ))
2798 status = STATUS_INVALID_IMAGE_FORMAT;
2799 goto failed;
2801 #endif
2802 status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
2803 if (status) goto failed;
2804 status = build_module( NULL, &nt_name, &module, &info, NULL, DONT_RESOLVE_DLL_REFERENCES, FALSE, &wm );
2805 if (status) goto failed;
2806 RtlFreeUnicodeString( &nt_name );
2807 wm->ldr.LoadCount = -1;
2808 return wm;
2809 failed:
2810 MESSAGE( "wine: failed to create main module for %s, status %lx\n",
2811 debugstr_us(&params->ImagePathName), status );
2812 NtTerminateProcess( GetCurrentProcess(), status );
2813 return NULL; /* unreached */
2817 /***********************************************************************
2818 * build_dlldata_path
2820 * Helper for find_actctx_dll.
2822 static NTSTATUS build_dlldata_path( LPCWSTR libname, ACTCTX_SECTION_KEYED_DATA *data, LPWSTR *fullname )
2824 struct dllredirect_data *dlldata = data->lpData;
2825 char *base = data->lpSectionBase;
2826 SIZE_T total = dlldata->total_len + (wcslen(libname) + 1) * sizeof(WCHAR);
2827 WCHAR *p, *buffer;
2828 NTSTATUS status = STATUS_SUCCESS;
2829 ULONG i;
2831 if (!(p = buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
2832 for (i = 0; i < dlldata->paths_count; i++)
2834 memcpy( p, base + dlldata->paths[i].offset, dlldata->paths[i].len );
2835 p += dlldata->paths[i].len / sizeof(WCHAR);
2837 if (p == buffer || p[-1] == '\\') wcscpy( p, libname );
2838 else *p = 0;
2840 if (dlldata->flags & DLL_REDIRECT_PATH_EXPAND)
2842 RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), NULL, 0, &total );
2843 if ((*fullname = RtlAllocateHeap( GetProcessHeap(), 0, total * sizeof(WCHAR) )))
2844 RtlExpandEnvironmentStrings( NULL, buffer, wcslen(buffer), *fullname, total, NULL );
2845 else
2846 status = STATUS_NO_MEMORY;
2848 RtlFreeHeap( GetProcessHeap(), 0, buffer );
2850 else *fullname = buffer;
2852 return status;
2856 /***********************************************************************
2857 * find_actctx_dll
2859 * Find the full path (if any) of the dll from the activation context.
2861 static NTSTATUS find_actctx_dll( LPCWSTR libname, LPWSTR *fullname )
2863 static const WCHAR winsxsW[] = {'\\','w','i','n','s','x','s','\\'};
2865 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info = NULL;
2866 ACTCTX_SECTION_KEYED_DATA data;
2867 struct dllredirect_data *dlldata;
2868 UNICODE_STRING nameW;
2869 NTSTATUS status;
2870 SIZE_T needed, size = 1024;
2871 WCHAR *p;
2873 RtlInitUnicodeString( &nameW, libname );
2874 data.cbSize = sizeof(data);
2875 status = RtlFindActivationContextSectionString( FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
2876 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
2877 &nameW, &data );
2878 if (status != STATUS_SUCCESS) return status;
2880 if (data.ulLength < offsetof( struct dllredirect_data, paths[0] ))
2882 status = STATUS_SXS_KEY_NOT_FOUND;
2883 goto done;
2885 dlldata = data.lpData;
2886 if (!(dlldata->flags & DLL_REDIRECT_PATH_OMITS_ASSEMBLY_ROOT))
2888 status = build_dlldata_path( libname, &data, fullname );
2889 goto done;
2892 for (;;)
2894 if (!(info = RtlAllocateHeap( GetProcessHeap(), 0, size )))
2896 status = STATUS_NO_MEMORY;
2897 goto done;
2899 status = RtlQueryInformationActivationContext( 0, data.hActCtx, &data.ulAssemblyRosterIndex,
2900 AssemblyDetailedInformationInActivationContext,
2901 info, size, &needed );
2902 if (status == STATUS_SUCCESS) break;
2903 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
2904 RtlFreeHeap( GetProcessHeap(), 0, info );
2905 size = needed;
2906 /* restart with larger buffer */
2909 if (!info->lpAssemblyManifestPath)
2911 status = STATUS_SXS_KEY_NOT_FOUND;
2912 goto done;
2915 if ((p = wcsrchr( info->lpAssemblyManifestPath, '\\' )))
2917 DWORD len, dirlen = info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2918 p++;
2919 len = wcslen( p );
2920 if (!dirlen || len <= dirlen ||
2921 RtlCompareUnicodeStrings( p, dirlen, info->lpAssemblyDirectoryName, dirlen, TRUE ) ||
2922 wcsicmp( p + dirlen, L".manifest" ))
2924 /* manifest name does not match directory name, so it's not a global
2925 * windows/winsxs manifest; use the manifest directory name instead */
2926 dirlen = p - info->lpAssemblyManifestPath;
2927 needed = (dirlen + 1) * sizeof(WCHAR) + nameW.Length;
2928 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2930 status = STATUS_NO_MEMORY;
2931 goto done;
2933 memcpy( p, info->lpAssemblyManifestPath, dirlen * sizeof(WCHAR) );
2934 p += dirlen;
2935 wcscpy( p, libname );
2936 goto done;
2940 if (!info->lpAssemblyDirectoryName)
2942 status = STATUS_SXS_KEY_NOT_FOUND;
2943 goto done;
2946 needed = (wcslen(windows_dir) * sizeof(WCHAR) +
2947 sizeof(winsxsW) + info->ulAssemblyDirectoryNameLength + nameW.Length + 2*sizeof(WCHAR));
2949 if (!(*fullname = p = RtlAllocateHeap( GetProcessHeap(), 0, needed )))
2951 status = STATUS_NO_MEMORY;
2952 goto done;
2954 wcscpy( p, windows_dir );
2955 p += wcslen(p);
2956 memcpy( p, winsxsW, sizeof(winsxsW) );
2957 p += ARRAY_SIZE( winsxsW );
2958 memcpy( p, info->lpAssemblyDirectoryName, info->ulAssemblyDirectoryNameLength );
2959 p += info->ulAssemblyDirectoryNameLength / sizeof(WCHAR);
2960 *p++ = '\\';
2961 wcscpy( p, libname );
2962 done:
2963 RtlFreeHeap( GetProcessHeap(), 0, info );
2964 RtlReleaseActivationContext( data.hActCtx );
2965 return status;
2970 /******************************************************************************
2971 * find_apiset_dll
2973 static NTSTATUS find_apiset_dll( const WCHAR *name, WCHAR **fullname )
2975 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
2976 const API_SET_NAMESPACE_ENTRY *entry;
2977 UNICODE_STRING str;
2978 ULONG len;
2980 if (get_apiset_entry( map, name, wcslen(name), &entry )) return STATUS_APISET_NOT_PRESENT;
2981 if (get_apiset_target( map, entry, NULL, &str )) return STATUS_DLL_NOT_FOUND;
2983 len = wcslen( system_dir ) + str.Length / sizeof(WCHAR);
2984 if (!(*fullname = RtlAllocateHeap( GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR) )))
2985 return STATUS_NO_MEMORY;
2986 wcscpy( *fullname, system_dir );
2987 memcpy( *fullname + wcslen( system_dir ), str.Buffer, str.Length );
2988 (*fullname)[len] = 0;
2989 return STATUS_SUCCESS;
2993 /***********************************************************************
2994 * get_env_var
2996 static NTSTATUS get_env_var( const WCHAR *name, SIZE_T extra, UNICODE_STRING *ret )
2998 NTSTATUS status;
2999 SIZE_T len, size = 1024 + extra;
3001 for (;;)
3003 ret->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) );
3004 status = RtlQueryEnvironmentVariable( NULL, name, wcslen(name),
3005 ret->Buffer, size - extra - 1, &len );
3006 if (!status)
3008 ret->Buffer[len] = 0;
3009 ret->Length = len * sizeof(WCHAR);
3010 ret->MaximumLength = size * sizeof(WCHAR);
3011 return status;
3013 RtlFreeHeap( GetProcessHeap(), 0, ret->Buffer );
3014 if (status != STATUS_BUFFER_TOO_SMALL)
3016 ret->Buffer = NULL;
3017 return status;
3019 size = len + 1 + extra;
3024 /***********************************************************************
3025 * find_builtin_without_file
3027 * Find a builtin dll when the corresponding file cannot be found in the prefix.
3028 * This is used during prefix bootstrap.
3030 static NTSTATUS find_builtin_without_file( const WCHAR *name, UNICODE_STRING *new_name,
3031 WINE_MODREF **pwm, HANDLE *mapping,
3032 SECTION_IMAGE_INFORMATION *image_info, struct file_id *id )
3034 const WCHAR *ext;
3035 WCHAR dllpath[32];
3036 DWORD i, len;
3037 NTSTATUS status = STATUS_DLL_NOT_FOUND;
3038 BOOL found_image = FALSE;
3040 if (contains_path( name )) return status;
3042 if (!is_prefix_bootstrap)
3044 /* 16-bit files can't be loaded from the prefix */
3045 if (!name[1] || wcscmp( name + wcslen(name) - 2, L"16" )) return status;
3048 if (!get_env_var( L"WINEBUILDDIR", 20 + 2 * wcslen(name) + wcslen(pe_dir), new_name ))
3050 len = new_name->Length;
3051 RtlAppendUnicodeToString( new_name, L"\\dlls\\" );
3052 RtlAppendUnicodeToString( new_name, name );
3053 if ((ext = wcsrchr( name, '.' )) && !wcscmp( ext, L".dll" )) new_name->Length -= 4 * sizeof(WCHAR);
3054 RtlAppendUnicodeToString( new_name, pe_dir );
3055 RtlAppendUnicodeToString( new_name, L"\\" );
3056 RtlAppendUnicodeToString( new_name, name );
3057 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3058 if (status != STATUS_DLL_NOT_FOUND) goto done;
3060 new_name->Length = len;
3061 RtlAppendUnicodeToString( new_name, L"\\programs\\" );
3062 RtlAppendUnicodeToString( new_name, name );
3063 RtlAppendUnicodeToString( new_name, pe_dir );
3064 RtlAppendUnicodeToString( new_name, L"\\" );
3065 RtlAppendUnicodeToString( new_name, name );
3066 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3067 if (status != STATUS_DLL_NOT_FOUND) goto done;
3068 RtlFreeUnicodeString( new_name );
3071 for (i = 0; ; i++)
3073 swprintf( dllpath, ARRAY_SIZE(dllpath), L"WINEDLLDIR%u", i );
3074 if (get_env_var( dllpath, wcslen(pe_dir) + wcslen(name) + 1, new_name )) break;
3075 len = new_name->Length;
3076 RtlAppendUnicodeToString( new_name, pe_dir );
3077 RtlAppendUnicodeToString( new_name, L"\\" );
3078 RtlAppendUnicodeToString( new_name, name );
3079 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3080 if (status != STATUS_DLL_NOT_FOUND) goto done;
3081 new_name->Length = len;
3082 RtlAppendUnicodeToString( new_name, L"\\" );
3083 RtlAppendUnicodeToString( new_name, name );
3084 status = open_dll_file( new_name, pwm, mapping, image_info, id );
3085 if (status == STATUS_NOT_SUPPORTED) found_image = TRUE;
3086 else if (status != STATUS_DLL_NOT_FOUND) goto done;
3087 RtlFreeUnicodeString( new_name );
3089 if (found_image) status = STATUS_NOT_SUPPORTED;
3091 done:
3092 RtlFreeUnicodeString( new_name );
3093 if (!status)
3095 new_name->Length = (4 + wcslen(system_dir) + wcslen(name)) * sizeof(WCHAR);
3096 new_name->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, new_name->Length + sizeof(WCHAR) );
3097 wcscpy( new_name->Buffer, L"\\??\\" );
3098 wcscat( new_name->Buffer, system_dir );
3099 wcscat( new_name->Buffer, name );
3101 return status;
3105 /***********************************************************************
3106 * search_dll_file
3108 * Search for dll in the specified paths.
3110 static NTSTATUS search_dll_file( LPCWSTR paths, LPCWSTR search, UNICODE_STRING *nt_name,
3111 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
3112 struct file_id *id )
3114 WCHAR *name;
3115 BOOL found_image = FALSE;
3116 NTSTATUS status = STATUS_DLL_NOT_FOUND;
3117 ULONG len;
3119 if (!paths) paths = default_load_path;
3120 len = wcslen( paths );
3122 if (len < wcslen( system_dir )) len = wcslen( system_dir );
3123 len += wcslen( search ) + 2;
3125 if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
3126 return STATUS_NO_MEMORY;
3128 while (*paths)
3130 LPCWSTR ptr = paths;
3132 while (*ptr && *ptr != ';') ptr++;
3133 len = ptr - paths;
3134 if (*ptr == ';') ptr++;
3135 memcpy( name, paths, len * sizeof(WCHAR) );
3136 if (len && name[len - 1] != '\\') name[len++] = '\\';
3137 wcscpy( name + len, search );
3139 nt_name->Buffer = NULL;
3140 if ((status = RtlDosPathNameToNtPathName_U_WithStatus( name, nt_name, NULL, NULL ))) goto done;
3142 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3143 if (status == STATUS_NOT_SUPPORTED) found_image = TRUE;
3144 else if (status != STATUS_DLL_NOT_FOUND) goto done;
3145 RtlFreeUnicodeString( nt_name );
3146 paths = ptr;
3149 if (found_image) status = STATUS_NOT_SUPPORTED;
3151 done:
3152 RtlFreeHeap( GetProcessHeap(), 0, name );
3153 return status;
3156 /***********************************************************************
3157 * find_dll_file
3159 * Find the file (or already loaded module) for a given dll name.
3161 static NTSTATUS find_dll_file( const WCHAR *load_path, const WCHAR *libname, UNICODE_STRING *nt_name,
3162 WINE_MODREF **pwm, HANDLE *mapping, SECTION_IMAGE_INFORMATION *image_info,
3163 struct file_id *id )
3165 WCHAR *fullname = NULL;
3166 NTSTATUS status;
3167 ULONG wow64_old_value = 0;
3169 *pwm = NULL;
3171 /* Win 7/2008R2 and up seem to re-enable WoW64 FS redirection when loading libraries */
3172 RtlWow64EnableFsRedirectionEx( 0, &wow64_old_value );
3174 nt_name->Buffer = NULL;
3176 if (!contains_path( libname ))
3178 status = find_apiset_dll( libname, &fullname );
3179 if (status == STATUS_DLL_NOT_FOUND) goto done;
3181 if (status) status = find_actctx_dll( libname, &fullname );
3183 if (status == STATUS_SUCCESS)
3185 TRACE ("found %s for %s\n", debugstr_w(fullname), debugstr_w(libname) );
3186 libname = fullname;
3188 else
3190 if (status != STATUS_SXS_KEY_NOT_FOUND) goto done;
3191 if ((*pwm = find_basename_module( libname )) != NULL)
3193 status = STATUS_SUCCESS;
3194 goto done;
3199 if (RtlDetermineDosPathNameType_U( libname ) == RELATIVE_PATH)
3201 status = search_dll_file( load_path, libname, nt_name, pwm, mapping, image_info, id );
3202 if (status == STATUS_DLL_NOT_FOUND)
3203 status = find_builtin_without_file( libname, nt_name, pwm, mapping, image_info, id );
3205 else if (!(status = RtlDosPathNameToNtPathName_U_WithStatus( libname, nt_name, NULL, NULL )))
3206 status = open_dll_file( nt_name, pwm, mapping, image_info, id );
3208 if (status == STATUS_NOT_SUPPORTED) status = STATUS_INVALID_IMAGE_FORMAT;
3210 done:
3211 RtlFreeHeap( GetProcessHeap(), 0, fullname );
3212 if (wow64_old_value) RtlWow64EnableFsRedirectionEx( 1, &wow64_old_value );
3213 return status;
3217 /***********************************************************************
3218 * load_dll (internal)
3220 * Load a PE style module according to the load order.
3221 * The loader_section must be locked while calling this function.
3223 static NTSTATUS load_dll( const WCHAR *load_path, const WCHAR *libname, DWORD flags, WINE_MODREF** pwm, BOOL system )
3225 UNICODE_STRING nt_name;
3226 struct file_id id;
3227 HANDLE mapping = 0;
3228 SECTION_IMAGE_INFORMATION image_info;
3229 NTSTATUS nts = STATUS_DLL_NOT_FOUND;
3230 ULONG64 prev;
3232 TRACE( "looking for %s in %s\n", debugstr_w(libname), debugstr_w(load_path) );
3234 if (system && system_dll_path.Buffer)
3235 nts = search_dll_file( system_dll_path.Buffer, libname, &nt_name, pwm, &mapping, &image_info, &id );
3237 if (nts)
3239 nts = find_dll_file( load_path, libname, &nt_name, pwm, &mapping, &image_info, &id );
3240 system = FALSE;
3243 if (*pwm) /* found already loaded module */
3245 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
3247 TRACE("Found %s for %s at %p, count=%d\n",
3248 debugstr_w((*pwm)->ldr.FullDllName.Buffer), debugstr_w(libname),
3249 (*pwm)->ldr.DllBase, (*pwm)->ldr.LoadCount);
3250 RtlFreeUnicodeString( &nt_name );
3251 return STATUS_SUCCESS;
3254 if (nts && nts != STATUS_INVALID_IMAGE_NOT_MZ) goto done;
3256 if (NtCurrentTeb64())
3258 prev = NtCurrentTeb64()->Tib.ArbitraryUserPointer;
3259 NtCurrentTeb64()->Tib.ArbitraryUserPointer = (ULONG_PTR)(nt_name.Buffer + 4);
3261 else
3263 prev = (ULONG_PTR)NtCurrentTeb()->Tib.ArbitraryUserPointer;
3264 NtCurrentTeb()->Tib.ArbitraryUserPointer = nt_name.Buffer + 4;
3267 switch (nts)
3269 case STATUS_INVALID_IMAGE_NOT_MZ: /* not in PE format, maybe it's a .so file */
3270 if (__wine_unixlib_handle) nts = load_so_dll( load_path, &nt_name, flags, pwm );
3271 break;
3273 case STATUS_SUCCESS: /* valid PE file */
3274 nts = load_native_dll( load_path, &nt_name, mapping, &image_info, &id, flags, system, pwm );
3275 break;
3278 if (NtCurrentTeb64())
3279 NtCurrentTeb64()->Tib.ArbitraryUserPointer = prev;
3280 else
3281 NtCurrentTeb()->Tib.ArbitraryUserPointer = (void *)(ULONG_PTR)prev;
3283 done:
3284 if (nts == STATUS_SUCCESS)
3285 TRACE("Loaded module %s at %p\n", debugstr_us(&nt_name), (*pwm)->ldr.DllBase);
3286 else
3287 WARN("Failed to load module %s; status=%lx\n", debugstr_w(libname), nts);
3289 if (mapping) NtClose( mapping );
3290 RtlFreeUnicodeString( &nt_name );
3291 return nts;
3295 /***********************************************************************
3296 * __wine_ctrl_routine
3298 NTSTATUS WINAPI __wine_ctrl_routine( void *arg )
3300 DWORD ret = pCtrlRoutine ? pCtrlRoutine( arg ) : 0;
3301 RtlExitUserThread( ret );
3305 /***********************************************************************
3306 * __wine_unix_call
3308 NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args )
3310 return __wine_unix_call_dispatcher( handle, code, args );
3314 /***********************************************************************
3315 * __wine_unix_spawnvp
3317 NTSTATUS WINAPI __wine_unix_spawnvp( char * const argv[], int wait )
3319 struct wine_spawnvp_params params = { (char **)argv, wait };
3321 return WINE_UNIX_CALL( unix_wine_spawnvp, &params );
3325 /***********************************************************************
3326 * wine_server_call
3328 unsigned int CDECL wine_server_call( void *req_ptr )
3330 return WINE_UNIX_CALL( unix_wine_server_call, req_ptr );
3334 /***********************************************************************
3335 * wine_server_fd_to_handle
3337 NTSTATUS CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes,
3338 HANDLE *handle )
3340 struct wine_server_fd_to_handle_params params = { fd, access, attributes, handle };
3342 return WINE_UNIX_CALL( unix_wine_server_fd_to_handle, &params );
3346 /***********************************************************************
3347 * wine_server_handle_to_fd (NTDLL.@)
3349 NTSTATUS CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd,
3350 unsigned int *options )
3352 struct wine_server_handle_to_fd_params params = { handle, access, unix_fd, options };
3354 return WINE_UNIX_CALL( unix_wine_server_handle_to_fd, &params );
3357 /******************************************************************
3358 * LdrLoadDll (NTDLL.@)
3360 NTSTATUS WINAPI DECLSPEC_HOTPATCH LdrLoadDll(LPCWSTR path_name, DWORD flags,
3361 const UNICODE_STRING *libname, HMODULE* hModule)
3363 WINE_MODREF *wm;
3364 NTSTATUS nts;
3365 WCHAR *dllname = append_dll_ext( libname->Buffer );
3367 RtlEnterCriticalSection( &loader_section );
3369 nts = load_dll( path_name, dllname ? dllname : libname->Buffer, flags, &wm, FALSE );
3371 if (nts == STATUS_SUCCESS && !(wm->ldr.Flags & LDR_DONT_RESOLVE_REFS))
3373 nts = process_attach( wm->ldr.DdagNode, NULL );
3374 if (nts != STATUS_SUCCESS)
3376 LdrUnloadDll(wm->ldr.DllBase);
3377 wm = NULL;
3380 *hModule = (wm) ? wm->ldr.DllBase : NULL;
3382 RtlLeaveCriticalSection( &loader_section );
3383 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3384 return nts;
3388 /******************************************************************
3389 * LdrGetDllFullName (NTDLL.@)
3391 NTSTATUS WINAPI LdrGetDllFullName( HMODULE module, UNICODE_STRING *name )
3393 WINE_MODREF *wm;
3394 NTSTATUS status;
3396 TRACE( "module %p, name %p.\n", module, name );
3398 if (!module) module = NtCurrentTeb()->Peb->ImageBaseAddress;
3400 RtlEnterCriticalSection( &loader_section );
3401 wm = get_modref( module );
3402 if (wm)
3404 RtlCopyUnicodeString( name, &wm->ldr.FullDllName );
3405 if (name->MaximumLength < wm->ldr.FullDllName.Length + sizeof(WCHAR)) status = STATUS_BUFFER_TOO_SMALL;
3406 else status = STATUS_SUCCESS;
3407 } else status = STATUS_DLL_NOT_FOUND;
3408 RtlLeaveCriticalSection( &loader_section );
3410 return status;
3414 /******************************************************************
3415 * LdrGetDllHandleEx (NTDLL.@)
3417 NTSTATUS WINAPI LdrGetDllHandleEx( ULONG flags, LPCWSTR load_path, ULONG *dll_characteristics,
3418 const UNICODE_STRING *name, HMODULE *base )
3420 static const ULONG supported_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
3421 | LDR_GET_DLL_HANDLE_EX_FLAG_PIN;
3422 static const ULONG valid_flags = LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT
3423 | LDR_GET_DLL_HANDLE_EX_FLAG_PIN | 4;
3424 SECTION_IMAGE_INFORMATION image_info;
3425 UNICODE_STRING nt_name;
3426 struct file_id id;
3427 NTSTATUS status;
3428 WINE_MODREF *wm;
3429 WCHAR *dllname;
3430 HANDLE mapping;
3432 TRACE( "flags %#lx, load_path %p, dll_characteristics %p, name %p, base %p.\n",
3433 flags, load_path, dll_characteristics, name, base );
3435 if (flags & ~valid_flags) return STATUS_INVALID_PARAMETER;
3437 if ((flags & (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
3438 == (LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | LDR_GET_DLL_HANDLE_EX_FLAG_PIN))
3439 return STATUS_INVALID_PARAMETER;
3441 if (flags & ~supported_flags) FIXME( "Unsupported flags %#lx.\n", flags );
3442 if (dll_characteristics) FIXME( "dll_characteristics unsupported.\n" );
3444 dllname = append_dll_ext( name->Buffer );
3446 RtlEnterCriticalSection( &loader_section );
3448 status = find_dll_file( load_path, dllname ? dllname : name->Buffer,
3449 &nt_name, &wm, &mapping, &image_info, &id );
3451 if (wm) *base = wm->ldr.DllBase;
3452 else
3454 if (status == STATUS_SUCCESS) NtClose( mapping );
3455 status = STATUS_DLL_NOT_FOUND;
3457 RtlFreeUnicodeString( &nt_name );
3459 if (!status)
3461 if (flags & LDR_GET_DLL_HANDLE_EX_FLAG_PIN)
3462 LdrAddRefDll( LDR_ADDREF_DLL_PIN, *base );
3463 else if (!(flags & LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
3464 LdrAddRefDll( 0, *base );
3467 RtlLeaveCriticalSection( &loader_section );
3468 RtlFreeHeap( GetProcessHeap(), 0, dllname );
3469 TRACE( "%s -> %p (load path %s)\n", debugstr_us(name), status ? NULL : *base, debugstr_w(load_path) );
3470 return status;
3474 /******************************************************************
3475 * LdrGetDllHandle (NTDLL.@)
3477 NTSTATUS WINAPI LdrGetDllHandle( LPCWSTR load_path, ULONG flags, const UNICODE_STRING *name, HMODULE *base )
3479 return LdrGetDllHandleEx( LDR_GET_DLL_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, load_path, NULL, name, base );
3483 /******************************************************************
3484 * LdrAddRefDll (NTDLL.@)
3486 NTSTATUS WINAPI LdrAddRefDll( ULONG flags, HMODULE module )
3488 NTSTATUS ret = STATUS_SUCCESS;
3489 WINE_MODREF *wm;
3491 if (flags & ~LDR_ADDREF_DLL_PIN) FIXME( "%p flags %lx not implemented\n", module, flags );
3493 RtlEnterCriticalSection( &loader_section );
3495 if ((wm = get_modref( module )))
3497 if (flags & LDR_ADDREF_DLL_PIN)
3498 wm->ldr.LoadCount = -1;
3499 else
3500 if (wm->ldr.LoadCount != -1) wm->ldr.LoadCount++;
3501 TRACE( "(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
3503 else ret = STATUS_INVALID_PARAMETER;
3505 RtlLeaveCriticalSection( &loader_section );
3506 return ret;
3510 /***********************************************************************
3511 * LdrProcessRelocationBlock (NTDLL.@)
3513 * Apply relocations to a given page of a mapped PE image.
3515 IMAGE_BASE_RELOCATION * WINAPI LdrProcessRelocationBlock( void *page, UINT count,
3516 USHORT *relocs, INT_PTR delta )
3518 while (count--)
3520 USHORT offset = *relocs & 0xfff;
3521 int type = *relocs >> 12;
3522 switch(type)
3524 case IMAGE_REL_BASED_ABSOLUTE:
3525 break;
3526 case IMAGE_REL_BASED_HIGH:
3527 *(short *)((char *)page + offset) += HIWORD(delta);
3528 break;
3529 case IMAGE_REL_BASED_LOW:
3530 *(short *)((char *)page + offset) += LOWORD(delta);
3531 break;
3532 case IMAGE_REL_BASED_HIGHLOW:
3533 *(int *)((char *)page + offset) += delta;
3534 break;
3535 #ifdef _WIN64
3536 case IMAGE_REL_BASED_DIR64:
3537 *(INT_PTR *)((char *)page + offset) += delta;
3538 break;
3539 #elif defined(__arm__)
3540 case IMAGE_REL_BASED_THUMB_MOV32:
3542 UINT *inst = (UINT *)((char *)page + offset);
3543 WORD lo = ((inst[0] << 1) & 0x0800) + ((inst[0] << 12) & 0xf000) +
3544 ((inst[0] >> 20) & 0x0700) + ((inst[0] >> 16) & 0x00ff);
3545 WORD hi = ((inst[1] << 1) & 0x0800) + ((inst[1] << 12) & 0xf000) +
3546 ((inst[1] >> 20) & 0x0700) + ((inst[1] >> 16) & 0x00ff);
3547 DWORD imm = MAKELONG( lo, hi ) + delta;
3549 lo = LOWORD( imm );
3550 hi = HIWORD( imm );
3552 if ((inst[0] & 0x8000fbf0) != 0x0000f240 || (inst[1] & 0x8000fbf0) != 0x0000f2c0)
3553 ERR("wrong Thumb2 instruction @%p %08x:%08x, expected MOVW/MOVT\n",
3554 inst, inst[0], inst[1] );
3556 inst[0] = (inst[0] & 0x8f00fbf0) + ((lo >> 1) & 0x0400) + ((lo >> 12) & 0x000f) +
3557 ((lo << 20) & 0x70000000) + ((lo << 16) & 0xff0000);
3558 inst[1] = (inst[1] & 0x8f00fbf0) + ((hi >> 1) & 0x0400) + ((hi >> 12) & 0x000f) +
3559 ((hi << 20) & 0x70000000) + ((hi << 16) & 0xff0000);
3560 break;
3562 #endif
3563 default:
3564 FIXME("Unknown/unsupported fixup type %x.\n", type);
3565 return NULL;
3567 relocs++;
3569 return (IMAGE_BASE_RELOCATION *)relocs; /* return address of next block */
3573 /******************************************************************
3574 * LdrQueryProcessModuleInformation
3577 NTSTATUS WINAPI LdrQueryProcessModuleInformation(RTL_PROCESS_MODULES *smi,
3578 ULONG buf_size, ULONG* req_size)
3580 RTL_PROCESS_MODULE_INFORMATION *sm = &smi->Modules[0];
3581 ULONG size = sizeof(ULONG);
3582 NTSTATUS nts = STATUS_SUCCESS;
3583 ANSI_STRING str;
3584 char* ptr;
3585 PLIST_ENTRY mark, entry;
3586 LDR_DATA_TABLE_ENTRY *mod;
3587 WORD id = 0;
3589 smi->ModulesCount = 0;
3591 RtlEnterCriticalSection( &loader_section );
3592 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3593 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
3595 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3596 size += sizeof(*sm);
3597 if (size <= buf_size)
3599 sm->Section = 0; /* FIXME */
3600 sm->MappedBaseAddress = mod->DllBase;
3601 sm->ImageBaseAddress = mod->DllBase;
3602 sm->ImageSize = mod->SizeOfImage;
3603 sm->Flags = mod->Flags;
3604 sm->LoadOrderIndex = id++;
3605 sm->InitOrderIndex = 0; /* FIXME */
3606 sm->LoadCount = mod->LoadCount;
3607 str.Length = 0;
3608 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
3609 str.Buffer = (char*)sm->Name;
3610 RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
3611 ptr = strrchr(str.Buffer, '\\');
3612 sm->NameOffset = (ptr != NULL) ? (ptr - str.Buffer + 1) : 0;
3614 smi->ModulesCount++;
3615 sm++;
3617 else nts = STATUS_INFO_LENGTH_MISMATCH;
3619 RtlLeaveCriticalSection( &loader_section );
3621 if (req_size) *req_size = size;
3623 return nts;
3627 static NTSTATUS query_dword_option( HANDLE hkey, LPCWSTR name, LONG *value )
3629 NTSTATUS status;
3630 UNICODE_STRING str;
3631 ULONG size;
3632 WCHAR buffer[64];
3633 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3635 RtlInitUnicodeString( &str, name );
3637 size = sizeof(buffer) - sizeof(WCHAR);
3638 if ((status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size )))
3639 return status;
3641 if (info->Type != REG_DWORD)
3643 buffer[size / sizeof(WCHAR)] = 0;
3644 *value = wcstoul( (WCHAR *)info->Data, 0, 16 );
3646 else memcpy( value, info->Data, sizeof(*value) );
3647 return status;
3650 static NTSTATUS query_string_option( HANDLE hkey, LPCWSTR name, ULONG type,
3651 void *data, ULONG in_size, ULONG *out_size )
3653 NTSTATUS status;
3654 UNICODE_STRING str;
3655 ULONG size;
3656 char *buffer;
3657 KEY_VALUE_PARTIAL_INFORMATION *info;
3658 static const int info_size = FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data );
3660 RtlInitUnicodeString( &str, name );
3662 size = info_size + in_size;
3663 if (!(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
3664 info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
3665 status = NtQueryValueKey( hkey, &str, KeyValuePartialInformation, buffer, size, &size );
3666 if (!status || status == STATUS_BUFFER_OVERFLOW)
3668 if (out_size) *out_size = info->DataLength;
3669 if (data && !status) memcpy( data, info->Data, info->DataLength );
3671 RtlFreeHeap( GetProcessHeap(), 0, buffer );
3672 return status;
3676 /******************************************************************
3677 * LdrQueryImageFileExecutionOptions (NTDLL.@)
3679 NTSTATUS WINAPI LdrQueryImageFileExecutionOptions( const UNICODE_STRING *key, LPCWSTR value, ULONG type,
3680 void *data, ULONG in_size, ULONG *out_size )
3682 static const WCHAR optionsW[] = L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\";
3683 WCHAR path[MAX_PATH + ARRAY_SIZE( optionsW )];
3684 OBJECT_ATTRIBUTES attr;
3685 UNICODE_STRING name_str;
3686 HANDLE hkey;
3687 NTSTATUS status;
3688 ULONG len;
3689 WCHAR *p;
3691 attr.Length = sizeof(attr);
3692 attr.RootDirectory = 0;
3693 attr.ObjectName = &name_str;
3694 attr.Attributes = OBJ_CASE_INSENSITIVE;
3695 attr.SecurityDescriptor = NULL;
3696 attr.SecurityQualityOfService = NULL;
3698 p = key->Buffer + key->Length / sizeof(WCHAR);
3699 while (p > key->Buffer && p[-1] != '\\') p--;
3700 len = key->Length - (p - key->Buffer) * sizeof(WCHAR);
3701 name_str.Buffer = path;
3702 name_str.Length = sizeof(optionsW) - sizeof(WCHAR) + len;
3703 name_str.MaximumLength = name_str.Length;
3704 memcpy( path, optionsW, sizeof(optionsW) );
3705 memcpy( path + ARRAY_SIZE( optionsW ) - 1, p, len );
3706 if ((status = NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))) return status;
3708 if (type == REG_DWORD)
3710 if (out_size) *out_size = sizeof(ULONG);
3711 if (in_size >= sizeof(ULONG)) status = query_dword_option( hkey, value, data );
3712 else status = STATUS_BUFFER_OVERFLOW;
3714 else status = query_string_option( hkey, value, type, data, in_size, out_size );
3716 NtClose( hkey );
3717 return status;
3721 /******************************************************************
3722 * RtlDllShutdownInProgress (NTDLL.@)
3724 BOOLEAN WINAPI RtlDllShutdownInProgress(void)
3726 return process_detaching;
3729 /****************************************************************************
3730 * LdrResolveDelayLoadedAPI (NTDLL.@)
3732 void* WINAPI LdrResolveDelayLoadedAPI( void* base, const IMAGE_DELAYLOAD_DESCRIPTOR* desc,
3733 PDELAYLOAD_FAILURE_DLL_CALLBACK dllhook,
3734 PDELAYLOAD_FAILURE_SYSTEM_ROUTINE syshook,
3735 IMAGE_THUNK_DATA* addr, ULONG flags )
3737 IMAGE_THUNK_DATA *pIAT, *pINT;
3738 DELAYLOAD_INFO delayinfo;
3739 UNICODE_STRING mod;
3740 const CHAR* name;
3741 HMODULE *phmod;
3742 NTSTATUS nts;
3743 FARPROC fp;
3744 DWORD id;
3746 TRACE( "(%p, %p, %p, %p, %p, 0x%08lx)\n", base, desc, dllhook, syshook, addr, flags );
3748 phmod = get_rva(base, desc->ModuleHandleRVA);
3749 pIAT = get_rva(base, desc->ImportAddressTableRVA);
3750 pINT = get_rva(base, desc->ImportNameTableRVA);
3751 name = get_rva(base, desc->DllNameRVA);
3752 id = addr - pIAT;
3754 if (!*phmod)
3756 if (!RtlCreateUnicodeStringFromAsciiz(&mod, name))
3758 nts = STATUS_NO_MEMORY;
3759 goto fail;
3761 nts = LdrLoadDll(NULL, 0, &mod, phmod);
3762 RtlFreeUnicodeString(&mod);
3763 if (nts) goto fail;
3766 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3767 nts = LdrGetProcedureAddress(*phmod, NULL, LOWORD(pINT[id].u1.Ordinal), (void**)&fp);
3768 else
3770 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3771 ANSI_STRING fnc;
3773 RtlInitAnsiString(&fnc, (char*)iibn->Name);
3774 nts = LdrGetProcedureAddress(*phmod, &fnc, 0, (void**)&fp);
3776 if (!nts)
3778 pIAT[id].u1.Function = (ULONG_PTR)fp;
3779 return fp;
3782 fail:
3783 delayinfo.Size = sizeof(delayinfo);
3784 delayinfo.DelayloadDescriptor = desc;
3785 delayinfo.ThunkAddress = addr;
3786 delayinfo.TargetDllName = name;
3787 delayinfo.TargetApiDescriptor.ImportDescribedByName = !IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal);
3788 delayinfo.TargetApiDescriptor.Description.Ordinal = LOWORD(pINT[id].u1.Ordinal);
3789 delayinfo.TargetModuleBase = *phmod;
3790 delayinfo.Unused = NULL;
3791 delayinfo.LastError = nts;
3793 if (dllhook)
3794 return dllhook(4, &delayinfo);
3796 if (IMAGE_SNAP_BY_ORDINAL(pINT[id].u1.Ordinal))
3798 DWORD_PTR ord = LOWORD(pINT[id].u1.Ordinal);
3799 return syshook(name, (const char *)ord);
3801 else
3803 const IMAGE_IMPORT_BY_NAME* iibn = get_rva(base, pINT[id].u1.AddressOfData);
3804 return syshook(name, (const char *)iibn->Name);
3808 /******************************************************************
3809 * LdrShutdownProcess (NTDLL.@)
3812 void WINAPI LdrShutdownProcess(void)
3814 BOOL detaching = process_detaching;
3816 TRACE("()\n");
3818 process_detaching = TRUE;
3819 if (!detaching)
3820 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3822 process_detach();
3826 /******************************************************************
3827 * RtlExitUserProcess (NTDLL.@)
3829 void WINAPI RtlExitUserProcess( DWORD status )
3831 RtlEnterCriticalSection( &loader_section );
3832 RtlAcquirePebLock();
3833 NtTerminateProcess( 0, status );
3834 LdrShutdownProcess();
3835 for (;;) NtTerminateProcess( GetCurrentProcess(), status );
3838 /******************************************************************
3839 * LdrShutdownThread (NTDLL.@)
3842 void WINAPI LdrShutdownThread(void)
3844 PLIST_ENTRY mark, entry;
3845 LDR_DATA_TABLE_ENTRY *mod;
3846 WINE_MODREF *wm;
3847 UINT i;
3848 void **pointers;
3850 TRACE("()\n");
3852 /* don't do any detach calls if process is exiting */
3853 if (process_detaching) return;
3855 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
3857 RtlEnterCriticalSection( &loader_section );
3858 wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
3860 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3861 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
3863 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY,
3864 InInitializationOrderLinks);
3865 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
3866 continue;
3867 if ( mod->Flags & LDR_NO_DLL_CALLS )
3868 continue;
3870 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
3871 DLL_THREAD_DETACH, NULL );
3874 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_DETACH );
3876 RtlAcquirePebLock();
3877 if (NtCurrentTeb()->TlsLinks.Flink) RemoveEntryList( &NtCurrentTeb()->TlsLinks );
3878 if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
3880 for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
3881 RtlFreeHeap( GetProcessHeap(), 0, pointers );
3883 RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
3884 NtCurrentTeb()->FlsSlots = NULL;
3885 RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
3886 NtCurrentTeb()->TlsExpansionSlots = NULL;
3887 RtlReleasePebLock();
3889 RtlLeaveCriticalSection( &loader_section );
3890 /* don't call DbgUiGetThreadDebugObject as some apps hook it and terminate if called */
3891 if (NtCurrentTeb()->DbgSsReserved[1]) NtClose( NtCurrentTeb()->DbgSsReserved[1] );
3892 RtlFreeThreadActivationContextStack();
3894 heap_thread_detach();
3898 /***********************************************************************
3899 * free_modref
3902 static void free_modref( WINE_MODREF *wm )
3904 SINGLE_LIST_ENTRY *entry;
3905 LDR_DEPENDENCY *dep;
3907 RemoveEntryList(&wm->ldr.InLoadOrderLinks);
3908 RemoveEntryList(&wm->ldr.InMemoryOrderLinks);
3909 if (wm->ldr.InInitializationOrderLinks.Flink)
3910 RemoveEntryList(&wm->ldr.InInitializationOrderLinks);
3912 while ((entry = wm->ldr.DdagNode->Dependencies.Tail))
3914 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_to_entry );
3915 assert( dep->dependency_from == wm->ldr.DdagNode );
3916 remove_module_dependency( dep );
3919 while ((entry = wm->ldr.DdagNode->IncomingDependencies.Tail))
3921 dep = CONTAINING_RECORD( entry, LDR_DEPENDENCY, dependency_from_entry );
3922 assert( dep->dependency_to == wm->ldr.DdagNode );
3923 remove_module_dependency( dep );
3926 RemoveEntryList(&wm->ldr.NodeModuleLink);
3927 if (IsListEmpty(&wm->ldr.DdagNode->Modules))
3928 RtlFreeHeap( GetProcessHeap(), 0, wm->ldr.DdagNode );
3930 TRACE(" unloading %s\n", debugstr_w(wm->ldr.FullDllName.Buffer));
3931 if (!TRACE_ON(module))
3932 TRACE_(loaddll)("Unloaded module %s : %s\n",
3933 debugstr_w(wm->ldr.FullDllName.Buffer),
3934 (wm->ldr.Flags & LDR_WINE_INTERNAL) ? "builtin" : "native" );
3936 free_tls_slot( &wm->ldr );
3937 RtlReleaseActivationContext( wm->ldr.ActivationContext );
3938 NtUnmapViewOfSection( NtCurrentProcess(), wm->ldr.DllBase );
3939 if (cached_modref == wm) cached_modref = NULL;
3940 RtlFreeUnicodeString( &wm->ldr.FullDllName );
3941 RtlFreeHeap( GetProcessHeap(), 0, wm );
3944 /***********************************************************************
3945 * MODULE_FlushModrefs
3947 * Remove all unused modrefs and call the internal unloading routines
3948 * for the library type.
3950 * The loader_section must be locked while calling this function.
3952 static void MODULE_FlushModrefs(void)
3954 PLIST_ENTRY mark, entry, prev;
3955 LDR_DATA_TABLE_ENTRY *mod;
3956 WINE_MODREF*wm;
3958 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
3959 for (entry = mark->Blink; entry != mark; entry = prev)
3961 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InInitializationOrderLinks);
3962 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3963 prev = entry->Blink;
3964 if (!mod->LoadCount) free_modref( wm );
3967 /* check load order list too for modules that haven't been initialized yet */
3968 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
3969 for (entry = mark->Blink; entry != mark; entry = prev)
3971 mod = CONTAINING_RECORD(entry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3972 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
3973 prev = entry->Blink;
3974 if (!mod->LoadCount) free_modref( wm );
3978 /***********************************************************************
3979 * MODULE_DecRefCount
3981 * The loader_section must be locked while calling this function.
3983 static NTSTATUS MODULE_DecRefCount( LDR_DDAG_NODE *node, void *context )
3985 LDR_DATA_TABLE_ENTRY *mod;
3986 WINE_MODREF *wm;
3988 mod = CONTAINING_RECORD( node->Modules.Flink, LDR_DATA_TABLE_ENTRY, NodeModuleLink );
3989 wm = CONTAINING_RECORD( mod, WINE_MODREF, ldr );
3991 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
3992 return STATUS_SUCCESS;
3994 if ( wm->ldr.LoadCount <= 0 )
3995 return STATUS_SUCCESS;
3997 --wm->ldr.LoadCount;
3998 TRACE("(%s) ldr.LoadCount: %d\n", debugstr_w(wm->ldr.BaseDllName.Buffer), wm->ldr.LoadCount );
4000 if ( wm->ldr.LoadCount == 0 )
4002 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
4003 walk_node_dependencies( node, context, MODULE_DecRefCount );
4004 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
4005 module_push_unload_trace( wm );
4007 return STATUS_SUCCESS;
4010 /******************************************************************
4011 * LdrUnloadDll (NTDLL.@)
4015 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
4017 WINE_MODREF *wm;
4018 NTSTATUS retv = STATUS_SUCCESS;
4020 if (process_detaching) return retv;
4022 TRACE("(%p)\n", hModule);
4024 RtlEnterCriticalSection( &loader_section );
4026 free_lib_count++;
4027 if ((wm = get_modref( hModule )) != NULL)
4029 TRACE("(%s) - START\n", debugstr_w(wm->ldr.BaseDllName.Buffer));
4031 /* Recursively decrement reference counts */
4032 MODULE_DecRefCount( wm->ldr.DdagNode, NULL );
4034 /* Call process detach notifications */
4035 if ( free_lib_count <= 1 )
4037 process_detach();
4038 MODULE_FlushModrefs();
4041 TRACE("END\n");
4043 else
4044 retv = STATUS_DLL_NOT_FOUND;
4046 free_lib_count--;
4048 RtlLeaveCriticalSection( &loader_section );
4050 return retv;
4053 /***********************************************************************
4054 * RtlImageNtHeader (NTDLL.@)
4056 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
4058 IMAGE_NT_HEADERS *ret;
4060 __TRY
4062 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
4064 ret = NULL;
4065 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
4067 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
4068 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
4071 __EXCEPT_PAGE_FAULT
4073 return NULL;
4075 __ENDTRY
4076 return ret;
4079 /***********************************************************************
4080 * load_global_options
4082 static void load_global_options(void)
4084 OBJECT_ATTRIBUTES attr;
4085 UNICODE_STRING bootstrap_mode_str = RTL_CONSTANT_STRING( L"WINEBOOTSTRAPMODE" );
4086 UNICODE_STRING session_manager_str =
4087 RTL_CONSTANT_STRING( L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager" );
4088 UNICODE_STRING val_str;
4089 HANDLE hkey;
4091 val_str.MaximumLength = 0;
4092 is_prefix_bootstrap =
4093 RtlQueryEnvironmentVariable_U( NULL, &bootstrap_mode_str, &val_str ) != STATUS_VARIABLE_NOT_FOUND;
4095 attr.Length = sizeof(attr);
4096 attr.RootDirectory = 0;
4097 attr.ObjectName = &session_manager_str;
4098 attr.Attributes = OBJ_CASE_INSENSITIVE;
4099 attr.SecurityDescriptor = NULL;
4100 attr.SecurityQualityOfService = NULL;
4102 if (!NtOpenKey( &hkey, KEY_QUERY_VALUE, &attr ))
4104 query_dword_option( hkey, L"SafeProcessSearchMode", &path_safe_mode );
4105 query_dword_option( hkey, L"SafeDllSearchMode", &dll_safe_mode );
4106 NtClose( hkey );
4112 #ifdef _WIN64
4114 static void build_wow64_main_module(void)
4116 UNICODE_STRING nt_name;
4117 WINE_MODREF *wm;
4118 RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters;
4119 void *module = NtCurrentTeb()->Peb->ImageBaseAddress;
4121 RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
4122 wm = alloc_module( module, &nt_name, FALSE );
4123 assert( wm );
4124 wm->ldr.LoadCount = -1;
4125 RtlFreeUnicodeString( &nt_name );
4128 static void (WINAPI *pWow64LdrpInitialize)( CONTEXT *ctx );
4130 void (WINAPI *pWow64PrepareForException)( EXCEPTION_RECORD *rec, CONTEXT *context ) = NULL;
4132 static void init_wow64( CONTEXT *context )
4134 if (!imports_fixup_done)
4136 HMODULE wow64;
4137 WINE_MODREF *wm;
4138 NTSTATUS status;
4139 static const WCHAR wow64_path[] = L"C:\\windows\\system32\\wow64.dll";
4141 build_wow64_main_module();
4142 build_ntdll_module();
4144 if ((status = load_dll( NULL, wow64_path, 0, &wm, FALSE )))
4146 ERR( "could not load %s, status %lx\n", debugstr_w(wow64_path), status );
4147 NtTerminateProcess( GetCurrentProcess(), status );
4149 wow64 = wm->ldr.DllBase;
4150 #define GET_PTR(name) \
4151 if (!(p ## name = RtlFindExportedRoutineByName( wow64, #name ))) ERR( "failed to load %s\n", #name )
4153 GET_PTR( Wow64LdrpInitialize );
4154 GET_PTR( Wow64PrepareForException );
4155 #undef GET_PTR
4156 imports_fixup_done = TRUE;
4159 RtlAcquirePebLock();
4160 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
4161 RtlReleasePebLock();
4163 RtlLeaveCriticalSection( &loader_section );
4164 pWow64LdrpInitialize( context );
4168 #else
4170 void *Wow64Transition = NULL;
4172 static void map_wow64cpu(void)
4174 SIZE_T size = 0;
4175 OBJECT_ATTRIBUTES attr;
4176 UNICODE_STRING string = RTL_CONSTANT_STRING( L"\\??\\C:\\windows\\sysnative\\wow64cpu.dll" );
4177 HANDLE file, section;
4178 IO_STATUS_BLOCK io;
4179 NTSTATUS status;
4181 InitializeObjectAttributes( &attr, &string, 0, NULL, NULL );
4182 if ((status = NtOpenFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ,
4183 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE )))
4185 WARN("failed to open wow64cpu, status %#lx\n", status);
4186 return;
4188 if (!NtCreateSection( &section, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
4189 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
4190 NULL, NULL, PAGE_EXECUTE_READ, SEC_COMMIT, file ))
4192 NtMapViewOfSection( section, NtCurrentProcess(), &Wow64Transition, 0,
4193 0, NULL, &size, ViewShare, 0, PAGE_EXECUTE_READ );
4194 NtClose( section );
4196 NtClose( file );
4199 static void init_wow64( CONTEXT *context )
4201 PEB *peb = NtCurrentTeb()->Peb;
4202 PEB64 *peb64 = UlongToPtr( NtCurrentTeb64()->Peb );
4204 if (Wow64Transition) return; /* already initialized */
4206 peb64->OSMajorVersion = peb->OSMajorVersion;
4207 peb64->OSMinorVersion = peb->OSMinorVersion;
4208 peb64->OSBuildNumber = peb->OSBuildNumber;
4209 peb64->OSPlatformId = peb->OSPlatformId;
4211 #define SET_INIT_BLOCK(func) LdrSystemDllInitBlock.p ## func = PtrToUlong( &func )
4212 SET_INIT_BLOCK( KiUserApcDispatcher );
4213 SET_INIT_BLOCK( KiUserExceptionDispatcher );
4214 SET_INIT_BLOCK( LdrInitializeThunk );
4215 SET_INIT_BLOCK( LdrSystemDllInitBlock );
4216 SET_INIT_BLOCK( RtlUserThreadStart );
4217 SET_INIT_BLOCK( KiUserCallbackDispatcher );
4218 /* SET_INIT_BLOCK( RtlpQueryProcessDebugInformationRemote ); */
4219 /* SET_INIT_BLOCK( RtlpFreezeTimeBias ); */
4220 /* LdrSystemDllInitBlock.ntdll_handle */
4221 #undef SET_INIT_BLOCK
4223 map_wow64cpu();
4225 #endif
4228 /* release some address space once dlls are loaded*/
4229 static void release_address_space(void)
4231 #ifndef _WIN64
4232 void *addr = (void *)1;
4233 SIZE_T size = 0;
4235 NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
4236 #endif
4239 /******************************************************************
4240 * loader_init
4242 * Attach to all the loaded dlls.
4243 * If this is the first time, perform the full process initialization.
4245 void loader_init( CONTEXT *context, void **entry )
4247 static int attach_done;
4248 NTSTATUS status;
4249 ULONG_PTR cookie, port = 0;
4250 WINE_MODREF *wm;
4252 if (process_detaching) NtTerminateThread( GetCurrentThread(), 0 );
4254 RtlEnterCriticalSection( &loader_section );
4256 if (!imports_fixup_done)
4258 ANSI_STRING ctrl_routine = RTL_CONSTANT_STRING( "CtrlRoutine" );
4259 WINE_MODREF *kernel32;
4260 PEB *peb = NtCurrentTeb()->Peb;
4262 peb->LdrData = &ldr;
4263 peb->FastPebLock = &peb_lock;
4264 peb->TlsBitmap = &tls_bitmap;
4265 peb->TlsExpansionBitmap = &tls_expansion_bitmap;
4266 peb->LoaderLock = &loader_section;
4267 peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL );
4269 RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
4270 RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
4271 sizeof(peb->TlsExpansionBitmapBits) * 8 );
4272 /* TLS index 0 is always reserved, and wow64 reserves extra TLS entries */
4273 RtlSetBits( peb->TlsBitmap, 0, NtCurrentTeb()->WowTebOffset ? WOW64_TLS_MAX_NUMBER : 1 );
4274 RtlSetBits( peb->TlsBitmap, NTDLL_TLS_ERRNO, 1 );
4276 init_user_process_params();
4277 load_global_options();
4278 version_init();
4280 if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
4282 wm = build_main_module();
4283 build_ntdll_module();
4285 if ((status = load_dll( NULL, L"kernel32.dll", 0, &kernel32, FALSE )) != STATUS_SUCCESS)
4287 MESSAGE( "wine: could not load kernel32.dll, status %lx\n", status );
4288 NtTerminateProcess( GetCurrentProcess(), status );
4290 node_kernel32 = kernel32->ldr.DdagNode;
4291 pBaseThreadInitThunk = RtlFindExportedRoutineByName( kernel32->ldr.DllBase, "BaseThreadInitThunk" );
4292 LdrGetProcedureAddress( kernel32->ldr.DllBase, &ctrl_routine, 0, (void **)&pCtrlRoutine );
4294 actctx_init();
4295 locale_init();
4296 get_env_var( L"WINESYSTEMDLLPATH", 0, &system_dll_path );
4297 if (wm->ldr.Flags & LDR_COR_ILONLY)
4298 status = fixup_imports_ilonly( wm, NULL, entry );
4299 else
4300 status = fixup_imports( wm, NULL );
4302 if (status)
4304 ERR( "Importing dlls for %s failed, status %lx\n",
4305 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4306 NtTerminateProcess( GetCurrentProcess(), status );
4308 imports_fixup_done = TRUE;
4310 else wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
4312 #ifdef _WIN64
4313 if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
4314 #endif
4316 RtlAcquirePebLock();
4317 InsertHeadList( &tls_links, &NtCurrentTeb()->TlsLinks );
4318 RtlReleasePebLock();
4320 NtCurrentTeb()->FlsSlots = fls_alloc_data();
4322 if (!attach_done) /* first time around */
4324 attach_done = 1;
4325 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4327 ERR( "TLS init failed when loading %s, status %lx\n",
4328 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4329 NtTerminateProcess( GetCurrentProcess(), status );
4331 wm->ldr.Flags |= LDR_PROCESS_ATTACHED; /* don't try to attach again */
4332 if (wm->ldr.ActivationContext)
4333 RtlActivateActivationContext( 0, wm->ldr.ActivationContext, &cookie );
4335 if ((status = process_attach( node_ntdll, context ))
4336 || (status = process_attach( node_kernel32, context )))
4338 ERR( "Initializing system dll for %s failed, status %lx\n",
4339 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4340 NtTerminateProcess( GetCurrentProcess(), status );
4343 if ((status = walk_node_dependencies( wm->ldr.DdagNode, context, process_attach )))
4345 if (last_failed_modref)
4346 ERR( "%s failed to initialize, aborting\n",
4347 debugstr_w(last_failed_modref->ldr.BaseDllName.Buffer) + 1 );
4348 ERR( "Initializing dlls for %s failed, status %lx\n",
4349 debugstr_w(NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer), status );
4350 NtTerminateProcess( GetCurrentProcess(), status );
4352 release_address_space();
4353 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_PROCESS_ATTACH );
4354 if (wm->ldr.ActivationContext) RtlDeactivateActivationContext( 0, cookie );
4356 NtQueryInformationProcess( GetCurrentProcess(), ProcessDebugPort, &port, sizeof(port), NULL );
4357 if (port) process_breakpoint();
4359 else
4361 if ((status = alloc_thread_tls()) != STATUS_SUCCESS)
4362 NtTerminateThread( GetCurrentThread(), status );
4363 thread_attach();
4364 if (wm->ldr.TlsIndex == -1) call_tls_callbacks( wm->ldr.DllBase, DLL_THREAD_ATTACH );
4367 RtlLeaveCriticalSection( &loader_section );
4371 /***********************************************************************
4372 * RtlImageDirectoryEntryToData (NTDLL.@)
4374 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
4376 const IMAGE_NT_HEADERS *nt;
4377 DWORD addr;
4379 if ((ULONG_PTR)module & 1) image = FALSE; /* mapped as data file */
4380 module = (HMODULE)((ULONG_PTR)module & ~3);
4381 if (!(nt = RtlImageNtHeader( module ))) return NULL;
4382 if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
4384 const IMAGE_NT_HEADERS64 *nt64 = (const IMAGE_NT_HEADERS64 *)nt;
4386 if (dir >= nt64->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4387 if (!(addr = nt64->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4388 *size = nt64->OptionalHeader.DataDirectory[dir].Size;
4389 if (image || addr < nt64->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4391 else if (nt->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
4393 const IMAGE_NT_HEADERS32 *nt32 = (const IMAGE_NT_HEADERS32 *)nt;
4395 if (dir >= nt32->OptionalHeader.NumberOfRvaAndSizes) return NULL;
4396 if (!(addr = nt32->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
4397 *size = nt32->OptionalHeader.DataDirectory[dir].Size;
4398 if (image || addr < nt32->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
4400 else return NULL;
4402 /* not mapped as image, need to find the section containing the virtual address */
4403 return RtlImageRvaToVa( nt, module, addr, NULL );
4407 /***********************************************************************
4408 * RtlImageRvaToSection (NTDLL.@)
4410 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
4411 HMODULE module, DWORD rva )
4413 int i;
4414 const IMAGE_SECTION_HEADER *sec = IMAGE_FIRST_SECTION( nt );
4416 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
4418 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4419 return (PIMAGE_SECTION_HEADER)sec;
4421 return NULL;
4425 /***********************************************************************
4426 * RtlImageRvaToVa (NTDLL.@)
4428 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
4429 DWORD rva, IMAGE_SECTION_HEADER **section )
4431 IMAGE_SECTION_HEADER *sec;
4433 if (section && *section) /* try this section first */
4435 sec = *section;
4436 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
4437 goto found;
4439 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
4440 found:
4441 if (section) *section = sec;
4442 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
4446 /***********************************************************************
4447 * RtlAddressInSectionTable (NTDLL.@)
4449 PVOID WINAPI RtlAddressInSectionTable( const IMAGE_NT_HEADERS *nt, HMODULE module,
4450 DWORD rva )
4452 return RtlImageRvaToVa( nt, module, rva, NULL );
4455 /***********************************************************************
4456 * RtlPcToFileHeader (NTDLL.@)
4458 PVOID WINAPI RtlPcToFileHeader( PVOID pc, PVOID *address )
4460 LDR_DATA_TABLE_ENTRY *module;
4461 PVOID ret = NULL;
4463 RtlEnterCriticalSection( &loader_section );
4464 if (!LdrFindEntryForAddress( pc, &module )) ret = module->DllBase;
4465 RtlLeaveCriticalSection( &loader_section );
4466 *address = ret;
4467 return ret;
4471 /****************************************************************************
4472 * LdrGetDllDirectory (NTDLL.@)
4474 NTSTATUS WINAPI LdrGetDllDirectory( UNICODE_STRING *dir )
4476 NTSTATUS status = STATUS_SUCCESS;
4478 RtlEnterCriticalSection( &dlldir_section );
4479 dir->Length = dll_directory.Length + sizeof(WCHAR);
4480 if (dir->MaximumLength >= dir->Length) RtlCopyUnicodeString( dir, &dll_directory );
4481 else
4483 status = STATUS_BUFFER_TOO_SMALL;
4484 if (dir->MaximumLength) dir->Buffer[0] = 0;
4486 RtlLeaveCriticalSection( &dlldir_section );
4487 return status;
4491 /****************************************************************************
4492 * LdrSetDllDirectory (NTDLL.@)
4494 NTSTATUS WINAPI LdrSetDllDirectory( const UNICODE_STRING *dir )
4496 NTSTATUS status = STATUS_SUCCESS;
4497 UNICODE_STRING new;
4499 if (!dir->Buffer) RtlInitUnicodeString( &new, NULL );
4500 else if ((status = RtlDuplicateUnicodeString( 1, dir, &new ))) return status;
4502 RtlEnterCriticalSection( &dlldir_section );
4503 RtlFreeUnicodeString( &dll_directory );
4504 dll_directory = new;
4505 RtlLeaveCriticalSection( &dlldir_section );
4506 return status;
4510 /****************************************************************************
4511 * LdrAddDllDirectory (NTDLL.@)
4513 NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
4515 FILE_BASIC_INFORMATION info;
4516 UNICODE_STRING nt_name;
4517 NTSTATUS status;
4518 OBJECT_ATTRIBUTES attr;
4519 DWORD len;
4520 struct dll_dir_entry *ptr;
4521 DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );
4523 if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
4524 return STATUS_INVALID_PARAMETER;
4526 status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );
4527 if (status) return status;
4528 len = nt_name.Length / sizeof(WCHAR);
4529 if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] ))))
4530 return STATUS_NO_MEMORY;
4531 memcpy( ptr->dir, nt_name.Buffer, len * sizeof(WCHAR) );
4533 attr.Length = sizeof(attr);
4534 attr.RootDirectory = 0;
4535 attr.Attributes = OBJ_CASE_INSENSITIVE;
4536 attr.ObjectName = &nt_name;
4537 attr.SecurityDescriptor = NULL;
4538 attr.SecurityQualityOfService = NULL;
4539 status = NtQueryAttributesFile( &attr, &info );
4540 RtlFreeUnicodeString( &nt_name );
4542 if (!status)
4544 TRACE( "%s\n", debugstr_w( ptr->dir ));
4545 RtlEnterCriticalSection( &dlldir_section );
4546 list_add_head( &dll_dir_list, &ptr->entry );
4547 RtlLeaveCriticalSection( &dlldir_section );
4548 *cookie = ptr;
4550 else RtlFreeHeap( GetProcessHeap(), 0, ptr );
4551 return status;
4555 /****************************************************************************
4556 * LdrRemoveDllDirectory (NTDLL.@)
4558 NTSTATUS WINAPI LdrRemoveDllDirectory( void *cookie )
4560 struct dll_dir_entry *ptr = cookie;
4562 TRACE( "%s\n", debugstr_w( ptr->dir ));
4564 RtlEnterCriticalSection( &dlldir_section );
4565 list_remove( &ptr->entry );
4566 RtlFreeHeap( GetProcessHeap(), 0, ptr );
4567 RtlLeaveCriticalSection( &dlldir_section );
4568 return STATUS_SUCCESS;
4572 /*************************************************************************
4573 * LdrSetDefaultDllDirectories (NTDLL.@)
4575 NTSTATUS WINAPI LdrSetDefaultDllDirectories( ULONG flags )
4577 /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
4578 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4579 LOAD_LIBRARY_SEARCH_USER_DIRS |
4580 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4581 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4583 if (!flags || (flags & ~load_library_search_flags)) return STATUS_INVALID_PARAMETER;
4584 default_search_flags = flags;
4585 return STATUS_SUCCESS;
4589 /******************************************************************
4590 * LdrGetDllPath (NTDLL.@)
4592 NTSTATUS WINAPI LdrGetDllPath( PCWSTR module, ULONG flags, PWSTR *path, PWSTR *unknown )
4594 NTSTATUS status;
4595 const ULONG load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
4596 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
4597 LOAD_LIBRARY_SEARCH_USER_DIRS |
4598 LOAD_LIBRARY_SEARCH_SYSTEM32 |
4599 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
4601 if (flags & LOAD_WITH_ALTERED_SEARCH_PATH)
4603 if (flags & load_library_search_flags) return STATUS_INVALID_PARAMETER;
4604 if (default_search_flags) flags |= default_search_flags | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
4606 else if (!(flags & load_library_search_flags)) flags |= default_search_flags;
4608 RtlEnterCriticalSection( &dlldir_section );
4610 if (flags & load_library_search_flags)
4612 status = get_dll_load_path_search_flags( module, flags, path );
4614 else
4616 const WCHAR *dlldir = dll_directory.Length ? dll_directory.Buffer : NULL;
4617 if (!(flags & LOAD_WITH_ALTERED_SEARCH_PATH) || !wcschr( module, L'\\' ))
4618 module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4619 status = get_dll_load_path( module, dlldir, dll_safe_mode, path );
4622 RtlLeaveCriticalSection( &dlldir_section );
4623 *unknown = NULL;
4624 return status;
4628 /*************************************************************************
4629 * RtlSetSearchPathMode (NTDLL.@)
4631 NTSTATUS WINAPI RtlSetSearchPathMode( ULONG flags )
4633 int val;
4635 switch (flags)
4637 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE:
4638 val = 1;
4639 break;
4640 case BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE:
4641 val = 0;
4642 break;
4643 case BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT:
4644 InterlockedExchange( &path_safe_mode, 2 );
4645 return STATUS_SUCCESS;
4646 default:
4647 return STATUS_INVALID_PARAMETER;
4650 for (;;)
4652 LONG prev = path_safe_mode;
4653 if (prev == 2) break; /* permanently set */
4654 if (InterlockedCompareExchange( &path_safe_mode, val, prev ) == prev) return STATUS_SUCCESS;
4656 return STATUS_ACCESS_DENIED;
4660 /******************************************************************
4661 * RtlGetExePath (NTDLL.@)
4663 NTSTATUS WINAPI RtlGetExePath( PCWSTR name, PWSTR *path )
4665 const WCHAR *dlldir = L".";
4666 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4668 /* same check as NeedCurrentDirectoryForExePathW */
4669 if (!wcschr( name, '\\' ))
4671 UNICODE_STRING name = RTL_CONSTANT_STRING( L"NoDefaultCurrentDirectoryInExePath" ), value = { 0 };
4673 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) != STATUS_VARIABLE_NOT_FOUND)
4674 dlldir = L"";
4676 return get_dll_load_path( module, dlldir, FALSE, path );
4680 /******************************************************************
4681 * RtlGetSearchPath (NTDLL.@)
4683 NTSTATUS WINAPI RtlGetSearchPath( PWSTR *path )
4685 const WCHAR *module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
4686 return get_dll_load_path( module, NULL, path_safe_mode, path );
4690 /******************************************************************
4691 * RtlReleasePath (NTDLL.@)
4693 void WINAPI RtlReleasePath( PWSTR path )
4695 RtlFreeHeap( GetProcessHeap(), 0, path );
4699 /*********************************************************************
4700 * ApiSetQueryApiSetPresence (NTDLL.@)
4702 NTSTATUS WINAPI ApiSetQueryApiSetPresence( const UNICODE_STRING *name, BOOLEAN *present )
4704 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
4705 const API_SET_NAMESPACE_ENTRY *entry;
4706 UNICODE_STRING str;
4708 *present = (!get_apiset_entry( map, name->Buffer, name->Length / sizeof(WCHAR), &entry ) &&
4709 !get_apiset_target( map, entry, NULL, &str ));
4710 return STATUS_SUCCESS;
4714 /*********************************************************************
4715 * ApiSetQueryApiSetPresenceEx (NTDLL.@)
4717 NTSTATUS WINAPI ApiSetQueryApiSetPresenceEx( const UNICODE_STRING *name, BOOLEAN *in_schema, BOOLEAN *present )
4719 const API_SET_NAMESPACE *map = NtCurrentTeb()->Peb->ApiSetMap;
4720 const API_SET_NAMESPACE_ENTRY *entry;
4721 NTSTATUS status;
4722 UNICODE_STRING str;
4723 ULONG i, len = name->Length / sizeof(WCHAR);
4725 /* extension not allowed */
4726 for (i = 0; i < len; i++) if (name->Buffer[i] == '.') return STATUS_INVALID_PARAMETER;
4728 status = get_apiset_entry( map, name->Buffer, len, &entry );
4729 if (status == STATUS_APISET_NOT_PRESENT)
4731 *in_schema = *present = FALSE;
4732 return STATUS_SUCCESS;
4734 if (status) return status;
4736 /* the name must match exactly */
4737 *in_schema = (entry->NameLength == name->Length &&
4738 !wcsnicmp( (WCHAR *)((char *)map + entry->NameOffset), name->Buffer, len ));
4739 *present = *in_schema && !get_apiset_target( map, entry, NULL, &str );
4740 return STATUS_SUCCESS;
4744 /******************************************************************
4745 * DllMain (NTDLL.@)
4747 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserved )
4749 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
4750 return TRUE;