Moved atom functions to dlls/kernel.
[wine] / dlls / ntdll / loader.c
1 /*
2  * Loader functions
3  *
4  * Copyright 1995, 2003 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 "snoop.h"
33 #include "wine/debug.h"
34 #include "wine/server.h"
35 #include "ntdll_misc.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(module);
38 WINE_DECLARE_DEBUG_CHANNEL(relay);
39 WINE_DECLARE_DEBUG_CHANNEL(snoop);
40 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
41
42 typedef DWORD (CALLBACK *DLLENTRYPROC)(HMODULE,DWORD,LPVOID);
43
44 WINE_MODREF *MODULE_modref_list = NULL;
45
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 */
49
50 /* filter for page-fault exceptions */
51 static WINE_EXCEPTION_FILTER(page_fault)
52 {
53     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
54         return EXCEPTION_EXECUTE_HANDLER;
55     return EXCEPTION_CONTINUE_SEARCH;
56 }
57
58 static const char * const reason_names[] =
59 {
60     "PROCESS_DETACH",
61     "PROCESS_ATTACH",
62     "THREAD_ATTACH",
63     "THREAD_DETACH"
64 };
65
66 static UINT tls_module_count;      /* number of modules with TLS directory */
67 static UINT tls_total_size;        /* total size of TLS storage */
68 static const IMAGE_TLS_DIRECTORY **tls_dirs;  /* array of TLS directories */
69
70 static CRITICAL_SECTION loader_section = CRITICAL_SECTION_INIT( "loader_section" );
71 static WINE_MODREF *cached_modref;
72 static WINE_MODREF *current_modref;
73
74 static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm );
75 static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
76                                   DWORD exp_size, const char *name, int hint );
77
78 /* convert PE image VirtualAddress to Real Address */
79 inline static void *get_rva( HMODULE module, DWORD va )
80 {
81     return (void *)((char *)module + va);
82 }
83
84 /*************************************************************************
85  *              get_modref
86  *
87  * Looks for the referenced HMODULE in the current process
88  * The loader_section must be locked while calling this function.
89  */
90 static WINE_MODREF *get_modref( HMODULE hmod )
91 {
92     WINE_MODREF *wm;
93
94     if (cached_modref && cached_modref->ldr.BaseAddress == hmod) return cached_modref;
95
96     for ( wm = MODULE_modref_list; wm; wm=wm->next )
97     {
98         if (wm->ldr.BaseAddress == hmod)
99         {
100             cached_modref = wm;
101             break;
102         }
103     }
104     return wm;
105 }
106
107
108 /*************************************************************************
109  *              find_forwarded_export
110  *
111  * Find the final function pointer for a forwarded function.
112  * The loader_section must be locked while calling this function.
113  */
114 static FARPROC find_forwarded_export( HMODULE module, const char *forward )
115 {
116     IMAGE_EXPORT_DIRECTORY *exports;
117     DWORD exp_size;
118     WINE_MODREF *wm;
119     char mod_name[256];
120     char *end = strchr(forward, '.');
121     FARPROC proc = NULL;
122
123     if (!end) return NULL;
124     if (end - forward >= sizeof(mod_name)) return NULL;
125     memcpy( mod_name, forward, end - forward );
126     mod_name[end-forward] = 0;
127
128     if (!(wm = MODULE_FindModule( mod_name )))
129     {
130         ERR("module not found for forward '%s' used by '%s'\n",
131             forward, get_modref(module)->filename );
132         return NULL;
133     }
134     if ((exports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
135                                                  IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
136         proc = find_named_export( wm->ldr.BaseAddress, exports, exp_size, end + 1, -1 );
137
138     if (!proc)
139     {
140         ERR("function not found for forward '%s' used by '%s'."
141             " If you are using builtin '%s', try using the native one instead.\n",
142             forward, get_modref(module)->filename, get_modref(module)->modname );
143     }
144     return proc;
145 }
146
147
148 /*************************************************************************
149  *              find_ordinal_export
150  *
151  * Find an exported function by ordinal.
152  * The exports base must have been subtracted from the ordinal already.
153  * The loader_section must be locked while calling this function.
154  */
155 static FARPROC find_ordinal_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
156                                     DWORD exp_size, int ordinal )
157 {
158     FARPROC proc;
159     DWORD *functions = get_rva( module, exports->AddressOfFunctions );
160
161     if (ordinal >= exports->NumberOfFunctions)
162     {
163         TRACE(" ordinal %ld out of range!\n", ordinal + exports->Base );
164         return NULL;
165     }
166     if (!functions[ordinal]) return NULL;
167
168     proc = get_rva( module, functions[ordinal] );
169
170     /* if the address falls into the export dir, it's a forward */
171     if (((char *)proc >= (char *)exports) && ((char *)proc < (char *)exports + exp_size))
172         return find_forwarded_export( module, (char *)proc );
173
174     if (TRACE_ON(snoop))
175     {
176         proc = SNOOP_GetProcAddress( module, exports, exp_size, proc, ordinal );
177     }
178     if (TRACE_ON(relay) && current_modref)
179     {
180         proc = RELAY_GetProcAddress( module, exports, exp_size, proc, current_modref->modname );
181     }
182     return proc;
183 }
184
185
186 /*************************************************************************
187  *              find_named_export
188  *
189  * Find an exported function by name.
190  * The loader_section must be locked while calling this function.
191  */
192 static FARPROC find_named_export( HMODULE module, IMAGE_EXPORT_DIRECTORY *exports,
193                                   DWORD exp_size, const char *name, int hint )
194 {
195     WORD *ordinals = get_rva( module, exports->AddressOfNameOrdinals );
196     DWORD *names = get_rva( module, exports->AddressOfNames );
197     int min = 0, max = exports->NumberOfNames - 1;
198
199     /* first check the hint */
200     if (hint >= 0 && hint <= max)
201     {
202         char *ename = get_rva( module, names[hint] );
203         if (!strcmp( ename, name ))
204             return find_ordinal_export( module, exports, exp_size, ordinals[hint] );
205     }
206
207     /* then do a binary search */
208     while (min <= max)
209     {
210         int res, pos = (min + max) / 2;
211         char *ename = get_rva( module, names[pos] );
212         if (!(res = strcmp( ename, name )))
213             return find_ordinal_export( module, exports, exp_size, ordinals[pos] );
214         if (res > 0) max = pos - 1;
215         else min = pos + 1;
216     }
217     return NULL;
218
219 }
220
221
222 /*************************************************************************
223  *              import_dll
224  *
225  * Import the dll specified by the given import descriptor.
226  * The loader_section must be locked while calling this function.
227  */
228 static WINE_MODREF *import_dll( HMODULE module, IMAGE_IMPORT_DESCRIPTOR *descr )
229 {
230     NTSTATUS status;
231     WINE_MODREF *wmImp;
232     HMODULE imp_mod;
233     IMAGE_EXPORT_DIRECTORY *exports;
234     DWORD exp_size;
235     IMAGE_THUNK_DATA *import_list, *thunk_list;
236     char *name = get_rva( module, descr->Name );
237
238     status = load_dll( name, 0, &wmImp );
239     if (status)
240     {
241         if (status == STATUS_NO_SUCH_FILE)
242             ERR("Module (file) %s (which is needed by %s) not found\n",
243                 name, current_modref->filename);
244         else
245             ERR("Loading module (file) %s (which is needed by %s) failed (error %ld).\n",
246                 name, current_modref->filename, status);
247         return NULL;
248     }
249
250     imp_mod = wmImp->ldr.BaseAddress;
251     if (!(exports = RtlImageDirectoryEntryToData( imp_mod, TRUE,
252                                                   IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
253         return NULL;
254
255     thunk_list = get_rva( module, (DWORD)descr->FirstThunk );
256     if (descr->u.OriginalFirstThunk)
257         import_list = get_rva( module, (DWORD)descr->u.OriginalFirstThunk );
258     else
259         import_list = thunk_list;
260
261     while (import_list->u1.Ordinal)
262     {
263         if (IMAGE_SNAP_BY_ORDINAL(import_list->u1.Ordinal))
264         {
265             int ordinal = IMAGE_ORDINAL(import_list->u1.Ordinal);
266
267             TRACE("--- Ordinal %s,%d\n", name, ordinal);
268             thunk_list->u1.Function = (PDWORD)find_ordinal_export( imp_mod, exports, exp_size,
269                                                                    ordinal - exports->Base );
270             if (!thunk_list->u1.Function)
271             {
272                 ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
273                     name, ordinal, current_modref->filename );
274                 thunk_list->u1.Function = (PDWORD)0xdeadbeef;
275             }
276         }
277         else  /* import by name */
278         {
279             IMAGE_IMPORT_BY_NAME *pe_name;
280             pe_name = get_rva( module, (DWORD)import_list->u1.AddressOfData );
281             TRACE("--- %s %s.%d\n", pe_name->Name, name, pe_name->Hint);
282             thunk_list->u1.Function = (PDWORD)find_named_export( imp_mod, exports, exp_size,
283                                                                  pe_name->Name, pe_name->Hint );
284             if (!thunk_list->u1.Function)
285             {
286                 ERR("No implementation for %s.%s imported from %s, setting to 0xdeadbeef\n",
287                     name, pe_name->Name, current_modref->filename );
288                 thunk_list->u1.Function = (PDWORD)0xdeadbeef;
289             }
290         }
291         import_list++;
292         thunk_list++;
293     }
294     return wmImp;
295 }
296
297
298 /****************************************************************
299  *      PE_fixup_imports
300  *
301  * Fixup all imports of a given module.
302  * The loader_section must be locked while calling this function.
303  */
304 DWORD PE_fixup_imports( WINE_MODREF *wm )
305 {
306     int i, nb_imports;
307     IMAGE_IMPORT_DESCRIPTOR *imports;
308     WINE_MODREF *prev;
309     DWORD size;
310
311     if (!(imports = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
312                                                   IMAGE_DIRECTORY_ENTRY_IMPORT, &size )))
313         return 0;
314
315     nb_imports = size / sizeof(*imports);
316     for (i = 0; i < nb_imports; i++)
317     {
318         if (!imports[i].Name)
319         {
320             nb_imports = i;
321             break;
322         }
323     }
324     if (!nb_imports) return 0;  /* no imports */
325
326     /* Allocate module dependency list */
327     wm->nDeps = nb_imports;
328     wm->deps  = RtlAllocateHeap( ntdll_get_process_heap(), 0, nb_imports*sizeof(WINE_MODREF *) );
329
330     /* load the imported modules. They are automatically
331      * added to the modref list of the process.
332      */
333     prev = current_modref;
334     current_modref = wm;
335     for (i = 0; i < nb_imports; i++)
336     {
337         if (!(wm->deps[i] = import_dll( wm->ldr.BaseAddress, &imports[i] ))) break;
338     }
339     current_modref = prev;
340     return (i < nb_imports);
341 }
342
343
344 /*************************************************************************
345  *              MODULE_AllocModRef
346  *
347  * Allocate a WINE_MODREF structure and add it to the process list
348  * The loader_section must be locked while calling this function.
349  */
350 WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
351 {
352     WINE_MODREF *wm;
353     IMAGE_NT_HEADERS *nt = RtlImageNtHeader(hModule);
354
355     DWORD long_len = strlen( filename );
356     DWORD short_len = GetShortPathNameA( filename, NULL, 0 );
357
358     if ((wm = RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY,
359                                sizeof(*wm) + long_len + short_len + 1 )))
360     {
361         wm->filename = wm->data;
362         memcpy( wm->filename, filename, long_len + 1 );
363         if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
364         else wm->modname = wm->filename;
365
366         wm->short_filename = wm->filename + long_len + 1;
367         GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 );
368         if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
369         else wm->short_modname = wm->short_filename;
370
371         wm->next = MODULE_modref_list;
372         if (wm->next) wm->next->prev = wm;
373         MODULE_modref_list = wm;
374
375         wm->ldr.InLoadOrderModuleList.Flink = NULL;
376         wm->ldr.InLoadOrderModuleList.Blink = NULL;
377         wm->ldr.InMemoryOrderModuleList.Flink = NULL;
378         wm->ldr.InMemoryOrderModuleList.Blink = NULL;
379         wm->ldr.InInitializationOrderModuleList.Flink = NULL;
380         wm->ldr.InInitializationOrderModuleList.Blink = NULL;
381         wm->ldr.BaseAddress = hModule;
382         wm->ldr.EntryPoint = (nt->OptionalHeader.AddressOfEntryPoint) ?
383                              ((char *)hModule + nt->OptionalHeader.AddressOfEntryPoint) : 0;
384         wm->ldr.SizeOfImage = nt->OptionalHeader.SizeOfImage;
385         RtlCreateUnicodeStringFromAsciiz( &wm->ldr.FullDllName, wm->filename);
386         RtlCreateUnicodeStringFromAsciiz( &wm->ldr.BaseDllName, wm->modname);
387         wm->ldr.Flags = 0;
388         wm->ldr.LoadCount = 0;
389         wm->ldr.TlsIndex = -1;
390         wm->ldr.SectionHandle = NULL;
391         wm->ldr.CheckSum = 0;
392         wm->ldr.TimeDateStamp = 0;
393
394         if (!(nt->FileHeader.Characteristics & IMAGE_FILE_DLL))
395         {
396             if (!exe_modref) exe_modref = wm;
397             else FIXME( "Trying to load second .EXE file: %s\n", filename );
398         }
399         else wm->ldr.Flags |= LDR_IMAGE_IS_DLL;
400     }
401     return wm;
402 }
403
404
405 /*************************************************************************
406  *              alloc_process_tls
407  *
408  * Allocate the process-wide structure for module TLS storage.
409  */
410 static NTSTATUS alloc_process_tls(void)
411 {
412     WINE_MODREF *wm;
413     IMAGE_TLS_DIRECTORY *dir;
414     ULONG size, i;
415
416     for (wm = MODULE_modref_list; wm; wm = wm->next)
417     {
418         if (!(dir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
419                                                   IMAGE_DIRECTORY_ENTRY_TLS, &size )))
420             continue;
421         size = (dir->EndAddressOfRawData - dir->StartAddressOfRawData) + dir->SizeOfZeroFill;
422         if (!size) continue;
423         tls_total_size += size;
424         tls_module_count++;
425     }
426     if (!tls_module_count) return STATUS_SUCCESS;
427
428     TRACE( "count %u size %u\n", tls_module_count, tls_total_size );
429
430     tls_dirs = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_module_count * sizeof(*tls_dirs) );
431     if (!tls_dirs) return STATUS_NO_MEMORY;
432
433     for (i = 0, wm = MODULE_modref_list; wm; wm = wm->next)
434     {
435         if (!(dir = RtlImageDirectoryEntryToData( wm->ldr.BaseAddress, TRUE,
436                                                   IMAGE_DIRECTORY_ENTRY_TLS, &size )))
437             continue;
438         tls_dirs[i] = dir;
439         *dir->AddressOfIndex = i;
440         wm->ldr.TlsIndex = i;
441         wm->ldr.LoadCount = -1;  /* can't unload it */
442         i++;
443     }
444     return STATUS_SUCCESS;
445 }
446
447
448 /*************************************************************************
449  *              alloc_thread_tls
450  *
451  * Allocate the per-thread structure for module TLS storage.
452  */
453 static NTSTATUS alloc_thread_tls(void)
454 {
455     void **pointers;
456     char *data;
457     UINT i;
458
459     if (!tls_module_count) return STATUS_SUCCESS;
460
461     if (!(pointers = RtlAllocateHeap( ntdll_get_process_heap(), 0,
462                                       tls_module_count * sizeof(*pointers) )))
463         return STATUS_NO_MEMORY;
464
465     if (!(data = RtlAllocateHeap( ntdll_get_process_heap(), 0, tls_total_size )))
466     {
467         RtlFreeHeap( ntdll_get_process_heap(), 0, pointers );
468         return STATUS_NO_MEMORY;
469     }
470
471     for (i = 0; i < tls_module_count; i++)
472     {
473         const IMAGE_TLS_DIRECTORY *dir = tls_dirs[i];
474         ULONG size = dir->EndAddressOfRawData - dir->StartAddressOfRawData;
475
476         TRACE( "thread %04lx idx %d: %ld/%ld bytes from %p to %p\n",
477                GetCurrentThreadId(), i, size, dir->SizeOfZeroFill,
478                (void *)dir->StartAddressOfRawData, data );
479
480         pointers[i] = data;
481         memcpy( data, (void *)dir->StartAddressOfRawData, size );
482         data += size;
483         memset( data, 0, dir->SizeOfZeroFill );
484         data += dir->SizeOfZeroFill;
485     }
486     NtCurrentTeb()->tls_ptr = pointers;
487     return STATUS_SUCCESS;
488 }
489
490
491 /*************************************************************************
492  *              call_tls_callbacks
493  */
494 static void call_tls_callbacks( HMODULE module, UINT reason )
495 {
496     const IMAGE_TLS_DIRECTORY *dir;
497     const PIMAGE_TLS_CALLBACK *callback;
498     ULONG dirsize;
499
500     dir = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_TLS, &dirsize );
501     if (!dir || !dir->AddressOfCallBacks) return;
502
503     for (callback = dir->AddressOfCallBacks; *callback; callback++)
504     {
505         if (TRACE_ON(relay))
506             DPRINTF("%04lx:Call TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
507                     GetCurrentThreadId(), *callback, module, reason_names[reason] );
508         (*callback)( module, reason, NULL );
509         if (TRACE_ON(relay))
510             DPRINTF("%04lx:Ret  TLS callback (proc=%p,module=%p,reason=%s,reserved=0)\n",
511                     GetCurrentThreadId(), *callback, module, reason_names[reason] );
512     }
513 }
514
515
516 /*************************************************************************
517  *              MODULE_InitDLL
518  */
519 static BOOL MODULE_InitDLL( WINE_MODREF *wm, UINT reason, LPVOID lpReserved )
520 {
521     char mod_name[32];
522     BOOL retv = TRUE;
523     DLLENTRYPROC entry = wm->ldr.EntryPoint;
524     void *module = wm->ldr.BaseAddress;
525
526     /* Skip calls for modules loaded with special load flags */
527
528     if (wm->ldr.Flags & LDR_DONT_RESOLVE_REFS) return TRUE;
529     if (wm->ldr.TlsIndex != -1) call_tls_callbacks( wm->ldr.BaseAddress, reason );
530     if (!entry || !(wm->ldr.Flags & LDR_IMAGE_IS_DLL)) return TRUE;
531
532     if (TRACE_ON(relay))
533     {
534         size_t len = max( strlen(wm->modname), sizeof(mod_name)-1 );
535         memcpy( mod_name, wm->modname, len );
536         mod_name[len] = 0;
537         DPRINTF("%04lx:Call PE DLL (proc=%p,module=%p (%s),reason=%s,res=%p)\n",
538                 GetCurrentThreadId(), entry, module, mod_name, reason_names[reason], lpReserved );
539     }
540     else TRACE("(%p (%s),%s,%p) - CALL\n", module, wm->modname, reason_names[reason], lpReserved );
541
542     retv = entry( module, reason, lpReserved );
543
544     /* The state of the module list may have changed due to the call
545        to the dll. We cannot assume that this module has not been
546        deleted.  */
547     if (TRACE_ON(relay))
548         DPRINTF("%04lx:Ret  PE DLL (proc=%p,module=%p (%s),reason=%s,res=%p) retval=%x\n",
549                 GetCurrentThreadId(), entry, module, mod_name, reason_names[reason], lpReserved, retv );
550     else TRACE("(%p,%s,%p) - RETURN %d\n", module, reason_names[reason], lpReserved, retv );
551
552     return retv;
553 }
554
555
556 /*************************************************************************
557  *              MODULE_DllProcessAttach
558  *
559  * Send the process attach notification to all DLLs the given module
560  * depends on (recursively). This is somewhat complicated due to the fact that
561  *
562  * - we have to respect the module dependencies, i.e. modules implicitly
563  *   referenced by another module have to be initialized before the module
564  *   itself can be initialized
565  *
566  * - the initialization routine of a DLL can itself call LoadLibrary,
567  *   thereby introducing a whole new set of dependencies (even involving
568  *   the 'old' modules) at any time during the whole process
569  *
570  * (Note that this routine can be recursively entered not only directly
571  *  from itself, but also via LoadLibrary from one of the called initialization
572  *  routines.)
573  *
574  * Furthermore, we need to rearrange the main WINE_MODREF list to allow
575  * the process *detach* notifications to be sent in the correct order.
576  * This must not only take into account module dependencies, but also
577  * 'hidden' dependencies created by modules calling LoadLibrary in their
578  * attach notification routine.
579  *
580  * The strategy is rather simple: we move a WINE_MODREF to the head of the
581  * list after the attach notification has returned.  This implies that the
582  * detach notifications are called in the reverse of the sequence the attach
583  * notifications *returned*.
584  */
585 NTSTATUS MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
586 {
587     NTSTATUS status = STATUS_SUCCESS;
588     int i;
589
590     RtlEnterCriticalSection( &loader_section );
591
592     if (!wm)
593     {
594         wm = exe_modref;
595         wm->ldr.LoadCount = -1;  /* can't unload main exe */
596         if ((status = alloc_process_tls()) != STATUS_SUCCESS) goto done;
597         if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
598     }
599     assert( wm );
600
601     /* prevent infinite recursion in case of cyclical dependencies */
602     if (    ( wm->ldr.Flags & LDR_LOAD_IN_PROGRESS )
603          || ( wm->ldr.Flags & LDR_PROCESS_ATTACHED ) )
604         goto done;
605
606     TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
607
608     /* Tag current MODREF to prevent recursive loop */
609     wm->ldr.Flags |= LDR_LOAD_IN_PROGRESS;
610
611     /* Recursively attach all DLLs this one depends on */
612     for ( i = 0; i < wm->nDeps; i++ )
613     {
614         if (!wm->deps[i]) continue;
615         if ((status = MODULE_DllProcessAttach( wm->deps[i], lpReserved )) != STATUS_SUCCESS) break;
616     }
617
618     /* Call DLL entry point */
619     if (status == STATUS_SUCCESS)
620     {
621         WINE_MODREF *prev = current_modref;
622         current_modref = wm;
623         if (MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved ))
624             wm->ldr.Flags |= LDR_PROCESS_ATTACHED;
625         else
626             status = STATUS_DLL_INIT_FAILED;
627         current_modref = prev;
628     }
629
630     /* Re-insert MODREF at head of list */
631     if (status == STATUS_SUCCESS && wm->prev )
632     {
633         wm->prev->next = wm->next;
634         if ( wm->next ) wm->next->prev = wm->prev;
635
636         wm->prev = NULL;
637         wm->next = MODULE_modref_list;
638         MODULE_modref_list = wm->next->prev = wm;
639     }
640
641     /* Remove recursion flag */
642     wm->ldr.Flags &= ~LDR_LOAD_IN_PROGRESS;
643
644     TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
645
646  done:
647     RtlLeaveCriticalSection( &loader_section );
648     return status;
649 }
650
651 /*************************************************************************
652  *              MODULE_DllProcessDetach
653  *
654  * Send DLL process detach notifications.  See the comment about calling
655  * sequence at MODULE_DllProcessAttach.  Unless the bForceDetach flag
656  * is set, only DLLs with zero refcount are notified.
657  */
658 static void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
659 {
660     WINE_MODREF *wm;
661
662     RtlEnterCriticalSection( &loader_section );
663     if (bForceDetach) process_detaching = 1;
664     do
665     {
666         for ( wm = MODULE_modref_list; wm; wm = wm->next )
667         {
668             /* Check whether to detach this DLL */
669             if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
670                 continue;
671             if ( wm->ldr.LoadCount && !bForceDetach )
672                 continue;
673
674             /* Call detach notification */
675             wm->ldr.Flags &= ~LDR_PROCESS_ATTACHED;
676             MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
677
678             /* Restart at head of WINE_MODREF list, as entries might have
679                been added and/or removed while performing the call ... */
680             break;
681         }
682     } while ( wm );
683
684     RtlLeaveCriticalSection( &loader_section );
685 }
686
687 /*************************************************************************
688  *              MODULE_DllThreadAttach
689  *
690  * Send DLL thread attach notifications. These are sent in the
691  * reverse sequence of process detach notification.
692  *
693  */
694 NTSTATUS MODULE_DllThreadAttach( LPVOID lpReserved )
695 {
696     WINE_MODREF *wm;
697     NTSTATUS status;
698
699     /* don't do any attach calls if process is exiting */
700     if (process_detaching) return STATUS_SUCCESS;
701     /* FIXME: there is still a race here */
702
703     RtlEnterCriticalSection( &loader_section );
704
705     if ((status = alloc_thread_tls()) != STATUS_SUCCESS) goto done;
706
707     for ( wm = MODULE_modref_list; wm; wm = wm->next )
708         if ( !wm->next )
709             break;
710
711     for ( ; wm; wm = wm->prev )
712     {
713         if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
714             continue;
715         if ( wm->ldr.Flags & LDR_NO_DLL_CALLS )
716             continue;
717
718         MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
719     }
720
721 done:
722     RtlLeaveCriticalSection( &loader_section );
723     return status;
724 }
725
726 /******************************************************************
727  *              LdrDisableThreadCalloutsForDll (NTDLL.@)
728  *
729  */
730 NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE hModule)
731 {
732     WINE_MODREF *wm;
733     NTSTATUS    ret = STATUS_SUCCESS;
734
735     RtlEnterCriticalSection( &loader_section );
736
737     wm = get_modref( hModule );
738     if (!wm || wm->ldr.TlsIndex != -1)
739         ret = STATUS_DLL_NOT_FOUND;
740     else
741         wm->ldr.Flags |= LDR_NO_DLL_CALLS;
742
743     RtlLeaveCriticalSection( &loader_section );
744
745     return ret;
746 }
747
748 /******************************************************************
749  *              LdrFindEntryForAddress (NTDLL.@)
750  *
751  * The loader_section must be locked while calling this function
752  */
753 NTSTATUS WINAPI LdrFindEntryForAddress(const void* addr, PLDR_MODULE* mod)
754 {
755     WINE_MODREF*        wm;
756
757     for ( wm = MODULE_modref_list; wm; wm = wm->next )
758     {
759         if ((const void *)wm->ldr.BaseAddress <= addr &&
760             (char *)addr < (char*)wm->ldr.BaseAddress + wm->ldr.SizeOfImage)
761         {
762             *mod = &wm->ldr;
763             return STATUS_SUCCESS;
764         }
765     }
766     return STATUS_NO_MORE_ENTRIES;
767 }
768
769 /**********************************************************************
770  *          MODULE_FindModule
771  *
772  * Find a (loaded) win32 module depending on path
773  *      LPCSTR path: [in] pathname of module/library to be found
774  *
775  * The loader_section must be locked while calling this function
776  * RETURNS
777  *      the module handle if found
778  *      0 if not
779  */
780 WINE_MODREF *MODULE_FindModule(LPCSTR path)
781 {
782     WINE_MODREF *wm;
783     char dllname[260], *p;
784
785     /* Append .DLL to name if no extension present */
786     strcpy( dllname, path );
787     if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
788             strcat( dllname, ".DLL" );
789
790     if ((wm = cached_modref) != NULL)
791     {
792         if ( !FILE_strcasecmp( dllname, wm->modname ) ) return wm;
793         if ( !FILE_strcasecmp( dllname, wm->filename ) ) return wm;
794         if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) return wm;
795         if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) return wm;
796     }
797
798     for ( wm = MODULE_modref_list; wm; wm = wm->next )
799     {
800         if ( !FILE_strcasecmp( dllname, wm->modname ) ) break;
801         if ( !FILE_strcasecmp( dllname, wm->filename ) ) break;
802         if ( !FILE_strcasecmp( dllname, wm->short_modname ) ) break;
803         if ( !FILE_strcasecmp( dllname, wm->short_filename ) ) break;
804     }
805     cached_modref = wm;
806     return wm;
807 }
808
809
810 /******************************************************************
811  *              LdrLockLoaderLock  (NTDLL.@)
812  *
813  * Note: flags are not implemented.
814  * Flag 0x01 is used to raise exceptions on errors.
815  * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
816  */
817 NTSTATUS WINAPI LdrLockLoaderLock( ULONG flags, ULONG *result, ULONG *magic )
818 {
819     if (flags) FIXME( "flags %lx not supported\n", flags );
820
821     if (result) *result = 1;
822     if (!magic) return STATUS_INVALID_PARAMETER_3;
823     RtlEnterCriticalSection( &loader_section );
824     *magic = GetCurrentThreadId();
825     return STATUS_SUCCESS;
826 }
827
828
829 /******************************************************************
830  *              LdrUnlockLoaderUnlock  (NTDLL.@)
831  */
832 NTSTATUS WINAPI LdrUnlockLoaderLock( ULONG flags, ULONG magic )
833 {
834     if (magic)
835     {
836         if (magic != GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2;
837         RtlLeaveCriticalSection( &loader_section );
838     }
839     return STATUS_SUCCESS;
840 }
841
842
843 /******************************************************************
844  *              LdrGetDllHandle (NTDLL.@)
845  *
846  *
847  */
848 NTSTATUS WINAPI LdrGetDllHandle(ULONG x, ULONG y, PUNICODE_STRING name, HMODULE *base)
849 {
850     WINE_MODREF *wm;
851     STRING str;
852
853     if (x != 0 || y != 0)
854         FIXME("Unknown behavior, please report\n");
855
856     /* FIXME: we should store module name information as unicode */
857     RtlUnicodeStringToAnsiString( &str, name, TRUE );
858     wm = MODULE_FindModule( str.Buffer );
859     RtlFreeAnsiString( &str );
860
861     if (!wm)
862     {
863         *base = 0;
864         return STATUS_DLL_NOT_FOUND;
865     }
866
867     *base = wm->ldr.BaseAddress;
868
869     TRACE("%lx %lx %s -> %p\n", x, y, debugstr_us(name), *base);
870
871     return STATUS_SUCCESS;
872 }
873
874
875 /******************************************************************
876  *              LdrGetProcedureAddress  (NTDLL.@)
877  */
878 NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE module, PANSI_STRING name, ULONG ord, PVOID *address)
879 {
880     IMAGE_EXPORT_DIRECTORY *exports;
881     DWORD exp_size;
882     NTSTATUS ret = STATUS_PROCEDURE_NOT_FOUND;
883
884     RtlEnterCriticalSection( &loader_section );
885
886     if ((exports = RtlImageDirectoryEntryToData( module, TRUE,
887                                                  IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size )))
888     {
889         void *proc = name ? find_named_export( module, exports, exp_size, name->Buffer, -1 )
890                           : find_ordinal_export( module, exports, exp_size, ord - exports->Base );
891         if (proc)
892         {
893             *address = proc;
894             ret = STATUS_SUCCESS;
895         }
896     }
897     else
898     {
899         /* check if the module itself is invalid to return the proper error */
900         if (!get_modref( module )) ret = STATUS_DLL_NOT_FOUND;
901     }
902
903     RtlLeaveCriticalSection( &loader_section );
904     return ret;
905 }
906
907
908 /***********************************************************************
909  *      allocate_lib_dir
910  *
911  * helper for MODULE_LoadLibraryExA.  Allocate space to hold the directory
912  * portion of the provided name and put the name in it.
913  *
914  */
915 static LPCSTR allocate_lib_dir(LPCSTR libname)
916 {
917     LPCSTR p, pmax;
918     LPSTR result;
919     int length;
920
921     pmax = libname;
922     if ((p = strrchr( pmax, '\\' ))) pmax = p + 1;
923     if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty.  MSDN says don't */
924     if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2;
925
926     length = pmax - libname;
927
928     result = RtlAllocateHeap (ntdll_get_process_heap(), 0, length+1);
929
930     if (result)
931     {
932         strncpy (result, libname, length);
933         result [length] = '\0';
934     }
935
936     return result;
937 }
938
939 /***********************************************************************
940  *      load_dll  (internal)
941  *
942  * Load a PE style module according to the load order.
943  *
944  * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
945  *        on this function.  When first called from LoadLibraryExA it will be
946  *        NULL but thereafter it may point to a buffer containing the path
947  *        portion of the library name.  Note that the recursion all occurs
948  *        within a Critical section (see LoadLibraryExA) so the use of a
949  *        static is acceptable.
950  *        (We have to use a static variable at some point anyway, to pass the
951  *        information from BUILTIN32_dlopen through dlopen and the builtin's
952  *        init function into load_library).
953  * allocated_libdir is TRUE in the stack frame that allocated libdir
954  */
955 static NTSTATUS load_dll( LPCSTR libname, DWORD flags, WINE_MODREF** pwm )
956 {
957     int i;
958     enum loadorder_type loadorder[LOADORDER_NTYPES];
959     LPSTR filename;
960     const char *filetype = "";
961     DWORD found;
962     BOOL allocated_libdir = FALSE;
963     static LPCSTR libdir = NULL; /* See above */
964     NTSTATUS nts = STATUS_SUCCESS;
965
966     *pwm = NULL;
967     if ( !libname ) return STATUS_DLL_NOT_FOUND; /* FIXME ? */
968
969     filename = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
970     if ( !filename ) return STATUS_NO_MEMORY;
971     *filename = 0; /* Just in case we don't set it before goto error */
972
973     RtlEnterCriticalSection( &loader_section );
974
975     if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname))
976     {
977         if (!(libdir = allocate_lib_dir(libname)))
978         {
979             nts = STATUS_NO_MEMORY;
980             goto error;
981         }
982         allocated_libdir = TRUE;
983     }
984
985     if (!libdir || allocated_libdir)
986         found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL);
987     else
988         found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL);
989
990     /* build the modules filename */
991     if (!found)
992     {
993         if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH ))
994         {
995             nts = STATUS_INTERNAL_ERROR;
996             goto error;
997         }
998     }
999
1000     /* Check for already loaded module */
1001     if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname))
1002     {
1003         LPSTR   fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 );
1004         if (fn)
1005         {
1006             /* since the default loading mechanism uses a more detailed algorithm
1007              * than SearchPath (like using PATH, which can even be modified between
1008              * two attempts of loading the same DLL), the look-up above (with
1009              * SearchPath) can have put the file in system directory, whereas it
1010              * has already been loaded but with a different path. So do a specific
1011              * look-up with filename (without any path)
1012              */
1013             strcpy ( fn, libname );
1014             /* if the filename doesn't have an extension append .DLL */
1015             if (!strrchr( fn, '.')) strcat( fn, ".dll" );
1016             if ((*pwm = MODULE_FindModule( fn )) != NULL)
1017                 strcpy( filename, fn );
1018             RtlFreeHeap( ntdll_get_process_heap(), 0, fn );
1019         }
1020     }
1021     if (*pwm)
1022     {
1023         if ((*pwm)->ldr.LoadCount != -1) (*pwm)->ldr.LoadCount++;
1024
1025         if (((*pwm)->ldr.Flags & LDR_DONT_RESOLVE_REFS) &&
1026             !(flags & DONT_RESOLVE_DLL_REFERENCES))
1027         {
1028             (*pwm)->ldr.Flags &= ~LDR_DONT_RESOLVE_REFS;
1029             PE_fixup_imports( *pwm );
1030         }
1031         TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->ldr.BaseAddress, (*pwm)->ldr.LoadCount);
1032         if (allocated_libdir)
1033         {
1034             RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
1035             libdir = NULL;
1036         }
1037         RtlLeaveCriticalSection( &loader_section );
1038         RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
1039         return STATUS_SUCCESS;
1040     }
1041
1042     MODULE_GetLoadOrder( loadorder, filename, TRUE);
1043
1044     for (i = 0; i < LOADORDER_NTYPES; i++)
1045     {
1046         if (loadorder[i] == LOADORDER_INVALID) break;
1047
1048         switch (loadorder[i])
1049         {
1050         case LOADORDER_DLL:
1051             TRACE("Trying native dll '%s'\n", filename);
1052             nts = PE_LoadLibraryExA(filename, flags, pwm);
1053             filetype = "native";
1054             break;
1055             
1056         case LOADORDER_BI:
1057             TRACE("Trying built-in '%s'\n", filename);
1058             nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm);
1059             filetype = "builtin";
1060             break;
1061             
1062         default:
1063             nts = STATUS_INTERNAL_ERROR;
1064             break;
1065         }
1066
1067         if (nts == STATUS_SUCCESS)
1068         {
1069             /* Initialize DLL just loaded */
1070             TRACE("Loaded module '%s' (%s) at %p\n", filename, filetype, (*pwm)->ldr.BaseAddress);
1071             if (!TRACE_ON(module))
1072                 TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype);
1073             /* Set the ldr.LoadCount here so that an attach failure will */
1074             /* decrement the dependencies through the MODULE_FreeLibrary call. */
1075             (*pwm)->ldr.LoadCount = 1;
1076             
1077             if (allocated_libdir)
1078             {
1079                 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
1080                 libdir = NULL;
1081             }
1082             RtlLeaveCriticalSection( &loader_section );
1083             RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
1084             return nts;
1085         }
1086
1087         if (nts != STATUS_NO_SUCH_FILE)
1088         {
1089             WARN("Loading of %s DLL %s failed (status %ld).\n",
1090                  filetype, filename, nts);
1091             break;
1092         }
1093     }
1094
1095  error:
1096     if (allocated_libdir)
1097     {
1098         RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir );
1099         libdir = NULL;
1100     }
1101     RtlLeaveCriticalSection( &loader_section );
1102     WARN("Failed to load module '%s'; status=%ld\n", filename, nts);
1103     RtlFreeHeap( ntdll_get_process_heap(), 0, filename );
1104     return nts;
1105 }
1106
1107 /******************************************************************
1108  *              LdrLoadDll (NTDLL.@)
1109  */
1110 NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libname, HMODULE* hModule)
1111 {
1112     WINE_MODREF *wm;
1113     NTSTATUS    nts = STATUS_SUCCESS;
1114     STRING      str;
1115
1116     RtlUnicodeStringToAnsiString(&str, libname, TRUE);
1117
1118     RtlEnterCriticalSection( &loader_section );
1119
1120     switch (nts = load_dll( str.Buffer, flags, &wm ))
1121     {
1122     case STATUS_SUCCESS:
1123         nts = MODULE_DllProcessAttach( wm, NULL );
1124         if (nts != STATUS_SUCCESS)
1125         {
1126             WARN("Attach failed for module '%s'.\n", str.Buffer);
1127             LdrUnloadDll(wm->ldr.BaseAddress);
1128             wm = NULL;
1129         }
1130         break;
1131     case STATUS_NO_SUCH_FILE:
1132         nts = STATUS_DLL_NOT_FOUND;
1133         break;
1134     default: /* keep error code as it is (memory...) */
1135         break;
1136     }
1137
1138     *hModule = (wm) ? wm->ldr.BaseAddress : NULL;
1139     
1140     RtlLeaveCriticalSection( &loader_section );
1141
1142     RtlFreeAnsiString(&str);
1143
1144     return nts;
1145 }
1146
1147 /******************************************************************
1148  *              LdrQueryProcessModuleInformation
1149  *
1150  */
1151 NTSTATUS WINAPI LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi, 
1152                                                  ULONG buf_size, ULONG* req_size)
1153 {
1154     SYSTEM_MODULE*      sm = &smi->Modules[0];
1155     ULONG               size = sizeof(ULONG);
1156     NTSTATUS            nts = STATUS_SUCCESS;
1157     ANSI_STRING         str;
1158     char*               ptr;
1159     WINE_MODREF*        wm;
1160
1161     smi->ModulesCount = 0;
1162
1163     RtlEnterCriticalSection( &loader_section );
1164     for ( wm = MODULE_modref_list; wm; wm = wm->next )
1165     {
1166         size += sizeof(*sm);
1167         if (size <= buf_size)
1168         {
1169             sm->Reserved1 = 0; /* FIXME */
1170             sm->Reserved2 = 0; /* FIXME */
1171             sm->ImageBaseAddress = wm->ldr.BaseAddress;
1172             sm->ImageSize = wm->ldr.SizeOfImage;
1173             sm->Flags = wm->ldr.Flags;
1174             sm->Id = 0; /* FIXME */
1175             sm->Rank = 0; /* FIXME */
1176             sm->Unknown = 0; /* FIXME */
1177             str.Length = 0;
1178             str.MaximumLength = MAXIMUM_FILENAME_LENGTH;
1179             str.Buffer = sm->Name;
1180             RtlUnicodeStringToAnsiString(&str, &wm->ldr.FullDllName, FALSE);
1181             ptr = strrchr(sm->Name, '\\');
1182             sm->NameOffset = (ptr != NULL) ? (ptr - (char*)sm->Name + 1) : 0;
1183
1184             smi->ModulesCount++;
1185             sm++;
1186         }
1187         else nts = STATUS_INFO_LENGTH_MISMATCH;
1188     }
1189     RtlLeaveCriticalSection( &loader_section );
1190
1191     if (req_size) *req_size = size;
1192
1193     return nts;
1194 }
1195
1196 /******************************************************************
1197  *              LdrShutdownProcess (NTDLL.@)
1198  *
1199  */
1200 void WINAPI LdrShutdownProcess(void)
1201 {
1202     TRACE("()\n");
1203     MODULE_DllProcessDetach( TRUE, (LPVOID)1 );
1204 }
1205
1206 /******************************************************************
1207  *              LdrShutdownThread (NTDLL.@)
1208  *
1209  */
1210 void WINAPI LdrShutdownThread(void)
1211 {
1212     WINE_MODREF *wm;
1213     TRACE("()\n");
1214
1215     /* don't do any detach calls if process is exiting */
1216     if (process_detaching) return;
1217     /* FIXME: there is still a race here */
1218
1219     RtlEnterCriticalSection( &loader_section );
1220
1221     for ( wm = MODULE_modref_list; wm; wm = wm->next )
1222     {
1223         if ( !(wm->ldr.Flags & LDR_PROCESS_ATTACHED) )
1224             continue;
1225         if ( wm->ldr.Flags & LDR_NO_DLL_CALLS )
1226             continue;
1227
1228         MODULE_InitDLL( wm, DLL_THREAD_DETACH, NULL );
1229     }
1230
1231     RtlLeaveCriticalSection( &loader_section );
1232 }
1233
1234 /***********************************************************************
1235  *           MODULE_FlushModrefs
1236  *
1237  * Remove all unused modrefs and call the internal unloading routines
1238  * for the library type.
1239  *
1240  * The loader_section must be locked while calling this function.
1241  */
1242 static void MODULE_FlushModrefs(void)
1243 {
1244     WINE_MODREF *wm, *next;
1245
1246     for (wm = MODULE_modref_list; wm; wm = next)
1247     {
1248         next = wm->next;
1249
1250         if (wm->ldr.LoadCount)
1251             continue;
1252
1253         /* Unlink this modref from the chain */
1254         if (wm->next)
1255             wm->next->prev = wm->prev;
1256         if (wm->prev)
1257             wm->prev->next = wm->next;
1258         if (wm == MODULE_modref_list)
1259             MODULE_modref_list = wm->next;
1260
1261         TRACE(" unloading %s\n", wm->filename);
1262         if (!TRACE_ON(module))
1263             TRACE_(loaddll)("Unloaded module '%s' : %s\n", wm->filename,
1264                             wm->dlhandle ? "builtin" : "native" );
1265
1266         SERVER_START_REQ( unload_dll )
1267         {
1268             req->base = wm->ldr.BaseAddress;
1269             wine_server_call( req );
1270         }
1271         SERVER_END_REQ;
1272
1273         if (wm->dlhandle) wine_dll_unload( wm->dlhandle );
1274         else NtUnmapViewOfSection( GetCurrentProcess(), wm->ldr.BaseAddress );
1275         FreeLibrary16( wm->hDummyMod );
1276         if (cached_modref == wm) cached_modref = NULL;
1277         RtlFreeHeap( ntdll_get_process_heap(), 0, wm->deps );
1278         RtlFreeHeap( ntdll_get_process_heap(), 0, wm );
1279     }
1280 }
1281
1282 /***********************************************************************
1283  *           MODULE_DecRefCount
1284  *
1285  * The loader_section must be locked while calling this function.
1286  */
1287 static void MODULE_DecRefCount( WINE_MODREF *wm )
1288 {
1289     int i;
1290
1291     if ( wm->ldr.Flags & LDR_UNLOAD_IN_PROGRESS )
1292         return;
1293
1294     if ( wm->ldr.LoadCount <= 0 )
1295         return;
1296
1297     --wm->ldr.LoadCount;
1298     TRACE("(%s) ldr.LoadCount: %d\n", wm->modname, wm->ldr.LoadCount );
1299
1300     if ( wm->ldr.LoadCount == 0 )
1301     {
1302         wm->ldr.Flags |= LDR_UNLOAD_IN_PROGRESS;
1303
1304         for ( i = 0; i < wm->nDeps; i++ )
1305             if ( wm->deps[i] )
1306                 MODULE_DecRefCount( wm->deps[i] );
1307
1308         wm->ldr.Flags &= ~LDR_UNLOAD_IN_PROGRESS;
1309     }
1310 }
1311
1312 /******************************************************************
1313  *              LdrUnloadDll (NTDLL.@)
1314  *
1315  *
1316  */
1317 NTSTATUS WINAPI LdrUnloadDll( HMODULE hModule )
1318 {
1319     NTSTATUS retv = STATUS_SUCCESS;
1320
1321     TRACE("(%p)\n", hModule);
1322
1323     RtlEnterCriticalSection( &loader_section );
1324
1325     /* if we're stopping the whole process (and forcing the removal of all
1326      * DLLs) the library will be freed anyway
1327      */
1328     if (!process_detaching)
1329     {
1330         WINE_MODREF *wm;
1331
1332         free_lib_count++;
1333         if ((wm = get_modref( hModule )) != NULL)
1334         {
1335             TRACE("(%s) - START\n", wm->modname);
1336
1337             /* Recursively decrement reference counts */
1338             MODULE_DecRefCount( wm );
1339
1340             /* Call process detach notifications */
1341             if ( free_lib_count <= 1 )
1342             {
1343                 MODULE_DllProcessDetach( FALSE, NULL );
1344                 MODULE_FlushModrefs();
1345             }
1346
1347             TRACE("END\n");
1348         }
1349         else
1350             retv = STATUS_DLL_NOT_FOUND;
1351
1352         free_lib_count--;
1353     }
1354
1355     RtlLeaveCriticalSection( &loader_section );
1356
1357     return retv;
1358 }
1359
1360 /***********************************************************************
1361  *           RtlImageNtHeader   (NTDLL.@)
1362  */
1363 PIMAGE_NT_HEADERS WINAPI RtlImageNtHeader(HMODULE hModule)
1364 {
1365     IMAGE_NT_HEADERS *ret;
1366
1367     __TRY
1368     {
1369         IMAGE_DOS_HEADER *dos = (IMAGE_DOS_HEADER *)hModule;
1370
1371         ret = NULL;
1372         if (dos->e_magic == IMAGE_DOS_SIGNATURE)
1373         {
1374             ret = (IMAGE_NT_HEADERS *)((char *)dos + dos->e_lfanew);
1375             if (ret->Signature != IMAGE_NT_SIGNATURE) ret = NULL;
1376         }
1377     }
1378     __EXCEPT(page_fault)
1379     {
1380         return NULL;
1381     }
1382     __ENDTRY
1383     return ret;
1384 }
1385
1386
1387 /***********************************************************************
1388  *           RtlImageDirectoryEntryToData   (NTDLL.@)
1389  */
1390 PVOID WINAPI RtlImageDirectoryEntryToData( HMODULE module, BOOL image, WORD dir, ULONG *size )
1391 {
1392     const IMAGE_NT_HEADERS *nt;
1393     DWORD addr;
1394
1395     if ((ULONG_PTR)module & 1)  /* mapped as data file */
1396     {
1397         module = (HMODULE)((ULONG_PTR)module & ~1);
1398         image = FALSE;
1399     }
1400     if (!(nt = RtlImageNtHeader( module ))) return NULL;
1401     if (dir >= nt->OptionalHeader.NumberOfRvaAndSizes) return NULL;
1402     if (!(addr = nt->OptionalHeader.DataDirectory[dir].VirtualAddress)) return NULL;
1403     *size = nt->OptionalHeader.DataDirectory[dir].Size;
1404     if (image || addr < nt->OptionalHeader.SizeOfHeaders) return (char *)module + addr;
1405
1406     /* not mapped as image, need to find the section containing the virtual address */
1407     return RtlImageRvaToVa( nt, module, addr, NULL );
1408 }
1409
1410
1411 /***********************************************************************
1412  *           RtlImageRvaToSection   (NTDLL.@)
1413  */
1414 PIMAGE_SECTION_HEADER WINAPI RtlImageRvaToSection( const IMAGE_NT_HEADERS *nt,
1415                                                    HMODULE module, DWORD rva )
1416 {
1417     int i;
1418     IMAGE_SECTION_HEADER *sec = (IMAGE_SECTION_HEADER*)((char*)&nt->OptionalHeader +
1419                                                         nt->FileHeader.SizeOfOptionalHeader);
1420     for (i = 0; i < nt->FileHeader.NumberOfSections; i++, sec++)
1421     {
1422         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1423             return sec;
1424     }
1425     return NULL;
1426 }
1427
1428
1429 /***********************************************************************
1430  *           RtlImageRvaToVa   (NTDLL.@)
1431  */
1432 PVOID WINAPI RtlImageRvaToVa( const IMAGE_NT_HEADERS *nt, HMODULE module,
1433                               DWORD rva, IMAGE_SECTION_HEADER **section )
1434 {
1435     IMAGE_SECTION_HEADER *sec;
1436
1437     if (section && *section)  /* try this section first */
1438     {
1439         sec = *section;
1440         if ((sec->VirtualAddress <= rva) && (sec->VirtualAddress + sec->SizeOfRawData > rva))
1441             goto found;
1442     }
1443     if (!(sec = RtlImageRvaToSection( nt, module, rva ))) return NULL;
1444  found:
1445     if (section) *section = sec;
1446     return (char *)module + sec->PointerToRawData + (rva - sec->VirtualAddress);
1447 }