Portability fixes.
[wine.git] / dlls / ntdll / loader.c
blob08f92e7e9192f6aca3cd799258b29289917c1c99
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <assert.h>
24 #include "winbase.h"
25 #include "winnt.h"
26 #include "winternl.h"
28 #include "module.h"
29 #include "file.h"
30 #include "wine/exception.h"
31 #include "excpt.h"
32 #include "snoop.h"
33 #include "wine/debug.h"
34 #include "wine/server.h"
35 #include "ntdll_misc.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(module);
38 WINE_DECLARE_DEBUG_CHANNEL(relay);
39 WINE_DECLARE_DEBUG_CHANNEL(snoop);
40 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
42 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
44 static int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */
45 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
47 /* filter for page-fault exceptions */
48 static WINE_EXCEPTION_FILTER(page_fault)
50 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
51 return EXCEPTION_EXECUTE_HANDLER;
52 return EXCEPTION_CONTINUE_SEARCH;
55 static const char * const reason_names[] =
57 "PROCESS_DETACH",
58 "PROCESS_ATTACH",
59 "THREAD_ATTACH",
60 "THREAD_DETACH"
63 static UINT tls_module_count; /* number of modules with TLS directory */
64 static UINT tls_total_size; /* total size of TLS storage */
65 static const IMAGE_TLS_DIRECTORY **tls_dirs; /* array of TLS directories */
67 static CRITICAL_SECTION loader_section;
68 static CRITICAL_SECTION_DEBUG critsect_debug =
70 0, 0, &loader_section,
71 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
72 0, 0, { 0, (DWORD)(__FILE__ ": loader_section") }
74 static CRITICAL_SECTION loader_section = { &critsect_debug, -1, 0, 0, 0, 0 };
76 static WINE_MODREF *cached_modref;
77 static WINE_MODREF *current_modref;
79 static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm );
80 static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
81 DWORD exp_size, const char *name, int hint );
83 /* convert PE image VirtualAddress to Real Address */
84 inline static void *get_rva( HMODULE module, DWORD va )
86 return (void *)((char *)module + va);
89 /*************************************************************************
90 * get_modref
92 * Looks for the referenced HMODULE in the current process
93 * The loader_section must be locked while calling this function.
95 static WINE_MODREF *get_modref( HMODULE hmod )
97 PLIST_ENTRY mark, entry;
98 PLDR_MODULE mod;
100 if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
102 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
103 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
105 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
106 if (mod->BaseAddress == hmod)
107 return cached_modref = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
108 if (mod->BaseAddress > (void*)hmod) break;
110 return NULL;
114 /*************************************************************************
115 * find_forwarded_export
117 * Find the final function pointer for a forwarded function.
118 * The loader_section must be locked while calling this function.
120 static FARPROC find_forwarded_export( HMODULE module, const char *forward )
122 IMAGE_EXPORT_DIRECTORY *exports;
123 DWORD exp_size;
124 WINE_MODREF *wm;
125 char mod_name[256];
126 char *end = strchr(forward, '.');
127 FARPROC proc = NULL;
129 if (!end) return NULL;
130 if (end - forward >= sizeof(mod_name)) return NULL;
131 memcpy( mod_name, forward, end - forward );
132 mod_name[end-forward] = 0;
134 if (!(wm = MODULE_FindModule( mod_name )))
136 ERR("module not found for forward '%s' used by '%s'\n",
137 forward, get_modref(module)->filename );
138 return NULL;
140 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
141 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
142 proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, end + 1, -1 );
144 if (!proc)
146 ERR("function not found for forward '%s' used by '%s'."
147 " If you are using builtin '%s', try using the native one instead.\n",
148 forward, get_modref(module)->filename, get_modref(module)->modname );
150 return proc;
154 /*************************************************************************
155 * find_ordinal_export
157 * Find an exported function by ordinal.
158 * The exports base must have been subtracted from the ordinal already.
159 * The loader_section must be locked while calling this function.
161 static FARPROC find_ordinal_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
162 DWORD exp_size, int ordinal )
164 FARPROC proc;
165 DWORD *functions = get_rva( module, exports->AddressOfFunctions );
167 if (ordinal >= exports->NumberOfFunctions)
169 TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base );
170 return NULL;
172 if (!functions[ordinal]) return NULL;
174 proc = get_rva( module, functions[ordinal] );
176 /* if the address falls into the export dir, it's a forward */
177 if (((char *)proc >= (char *)exports) && ((char *)proc < (char *)exports + exp_size))
178 return find_forwarded_export( module, (char *)proc );
180 if (TRACE_ON(snoop))
182 proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal );
184 if (TRACE_ON(relay) && current_modref)
186 proc = RELAY_GetProcAddress( module, exports, exp_size, proc, current_modref->modname );
188 return proc;
192 /*************************************************************************
193 * find_named_export
195 * Find an exported function by name.
196 * The loader_section must be locked while calling this function.
198 static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
199 DWORD exp_size, const char *name, int hint )
201 WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
202 DWORD *names = get_rva( module, exports->AddressOfNames );
203 int min = 0, max = exports->NumberOfNames - 1;
205 /* first check the hint */
206 if (hint >= 0 && hint <= max)
208 char *ename = get_rva( module, names[hint] );
209 if (!strcmp( ename, name ))
210 return find_ordinal_export( module, exports, exp_size, ordinals[hint] );
213 /* then do a binary search */
214 while (min <= max)
216 int res, pos = (min + max) / 2;
217 char *ename = get_rva( module, names[pos] );
218 if (!(res = strcmp( ename, name )))
219 return find_ordinal_export( module, exports, exp_size, ordinals[pos] );
220 if (res > 0) max = pos - 1;
221 else min = pos + 1;
223 return NULL;
228 /*************************************************************************
229 * import_dll
231 * Import the dll specified by the given import descriptor.
232 * The loader_section must be locked while calling this function.
234 static WINE_MODREF *import_dll( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *descr )
236 NTSTATUS status;
237 WINE_MODREF *wmImp;
238 HMODULE imp_mod;
239 IMAGE_EXPORT_DIRECTORY *exports;
240 DWORD exp_size;
241 IMAGE_THUNK_DATA *import_list, *thunk_list;
242 char *name = get_rva( module, descr->Name );
244 status = load_dll( name, 0, &wmImp );
245 if (status)
247 if (status == STATUS_NO_SUCH_FILE)
248 ERR("Module (file) %s (which is needed by %s) not found\n",
249 name, current_modref->filename);
250 else
251 ERR("Loading module (file) %s (which is needed by %s) failed (error %lx).\n",
252 name, current_modref->filename, status);
253 return NULL;
256 imp_mod = wmImp->ldr.BaseAddress;
257 if (!(exports = RtlImageDirectoryEntryToData( imp_mod, TRUE,
258 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
259 return NULL;
261 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
262 if (descr->u.OriginalFirstThunk)
263 import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
264 else
265 import_list = thunk_list;
267 while (import_list->u1.Ordinal)
269 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
271 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
273 TRACE("--- Ordinal %s,%d\n", name, ordinal);
274 thunk_list->u1.Function = (PDWORD)find_ordinal_export( imp_mod, exports, exp_size,
275 ordinal - exports->Base );
276 if (!thunk_list->u1.Function)
278 ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
279 name, ordinal, current_modref->filename );
280 thunk_list->u1.Function = (PDWORD)0xdeadbeef;
283 else /* import by name */
285 IMAGE_IMPORT_BY_NAME *pe_name;
286 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
287 TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
288 thunk_list->u1.Function = (PDWORD)find_named_export( imp_mod, exports, exp_size,
289 pe_name->Name, pe_name->Hint );
290 if (!thunk_list->u1.Function)
292 ERR("No implementation for %s.%s imported from %s, setting to 0xdeadbeef\n",
293 name, pe_name->Name, current_modref->filename );
294 thunk_list->u1.Function = (PDWORD)0xdeadbeef;
297 import_list++;
298 thunk_list++;
300 return wmImp;
304 /****************************************************************
305 * PE_fixup_imports
307 * Fixup all imports of a given module.
308 * The loader_section must be locked while calling this function.
310 DWORD PE_fixup_imports( WINE_MODREF *wm )
312 int i, nb_imports;
313 IMAGE_IMPORT_DESCRIPTOR *imports;
314 WINE_MODREF *prev;
315 DWORD size;
317 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
318 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
319 return 0;
321 nb_imports = size / sizeof(*imports);
322 for (i = 0; i < nb_imports; i++)
324 if (!imports[i].Name)
326 nb_imports = i;
327 break;
330 if (!nb_imports) return 0; /* no imports */
332 /* Allocate module dependency list */
333 wm->nDeps = nb_imports;
334 wm->deps = RtlAllocateHeap( ntdll_get_process_heap(), 0, nb_imports*sizeof(WINE_MODREF *) );
336 /* load the imported modules. They are automatically
337 * added to the modref list of the process.
339 prev = current_modref;
340 current_modref = wm;
341 for (i = 0; i < nb_imports; i++)
343 if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i] ))) break;
345 current_modref = prev;
346 return (i < nb_imports);
350 /*************************************************************************
351 * MODULE_AllocModRef
353 * Allocate a WINE_MODREF structure and add it to the process list
354 * The loader_section must be locked while calling this function.
356 WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
358 WINE_MODREF *wm;
359 IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
360 PLIST_ENTRY entry, mark;
361 BOOLEAN linked = FALSE;
363 DWORD long_len = strlen( filename );
364 DWORD short_len = GetShortPathNameA( filename, NULL, 0 );
366 if ((wm = RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY,
367 sizeof(*wm) + long_len + short_len + 1 )))
369 wm->filename = wm->data;
370 memcpy( wm->filename, filename, long_len + 1 );
371 if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
372 else wm->modname = wm->filename;
374 wm->short_filename = wm->filename + long_len + 1;
375 GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 );
376 if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
377 else wm->short_modname = wm->short_filename;
379 wm->ldr.BaseAddress = hModule;
380 wm->ldr.EntryPoint = (nt->OptionalHeader.AddressOfEntryPoint) ?
381 ((char *)hModule + nt->OptionalHeader.AddressOfEntryPoint) : 0;
382 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
383 RtlCreateUnicodeStringFromAsciiz( &wm->ldr.FullDllName, wm->filename);
384 RtlCreateUnicodeStringFromAsciiz( &wm->ldr.BaseDllName, wm->modname);
385 wm->ldr.Flags = 0;
386 wm->ldr.LoadCount = 0;
387 wm->ldr.TlsIndex = -1;
388 wm->ldr.SectionHandle = NULL;
389 wm->ldr.CheckSum = 0;
390 wm->ldr.TimeDateStamp = 0;
392 /* this is a bit ugly, but we need to have app module first in LoadOrder
393 * list, But in wine, ntdll is loaded first, so by inserting DLLs at the tail
394 * and app module at the head we insure that order
396 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
398 /* is first loaded module a DLL or an exec ? */
399 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
400 if (mark->Flink == mark ||
401 (CONTAINING_RECORD(mark->Flink, LDR_MODULE, InLoadOrderModuleList)->Flags & LDR_IMAGE_IS_DLL))
403 InsertHeadList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
404 &wm->ldr.InLoadOrderModuleList);
405 linked = TRUE;
408 else wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
410 if (!linked)
411 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList,
412 &wm->ldr.InLoadOrderModuleList);
414 /* insert module in MemoryList, sorted in increasing base addresses */
415 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
416 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
418 if (CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList)->BaseAddress > wm->ldr.BaseAddress)
419 break;
421 entry->Blink->Flink = &wm->ldr.InMemoryOrderModuleList;
422 wm->ldr.InMemoryOrderModuleList.Blink = entry->Blink;
423 wm->ldr.InMemoryOrderModuleList.Flink = entry;
424 entry->Blink = &wm->ldr.InMemoryOrderModuleList;
426 /* wait until init is called for inserting into this list */
427 wm->ldr.InInitializationOrderModuleList.Flink = NULL;
428 wm->ldr.InInitializationOrderModuleList.Blink = NULL;
430 return wm;
434 /*************************************************************************
435 * alloc_process_tls
437 * Allocate the process-wide structure for module TLS storage.
439 static NTSTATUS alloc_process_tls(void)
441 PLIST_ENTRY mark, entry;
442 PLDR_MODULE mod;
443 IMAGE_TLS_DIRECTORY *dir;
444 ULONG size, i;
446 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
447 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
449 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
450 if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
451 IMAGE_DIRECTORY_ENTRY_TLS, &size )))
452 continue;
453 size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill;
454 if (!size) continue;
455 tls_total_size += size;
456 tls_module_count++;
458 if (!tls_module_count) return STATUS_SUCCESS;
460 TRACE( "count %u size %u\n", tls_module_count, tls_total_size );
462 tls_dirs = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_module_count * sizeof(*tls_dirs) );
463 if (!tls_dirs) return STATUS_NO_MEMORY;
465 for (i = 0, entry = mark->Flink; entry != mark; entry = entry->Flink)
467 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
468 if (!(dir = RtlImageDirectoryEntryToData( mod->BaseAddress, TRUE,
469 IMAGE_DIRECTORY_ENTRY_TLS, &size )))
470 continue;
471 tls_dirs[i] = dir;
472 *dir->AddressOfIndex = i;
473 mod->TlsIndex = i;
474 mod->LoadCount = -1; /* can't unload it */
475 i++;
477 return STATUS_SUCCESS;
481 /*************************************************************************
482 * alloc_thread_tls
484 * Allocate the per-thread structure for module TLS storage.
486 static NTSTATUS alloc_thread_tls(void)
488 void **pointers;
489 char *data;
490 UINT i;
492 if (!tls_module_count) return STATUS_SUCCESS;
494 if (!(pointers = RtlAllocateHeap( ntdll_get_process_heap(), 0,
495 tls_module_count * sizeof(*pointers) )))
496 return STATUS_NO_MEMORY;
498 if (!(data = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_total_size )))
500 RtlFreeHeap( ntdll_get_process_heap(), 0, pointers );
501 return STATUS_NO_MEMORY;
504 for (i = 0; i < tls_module_count; i++)
506 const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i];
507 ULONG size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
509 TRACE( "thread %04lx idx %d: %ld/%ld bytes from %p to %p\n",
510 GetCurrentThreadId(), i, size, dir->SizeOfZeroFill,
511 (void *)dir->StartAddressOfRawData, data );
513 pointers[i] = data;
514 memcpy( data, (void *)dir->StartAddressOfRawData, size );
515 data += size;
516 memset( data, 0, dir->SizeOfZeroFill );
517 data += dir->SizeOfZeroFill;
519 NtCurrentTeb()->tls_ptr = pointers;
520 return STATUS_SUCCESS;
524 /*************************************************************************
525 * call_tls_callbacks
527 static void call_tls_callbacks( HMODULE module, UINT reason )
529 const IMAGE_TLS_DIRECTORY *dir;
530 const PIMAGE_TLS_CALLBACK *callback;
531 ULONG dirsize;
533 dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
534 if (!dir || !dir->AddressOfCallBacks) return;
536 for (callback = dir->AddressOfCallBacks; *callback; callback++)
538 if (TRACE_ON(relay))
539 DPRINTF("%04lx:Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
540 GetCurrentThreadId(), *callback, module, reason_names[reason] );
541 (*callback)( module, reason, NULL );
542 if (TRACE_ON(relay))
543 DPRINTF("%04lx:Ret TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
544 GetCurrentThreadId(), *callback, module, reason_names[reason] );
549 /*************************************************************************
550 * MODULE_InitDLL
552 static BOOL MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
554 char mod_name[32];
555 BOOL retv = TRUE;
556 DLLENTRYPROC entry = wm->ldr.EntryPoint;
557 void *module = wm->ldr.BaseAddress;
559 /* Skip calls for modules loaded with special load flags */
561 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return TRUE;
562 if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
563 if (!entry || !(wm->ldr.Flags & LDR_IMAGE_IS_DLL)) return TRUE;
565 if (TRACE_ON(relay))
567 size_t len = max( strlen(wm->modname), sizeof(mod_name)-1 );
568 memcpy( mod_name, wm->modname, len );
569 mod_name[len] = 0;
570 DPRINTF("%04lx:Call PE DLL (proc=%p,module=%p (%s),reason=%s,res=%p)\n",
571 GetCurrentThreadId(), entry, module, mod_name, reason_names[reason], lpReserved );
573 else TRACE("(%p (%s),%s,%p) - CALL\n", module, wm->modname, reason_names[reason], lpReserved );
575 retv = entry( module, reason, lpReserved );
577 /* The state of the module list may have changed due to the call
578 to the dll. We cannot assume that this module has not been
579 deleted. */
580 if (TRACE_ON(relay))
581 DPRINTF("%04lx:Ret PE DLL (proc=%p,module=%p (%s),reason=%s,res=%p) retval=%x\n",
582 GetCurrentThreadId(), entry, module, mod_name, reason_names[reason], lpReserved, retv );
583 else TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
585 return retv;
589 /*************************************************************************
590 * MODULE_DllProcessAttach
592 * Send the process attach notification to all DLLs the given module
593 * depends on (recursively). This is somewhat complicated due to the fact that
595 * - we have to respect the module dependencies, i.e. modules implicitly
596 * referenced by another module have to be initialized before the module
597 * itself can be initialized
599 * - the initialization routine of a DLL can itself call LoadLibrary,
600 * thereby introducing a whole new set of dependencies (even involving
601 * the 'old' modules) at any time during the whole process
603 * (Note that this routine can be recursively entered not only directly
604 * from itself, but also via LoadLibrary from one of the called initialization
605 * routines.)
607 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
608 * the process *detach* notifications to be sent in the correct order.
609 * This must not only take into account module dependencies, but also
610 * 'hidden' dependencies created by modules calling LoadLibrary in their
611 * attach notification routine.
613 * The strategy is rather simple: we move a WINE_MODREF to the head of the
614 * list after the attach notification has returned. This implies that the
615 * detach notifications are called in the reverse of the sequence the attach
616 * notifications *returned*.
618 NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
620 NTSTATUS status = STATUS_SUCCESS;
621 int i;
623 RtlEnterCriticalSection( &loader_section );
625 if (!wm)
627 PLIST_ENTRY mark;
629 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
630 wm = CONTAINING_RECORD(CONTAINING_RECORD(mark->Flink,
631 LDR_MODULE, InLoadOrderModuleList),
632 WINE_MODREF, ldr);
633 wm->ldr.LoadCount = -1; /* can't unload main exe */
634 if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto done;
635 if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
637 assert( wm );
639 /* prevent infinite recursion in case of cyclical dependencies */
640 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
641 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
642 goto done;
644 TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
646 /* Tag current MODREF to prevent recursive loop */
647 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
649 /* Recursively attach all DLLs this one depends on */
650 for ( i = 0; i < wm->nDeps; i++ )
652 if (!wm->deps[i]) continue;
653 if ((status = MODULE_DllProcessAttach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
656 /* Call DLL entry point */
657 if (status == STATUS_SUCCESS)
659 WINE_MODREF *prev = current_modref;
660 current_modref = wm;
661 if (MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved ))
662 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
663 else
664 status = STATUS_DLL_INIT_FAILED;
665 current_modref = prev;
668 InsertTailList(&NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList,
669 &wm->ldr.InInitializationOrderModuleList);
671 /* Remove recursion flag */
672 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
674 TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
676 done:
677 RtlLeaveCriticalSection( &loader_section );
678 return status;
681 /*************************************************************************
682 * MODULE_DllProcessDetach
684 * Send DLL process detach notifications. See the comment about calling
685 * sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
686 * is set, only DLLs with zero refcount are notified.
688 static void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
690 PLIST_ENTRY mark, entry;
691 PLDR_MODULE mod;
693 RtlEnterCriticalSection( &loader_section );
694 if (bForceDetach) process_detaching = 1;
695 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
698 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
700 mod = CONTAINING_RECORD(entry, LDR_MODULE,
701 InInitializationOrderModuleList);
702 /* Check whether to detach this DLL */
703 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
704 continue;
705 if ( mod->LoadCount && !bForceDetach )
706 continue;
708 /* Call detach notification */
709 mod->Flags &= ~LDR_PROCESS_ATTACHED;
710 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
711 DLL_PROCESS_DETACH, lpReserved );
713 /* Restart at head of WINE_MODREF list, as entries might have
714 been added and/or removed while performing the call ... */
715 break;
717 } while (entry != mark);
719 RtlLeaveCriticalSection( &loader_section );
722 /*************************************************************************
723 * MODULE_DllThreadAttach
725 * Send DLL thread attach notifications. These are sent in the
726 * reverse sequence of process detach notification.
729 NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved )
731 PLIST_ENTRY mark, entry;
732 PLDR_MODULE mod;
733 NTSTATUS status;
735 /* don't do any attach calls if process is exiting */
736 if (process_detaching) return STATUS_SUCCESS;
737 /* FIXME: there is still a race here */
739 RtlEnterCriticalSection( &loader_section );
741 if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
743 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
744 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
746 mod = CONTAINING_RECORD(entry, LDR_MODULE,
747 InInitializationOrderModuleList);
748 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
749 continue;
750 if ( mod->Flags & LDR_NO_DLL_CALLS )
751 continue;
753 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
754 DLL_THREAD_ATTACH, lpReserved );
757 done:
758 RtlLeaveCriticalSection( &loader_section );
759 return status;
762 /******************************************************************
763 * LdrDisableThreadCalloutsForDll (NTDLL.@)
766 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
768 WINE_MODREF *wm;
769 NTSTATUS ret = STATUS_SUCCESS;
771 RtlEnterCriticalSection( &loader_section );
773 wm = get_modref( hModule );
774 if (!wm || wm->ldr.TlsIndex != -1)
775 ret = STATUS_DLL_NOT_FOUND;
776 else
777 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
779 RtlLeaveCriticalSection( &loader_section );
781 return ret;
784 /******************************************************************
785 * LdrFindEntryForAddress (NTDLL.@)
787 * The loader_section must be locked while calling this function
789 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* pmod)
791 PLIST_ENTRY mark, entry;
792 PLDR_MODULE mod;
794 mark = &NtCurrentTeb()->Peb->LdrData->InMemoryOrderModuleList;
795 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
797 mod = CONTAINING_RECORD(entry, LDR_MODULE, InMemoryOrderModuleList);
798 if ((const void *)mod->BaseAddress <= addr &&
799 (char *)addr < (char*)mod->BaseAddress + mod->SizeOfImage)
801 *pmod = mod;
802 return STATUS_SUCCESS;
804 if ((const void *)mod->BaseAddress > addr) break;
806 return STATUS_NO_MORE_ENTRIES;
809 /**********************************************************************
810 * MODULE_FindModule
812 * Find a (loaded) win32 module depending on path
813 * LPCSTR path: [in] pathname of module/library to be found
815 * The loader_section must be locked while calling this function
816 * RETURNS
817 * the module handle if found
818 * 0 if not
820 WINE_MODREF *MODULE_FindModule(LPCSTR path)
822 WINE_MODREF *wm;
823 PLIST_ENTRY mark, entry;
824 PLDR_MODULE mod;
825 char dllname[260], *p;
827 /* Append .DLL to name if no extension present */
828 strcpy( dllname, path );
829 if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
830 strcat( dllname, ".DLL" );
832 if ((wm = cached_modref) != NULL)
834 if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
835 if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
836 if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
837 if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
840 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
841 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
843 mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
844 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
846 if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
847 if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
848 if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
849 if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
851 if (entry == mark) wm = NULL;
853 cached_modref = wm;
854 return wm;
858 /******************************************************************
859 * LdrLockLoaderLock (NTDLL.@)
861 * Note: flags are not implemented.
862 * Flag 0x01 is used to raise exceptions on errors.
863 * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
865 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
867 if (flags) FIXME( "flags %lx not supported\n", flags );
869 if (result) *result = 1;
870 if (!magic) return STATUS_INVALID_PARAMETER_3;
871 RtlEnterCriticalSection( &loader_section );
872 *magic = GetCurrentThreadId();
873 return STATUS_SUCCESS;
877 /******************************************************************
878 * LdrUnlockLoaderUnlock (NTDLL.@)
880 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
882 if (magic)
884 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
885 RtlLeaveCriticalSection( &loader_section );
887 return STATUS_SUCCESS;
891 /******************************************************************
892 * LdrGetDllHandle (NTDLL.@)
896 NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE *base)
898 WINE_MODREF *wm;
899 STRING str;
901 if (x != 0 || y != 0)
902 FIXME("Unknown behavior, please report\n");
904 /* FIXME: we should store module name information as unicode */
905 RtlUnicodeStringToAnsiString( &str, name, TRUE );
906 wm = MODULE_FindModule( str.Buffer );
907 RtlFreeAnsiString( &str );
909 if (!wm)
911 *base = 0;
912 return STATUS_DLL_NOT_FOUND;
915 *base = wm->ldr.BaseAddress;
917 TRACE("%lx %lx %s -> %p\n", x, y, debugstr_us(name), *base);
919 return STATUS_SUCCESS;
923 /******************************************************************
924 * LdrGetProcedureAddress (NTDLL.@)
926 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, PANSI_STRING name, ULONG ord, PVOID *address)
928 IMAGE_EXPORT_DIRECTORY *exports;
929 DWORD exp_size;
930 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
932 RtlEnterCriticalSection( &loader_section );
934 if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
935 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
937 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1 )
938 : find_ordinal_export( module, exports, exp_size, ord - exports->Base );
939 if (proc)
941 *address = proc;
942 ret = STATUS_SUCCESS;
945 else
947 /* check if the module itself is invalid to return the proper error */
948 if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
951 RtlLeaveCriticalSection( &loader_section );
952 return ret;
956 /***********************************************************************
957 * allocate_lib_dir
959 * helper for MODULE_LoadLibraryExA. Allocate space to hold the directory
960 * portion of the provided name and put the name in it.
963 static LPCSTR allocate_lib_dir(LPCSTR libname)
965 LPCSTR p, pmax;
966 LPSTR result;
967 int length;
969 pmax = libname;
970 if ((p = strrchr( pmax, '\\' ))) pmax = p + 1;
971 if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty. MSDN says don't */
972 if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2;
974 length = pmax - libname;
976 result = RtlAllocateHeap (ntdll_get_process_heap(), 0, length+1);
978 if (result)
980 strncpy (result, libname, length);
981 result [length] = '\0';
984 return result;
987 /***********************************************************************
988 * load_dll (internal)
990 * Load a PE style module according to the load order.
992 * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
993 * on this function. When first called from LoadLibraryExA it will be
994 * NULL but thereafter it may point to a buffer containing the path
995 * portion of the library name. Note that the recursion all occurs
996 * within a Critical section (see LoadLibraryExA) so the use of a
997 * static is acceptable.
998 * (We have to use a static variable at some point anyway, to pass the
999 * information from BUILTIN32_dlopen through dlopen and the builtin's
1000 * init function into load_library).
1001 * allocated_libdir is TRUE in the stack frame that allocated libdir
1003 static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
1005 int i;
1006 enum loadorder_type loadorder[LOADORDER_NTYPES];
1007 LPSTR filename;
1008 const char *filetype = "";
1009 DWORD found;
1010 BOOL allocated_libdir = FALSE;
1011 static LPCSTR libdir = NULL; /* See above */
1012 NTSTATUS nts = STATUS_NO_SUCH_FILE;
1014 *pwm = NULL;
1015 if ( !libname ) return STATUS_DLL_NOT_FOUND; /* FIXME ? */
1017 filename = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
1018 if ( !filename ) return STATUS_NO_MEMORY;
1019 *filename = 0; /* Just in case we don't set it before goto error */
1021 RtlEnterCriticalSection( &loader_section );
1023 if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname))
1025 if (!(libdir = allocate_lib_dir(libname)))
1027 nts = STATUS_NO_MEMORY;
1028 goto error;
1030 allocated_libdir = TRUE;
1033 if (!libdir || allocated_libdir)
1034 found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL);
1035 else
1036 found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL);
1038 /* build the modules filename */
1039 if (!found)
1041 if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH ))
1043 nts = STATUS_INTERNAL_ERROR;
1044 goto error;
1048 /* Check for already loaded module */
1049 if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
1051 LPSTR fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
1052 if (fn)
1054 /* since the default loading mechanism uses a more detailed algorithm
1055 * than SearchPath (like using PATH, which can even be modified between
1056 * two attempts of loading the same DLL), the look-up above (with
1057 * SearchPath) can have put the file in system directory, whereas it
1058 * has already been loaded but with a different path. So do a specific
1059 * look-up with filename (without any path)
1061 strcpy ( fn, libname );
1062 /* if the filename doesn't have an extension append .DLL */
1063 if (!strrchr( fn, '.')) strcat( fn, ".dll" );
1064 if ((*pwm = MODULE_FindModule( fn )) != NULL)
1065 strcpy( filename, fn );
1066 RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
1069 if (*pwm)
1071 if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
1073 if (((*pwm)->ldr.Flags & LDR_DONT_RESOLVE_REFS) &&
1074 !(flags & DONT_RESOLVE_DLL_REFERENCES))
1076 (*pwm)->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1077 PE_fixup_imports( *pwm );
1079 TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
1080 if (allocated_libdir)
1082 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
1083 libdir = NULL;
1085 RtlLeaveCriticalSection( &loader_section );
1086 RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
1087 return STATUS_SUCCESS;
1090 MODULE_GetLoadOrder( loadorder, filename, TRUE);
1092 for (i = 0; i < LOADORDER_NTYPES; i++)
1094 if (loadorder[i] == LOADORDER_INVALID) break;
1096 switch (loadorder[i])
1098 case LOADORDER_DLL:
1099 TRACE("Trying native dll '%s'\n", filename);
1100 nts = PE_LoadLibraryExA(filename, flags, pwm);
1101 filetype = "native";
1102 break;
1104 case LOADORDER_BI:
1105 TRACE("Trying built-in '%s'\n", filename);
1106 nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
1107 filetype = "builtin";
1108 break;
1110 default:
1111 nts = STATUS_INTERNAL_ERROR;
1112 break;
1115 if (nts == STATUS_SUCCESS)
1117 /* Initialize DLL just loaded */
1118 TRACE("Loaded module '%s' (%s) at %p\n", filename, filetype, (*pwm)->ldr.BaseAddress);
1119 if (!TRACE_ON(module))
1120 TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype);
1121 /* Set the ldr.LoadCount here so that an attach failure will */
1122 /* decrement the dependencies through the MODULE_FreeLibrary call. */
1123 (*pwm)->ldr.LoadCount = 1;
1125 if (allocated_libdir)
1127 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
1128 libdir = NULL;
1130 RtlLeaveCriticalSection( &loader_section );
1131 RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
1132 return nts;
1135 if (nts != STATUS_NO_SUCH_FILE)
1137 WARN("Loading of %s DLL %s failed (status %lx).\n",
1138 filetype, filename, nts);
1139 break;
1143 error:
1144 if (allocated_libdir)
1146 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
1147 libdir = NULL;
1149 RtlLeaveCriticalSection( &loader_section );
1150 WARN("Failed to load module '%s'; status=%lx\n", filename, nts);
1151 RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
1152 return nts;
1155 /******************************************************************
1156 * LdrLoadDll (NTDLL.@)
1158 NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libname, HMODULE* hModule)
1160 WINE_MODREF *wm;
1161 NTSTATUS nts = STATUS_SUCCESS;
1162 STRING str;
1164 RtlUnicodeStringToAnsiString(&str, libname, TRUE);
1166 RtlEnterCriticalSection( &loader_section );
1168 switch (nts = load_dll( str.Buffer, flags, &wm ))
1170 case STATUS_SUCCESS:
1171 nts = MODULE_DllProcessAttach( wm, NULL );
1172 if (nts != STATUS_SUCCESS)
1174 WARN("Attach failed for module '%s'.\n", str.Buffer);
1175 LdrUnloadDll(wm->ldr.BaseAddress);
1176 wm = NULL;
1178 break;
1179 case STATUS_NO_SUCH_FILE:
1180 nts = STATUS_DLL_NOT_FOUND;
1181 break;
1182 default: /* keep error code as it is (memory...) */
1183 break;
1186 *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
1188 RtlLeaveCriticalSection( &loader_section );
1190 RtlFreeAnsiString(&str);
1192 return nts;
1195 /******************************************************************
1196 * LdrQueryProcessModuleInformation
1199 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi,
1200 ULONG buf_size, ULONG* req_size)
1202 SYSTEM_MODULE* sm = &smi->Modules[0];
1203 ULONG size = sizeof(ULONG);
1204 NTSTATUS nts = STATUS_SUCCESS;
1205 ANSI_STRING str;
1206 char* ptr;
1207 PLIST_ENTRY mark, entry;
1208 PLDR_MODULE mod;
1210 smi->ModulesCount = 0;
1212 RtlEnterCriticalSection( &loader_section );
1213 mark = &NtCurrentTeb()->Peb->LdrData->InLoadOrderModuleList;
1214 for (entry = mark->Flink; entry != mark; entry = entry->Flink)
1216 mod = CONTAINING_RECORD(entry, LDR_MODULE, InLoadOrderModuleList);
1217 size += sizeof(*sm);
1218 if (size <= buf_size)
1220 sm->Reserved1 = 0; /* FIXME */
1221 sm->Reserved2 = 0; /* FIXME */
1222 sm->ImageBaseAddress = mod->BaseAddress;
1223 sm->ImageSize = mod->SizeOfImage;
1224 sm->Flags = mod->Flags;
1225 sm->Id = 0; /* FIXME */
1226 sm->Rank = 0; /* FIXME */
1227 sm->Unknown = 0; /* FIXME */
1228 str.Length = 0;
1229 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
1230 str.Buffer = sm->Name;
1231 RtlUnicodeStringToAnsiString(&str, &mod->FullDllName, FALSE);
1232 ptr = strrchr(sm->Name, '\\');
1233 sm->NameOffset = (ptr != NULL) ? (ptr - (char*)sm->Name + 1) : 0;
1235 smi->ModulesCount++;
1236 sm++;
1238 else nts = STATUS_INFO_LENGTH_MISMATCH;
1240 RtlLeaveCriticalSection( &loader_section );
1242 if (req_size) *req_size = size;
1244 return nts;
1247 /******************************************************************
1248 * LdrShutdownProcess (NTDLL.@)
1251 void WINAPI LdrShutdownProcess(void)
1253 TRACE("()\n");
1254 MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
1257 /******************************************************************
1258 * LdrShutdownThread (NTDLL.@)
1261 void WINAPI LdrShutdownThread(void)
1263 PLIST_ENTRY mark, entry;
1264 PLDR_MODULE mod;
1266 TRACE("()\n");
1268 /* don't do any detach calls if process is exiting */
1269 if (process_detaching) return;
1270 /* FIXME: there is still a race here */
1272 RtlEnterCriticalSection( &loader_section );
1274 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1275 for (entry = mark->Blink; entry != mark; entry = entry->Blink)
1277 mod = CONTAINING_RECORD(entry, LDR_MODULE,
1278 InInitializationOrderModuleList);
1279 if ( !(mod->Flags & LDR_PROCESS_ATTACHED) )
1280 continue;
1281 if ( mod->Flags & LDR_NO_DLL_CALLS )
1282 continue;
1284 MODULE_InitDLL( CONTAINING_RECORD(mod, WINE_MODREF, ldr),
1285 DLL_THREAD_DETACH, NULL );
1288 RtlLeaveCriticalSection( &loader_section );
1291 /***********************************************************************
1292 * MODULE_FlushModrefs
1294 * Remove all unused modrefs and call the internal unloading routines
1295 * for the library type.
1297 * The loader_section must be locked while calling this function.
1299 static void MODULE_FlushModrefs(void)
1301 PLIST_ENTRY mark, entry, prev;
1302 PLDR_MODULE mod;
1303 WINE_MODREF*wm;
1305 mark = &NtCurrentTeb()->Peb->LdrData->InInitializationOrderModuleList;
1306 for (entry = mark->Blink; entry != mark; entry = prev)
1308 mod = CONTAINING_RECORD(entry, LDR_MODULE,
1309 InInitializationOrderModuleList);
1310 wm = CONTAINING_RECORD(mod, WINE_MODREF, ldr);
1312 prev = entry->Blink;
1313 if (wm->ldr.LoadCount) continue;
1315 RemoveEntryList(&wm->ldr.InLoadOrderModuleList);
1316 RemoveEntryList(&wm->ldr.InMemoryOrderModuleList);
1317 RemoveEntryList(&wm->ldr.InInitializationOrderModuleList);
1319 TRACE(" unloading %s\n", wm->filename);
1320 if (!TRACE_ON(module))
1321 TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
1322 wm->dlhandle ? "builtin" : "native" );
1324 SERVER_START_REQ( unload_dll )
1326 req->base = wm->ldr.BaseAddress;
1327 wine_server_call( req );
1329 SERVER_END_REQ;
1331 if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
1332 else NtUnmapViewOfSection( GetCurrentProcess(), wm->ldr.BaseAddress );
1333 if (cached_modref == wm) cached_modref = NULL;
1334 RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps );
1335 RtlFreeHeap( ntdll_get_process_heap(), 0, wm );
1339 /***********************************************************************
1340 * MODULE_DecRefCount
1342 * The loader_section must be locked while calling this function.
1344 static void MODULE_DecRefCount( WINE_MODREF *wm )
1346 int i;
1348 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
1349 return;
1351 if ( wm->ldr.LoadCount <= 0 )
1352 return;
1354 --wm->ldr.LoadCount;
1355 TRACE("(%s) ldr.LoadCount: %d\n", wm->modname, wm->ldr.LoadCount );
1357 if ( wm->ldr.LoadCount == 0 )
1359 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
1361 for ( i = 0; i < wm->nDeps; i++ )
1362 if ( wm->deps[i] )
1363 MODULE_DecRefCount( wm->deps[i] );
1365 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
1369 /******************************************************************
1370 * LdrUnloadDll (NTDLL.@)
1374 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
1376 NTSTATUS retv = STATUS_SUCCESS;
1378 TRACE("(%p)\n", hModule);
1380 RtlEnterCriticalSection( &loader_section );
1382 /* if we're stopping the whole process (and forcing the removal of all
1383 * DLLs) the library will be freed anyway
1385 if (!process_detaching)
1387 WINE_MODREF *wm;
1389 free_lib_count++;
1390 if ((wm = get_modref( hModule )) != NULL)
1392 TRACE("(%s) - START\n", wm->modname);
1394 /* Recursively decrement reference counts */
1395 MODULE_DecRefCount( wm );
1397 /* Call process detach notifications */
1398 if ( free_lib_count <= 1 )
1400 MODULE_DllProcessDetach( FALSE, NULL );
1401 MODULE_FlushModrefs();
1404 TRACE("END\n");
1406 else
1407 retv = STATUS_DLL_NOT_FOUND;
1409 free_lib_count--;
1412 RtlLeaveCriticalSection( &loader_section );
1414 return retv;
1417 /***********************************************************************
1418 * RtlImageNtHeader (NTDLL.@)
1420 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
1422 IMAGE_NT_HEADERS *ret;
1424 __TRY
1426 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
1428 ret = NULL;
1429 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
1431 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
1432 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
1435 __EXCEPT(page_fault)
1437 return NULL;
1439 __ENDTRY
1440 return ret;
1444 /***********************************************************************
1445 * RtlImageDirectoryEntryToData (NTDLL.@)
1447 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
1449 const IMAGE_NT_HEADERS *nt;
1450 DWORD addr;
1452 if ((ULONG_PTR)module & 1) /* mapped as data file */
1454 module = (HMODULE)((ULONG_PTR)module & ~1);
1455 image = FALSE;
1457 if (!(nt = RtlImageNtHeader( module ))) return NULL;
1458 if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
1459 if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
1460 *size = nt->OptionalHeader.DataDirectory[dir].Size;
1461 if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
1463 /* not mapped as image, need to find the section containing the virtual address */
1464 return RtlImageRvaToVa( nt, module, addr, NULL );
1468 /***********************************************************************
1469 * RtlImageRvaToSection (NTDLL.@)
1471 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
1472 HMODULE module, DWORD rva )
1474 int i;
1475 IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader +
1476 nt->FileHeader.SizeOfOptionalHeader);
1477 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
1479 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1480 return sec;
1482 return NULL;
1486 /***********************************************************************
1487 * RtlImageRvaToVa (NTDLL.@)
1489 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
1490 DWORD rva, IMAGE_SECTION_HEADER **section )
1492 IMAGE_SECTION_HEADER *sec;
1494 if (section && *section) /* try this section first */
1496 sec = *section;
1497 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1498 goto found;
1500 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
1501 found:
1502 if (section) *section = sec;
1503 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);