Partially implemented LdrLock/UnlockLoaderLock.
[wine] / dlls / ntdll / loader.c
1 /*
2  * Copyright 2002 Dmitry Timoshkov for Codeweavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 #include <assert.h>
20
21 #include "winbase.h"
22 #include "winnt.h"
23 #include "winternl.h"
24
25 #include "module.h"
26 #include "file.h"
27 #include "wine/exception.h"
28 #include "excpt.h"
29 #include "wine/debug.h"
30 #include "wine/server.h"
31 #include "ntdll_misc.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
34 WINE_DECLARE_DEBUG_CHANNEL(module);
35 WINE_DECLARE_DEBUG_CHANNEL(module);
36 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
37
38 static int free_lib_count;   /* recursion depth of LdrUnloadDll calls */
39
40 /* filter for page-fault exceptions */
41 static WINE_EXCEPTION_FILTER(page_fault)
42 {
43     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
44         return EXCEPTION_EXECUTE_HANDLER;
45     return EXCEPTION_CONTINUE_SEARCH;
46 }
47
48 CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
49
50 /*************************************************************************
51  *              MODULE32_LookupHMODULE
52  * looks for the referenced HMODULE in the current process
53  * NOTE: Assumes that the process critical section is held!
54  */
55 static WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hmod )
56 {
57     WINE_MODREF *wm;
58
59     if (!hmod)
60         return exe_modref;
61
62     if (!HIWORD(hmod)) {
63         ERR("tried to lookup %p in win32 module handler!\n",hmod);
64         return NULL;
65     }
66     for ( wm = MODULE_modref_list; wm; wm=wm->next )
67         if (wm->module == hmod)
68             return wm;
69     return NULL;
70 }
71
72 /*************************************************************************
73  *              MODULE_AllocModRef
74  *
75  * Allocate a WINE_MODREF structure and add it to the process list
76  * NOTE: Assumes that the process critical section is held!
77  */
78 WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
79 {
80     WINE_MODREF *wm;
81     IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
82
83     DWORD long_len = strlen( filename );
84     DWORD short_len = GetShortPathNameA( filename, NULL, 0 );
85
86     if ((wm = RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY,
87                                sizeof(*wm) + long_len + short_len + 1 )))
88     {
89         wm->module = hModule;
90         wm->tlsindex = -1;
91
92         wm->filename = wm->data;
93         memcpy( wm->filename, filename, long_len + 1 );
94         if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
95         else wm->modname = wm->filename;
96
97         wm->short_filename = wm->filename + long_len + 1;
98         GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 );
99         if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
100         else wm->short_modname = wm->short_filename;
101
102         wm->next = MODULE_modref_list;
103         if (wm->next) wm->next->prev = wm;
104         MODULE_modref_list = wm;
105
106         wm->ldr.InLoadOrderModuleList.Flink = NULL;
107         wm->ldr.InLoadOrderModuleList.Blink = NULL;
108         wm->ldr.InMemoryOrderModuleList.Flink = NULL;
109         wm->ldr.InMemoryOrderModuleList.Blink = NULL;
110         wm->ldr.InInitializationOrderModuleList.Flink = NULL;
111         wm->ldr.InInitializationOrderModuleList.Blink = NULL;
112         wm->ldr.BaseAddress = hModule;
113         wm->ldr.EntryPoint = (nt->OptionalHeader.AddressOfEntryPoint) ?
114                              ((char *)hModule + nt->OptionalHeader.AddressOfEntryPoint) : 0;
115         wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
116         RtlCreateUnicodeStringFromAsciiz( &wm->ldr.FullDllName, wm->filename);
117         RtlCreateUnicodeStringFromAsciiz( &wm->ldr.BaseDllName, wm->modname);
118         wm->ldr.Flags = 0;
119         wm->ldr.LoadCount = 0;
120         wm->ldr.TlsIndex = 0;
121         wm->ldr.SectionHandle = NULL;
122         wm->ldr.CheckSum = 0;
123         wm->ldr.TimeDateStamp = 0;
124
125         if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
126         {
127             if (!exe_modref) exe_modref = wm;
128             else FIXME( "Trying to load second .EXE file: %s\n", filename );
129         }
130     }
131     return wm;
132 }
133
134 /******************************************************************
135  *              LdrDisableThreadCalloutsForDll (NTDLL.@)
136  *
137  */
138 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
139 {
140     WINE_MODREF *wm;
141     NTSTATUS    ret = STATUS_SUCCESS;
142
143     RtlEnterCriticalSection( &loader_section );
144
145     wm = MODULE32_LookupHMODULE( hModule );
146     if ( !wm )
147         ret = STATUS_DLL_NOT_FOUND;
148     else
149         wm->flags |= WINE_MODREF_NO_DLL_CALLS;
150
151     RtlLeaveCriticalSection( &loader_section );
152
153     return ret;
154 }
155
156 /******************************************************************
157  *              LdrFindEntryForAddress (NTDLL.@)
158  *
159  * The loader_section must be locked while calling this function
160  */
161 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* mod)
162 {
163     WINE_MODREF*        wm;
164
165     for ( wm = MODULE_modref_list; wm; wm = wm->next )
166     {
167         if ((const void *)wm->module <= addr &&
168             (char *)addr < (char*)wm->module + wm->ldr.SizeOfImage)
169         {
170             *mod = &wm->ldr;
171             return STATUS_SUCCESS;
172         }
173     }
174     return STATUS_NO_MORE_ENTRIES;
175 }
176
177 /**********************************************************************
178  *          MODULE_FindModule
179  *
180  * Find a (loaded) win32 module depending on path
181  *      LPCSTR path: [in] pathname of module/library to be found
182  *
183  * The loader_section must be locked while calling this function
184  * RETURNS
185  *      the module handle if found
186  *      0 if not
187  */
188 WINE_MODREF *MODULE_FindModule(LPCSTR path)
189 {
190     WINE_MODREF *wm;
191     char dllname[260], *p;
192
193     /* Append .DLL to name if no extension present */
194     strcpy( dllname, path );
195     if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
196             strcat( dllname, ".DLL" );
197
198     for ( wm = MODULE_modref_list; wm; wm = wm->next )
199     {
200         if ( !FILE_strcasecmp( dllname, wm->modname ) )
201             break;
202         if ( !FILE_strcasecmp( dllname, wm->filename ) )
203             break;
204         if ( !FILE_strcasecmp( dllname, wm->short_modname ) )
205             break;
206         if ( !FILE_strcasecmp( dllname, wm->short_filename ) )
207             break;
208     }
209
210     return wm;
211 }
212
213
214 /******************************************************************
215  *              LdrLockLoaderLock  (NTDLL.@)
216  *
217  * Note: flags are not implemented.
218  * Flag 0x01 is used to raise exceptions on errors.
219  * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
220  */
221 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
222 {
223     if (flags) FIXME( "flags %lx not supported\n", flags );
224
225     if (result) *result = 1;
226     if (!magic) return STATUS_INVALID_PARAMETER_3;
227     RtlEnterCriticalSection( &loader_section );
228     *magic = GetCurrentThreadId();
229     return STATUS_SUCCESS;
230 }
231
232
233 /******************************************************************
234  *              LdrUnlockLoaderUnlock  (NTDLL.@)
235  */
236 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
237 {
238     if (magic)
239     {
240         if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
241         RtlLeaveCriticalSection( &loader_section );
242     }
243     return STATUS_SUCCESS;
244 }
245
246
247 /******************************************************************
248  *              LdrGetDllHandle (NTDLL.@)
249  *
250  *
251  */
252 NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE *base)
253 {
254     WINE_MODREF *wm;
255
256     TRACE("%08lx %08lx %s %p\n",
257           x, y, name ? debugstr_wn(name->Buffer, name->Length) : NULL, base);
258
259     if (x != 0 || y != 0)
260         FIXME("Unknown behavior, please report\n");
261
262     /* FIXME: we should store module name information as unicode */
263     if (name)
264     {
265         STRING str;
266
267         RtlUnicodeStringToAnsiString( &str, name, TRUE );
268
269         wm = MODULE_FindModule( str.Buffer );
270         RtlFreeAnsiString( &str );
271     }
272     else
273         wm = exe_modref;
274
275     if (!wm)
276     {
277         *base = 0;
278         return STATUS_DLL_NOT_FOUND;
279     }
280
281     *base = wm->module;
282     return STATUS_SUCCESS;
283 }
284
285 /***********************************************************************
286  *           MODULE_GetProcAddress              (internal)
287  */
288 FARPROC MODULE_GetProcAddress(
289         HMODULE hModule,        /* [in] current module handle */
290         LPCSTR function,        /* [in] function to be looked up */
291         int hint,
292         BOOL snoop )
293 {
294     WINE_MODREF *wm;
295     FARPROC     retproc = 0;
296
297     if (HIWORD(function))
298         TRACE("(%p,%s (%d))\n",hModule,function,hint);
299     else
300         TRACE("(%p,%p)\n",hModule,function);
301
302     RtlEnterCriticalSection( &loader_section );
303     if ((wm = MODULE32_LookupHMODULE( hModule )))
304     {
305         retproc = wm->find_export( wm, function, hint, snoop );
306     }
307     RtlLeaveCriticalSection( &loader_section );
308     return retproc;
309 }
310
311
312 /******************************************************************
313  *              LdrGetProcedureAddress (NTDLL.@)
314  *
315  *
316  */
317 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG ord, PVOID *address)
318 {
319     WARN("%p %s %ld %p\n", base, name ? debugstr_an(name->Buffer, name->Length) : NULL, ord, address);
320
321     *address = MODULE_GetProcAddress( base, name ? name->Buffer : (LPSTR)ord, -1, TRUE );
322
323     return (*address) ? STATUS_SUCCESS : STATUS_PROCEDURE_NOT_FOUND;
324 }
325
326
327 /***********************************************************************
328  *      allocate_lib_dir
329  *
330  * helper for MODULE_LoadLibraryExA.  Allocate space to hold the directory
331  * portion of the provided name and put the name in it.
332  *
333  */
334 static LPCSTR allocate_lib_dir(LPCSTR libname)
335 {
336     LPCSTR p, pmax;
337     LPSTR result;
338     int length;
339
340     pmax = libname;
341     if ((p = strrchr( pmax, '\\' ))) pmax = p + 1;
342     if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty.  MSDN says don't */
343     if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2;
344
345     length = pmax - libname;
346
347     result = RtlAllocateHeap (ntdll_get_process_heap(), 0, length+1);
348
349     if (result)
350     {
351         strncpy (result, libname, length);
352         result [length] = '\0';
353     }
354
355     return result;
356 }
357
358 /***********************************************************************
359  *      MODULE_LoadLibraryExA   (internal)
360  *
361  * Load a PE style module according to the load order.
362  *
363  * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
364  *        on this function.  When first called from LoadLibraryExA it will be
365  *        NULL but thereafter it may point to a buffer containing the path
366  *        portion of the library name.  Note that the recursion all occurs
367  *        within a Critical section (see LoadLibraryExA) so the use of a
368  *        static is acceptable.
369  *        (We have to use a static variable at some point anyway, to pass the
370  *        information from BUILTIN32_dlopen through dlopen and the builtin's
371  *        init function into load_library).
372  * allocated_libdir is TRUE in the stack frame that allocated libdir
373  */
374 NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** pwm)
375 {
376     int i;
377     enum loadorder_type loadorder[LOADORDER_NTYPES];
378     LPSTR filename;
379     const char *filetype = "";
380     DWORD found;
381     BOOL allocated_libdir = FALSE;
382     static LPCSTR libdir = NULL; /* See above */
383     NTSTATUS nts = STATUS_SUCCESS;
384
385     *pwm = NULL;
386     if ( !libname ) return STATUS_DLL_NOT_FOUND; /* FIXME ? */
387
388     filename = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
389     if ( !filename ) return STATUS_NO_MEMORY;
390     *filename = 0; /* Just in case we don't set it before goto error */
391
392     RtlEnterCriticalSection( &loader_section );
393
394     if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname))
395     {
396         if (!(libdir = allocate_lib_dir(libname)))
397         {
398             nts = STATUS_NO_MEMORY;
399             goto error;
400         }
401         allocated_libdir = TRUE;
402     }
403
404     if (!libdir || allocated_libdir)
405         found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL);
406     else
407         found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL);
408
409     /* build the modules filename */
410     if (!found)
411     {
412         if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH ))
413         {
414             nts = STATUS_INTERNAL_ERROR;
415             goto error;
416         }
417     }
418
419     /* Check for already loaded module */
420     if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
421     {
422         LPSTR   fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
423         if (fn)
424         {
425             /* since the default loading mechanism uses a more detailed algorithm
426              * than SearchPath (like using PATH, which can even be modified between
427              * two attempts of loading the same DLL), the look-up above (with
428              * SearchPath) can have put the file in system directory, whereas it
429              * has already been loaded but with a different path. So do a specific
430              * look-up with filename (without any path)
431              */
432             strcpy ( fn, libname );
433             /* if the filename doesn't have an extension append .DLL */
434             if (!strrchr( fn, '.')) strcat( fn, ".dll" );
435             if ((*pwm = MODULE_FindModule( fn )) != NULL)
436                 strcpy( filename, fn );
437             RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
438         }
439     }
440     if (*pwm)
441     {
442         (*pwm)->refCount++;
443         
444         if (((*pwm)->flags & WINE_MODREF_DONT_RESOLVE_REFS) &&
445             !(flags & DONT_RESOLVE_DLL_REFERENCES))
446         {
447             (*pwm)->flags &= ~WINE_MODREF_DONT_RESOLVE_REFS;
448             PE_fixup_imports( *pwm );
449         }
450         TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->module, (*pwm)->refCount);
451         if (allocated_libdir)
452         {
453             RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
454             libdir = NULL;
455         }
456         RtlLeaveCriticalSection( &loader_section );
457         RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
458         return STATUS_SUCCESS;
459     }
460
461     MODULE_GetLoadOrder( loadorder, filename, TRUE);
462
463     for (i = 0; i < LOADORDER_NTYPES; i++)
464     {
465         if (loadorder[i] == LOADORDER_INVALID) break;
466
467         switch (loadorder[i])
468         {
469         case LOADORDER_DLL:
470             TRACE("Trying native dll '%s'\n", filename);
471             nts = PE_LoadLibraryExA(filename, flags, pwm);
472             filetype = "native";
473             break;
474             
475         case LOADORDER_BI:
476             TRACE("Trying built-in '%s'\n", filename);
477             nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
478             filetype = "builtin";
479             break;
480             
481         default:
482             nts = STATUS_INTERNAL_ERROR;
483             break;
484         }
485
486         if (nts == STATUS_SUCCESS)
487         {
488             /* Initialize DLL just loaded */
489             TRACE("Loaded module '%s' at %p\n", filename, (*pwm)->module);
490             if (!TRACE_ON(module))
491                 TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype);
492             /* Set the refCount here so that an attach failure will */
493             /* decrement the dependencies through the MODULE_FreeLibrary call. */
494             (*pwm)->refCount = 1;
495             
496             if (allocated_libdir)
497             {
498                 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
499                 libdir = NULL;
500             }
501             RtlLeaveCriticalSection( &loader_section );
502             RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
503             return nts;
504         }
505
506         if (nts != STATUS_NO_SUCH_FILE)
507         {
508             WARN("Loading of %s DLL %s failed (status %ld).\n",
509                  filetype, filename, nts);
510             break;
511         }
512     }
513
514  error:
515     if (allocated_libdir)
516     {
517         RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
518         libdir = NULL;
519     }
520     RtlLeaveCriticalSection( &loader_section );
521     WARN("Failed to load module '%s'; status=%ld\n", filename, nts);
522     RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
523     return nts;
524 }
525
526 /******************************************************************
527  *              LdrLoadDll (NTDLL.@)
528  */
529 NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libname, HMODULE* hModule)
530 {
531     WINE_MODREF *wm;
532     NTSTATUS    nts = STATUS_SUCCESS;
533     STRING      str;
534
535     RtlUnicodeStringToAnsiString(&str, libname, TRUE);
536
537     RtlEnterCriticalSection( &loader_section );
538
539     switch (nts = MODULE_LoadLibraryExA( str.Buffer, flags, &wm ))
540     {
541     case STATUS_SUCCESS:
542         if ( !MODULE_DllProcessAttach( wm, NULL ) )
543         {
544             WARN_(module)("Attach failed for module '%s'.\n", str.Buffer);
545             LdrUnloadDll(wm->module);
546             nts = STATUS_DLL_INIT_FAILED;
547             wm = NULL;
548         }
549         break;
550     case STATUS_NO_SUCH_FILE:
551         nts = STATUS_DLL_NOT_FOUND;
552         break;
553     default: /* keep error code as it is (memory...) */
554         break;
555     }
556
557     *hModule = (wm) ? wm->module : NULL;
558     
559     RtlLeaveCriticalSection( &loader_section );
560
561     RtlFreeAnsiString(&str);
562
563     return nts;
564 }
565
566 /******************************************************************
567  *              LdrShutdownProcess (NTDLL.@)
568  *
569  */
570 NTSTATUS    WINAPI  LdrShutdownProcess(void)
571 {
572     TRACE("()\n");
573     MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
574     return STATUS_SUCCESS; /* FIXME */
575 }
576
577 /******************************************************************
578  *              LdrShutdownThread (NTDLL.@)
579  *
580  */
581 NTSTATUS WINAPI LdrShutdownThread(void)
582 {
583     WINE_MODREF *wm;
584     TRACE("()\n");
585
586     /* don't do any detach calls if process is exiting */
587     if (process_detaching) return STATUS_SUCCESS;
588     /* FIXME: there is still a race here */
589
590     RtlEnterCriticalSection( &loader_section );
591
592     for ( wm = MODULE_modref_list; wm; wm = wm->next )
593     {
594         if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
595             continue;
596         if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
597             continue;
598
599         MODULE_InitDLL( wm, DLL_THREAD_DETACH, NULL );
600     }
601
602     RtlLeaveCriticalSection( &loader_section );
603     return STATUS_SUCCESS; /* FIXME */
604 }
605
606 /***********************************************************************
607  *           MODULE_FlushModrefs
608  *
609  * NOTE: Assumes that the process critical section is held!
610  *
611  * Remove all unused modrefs and call the internal unloading routines
612  * for the library type.
613  */
614 static void MODULE_FlushModrefs(void)
615 {
616     WINE_MODREF *wm, *next;
617
618     for (wm = MODULE_modref_list; wm; wm = next)
619     {
620         next = wm->next;
621
622         if (wm->refCount)
623             continue;
624
625         /* Unlink this modref from the chain */
626         if (wm->next)
627             wm->next->prev = wm->prev;
628         if (wm->prev)
629             wm->prev->next = wm->next;
630         if (wm == MODULE_modref_list)
631             MODULE_modref_list = wm->next;
632
633         TRACE(" unloading %s\n", wm->filename);
634         if (!TRACE_ON(module))
635             TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
636                             wm->dlhandle ? "builtin" : "native" );
637
638         SERVER_START_REQ( unload_dll )
639         {
640             req->base = (void *)wm->module;
641             wine_server_call( req );
642         }
643         SERVER_END_REQ;
644
645         if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
646         else UnmapViewOfFile( (LPVOID)wm->module );
647         FreeLibrary16( wm->hDummyMod );
648         RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps );
649         RtlFreeHeap( ntdll_get_process_heap(), 0, wm );
650     }
651 }
652
653 /***********************************************************************
654  *           MODULE_DecRefCount
655  *
656  * NOTE: Assumes that the process critical section is held!
657  */
658 static void MODULE_DecRefCount( WINE_MODREF *wm )
659 {
660     int i;
661
662     if ( wm->flags & WINE_MODREF_MARKER )
663         return;
664
665     if ( wm->refCount <= 0 )
666         return;
667
668     --wm->refCount;
669     TRACE("(%s) refCount: %d\n", wm->modname, wm->refCount );
670
671     if ( wm->refCount == 0 )
672     {
673         wm->flags |= WINE_MODREF_MARKER;
674
675         for ( i = 0; i < wm->nDeps; i++ )
676             if ( wm->deps[i] )
677                 MODULE_DecRefCount( wm->deps[i] );
678
679         wm->flags &= ~WINE_MODREF_MARKER;
680     }
681 }
682
683 /******************************************************************
684  *              LdrUnloadDll (NTDLL.@)
685  *
686  *
687  */
688 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
689 {
690     NTSTATUS retv = STATUS_SUCCESS;
691
692     TRACE("(%p)\n", hModule);
693
694     RtlEnterCriticalSection( &loader_section );
695
696     /* if we're stopping the whole process (and forcing the removal of all
697      * DLLs) the library will be freed anyway
698      */
699     if (!process_detaching)
700     {
701         WINE_MODREF *wm;
702
703         free_lib_count++;
704         if ((wm = MODULE32_LookupHMODULE( hModule )) != NULL)
705         {
706             TRACE("(%s) - START\n", wm->modname);
707
708             /* Recursively decrement reference counts */
709             MODULE_DecRefCount( wm );
710
711             /* Call process detach notifications */
712             if ( free_lib_count <= 1 )
713             {
714                 MODULE_DllProcessDetach( FALSE, NULL );
715                 MODULE_FlushModrefs();
716             }
717
718             TRACE("END\n");
719         }
720         else
721             retv = STATUS_DLL_NOT_FOUND;
722
723         free_lib_count--;
724     }
725
726     RtlLeaveCriticalSection( &loader_section );
727
728     return retv;
729 }
730
731 /***********************************************************************
732  *           RtlImageNtHeader   (NTDLL.@)
733  */
734 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
735 {
736     IMAGE_NT_HEADERS *ret;
737
738     __TRY
739     {
740         IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
741
742         ret = NULL;
743         if (dos->e_magic == IMAGE_DOS_SIGNATURE)
744         {
745             ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
746             if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
747         }
748     }
749     __EXCEPT(page_fault)
750     {
751         return NULL;
752     }
753     __ENDTRY
754     return ret;
755 }
756
757
758 /***********************************************************************
759  *           RtlImageDirectoryEntryToData   (NTDLL.@)
760  */
761 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
762 {
763     const IMAGE_NT_HEADERS *nt;
764     DWORD addr;
765
766     if ((ULONG_PTR)module & 1)  /* mapped as data file */
767     {
768         module = (HMODULE)((ULONG_PTR)module & ~1);
769         image = FALSE;
770     }
771     if (!(nt = RtlImageNtHeader( module ))) return NULL;
772     if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
773     if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
774     *size = nt->OptionalHeader.DataDirectory[dir].Size;
775     if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
776
777     /* not mapped as image, need to find the section containing the virtual address */
778     return RtlImageRvaToVa( nt, module, addr, NULL );
779 }
780
781
782 /***********************************************************************
783  *           RtlImageRvaToSection   (NTDLL.@)
784  */
785 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
786                                                    HMODULE module, DWORD rva )
787 {
788     int i;
789     IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader +
790                                                         nt->FileHeader.SizeOfOptionalHeader);
791     for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
792     {
793         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
794             return sec;
795     }
796     return NULL;
797 }
798
799
800 /***********************************************************************
801  *           RtlImageRvaToVa   (NTDLL.@)
802  */
803 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
804                               DWORD rva, IMAGE_SECTION_HEADER **section )
805 {
806     IMAGE_SECTION_HEADER *sec;
807
808     if (section && *section)  /* try this section first */
809     {
810         sec = *section;
811         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
812             goto found;
813     }
814     if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
815  found:
816     if (section) *section = sec;
817     return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
818 }