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