Rewrote most of the import fixup code to avoid doing redundant work
[wine/wine-kai.git] / dlls / ntdll / loader.c
blobfb0a60dcc0d8960e0c6f1c225b456cf6535d4f6b
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 WINE_MODREF *MODULE_modref_list = NULL;
46 static WINE_MODREF *exe_modref;
47 static int process_detaching = 0; /* set on process detach to avoid deadlocks with thread detach */
48 static int free_lib_count; /* recursion depth of LdrUnloadDll calls */
50 /* filter for page-fault exceptions */
51 static WINE_EXCEPTION_FILTER(page_fault)
53 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
54 return EXCEPTION_EXECUTE_HANDLER;
55 return EXCEPTION_CONTINUE_SEARCH;
58 static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
59 static WINE_MODREF *cached_modref;
61 static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm );
62 static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
63 DWORD exp_size, const char *name, int hint );
65 /* convert PE image VirtualAddress to Real Address */
66 inline static void *get_rva( HMODULE module, DWORD va )
68 return (void *)((char *)module + va);
71 /*************************************************************************
72 * get_modref
74 * Looks for the referenced HMODULE in the current process
75 * The loader_section must be locked while calling this function.
77 static WINE_MODREF *get_modref( HMODULE hmod )
79 WINE_MODREF *wm;
81 if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
83 for ( wm = MODULE_modref_list; wm; wm=wm->next )
85 if (wm->ldr.BaseAddress == hmod)
87 cached_modref = wm;
88 break;
91 return wm;
95 /*************************************************************************
96 * find_forwarded_export
98 * Find the final function pointer for a forwarded function.
99 * The loader_section must be locked while calling this function.
101 static FARPROC find_forwarded_export( HMODULE module, const char *forward )
103 IMAGE_EXPORT_DIRECTORY *exports;
104 DWORD exp_size;
105 WINE_MODREF *wm;
106 char mod_name[256];
107 char *end = strchr(forward, '.');
108 FARPROC proc = NULL;
110 if (!end) return NULL;
111 if (end - forward >= sizeof(mod_name)) return NULL;
112 memcpy( mod_name, forward, end - forward );
113 mod_name[end-forward] = 0;
115 if (!(wm = MODULE_FindModule( mod_name )))
117 WINE_MODREF *user = get_modref( module );
118 ERR("module not found for forward '%s' used by '%s'\n", forward, user->filename );
119 return NULL;
121 if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
122 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
123 proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, end + 1, -1 );
125 if (!proc)
127 WINE_MODREF *user = get_modref( module );
128 ERR("function not found for forward '%s' used by '%s'."
129 " If you are using builtin '%s', try using the native one instead.\n",
130 forward, user->filename, user->modname );
132 return proc;
136 /*************************************************************************
137 * find_ordinal_export
139 * Find an exported function by ordinal.
140 * The exports base must have been subtracted from the ordinal already.
141 * The loader_section must be locked while calling this function.
143 static FARPROC find_ordinal_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
144 DWORD exp_size, int ordinal )
146 FARPROC proc;
147 WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
148 DWORD *functions = get_rva( module, exports->AddressOfFunctions );
150 if (ordinal >= exports->NumberOfFunctions)
152 TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base );
153 return NULL;
155 if (!functions[ordinal]) return NULL;
157 proc = get_rva( module, functions[ordinal] );
159 /* if the address falls into the export dir, it's a forward */
160 if (((char *)proc >= (char *)exports) && ((char *)proc < (char *)exports + exp_size))
161 return find_forwarded_export( module, (char *)proc );
163 if (TRACE_ON(snoop))
165 /* try to find a name for it */
166 int i;
167 char *ename = "@";
168 DWORD *name = get_rva( module, exports->AddressOfNames );
169 if (name) for (i = 0; i < exports->NumberOfNames; i++)
171 if (ordinals[i] == ordinal)
173 ename = get_rva( module, name[i] );
174 break;
177 proc = SNOOP_GetProcAddress( module, ename, ordinal, proc );
179 return proc;
183 /*************************************************************************
184 * find_named_export
186 * Find an exported function by name.
187 * The loader_section must be locked while calling this function.
189 static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
190 DWORD exp_size, const char *name, int hint )
192 WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
193 DWORD *names = get_rva( module, exports->AddressOfNames );
194 int min = 0, max = exports->NumberOfNames - 1;
196 /* first check the hint */
197 if (hint >= 0 && hint <= max)
199 char *ename = get_rva( module, names[hint] );
200 if (!strcmp( ename, name ))
201 return find_ordinal_export( module, exports, exp_size, ordinals[hint] );
204 /* then do a binary search */
205 while (min <= max)
207 int res, pos = (min + max) / 2;
208 char *ename = get_rva( module, names[pos] );
209 if (!(res = strcmp( ename, name )))
210 return find_ordinal_export( module, exports, exp_size, ordinals[pos] );
211 if (res > 0) max = pos - 1;
212 else min = pos + 1;
214 return NULL;
219 /*************************************************************************
220 * import_dll
222 * Import the dll specified by the given import descriptor.
223 * The loader_section must be locked while calling this function.
225 static WINE_MODREF *import_dll( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *descr )
227 NTSTATUS status;
228 WINE_MODREF *wmImp;
229 HMODULE imp_mod;
230 IMAGE_EXPORT_DIRECTORY *exports;
231 DWORD exp_size;
232 IMAGE_THUNK_DATA *import_list, *thunk_list;
233 char *name = get_rva( module, descr->Name );
235 status = load_dll( name, 0, &wmImp );
236 if (status)
238 WINE_MODREF *user = get_modref( module );
239 if (status == STATUS_NO_SUCH_FILE)
240 ERR("Module (file) %s (which is needed by %s) not found\n", name, user->filename);
241 else
242 ERR("Loading module (file) %s (which is needed by %s) failed (error %ld).\n",
243 name, user->filename, status);
244 return NULL;
247 imp_mod = wmImp->ldr.BaseAddress;
248 if (!(exports = RtlImageDirectoryEntryToData( imp_mod, TRUE,
249 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
250 return NULL;
252 thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
253 if (descr->u.OriginalFirstThunk)
254 import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
255 else
256 import_list = thunk_list;
258 while (import_list->u1.Ordinal)
260 if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
262 int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
264 TRACE("--- Ordinal %s,%d\n", name, ordinal);
265 thunk_list->u1.Function = (PDWORD)find_ordinal_export( imp_mod, exports, exp_size,
266 ordinal - exports->Base );
267 if (!thunk_list->u1.Function)
269 WINE_MODREF *user = get_modref( module );
270 ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
271 name, ordinal, user->filename );
272 thunk_list->u1.Function = (PDWORD)0xdeadbeef;
275 else /* import by name */
277 IMAGE_IMPORT_BY_NAME *pe_name;
278 pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
279 TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
280 thunk_list->u1.Function = (PDWORD)find_named_export( imp_mod, exports, exp_size,
281 pe_name->Name, pe_name->Hint );
282 if (!thunk_list->u1.Function)
284 WINE_MODREF *user = get_modref( module );
285 ERR("No implementation for %s.%s imported from %s, setting to 0xdeadbeef\n",
286 name, pe_name->Name, user->filename );
287 thunk_list->u1.Function = (PDWORD)0xdeadbeef;
290 import_list++;
291 thunk_list++;
293 return wmImp;
297 /****************************************************************
298 * PE_fixup_imports
300 * Fixup all imports of a given module.
301 * The loader_section must be locked while calling this function.
303 DWORD PE_fixup_imports( WINE_MODREF *wm )
305 int i, nb_imports;
306 IMAGE_IMPORT_DESCRIPTOR *imports;
307 DWORD size;
309 if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
310 IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
311 return 0;
313 nb_imports = size / sizeof(*imports);
314 for (i = 0; i < nb_imports; i++)
316 if (!imports[i].Name)
318 nb_imports = i;
319 break;
322 if (!nb_imports) return 0; /* no imports */
324 /* Allocate module dependency list */
325 wm->nDeps = nb_imports;
326 wm->deps = RtlAllocateHeap( ntdll_get_process_heap(), 0, nb_imports*sizeof(WINE_MODREF *) );
328 /* load the imported modules. They are automatically
329 * added to the modref list of the process.
331 for (i = 0; i < nb_imports; i++)
333 if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i] ))) return 1;
335 return 0;
339 /*************************************************************************
340 * MODULE_AllocModRef
342 * Allocate a WINE_MODREF structure and add it to the process list
343 * The loader_section must be locked while calling this function.
345 WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
347 WINE_MODREF *wm;
348 IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
350 DWORD long_len = strlen( filename );
351 DWORD short_len = GetShortPathNameA( filename, NULL, 0 );
353 if ((wm = RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY,
354 sizeof(*wm) + long_len + short_len + 1 )))
356 wm->filename = wm->data;
357 memcpy( wm->filename, filename, long_len + 1 );
358 if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
359 else wm->modname = wm->filename;
361 wm->short_filename = wm->filename + long_len + 1;
362 GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 );
363 if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
364 else wm->short_modname = wm->short_filename;
366 wm->next = MODULE_modref_list;
367 if (wm->next) wm->next->prev = wm;
368 MODULE_modref_list = wm;
370 wm->ldr.InLoadOrderModuleList.Flink = NULL;
371 wm->ldr.InLoadOrderModuleList.Blink = NULL;
372 wm->ldr.InMemoryOrderModuleList.Flink = NULL;
373 wm->ldr.InMemoryOrderModuleList.Blink = NULL;
374 wm->ldr.InInitializationOrderModuleList.Flink = NULL;
375 wm->ldr.InInitializationOrderModuleList.Blink = NULL;
376 wm->ldr.BaseAddress = hModule;
377 wm->ldr.EntryPoint = (nt->OptionalHeader.AddressOfEntryPoint) ?
378 ((char *)hModule + nt->OptionalHeader.AddressOfEntryPoint) : 0;
379 wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
380 RtlCreateUnicodeStringFromAsciiz( &wm->ldr.FullDllName, wm->filename);
381 RtlCreateUnicodeStringFromAsciiz( &wm->ldr.BaseDllName, wm->modname);
382 wm->ldr.Flags = 0;
383 wm->ldr.LoadCount = 0;
384 wm->ldr.TlsIndex = -1;
385 wm->ldr.SectionHandle = NULL;
386 wm->ldr.CheckSum = 0;
387 wm->ldr.TimeDateStamp = 0;
389 if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
391 if (!exe_modref) exe_modref = wm;
392 else FIXME( "Trying to load second .EXE file: %s\n", filename );
394 else wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
396 return wm;
399 /*************************************************************************
400 * MODULE_InitDLL
402 static BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
404 static const char * const typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH",
405 "THREAD_ATTACH", "THREAD_DETACH" };
406 BOOL retv = TRUE;
407 DLLENTRYPROC entry = wm->ldr.EntryPoint;
408 void *module = wm->ldr.BaseAddress;
410 /* Skip calls for modules loaded with special load flags */
412 if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return TRUE;
413 if (!entry || !(wm->ldr.Flags & LDR_IMAGE_IS_DLL)) return TRUE;
415 TRACE("(%p (%s),%s,%p) - CALL\n", module, wm->modname, typeName[type], lpReserved );
417 if (TRACE_ON(relay))
418 DPRINTF("%04lx:Call PE DLL (proc=%p,module=%p,type=%ld,res=%p)\n",
419 GetCurrentThreadId(), entry, module, type, lpReserved );
421 retv = entry( module, type, lpReserved );
423 if (TRACE_ON(relay))
424 DPRINTF("%04lx:Ret PE DLL (proc=%p,module=%p,type=%ld,res=%p) retval=%x\n",
425 GetCurrentThreadId(), entry, module, type, lpReserved, retv );
427 /* The state of the module list may have changed due to the call
428 to the dll. We cannot assume that this module has not been
429 deleted. */
430 TRACE("(%p,%s,%p) - RETURN %d\n", module, typeName[type], lpReserved, retv );
432 return retv;
436 /*************************************************************************
437 * MODULE_DllProcessAttach
439 * Send the process attach notification to all DLLs the given module
440 * depends on (recursively). This is somewhat complicated due to the fact that
442 * - we have to respect the module dependencies, i.e. modules implicitly
443 * referenced by another module have to be initialized before the module
444 * itself can be initialized
446 * - the initialization routine of a DLL can itself call LoadLibrary,
447 * thereby introducing a whole new set of dependencies (even involving
448 * the 'old' modules) at any time during the whole process
450 * (Note that this routine can be recursively entered not only directly
451 * from itself, but also via LoadLibrary from one of the called initialization
452 * routines.)
454 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
455 * the process *detach* notifications to be sent in the correct order.
456 * This must not only take into account module dependencies, but also
457 * 'hidden' dependencies created by modules calling LoadLibrary in their
458 * attach notification routine.
460 * The strategy is rather simple: we move a WINE_MODREF to the head of the
461 * list after the attach notification has returned. This implies that the
462 * detach notifications are called in the reverse of the sequence the attach
463 * notifications *returned*.
465 BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
467 BOOL retv = TRUE;
468 int i;
470 RtlEnterCriticalSection( &loader_section );
472 if (!wm)
474 wm = exe_modref;
475 PE_InitTls();
477 assert( wm );
479 /* prevent infinite recursion in case of cyclical dependencies */
480 if ( ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
481 || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
482 goto done;
484 TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
486 /* Tag current MODREF to prevent recursive loop */
487 wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
489 /* Recursively attach all DLLs this one depends on */
490 for ( i = 0; retv && i < wm->nDeps; i++ )
491 if ( wm->deps[i] )
492 retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
494 /* Call DLL entry point */
495 if ( retv )
497 retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
498 if ( retv )
499 wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
502 /* Re-insert MODREF at head of list */
503 if ( retv && wm->prev )
505 wm->prev->next = wm->next;
506 if ( wm->next ) wm->next->prev = wm->prev;
508 wm->prev = NULL;
509 wm->next = MODULE_modref_list;
510 MODULE_modref_list = wm->next->prev = wm;
513 /* Remove recursion flag */
514 wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
516 TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
519 done:
520 RtlLeaveCriticalSection( &loader_section );
521 return retv;
524 /*************************************************************************
525 * MODULE_DllProcessDetach
527 * Send DLL process detach notifications. See the comment about calling
528 * sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
529 * is set, only DLLs with zero refcount are notified.
531 void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
533 WINE_MODREF *wm;
535 RtlEnterCriticalSection( &loader_section );
536 if (bForceDetach) process_detaching = 1;
539 for ( wm = MODULE_modref_list; wm; wm = wm->next )
541 /* Check whether to detach this DLL */
542 if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
543 continue;
544 if ( wm->ldr.LoadCount > 0 && !bForceDetach )
545 continue;
547 /* Call detach notification */
548 wm->ldr.Flags &= ~LDR_PROCESS_ATTACHED;
549 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
551 /* Restart at head of WINE_MODREF list, as entries might have
552 been added and/or removed while performing the call ... */
553 break;
555 } while ( wm );
557 RtlLeaveCriticalSection( &loader_section );
560 /*************************************************************************
561 * MODULE_DllThreadAttach
563 * Send DLL thread attach notifications. These are sent in the
564 * reverse sequence of process detach notification.
567 void MODULE_DllThreadAttach( LPVOID lpReserved )
569 WINE_MODREF *wm;
571 /* don't do any attach calls if process is exiting */
572 if (process_detaching) return;
573 /* FIXME: there is still a race here */
575 RtlEnterCriticalSection( &loader_section );
577 PE_InitTls();
579 for ( wm = MODULE_modref_list; wm; wm = wm->next )
580 if ( !wm->next )
581 break;
583 for ( ; wm; wm = wm->prev )
585 if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
586 continue;
587 if ( wm->ldr.Flags & LDR_NO_DLL_CALLS )
588 continue;
590 MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
593 RtlLeaveCriticalSection( &loader_section );
596 /******************************************************************
597 * LdrDisableThreadCalloutsForDll (NTDLL.@)
600 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
602 WINE_MODREF *wm;
603 NTSTATUS ret = STATUS_SUCCESS;
605 RtlEnterCriticalSection( &loader_section );
607 wm = get_modref( hModule );
608 if ( !wm )
609 ret = STATUS_DLL_NOT_FOUND;
610 else
611 wm->ldr.Flags |= LDR_NO_DLL_CALLS;
613 RtlLeaveCriticalSection( &loader_section );
615 return ret;
618 /******************************************************************
619 * LdrFindEntryForAddress (NTDLL.@)
621 * The loader_section must be locked while calling this function
623 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* mod)
625 WINE_MODREF* wm;
627 for ( wm = MODULE_modref_list; wm; wm = wm->next )
629 if ((const void *)wm->ldr.BaseAddress <= addr &&
630 (char *)addr < (char*)wm->ldr.BaseAddress + wm->ldr.SizeOfImage)
632 *mod = &wm->ldr;
633 return STATUS_SUCCESS;
636 return STATUS_NO_MORE_ENTRIES;
639 /**********************************************************************
640 * MODULE_FindModule
642 * Find a (loaded) win32 module depending on path
643 * LPCSTR path: [in] pathname of module/library to be found
645 * The loader_section must be locked while calling this function
646 * RETURNS
647 * the module handle if found
648 * 0 if not
650 WINE_MODREF *MODULE_FindModule(LPCSTR path)
652 WINE_MODREF *wm;
653 char dllname[260], *p;
655 /* Append .DLL to name if no extension present */
656 strcpy( dllname, path );
657 if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
658 strcat( dllname, ".DLL" );
660 if ((wm = cached_modref) != NULL)
662 if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
663 if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
664 if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
665 if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
668 for ( wm = MODULE_modref_list; wm; wm = wm->next )
670 if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
671 if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
672 if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
673 if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
675 cached_modref = wm;
676 return wm;
680 /******************************************************************
681 * LdrLockLoaderLock (NTDLL.@)
683 * Note: flags are not implemented.
684 * Flag 0x01 is used to raise exceptions on errors.
685 * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
687 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
689 if (flags) FIXME( "flags %lx not supported\n", flags );
691 if (result) *result = 1;
692 if (!magic) return STATUS_INVALID_PARAMETER_3;
693 RtlEnterCriticalSection( &loader_section );
694 *magic = GetCurrentThreadId();
695 return STATUS_SUCCESS;
699 /******************************************************************
700 * LdrUnlockLoaderUnlock (NTDLL.@)
702 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
704 if (magic)
706 if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
707 RtlLeaveCriticalSection( &loader_section );
709 return STATUS_SUCCESS;
713 /******************************************************************
714 * LdrGetDllHandle (NTDLL.@)
718 NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE *base)
720 WINE_MODREF *wm;
721 STRING str;
723 if (x != 0 || y != 0)
724 FIXME("Unknown behavior, please report\n");
726 /* FIXME: we should store module name information as unicode */
727 RtlUnicodeStringToAnsiString( &str, name, TRUE );
728 wm = MODULE_FindModule( str.Buffer );
729 RtlFreeAnsiString( &str );
731 if (!wm)
733 *base = 0;
734 return STATUS_DLL_NOT_FOUND;
737 *base = wm->ldr.BaseAddress;
739 TRACE("%lx %lx %s -> %p\n", x, y, debugstr_us(name), *base);
741 return STATUS_SUCCESS;
745 /******************************************************************
746 * LdrGetProcedureAddress (NTDLL.@)
748 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, PANSI_STRING name, ULONG ord, PVOID *address)
750 IMAGE_EXPORT_DIRECTORY *exports;
751 DWORD exp_size;
752 NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
754 RtlEnterCriticalSection( &loader_section );
756 if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
757 IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
759 void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1 )
760 : find_ordinal_export( module, exports, exp_size, ord - exports->Base );
761 if (proc)
763 *address = proc;
764 ret = STATUS_SUCCESS;
767 else
769 /* check if the module itself is invalid to return the proper error */
770 if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
773 RtlLeaveCriticalSection( &loader_section );
774 return ret;
778 /***********************************************************************
779 * allocate_lib_dir
781 * helper for MODULE_LoadLibraryExA. Allocate space to hold the directory
782 * portion of the provided name and put the name in it.
785 static LPCSTR allocate_lib_dir(LPCSTR libname)
787 LPCSTR p, pmax;
788 LPSTR result;
789 int length;
791 pmax = libname;
792 if ((p = strrchr( pmax, '\\' ))) pmax = p + 1;
793 if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty. MSDN says don't */
794 if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2;
796 length = pmax - libname;
798 result = RtlAllocateHeap (ntdll_get_process_heap(), 0, length+1);
800 if (result)
802 strncpy (result, libname, length);
803 result [length] = '\0';
806 return result;
809 /***********************************************************************
810 * load_dll (internal)
812 * Load a PE style module according to the load order.
814 * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
815 * on this function. When first called from LoadLibraryExA it will be
816 * NULL but thereafter it may point to a buffer containing the path
817 * portion of the library name. Note that the recursion all occurs
818 * within a Critical section (see LoadLibraryExA) so the use of a
819 * static is acceptable.
820 * (We have to use a static variable at some point anyway, to pass the
821 * information from BUILTIN32_dlopen through dlopen and the builtin's
822 * init function into load_library).
823 * allocated_libdir is TRUE in the stack frame that allocated libdir
825 static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
827 int i;
828 enum loadorder_type loadorder[LOADORDER_NTYPES];
829 LPSTR filename;
830 const char *filetype = "";
831 DWORD found;
832 BOOL allocated_libdir = FALSE;
833 static LPCSTR libdir = NULL; /* See above */
834 NTSTATUS nts = STATUS_SUCCESS;
836 *pwm = NULL;
837 if ( !libname ) return STATUS_DLL_NOT_FOUND; /* FIXME ? */
839 filename = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
840 if ( !filename ) return STATUS_NO_MEMORY;
841 *filename = 0; /* Just in case we don't set it before goto error */
843 RtlEnterCriticalSection( &loader_section );
845 if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname))
847 if (!(libdir = allocate_lib_dir(libname)))
849 nts = STATUS_NO_MEMORY;
850 goto error;
852 allocated_libdir = TRUE;
855 if (!libdir || allocated_libdir)
856 found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL);
857 else
858 found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL);
860 /* build the modules filename */
861 if (!found)
863 if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH ))
865 nts = STATUS_INTERNAL_ERROR;
866 goto error;
870 /* Check for already loaded module */
871 if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
873 LPSTR fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
874 if (fn)
876 /* since the default loading mechanism uses a more detailed algorithm
877 * than SearchPath (like using PATH, which can even be modified between
878 * two attempts of loading the same DLL), the look-up above (with
879 * SearchPath) can have put the file in system directory, whereas it
880 * has already been loaded but with a different path. So do a specific
881 * look-up with filename (without any path)
883 strcpy ( fn, libname );
884 /* if the filename doesn't have an extension append .DLL */
885 if (!strrchr( fn, '.')) strcat( fn, ".dll" );
886 if ((*pwm = MODULE_FindModule( fn )) != NULL)
887 strcpy( filename, fn );
888 RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
891 if (*pwm)
893 (*pwm)->ldr.LoadCount++;
895 if (((*pwm)->ldr.Flags & LDR_DONT_RESOLVE_REFS) &&
896 !(flags & DONT_RESOLVE_DLL_REFERENCES))
898 (*pwm)->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
899 PE_fixup_imports( *pwm );
901 TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
902 if (allocated_libdir)
904 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
905 libdir = NULL;
907 RtlLeaveCriticalSection( &loader_section );
908 RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
909 return STATUS_SUCCESS;
912 MODULE_GetLoadOrder( loadorder, filename, TRUE);
914 for (i = 0; i < LOADORDER_NTYPES; i++)
916 if (loadorder[i] == LOADORDER_INVALID) break;
918 switch (loadorder[i])
920 case LOADORDER_DLL:
921 TRACE("Trying native dll '%s'\n", filename);
922 nts = PE_LoadLibraryExA(filename, flags, pwm);
923 filetype = "native";
924 break;
926 case LOADORDER_BI:
927 TRACE("Trying built-in '%s'\n", filename);
928 nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
929 filetype = "builtin";
930 break;
932 default:
933 nts = STATUS_INTERNAL_ERROR;
934 break;
937 if (nts == STATUS_SUCCESS)
939 /* Initialize DLL just loaded */
940 TRACE("Loaded module '%s' (%s) at %p\n", filename, filetype, (*pwm)->ldr.BaseAddress);
941 if (!TRACE_ON(module))
942 TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype);
943 /* Set the ldr.LoadCount here so that an attach failure will */
944 /* decrement the dependencies through the MODULE_FreeLibrary call. */
945 (*pwm)->ldr.LoadCount = 1;
947 if (allocated_libdir)
949 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
950 libdir = NULL;
952 RtlLeaveCriticalSection( &loader_section );
953 RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
954 return nts;
957 if (nts != STATUS_NO_SUCH_FILE)
959 WARN("Loading of %s DLL %s failed (status %ld).\n",
960 filetype, filename, nts);
961 break;
965 error:
966 if (allocated_libdir)
968 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
969 libdir = NULL;
971 RtlLeaveCriticalSection( &loader_section );
972 WARN("Failed to load module '%s'; status=%ld\n", filename, nts);
973 RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
974 return nts;
977 /******************************************************************
978 * LdrLoadDll (NTDLL.@)
980 NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libname, HMODULE* hModule)
982 WINE_MODREF *wm;
983 NTSTATUS nts = STATUS_SUCCESS;
984 STRING str;
986 RtlUnicodeStringToAnsiString(&str, libname, TRUE);
988 RtlEnterCriticalSection( &loader_section );
990 switch (nts = load_dll( str.Buffer, flags, &wm ))
992 case STATUS_SUCCESS:
993 if ( !MODULE_DllProcessAttach( wm, NULL ) )
995 WARN("Attach failed for module '%s'.\n", str.Buffer);
996 LdrUnloadDll(wm->ldr.BaseAddress);
997 nts = STATUS_DLL_INIT_FAILED;
998 wm = NULL;
1000 break;
1001 case STATUS_NO_SUCH_FILE:
1002 nts = STATUS_DLL_NOT_FOUND;
1003 break;
1004 default: /* keep error code as it is (memory...) */
1005 break;
1008 *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
1010 RtlLeaveCriticalSection( &loader_section );
1012 RtlFreeAnsiString(&str);
1014 return nts;
1017 /******************************************************************
1018 * LdrQueryProcessModuleInformation
1021 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi,
1022 ULONG buf_size, ULONG* req_size)
1024 SYSTEM_MODULE* sm = &smi->Modules[0];
1025 ULONG size = sizeof(ULONG);
1026 NTSTATUS nts = STATUS_SUCCESS;
1027 ANSI_STRING str;
1028 char* ptr;
1029 WINE_MODREF* wm;
1031 smi->ModulesCount = 0;
1033 RtlEnterCriticalSection( &loader_section );
1034 for ( wm = MODULE_modref_list; wm; wm = wm->next )
1036 size += sizeof(*sm);
1037 if (size <= buf_size)
1039 sm->Reserved1 = 0; /* FIXME */
1040 sm->Reserved2 = 0; /* FIXME */
1041 sm->ImageBaseAddress = wm->ldr.BaseAddress;
1042 sm->ImageSize = wm->ldr.SizeOfImage;
1043 sm->Flags = wm->ldr.Flags;
1044 sm->Id = 0; /* FIXME */
1045 sm->Rank = 0; /* FIXME */
1046 sm->Unknown = 0; /* FIXME */
1047 str.Length = 0;
1048 str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
1049 str.Buffer = sm->Name;
1050 RtlUnicodeStringToAnsiString(&str, &wm->ldr.FullDllName, FALSE);
1051 ptr = strrchr(sm->Name, '\\');
1052 sm->NameOffset = (ptr != NULL) ? (ptr - (char*)sm->Name + 1) : 0;
1054 smi->ModulesCount++;
1055 sm++;
1057 else nts = STATUS_INFO_LENGTH_MISMATCH;
1059 RtlLeaveCriticalSection( &loader_section );
1061 if (req_size) *req_size = size;
1063 return nts;
1066 /******************************************************************
1067 * LdrShutdownProcess (NTDLL.@)
1070 NTSTATUS WINAPI LdrShutdownProcess(void)
1072 TRACE("()\n");
1073 MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
1074 return STATUS_SUCCESS; /* FIXME */
1077 /******************************************************************
1078 * LdrShutdownThread (NTDLL.@)
1081 NTSTATUS WINAPI LdrShutdownThread(void)
1083 WINE_MODREF *wm;
1084 TRACE("()\n");
1086 /* don't do any detach calls if process is exiting */
1087 if (process_detaching) return STATUS_SUCCESS;
1088 /* FIXME: there is still a race here */
1090 RtlEnterCriticalSection( &loader_section );
1092 for ( wm = MODULE_modref_list; wm; wm = wm->next )
1094 if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
1095 continue;
1096 if ( wm->ldr.Flags & LDR_NO_DLL_CALLS )
1097 continue;
1099 MODULE_InitDLL( wm, DLL_THREAD_DETACH, NULL );
1102 RtlLeaveCriticalSection( &loader_section );
1103 return STATUS_SUCCESS; /* FIXME */
1106 /***********************************************************************
1107 * MODULE_FlushModrefs
1109 * Remove all unused modrefs and call the internal unloading routines
1110 * for the library type.
1112 * The loader_section must be locked while calling this function.
1114 static void MODULE_FlushModrefs(void)
1116 WINE_MODREF *wm, *next;
1118 for (wm = MODULE_modref_list; wm; wm = next)
1120 next = wm->next;
1122 if (wm->ldr.LoadCount)
1123 continue;
1125 /* Unlink this modref from the chain */
1126 if (wm->next)
1127 wm->next->prev = wm->prev;
1128 if (wm->prev)
1129 wm->prev->next = wm->next;
1130 if (wm == MODULE_modref_list)
1131 MODULE_modref_list = wm->next;
1133 TRACE(" unloading %s\n", wm->filename);
1134 if (!TRACE_ON(module))
1135 TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
1136 wm->dlhandle ? "builtin" : "native" );
1138 SERVER_START_REQ( unload_dll )
1140 req->base = wm->ldr.BaseAddress;
1141 wine_server_call( req );
1143 SERVER_END_REQ;
1145 if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
1146 else NtUnmapViewOfSection( GetCurrentProcess(), wm->ldr.BaseAddress );
1147 FreeLibrary16( wm->hDummyMod );
1148 if (cached_modref == wm) cached_modref = NULL;
1149 RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps );
1150 RtlFreeHeap( ntdll_get_process_heap(), 0, wm );
1154 /***********************************************************************
1155 * MODULE_DecRefCount
1157 * The loader_section must be locked while calling this function.
1159 static void MODULE_DecRefCount( WINE_MODREF *wm )
1161 int i;
1163 if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
1164 return;
1166 if ( wm->ldr.LoadCount <= 0 )
1167 return;
1169 --wm->ldr.LoadCount;
1170 TRACE("(%s) ldr.LoadCount: %d\n", wm->modname, wm->ldr.LoadCount );
1172 if ( wm->ldr.LoadCount == 0 )
1174 wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
1176 for ( i = 0; i < wm->nDeps; i++ )
1177 if ( wm->deps[i] )
1178 MODULE_DecRefCount( wm->deps[i] );
1180 wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
1184 /******************************************************************
1185 * LdrUnloadDll (NTDLL.@)
1189 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
1191 NTSTATUS retv = STATUS_SUCCESS;
1193 TRACE("(%p)\n", hModule);
1195 RtlEnterCriticalSection( &loader_section );
1197 /* if we're stopping the whole process (and forcing the removal of all
1198 * DLLs) the library will be freed anyway
1200 if (!process_detaching)
1202 WINE_MODREF *wm;
1204 free_lib_count++;
1205 if ((wm = get_modref( hModule )) != NULL)
1207 TRACE("(%s) - START\n", wm->modname);
1209 /* Recursively decrement reference counts */
1210 MODULE_DecRefCount( wm );
1212 /* Call process detach notifications */
1213 if ( free_lib_count <= 1 )
1215 MODULE_DllProcessDetach( FALSE, NULL );
1216 MODULE_FlushModrefs();
1219 TRACE("END\n");
1221 else
1222 retv = STATUS_DLL_NOT_FOUND;
1224 free_lib_count--;
1227 RtlLeaveCriticalSection( &loader_section );
1229 return retv;
1232 /***********************************************************************
1233 * RtlImageNtHeader (NTDLL.@)
1235 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
1237 IMAGE_NT_HEADERS *ret;
1239 __TRY
1241 IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
1243 ret = NULL;
1244 if (dos->e_magic == IMAGE_DOS_SIGNATURE)
1246 ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
1247 if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
1250 __EXCEPT(page_fault)
1252 return NULL;
1254 __ENDTRY
1255 return ret;
1259 /***********************************************************************
1260 * RtlImageDirectoryEntryToData (NTDLL.@)
1262 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
1264 const IMAGE_NT_HEADERS *nt;
1265 DWORD addr;
1267 if ((ULONG_PTR)module & 1) /* mapped as data file */
1269 module = (HMODULE)((ULONG_PTR)module & ~1);
1270 image = FALSE;
1272 if (!(nt = RtlImageNtHeader( module ))) return NULL;
1273 if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
1274 if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
1275 *size = nt->OptionalHeader.DataDirectory[dir].Size;
1276 if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
1278 /* not mapped as image, need to find the section containing the virtual address */
1279 return RtlImageRvaToVa( nt, module, addr, NULL );
1283 /***********************************************************************
1284 * RtlImageRvaToSection (NTDLL.@)
1286 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
1287 HMODULE module, DWORD rva )
1289 int i;
1290 IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader +
1291 nt->FileHeader.SizeOfOptionalHeader);
1292 for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
1294 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1295 return sec;
1297 return NULL;
1301 /***********************************************************************
1302 * RtlImageRvaToVa (NTDLL.@)
1304 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
1305 DWORD rva, IMAGE_SECTION_HEADER **section )
1307 IMAGE_SECTION_HEADER *sec;
1309 if (section && *section) /* try this section first */
1311 sec = *section;
1312 if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1313 goto found;
1315 if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
1316 found:
1317 if (section) *section = sec;
1318 return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);