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