Removed no longer needed MODREF.find_export field.
[wine] / dlls / ntdll / loader.c
1 /*
2  * Loader functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  * Copyright 2002 Dmitry Timoshkov for Codeweavers
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include <assert.h>
23
24 #include "winbase.h"
25 #include "winnt.h"
26 #include "winternl.h"
27
28 #include "module.h"
29 #include "file.h"
30 #include "wine/exception.h"
31 #include "excpt.h"
32 #include "wine/debug.h"
33 #include "wine/server.h"
34 #include "ntdll_misc.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
37 WINE_DECLARE_DEBUG_CHANNEL(module);
38 WINE_DECLARE_DEBUG_CHANNEL(module);
39 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
40
41 WINE_MODREF *MODULE_modref_list = NULL;
42
43 static WINE_MODREF *exe_modref;
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 */
46
47 /* filter for page-fault exceptions */
48 static WINE_EXCEPTION_FILTER(page_fault)
49 {
50     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
51         return EXCEPTION_EXECUTE_HANDLER;
52     return EXCEPTION_CONTINUE_SEARCH;
53 }
54
55 static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
56
57 /*************************************************************************
58  *              MODULE32_LookupHMODULE
59  * looks for the referenced HMODULE in the current process
60  * NOTE: Assumes that the process critical section is held!
61  */
62 static WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hmod )
63 {
64     WINE_MODREF *wm;
65
66     if (!hmod)
67         return exe_modref;
68
69     if (!HIWORD(hmod)) {
70         ERR("tried to lookup %p in win32 module handler!\n",hmod);
71         return NULL;
72     }
73     for ( wm = MODULE_modref_list; wm; wm=wm->next )
74         if (wm->ldr.BaseAddress == hmod)
75             return wm;
76     return NULL;
77 }
78
79 /*************************************************************************
80  *              MODULE_AllocModRef
81  *
82  * Allocate a WINE_MODREF structure and add it to the process list
83  * NOTE: Assumes that the process critical section is held!
84  */
85 WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
86 {
87     WINE_MODREF *wm;
88     IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
89
90     DWORD long_len = strlen( filename );
91     DWORD short_len = GetShortPathNameA( filename, NULL, 0 );
92
93     if ((wm = RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY,
94                                sizeof(*wm) + long_len + short_len + 1 )))
95     {
96         wm->ldr.BaseAddress = hModule;
97         wm->ldr.TlsIndex = -1;
98
99         wm->filename = wm->data;
100         memcpy( wm->filename, filename, long_len + 1 );
101         if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
102         else wm->modname = wm->filename;
103
104         wm->short_filename = wm->filename + long_len + 1;
105         GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 );
106         if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
107         else wm->short_modname = wm->short_filename;
108
109         wm->next = MODULE_modref_list;
110         if (wm->next) wm->next->prev = wm;
111         MODULE_modref_list = wm;
112
113         wm->ldr.InLoadOrderModuleList.Flink = NULL;
114         wm->ldr.InLoadOrderModuleList.Blink = NULL;
115         wm->ldr.InMemoryOrderModuleList.Flink = NULL;
116         wm->ldr.InMemoryOrderModuleList.Blink = NULL;
117         wm->ldr.InInitializationOrderModuleList.Flink = NULL;
118         wm->ldr.InInitializationOrderModuleList.Blink = NULL;
119         wm->ldr.BaseAddress = hModule;
120         wm->ldr.EntryPoint = (nt->OptionalHeader.AddressOfEntryPoint) ?
121                              ((char *)hModule + nt->OptionalHeader.AddressOfEntryPoint) : 0;
122         wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
123         RtlCreateUnicodeStringFromAsciiz( &wm->ldr.FullDllName, wm->filename);
124         RtlCreateUnicodeStringFromAsciiz( &wm->ldr.BaseDllName, wm->modname);
125         wm->ldr.Flags = 0;
126         wm->ldr.LoadCount = 0;
127         wm->ldr.TlsIndex = 0;
128         wm->ldr.SectionHandle = NULL;
129         wm->ldr.CheckSum = 0;
130         wm->ldr.TimeDateStamp = 0;
131
132         if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
133         {
134             if (!exe_modref) exe_modref = wm;
135             else FIXME( "Trying to load second .EXE file: %s\n", filename );
136         }
137         else wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
138     }
139     return wm;
140 }
141
142 /*************************************************************************
143  *              MODULE_InitDLL
144  */
145 static BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
146 {
147     static const char * const typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH",
148                                              "THREAD_ATTACH", "THREAD_DETACH" };
149     BOOL retv = TRUE;
150
151     /* Skip calls for modules loaded with special load flags */
152
153     if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return TRUE;
154
155     TRACE("(%s,%s,%p) - CALL\n", wm->modname, typeName[type], lpReserved );
156
157     /* Call the initialization routine */
158     retv = PE_InitDLL( wm->ldr.BaseAddress, type, lpReserved );
159
160     /* The state of the module list may have changed due to the call
161        to PE_InitDLL. We cannot assume that this module has not been
162        deleted.  */
163     TRACE("(%p,%s,%p) - RETURN %d\n", wm, typeName[type], lpReserved, retv );
164
165     return retv;
166 }
167
168
169 /*************************************************************************
170  *              MODULE_DllProcessAttach
171  *
172  * Send the process attach notification to all DLLs the given module
173  * depends on (recursively). This is somewhat complicated due to the fact that
174  *
175  * - we have to respect the module dependencies, i.e. modules implicitly
176  *   referenced by another module have to be initialized before the module
177  *   itself can be initialized
178  *
179  * - the initialization routine of a DLL can itself call LoadLibrary,
180  *   thereby introducing a whole new set of dependencies (even involving
181  *   the 'old' modules) at any time during the whole process
182  *
183  * (Note that this routine can be recursively entered not only directly
184  *  from itself, but also via LoadLibrary from one of the called initialization
185  *  routines.)
186  *
187  * Furthermore, we need to rearrange the main WINE_MODREF list to allow
188  * the process *detach* notifications to be sent in the correct order.
189  * This must not only take into account module dependencies, but also
190  * 'hidden' dependencies created by modules calling LoadLibrary in their
191  * attach notification routine.
192  *
193  * The strategy is rather simple: we move a WINE_MODREF to the head of the
194  * list after the attach notification has returned.  This implies that the
195  * detach notifications are called in the reverse of the sequence the attach
196  * notifications *returned*.
197  */
198 BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
199 {
200     BOOL retv = TRUE;
201     int i;
202
203     RtlEnterCriticalSection( &loader_section );
204
205     if (!wm)
206     {
207         wm = exe_modref;
208         PE_InitTls();
209     }
210     assert( wm );
211
212     /* prevent infinite recursion in case of cyclical dependencies */
213     if (    ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
214          || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
215         goto done;
216
217     TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
218
219     /* Tag current MODREF to prevent recursive loop */
220     wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
221
222     /* Recursively attach all DLLs this one depends on */
223     for ( i = 0; retv && i < wm->nDeps; i++ )
224         if ( wm->deps[i] )
225             retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
226
227     /* Call DLL entry point */
228     if ( retv )
229     {
230         retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
231         if ( retv )
232             wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
233     }
234
235     /* Re-insert MODREF at head of list */
236     if ( retv && wm->prev )
237     {
238         wm->prev->next = wm->next;
239         if ( wm->next ) wm->next->prev = wm->prev;
240
241         wm->prev = NULL;
242         wm->next = MODULE_modref_list;
243         MODULE_modref_list = wm->next->prev = wm;
244     }
245
246     /* Remove recursion flag */
247     wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
248
249     TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
250
251
252  done:
253     RtlLeaveCriticalSection( &loader_section );
254     return retv;
255 }
256
257 /*************************************************************************
258  *              MODULE_DllProcessDetach
259  *
260  * Send DLL process detach notifications.  See the comment about calling
261  * sequence at MODULE_DllProcessAttach.  Unless the bForceDetach flag
262  * is set, only DLLs with zero refcount are notified.
263  */
264 void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
265 {
266     WINE_MODREF *wm;
267
268     RtlEnterCriticalSection( &loader_section );
269     if (bForceDetach) process_detaching = 1;
270     do
271     {
272         for ( wm = MODULE_modref_list; wm; wm = wm->next )
273         {
274             /* Check whether to detach this DLL */
275             if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
276                 continue;
277             if ( wm->ldr.LoadCount > 0 && !bForceDetach )
278                 continue;
279
280             /* Call detach notification */
281             wm->ldr.Flags &= ~LDR_PROCESS_ATTACHED;
282             MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
283
284             /* Restart at head of WINE_MODREF list, as entries might have
285                been added and/or removed while performing the call ... */
286             break;
287         }
288     } while ( wm );
289
290     RtlLeaveCriticalSection( &loader_section );
291 }
292
293 /*************************************************************************
294  *              MODULE_DllThreadAttach
295  *
296  * Send DLL thread attach notifications. These are sent in the
297  * reverse sequence of process detach notification.
298  *
299  */
300 void MODULE_DllThreadAttach( LPVOID lpReserved )
301 {
302     WINE_MODREF *wm;
303
304     /* don't do any attach calls if process is exiting */
305     if (process_detaching) return;
306     /* FIXME: there is still a race here */
307
308     RtlEnterCriticalSection( &loader_section );
309
310     PE_InitTls();
311
312     for ( wm = MODULE_modref_list; wm; wm = wm->next )
313         if ( !wm->next )
314             break;
315
316     for ( ; wm; wm = wm->prev )
317     {
318         if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
319             continue;
320         if ( wm->ldr.Flags & LDR_NO_DLL_CALLS )
321             continue;
322
323         MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
324     }
325
326     RtlLeaveCriticalSection( &loader_section );
327 }
328
329 /******************************************************************
330  *              LdrDisableThreadCalloutsForDll (NTDLL.@)
331  *
332  */
333 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
334 {
335     WINE_MODREF *wm;
336     NTSTATUS    ret = STATUS_SUCCESS;
337
338     RtlEnterCriticalSection( &loader_section );
339
340     wm = MODULE32_LookupHMODULE( hModule );
341     if ( !wm )
342         ret = STATUS_DLL_NOT_FOUND;
343     else
344         wm->ldr.Flags |= LDR_NO_DLL_CALLS;
345
346     RtlLeaveCriticalSection( &loader_section );
347
348     return ret;
349 }
350
351 /******************************************************************
352  *              LdrFindEntryForAddress (NTDLL.@)
353  *
354  * The loader_section must be locked while calling this function
355  */
356 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* mod)
357 {
358     WINE_MODREF*        wm;
359
360     for ( wm = MODULE_modref_list; wm; wm = wm->next )
361     {
362         if ((const void *)wm->ldr.BaseAddress <= addr &&
363             (char *)addr < (char*)wm->ldr.BaseAddress + wm->ldr.SizeOfImage)
364         {
365             *mod = &wm->ldr;
366             return STATUS_SUCCESS;
367         }
368     }
369     return STATUS_NO_MORE_ENTRIES;
370 }
371
372 /**********************************************************************
373  *          MODULE_FindModule
374  *
375  * Find a (loaded) win32 module depending on path
376  *      LPCSTR path: [in] pathname of module/library to be found
377  *
378  * The loader_section must be locked while calling this function
379  * RETURNS
380  *      the module handle if found
381  *      0 if not
382  */
383 WINE_MODREF *MODULE_FindModule(LPCSTR path)
384 {
385     WINE_MODREF *wm;
386     char dllname[260], *p;
387
388     /* Append .DLL to name if no extension present */
389     strcpy( dllname, path );
390     if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
391             strcat( dllname, ".DLL" );
392
393     for ( wm = MODULE_modref_list; wm; wm = wm->next )
394     {
395         if ( !FILE_strcasecmp( dllname, wm->modname ) )
396             break;
397         if ( !FILE_strcasecmp( dllname, wm->filename ) )
398             break;
399         if ( !FILE_strcasecmp( dllname, wm->short_modname ) )
400             break;
401         if ( !FILE_strcasecmp( dllname, wm->short_filename ) )
402             break;
403     }
404
405     return wm;
406 }
407
408
409 /******************************************************************
410  *              LdrLockLoaderLock  (NTDLL.@)
411  *
412  * Note: flags are not implemented.
413  * Flag 0x01 is used to raise exceptions on errors.
414  * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
415  */
416 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
417 {
418     if (flags) FIXME( "flags %lx not supported\n", flags );
419
420     if (result) *result = 1;
421     if (!magic) return STATUS_INVALID_PARAMETER_3;
422     RtlEnterCriticalSection( &loader_section );
423     *magic = GetCurrentThreadId();
424     return STATUS_SUCCESS;
425 }
426
427
428 /******************************************************************
429  *              LdrUnlockLoaderUnlock  (NTDLL.@)
430  */
431 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
432 {
433     if (magic)
434     {
435         if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
436         RtlLeaveCriticalSection( &loader_section );
437     }
438     return STATUS_SUCCESS;
439 }
440
441
442 /******************************************************************
443  *              LdrGetDllHandle (NTDLL.@)
444  *
445  *
446  */
447 NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE *base)
448 {
449     WINE_MODREF *wm;
450
451     TRACE("%08lx %08lx %s %p\n",
452           x, y, name ? debugstr_wn(name->Buffer, name->Length) : NULL, base);
453
454     if (x != 0 || y != 0)
455         FIXME("Unknown behavior, please report\n");
456
457     /* FIXME: we should store module name information as unicode */
458     if (name)
459     {
460         STRING str;
461
462         RtlUnicodeStringToAnsiString( &str, name, TRUE );
463
464         wm = MODULE_FindModule( str.Buffer );
465         RtlFreeAnsiString( &str );
466     }
467     else
468         wm = exe_modref;
469
470     if (!wm)
471     {
472         *base = 0;
473         return STATUS_DLL_NOT_FOUND;
474     }
475
476     *base = wm->ldr.BaseAddress;
477     return STATUS_SUCCESS;
478 }
479
480 /***********************************************************************
481  *           MODULE_GetProcAddress              (internal)
482  */
483 FARPROC MODULE_GetProcAddress(
484         HMODULE hModule,        /* [in] current module handle */
485         LPCSTR function,        /* [in] function to be looked up */
486         int hint,
487         BOOL snoop )
488 {
489     WINE_MODREF *wm;
490     FARPROC     retproc = 0;
491
492     if (HIWORD(function))
493         TRACE("(%p,%s (%d))\n",hModule,function,hint);
494     else
495         TRACE("(%p,%p)\n",hModule,function);
496
497     RtlEnterCriticalSection( &loader_section );
498     if ((wm = MODULE32_LookupHMODULE( hModule )))
499     {
500         retproc = PE_FindExportedFunction( wm, function, hint, snoop );
501     }
502     RtlLeaveCriticalSection( &loader_section );
503     return retproc;
504 }
505
506
507 /******************************************************************
508  *              LdrGetProcedureAddress (NTDLL.@)
509  *
510  *
511  */
512 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG ord, PVOID *address)
513 {
514     WARN("%p %s %ld %p\n", base, name ? debugstr_an(name->Buffer, name->Length) : NULL, ord, address);
515
516     *address = MODULE_GetProcAddress( base, name ? name->Buffer : (LPSTR)ord, -1, TRUE );
517
518     return (*address) ? STATUS_SUCCESS : STATUS_PROCEDURE_NOT_FOUND;
519 }
520
521
522 /***********************************************************************
523  *      allocate_lib_dir
524  *
525  * helper for MODULE_LoadLibraryExA.  Allocate space to hold the directory
526  * portion of the provided name and put the name in it.
527  *
528  */
529 static LPCSTR allocate_lib_dir(LPCSTR libname)
530 {
531     LPCSTR p, pmax;
532     LPSTR result;
533     int length;
534
535     pmax = libname;
536     if ((p = strrchr( pmax, '\\' ))) pmax = p + 1;
537     if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty.  MSDN says don't */
538     if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2;
539
540     length = pmax - libname;
541
542     result = RtlAllocateHeap (ntdll_get_process_heap(), 0, length+1);
543
544     if (result)
545     {
546         strncpy (result, libname, length);
547         result [length] = '\0';
548     }
549
550     return result;
551 }
552
553 /***********************************************************************
554  *      MODULE_LoadLibraryExA   (internal)
555  *
556  * Load a PE style module according to the load order.
557  *
558  * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
559  *        on this function.  When first called from LoadLibraryExA it will be
560  *        NULL but thereafter it may point to a buffer containing the path
561  *        portion of the library name.  Note that the recursion all occurs
562  *        within a Critical section (see LoadLibraryExA) so the use of a
563  *        static is acceptable.
564  *        (We have to use a static variable at some point anyway, to pass the
565  *        information from BUILTIN32_dlopen through dlopen and the builtin's
566  *        init function into load_library).
567  * allocated_libdir is TRUE in the stack frame that allocated libdir
568  */
569 NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** pwm)
570 {
571     int i;
572     enum loadorder_type loadorder[LOADORDER_NTYPES];
573     LPSTR filename;
574     const char *filetype = "";
575     DWORD found;
576     BOOL allocated_libdir = FALSE;
577     static LPCSTR libdir = NULL; /* See above */
578     NTSTATUS nts = STATUS_SUCCESS;
579
580     *pwm = NULL;
581     if ( !libname ) return STATUS_DLL_NOT_FOUND; /* FIXME ? */
582
583     filename = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
584     if ( !filename ) return STATUS_NO_MEMORY;
585     *filename = 0; /* Just in case we don't set it before goto error */
586
587     RtlEnterCriticalSection( &loader_section );
588
589     if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname))
590     {
591         if (!(libdir = allocate_lib_dir(libname)))
592         {
593             nts = STATUS_NO_MEMORY;
594             goto error;
595         }
596         allocated_libdir = TRUE;
597     }
598
599     if (!libdir || allocated_libdir)
600         found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL);
601     else
602         found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL);
603
604     /* build the modules filename */
605     if (!found)
606     {
607         if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH ))
608         {
609             nts = STATUS_INTERNAL_ERROR;
610             goto error;
611         }
612     }
613
614     /* Check for already loaded module */
615     if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
616     {
617         LPSTR   fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
618         if (fn)
619         {
620             /* since the default loading mechanism uses a more detailed algorithm
621              * than SearchPath (like using PATH, which can even be modified between
622              * two attempts of loading the same DLL), the look-up above (with
623              * SearchPath) can have put the file in system directory, whereas it
624              * has already been loaded but with a different path. So do a specific
625              * look-up with filename (without any path)
626              */
627             strcpy ( fn, libname );
628             /* if the filename doesn't have an extension append .DLL */
629             if (!strrchr( fn, '.')) strcat( fn, ".dll" );
630             if ((*pwm = MODULE_FindModule( fn )) != NULL)
631                 strcpy( filename, fn );
632             RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
633         }
634     }
635     if (*pwm)
636     {
637         (*pwm)->ldr.LoadCount++;
638         
639         if (((*pwm)->ldr.Flags & LDR_DONT_RESOLVE_REFS) &&
640             !(flags & DONT_RESOLVE_DLL_REFERENCES))
641         {
642             (*pwm)->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
643             PE_fixup_imports( *pwm );
644         }
645         TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
646         if (allocated_libdir)
647         {
648             RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
649             libdir = NULL;
650         }
651         RtlLeaveCriticalSection( &loader_section );
652         RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
653         return STATUS_SUCCESS;
654     }
655
656     MODULE_GetLoadOrder( loadorder, filename, TRUE);
657
658     for (i = 0; i < LOADORDER_NTYPES; i++)
659     {
660         if (loadorder[i] == LOADORDER_INVALID) break;
661
662         switch (loadorder[i])
663         {
664         case LOADORDER_DLL:
665             TRACE("Trying native dll '%s'\n", filename);
666             nts = PE_LoadLibraryExA(filename, flags, pwm);
667             filetype = "native";
668             break;
669             
670         case LOADORDER_BI:
671             TRACE("Trying built-in '%s'\n", filename);
672             nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
673             filetype = "builtin";
674             break;
675             
676         default:
677             nts = STATUS_INTERNAL_ERROR;
678             break;
679         }
680
681         if (nts == STATUS_SUCCESS)
682         {
683             /* Initialize DLL just loaded */
684             TRACE("Loaded module '%s' at %p\n", filename, (*pwm)->ldr.BaseAddress);
685             if (!TRACE_ON(module))
686                 TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype);
687             /* Set the ldr.LoadCount here so that an attach failure will */
688             /* decrement the dependencies through the MODULE_FreeLibrary call. */
689             (*pwm)->ldr.LoadCount = 1;
690             
691             if (allocated_libdir)
692             {
693                 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
694                 libdir = NULL;
695             }
696             RtlLeaveCriticalSection( &loader_section );
697             RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
698             return nts;
699         }
700
701         if (nts != STATUS_NO_SUCH_FILE)
702         {
703             WARN("Loading of %s DLL %s failed (status %ld).\n",
704                  filetype, filename, nts);
705             break;
706         }
707     }
708
709  error:
710     if (allocated_libdir)
711     {
712         RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
713         libdir = NULL;
714     }
715     RtlLeaveCriticalSection( &loader_section );
716     WARN("Failed to load module '%s'; status=%ld\n", filename, nts);
717     RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
718     return nts;
719 }
720
721 /******************************************************************
722  *              LdrLoadDll (NTDLL.@)
723  */
724 NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libname, HMODULE* hModule)
725 {
726     WINE_MODREF *wm;
727     NTSTATUS    nts = STATUS_SUCCESS;
728     STRING      str;
729
730     RtlUnicodeStringToAnsiString(&str, libname, TRUE);
731
732     RtlEnterCriticalSection( &loader_section );
733
734     switch (nts = MODULE_LoadLibraryExA( str.Buffer, flags, &wm ))
735     {
736     case STATUS_SUCCESS:
737         if ( !MODULE_DllProcessAttach( wm, NULL ) )
738         {
739             WARN_(module)("Attach failed for module '%s'.\n", str.Buffer);
740             LdrUnloadDll(wm->ldr.BaseAddress);
741             nts = STATUS_DLL_INIT_FAILED;
742             wm = NULL;
743         }
744         break;
745     case STATUS_NO_SUCH_FILE:
746         nts = STATUS_DLL_NOT_FOUND;
747         break;
748     default: /* keep error code as it is (memory...) */
749         break;
750     }
751
752     *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
753     
754     RtlLeaveCriticalSection( &loader_section );
755
756     RtlFreeAnsiString(&str);
757
758     return nts;
759 }
760
761 /******************************************************************
762  *              LdrQueryProcessModuleInformation
763  *
764  */
765 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi, 
766                                                  ULONG buf_size, ULONG* req_size)
767 {
768     SYSTEM_MODULE*      sm = &smi->Modules[0];
769     ULONG               size = sizeof(ULONG);
770     NTSTATUS            nts = STATUS_SUCCESS;
771     ANSI_STRING         str;
772     char*               ptr;
773     WINE_MODREF*        wm;
774
775     smi->ModulesCount = 0;
776
777     RtlEnterCriticalSection( &loader_section );
778     for ( wm = MODULE_modref_list; wm; wm = wm->next )
779     {
780         size += sizeof(*sm);
781         if (size <= buf_size)
782         {
783             sm->Reserved1 = 0; /* FIXME */
784             sm->Reserved2 = 0; /* FIXME */
785             sm->ImageBaseAddress = wm->ldr.BaseAddress;
786             sm->ImageSize = wm->ldr.SizeOfImage;
787             sm->Flags = wm->ldr.Flags;
788             sm->Id = 0; /* FIXME */
789             sm->Rank = 0; /* FIXME */
790             sm->Unknown = 0; /* FIXME */
791             str.Length = 0;
792             str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
793             str.Buffer = sm->Name;
794             RtlUnicodeStringToAnsiString(&str, &wm->ldr.FullDllName, FALSE);
795             ptr = strrchr(sm->Name, '\\');
796             sm->NameOffset = (ptr != NULL) ? (ptr - (char*)sm->Name + 1) : 0;
797
798             smi->ModulesCount++;
799             sm++;
800         }
801         else nts = STATUS_INFO_LENGTH_MISMATCH;
802     }
803     RtlLeaveCriticalSection( &loader_section );
804
805     if (req_size) *req_size = size;
806
807     return nts;
808 }
809
810 /******************************************************************
811  *              LdrShutdownProcess (NTDLL.@)
812  *
813  */
814 NTSTATUS    WINAPI  LdrShutdownProcess(void)
815 {
816     TRACE("()\n");
817     MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
818     return STATUS_SUCCESS; /* FIXME */
819 }
820
821 /******************************************************************
822  *              LdrShutdownThread (NTDLL.@)
823  *
824  */
825 NTSTATUS WINAPI LdrShutdownThread(void)
826 {
827     WINE_MODREF *wm;
828     TRACE("()\n");
829
830     /* don't do any detach calls if process is exiting */
831     if (process_detaching) return STATUS_SUCCESS;
832     /* FIXME: there is still a race here */
833
834     RtlEnterCriticalSection( &loader_section );
835
836     for ( wm = MODULE_modref_list; wm; wm = wm->next )
837     {
838         if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
839             continue;
840         if ( wm->ldr.Flags & LDR_NO_DLL_CALLS )
841             continue;
842
843         MODULE_InitDLL( wm, DLL_THREAD_DETACH, NULL );
844     }
845
846     RtlLeaveCriticalSection( &loader_section );
847     return STATUS_SUCCESS; /* FIXME */
848 }
849
850 /***********************************************************************
851  *           MODULE_FlushModrefs
852  *
853  * NOTE: Assumes that the process critical section is held!
854  *
855  * Remove all unused modrefs and call the internal unloading routines
856  * for the library type.
857  */
858 static void MODULE_FlushModrefs(void)
859 {
860     WINE_MODREF *wm, *next;
861
862     for (wm = MODULE_modref_list; wm; wm = next)
863     {
864         next = wm->next;
865
866         if (wm->ldr.LoadCount)
867             continue;
868
869         /* Unlink this modref from the chain */
870         if (wm->next)
871             wm->next->prev = wm->prev;
872         if (wm->prev)
873             wm->prev->next = wm->next;
874         if (wm == MODULE_modref_list)
875             MODULE_modref_list = wm->next;
876
877         TRACE(" unloading %s\n", wm->filename);
878         if (!TRACE_ON(module))
879             TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
880                             wm->dlhandle ? "builtin" : "native" );
881
882         SERVER_START_REQ( unload_dll )
883         {
884             req->base = wm->ldr.BaseAddress;
885             wine_server_call( req );
886         }
887         SERVER_END_REQ;
888
889         if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
890         else NtUnmapViewOfSection( GetCurrentProcess(), wm->ldr.BaseAddress );
891         FreeLibrary16( wm->hDummyMod );
892         RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps );
893         RtlFreeHeap( ntdll_get_process_heap(), 0, wm );
894     }
895 }
896
897 /***********************************************************************
898  *           MODULE_DecRefCount
899  *
900  * NOTE: Assumes that the process critical section is held!
901  */
902 static void MODULE_DecRefCount( WINE_MODREF *wm )
903 {
904     int i;
905
906     if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
907         return;
908
909     if ( wm->ldr.LoadCount <= 0 )
910         return;
911
912     --wm->ldr.LoadCount;
913     TRACE("(%s) ldr.LoadCount: %d\n", wm->modname, wm->ldr.LoadCount );
914
915     if ( wm->ldr.LoadCount == 0 )
916     {
917         wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
918
919         for ( i = 0; i < wm->nDeps; i++ )
920             if ( wm->deps[i] )
921                 MODULE_DecRefCount( wm->deps[i] );
922
923         wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
924     }
925 }
926
927 /******************************************************************
928  *              LdrUnloadDll (NTDLL.@)
929  *
930  *
931  */
932 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
933 {
934     NTSTATUS retv = STATUS_SUCCESS;
935
936     TRACE("(%p)\n", hModule);
937
938     RtlEnterCriticalSection( &loader_section );
939
940     /* if we're stopping the whole process (and forcing the removal of all
941      * DLLs) the library will be freed anyway
942      */
943     if (!process_detaching)
944     {
945         WINE_MODREF *wm;
946
947         free_lib_count++;
948         if ((wm = MODULE32_LookupHMODULE( hModule )) != NULL)
949         {
950             TRACE("(%s) - START\n", wm->modname);
951
952             /* Recursively decrement reference counts */
953             MODULE_DecRefCount( wm );
954
955             /* Call process detach notifications */
956             if ( free_lib_count <= 1 )
957             {
958                 MODULE_DllProcessDetach( FALSE, NULL );
959                 MODULE_FlushModrefs();
960             }
961
962             TRACE("END\n");
963         }
964         else
965             retv = STATUS_DLL_NOT_FOUND;
966
967         free_lib_count--;
968     }
969
970     RtlLeaveCriticalSection( &loader_section );
971
972     return retv;
973 }
974
975 /***********************************************************************
976  *           RtlImageNtHeader   (NTDLL.@)
977  */
978 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
979 {
980     IMAGE_NT_HEADERS *ret;
981
982     __TRY
983     {
984         IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
985
986         ret = NULL;
987         if (dos->e_magic == IMAGE_DOS_SIGNATURE)
988         {
989             ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
990             if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
991         }
992     }
993     __EXCEPT(page_fault)
994     {
995         return NULL;
996     }
997     __ENDTRY
998     return ret;
999 }
1000
1001
1002 /***********************************************************************
1003  *           RtlImageDirectoryEntryToData   (NTDLL.@)
1004  */
1005 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
1006 {
1007     const IMAGE_NT_HEADERS *nt;
1008     DWORD addr;
1009
1010     if ((ULONG_PTR)module & 1)  /* mapped as data file */
1011     {
1012         module = (HMODULE)((ULONG_PTR)module & ~1);
1013         image = FALSE;
1014     }
1015     if (!(nt = RtlImageNtHeader( module ))) return NULL;
1016     if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
1017     if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
1018     *size = nt->OptionalHeader.DataDirectory[dir].Size;
1019     if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
1020
1021     /* not mapped as image, need to find the section containing the virtual address */
1022     return RtlImageRvaToVa( nt, module, addr, NULL );
1023 }
1024
1025
1026 /***********************************************************************
1027  *           RtlImageRvaToSection   (NTDLL.@)
1028  */
1029 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
1030                                                    HMODULE module, DWORD rva )
1031 {
1032     int i;
1033     IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader +
1034                                                         nt->FileHeader.SizeOfOptionalHeader);
1035     for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
1036     {
1037         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1038             return sec;
1039     }
1040     return NULL;
1041 }
1042
1043
1044 /***********************************************************************
1045  *           RtlImageRvaToVa   (NTDLL.@)
1046  */
1047 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
1048                               DWORD rva, IMAGE_SECTION_HEADER **section )
1049 {
1050     IMAGE_SECTION_HEADER *sec;
1051
1052     if (section && *section)  /* try this section first */
1053     {
1054         sec = *section;
1055         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1056             goto found;
1057     }
1058     if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
1059  found:
1060     if (section) *section = sec;
1061     return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
1062 }