4 * Copyright 1995, 2003 Alexandre Julliard
5 * Copyright 2002 Dmitry Timoshkov for Codeweavers
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.
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.
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
30 #include "wine/exception.h"
33 #include "wine/debug.h"
34 #include "wine/server.h"
35 #include "ntdll_misc.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(module
);
38 WINE_DECLARE_DEBUG_CHANNEL(relay
);
39 WINE_DECLARE_DEBUG_CHANNEL(snoop
);
40 WINE_DECLARE_DEBUG_CHANNEL(loaddll
);
42 typedef DWORD (CALLBACK
*DLLENTRYPROC
)(HMODULE
,DWORD
,LPVOID
);
44 WINE_MODREF
*MODULE_modref_list
= NULL
;
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 */
50 /* filter for page-fault exceptions */
51 static WINE_EXCEPTION_FILTER(page_fault
)
53 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION
)
54 return EXCEPTION_EXECUTE_HANDLER
;
55 return EXCEPTION_CONTINUE_SEARCH
;
58 static CRITICAL_SECTION loader_section
= CRITICAL_SECTION_INIT( "loader_section" );
59 static WINE_MODREF
*cached_modref
;
61 static NTSTATUS
load_dll( LPCSTR libname
, DWORD flags
, WINE_MODREF
** pwm
);
62 static FARPROC
find_named_export( HMODULE module
, IMAGE_EXPORT_DIRECTORY
*exports
,
63 DWORD exp_size
, const char *name
, int hint
);
65 /* convert PE image VirtualAddress to Real Address */
66 inline static void *get_rva( HMODULE module
, DWORD va
)
68 return (void *)((char *)module
+ va
);
71 /*************************************************************************
74 * Looks for the referenced HMODULE in the current process
75 * The loader_section must be locked while calling this function.
77 static WINE_MODREF
*get_modref( HMODULE hmod
)
81 if (cached_modref
&& cached_modref
->ldr
.BaseAddress
== hmod
) return cached_modref
;
83 for ( wm
= MODULE_modref_list
; wm
; wm
=wm
->next
)
85 if (wm
->ldr
.BaseAddress
== hmod
)
95 /*************************************************************************
96 * find_forwarded_export
98 * Find the final function pointer for a forwarded function.
99 * The loader_section must be locked while calling this function.
101 static FARPROC
find_forwarded_export( HMODULE module
, const char *forward
)
103 IMAGE_EXPORT_DIRECTORY
*exports
;
107 char *end
= strchr(forward
, '.');
110 if (!end
) return NULL
;
111 if (end
- forward
>= sizeof(mod_name
)) return NULL
;
112 memcpy( mod_name
, forward
, end
- forward
);
113 mod_name
[end
-forward
] = 0;
115 if (!(wm
= MODULE_FindModule( mod_name
)))
117 WINE_MODREF
*user
= get_modref( module
);
118 ERR("module not found for forward '%s' used by '%s'\n", forward
, user
->filename
);
121 if ((exports
= RtlImageDirectoryEntryToData( wm
->ldr
.BaseAddress
, TRUE
,
122 IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
)))
123 proc
= find_named_export( wm
->ldr
.BaseAddress
, exports
, exp_size
, end
+ 1, -1 );
127 WINE_MODREF
*user
= get_modref( module
);
128 ERR("function not found for forward '%s' used by '%s'."
129 " If you are using builtin '%s', try using the native one instead.\n",
130 forward
, user
->filename
, user
->modname
);
136 /*************************************************************************
137 * find_ordinal_export
139 * Find an exported function by ordinal.
140 * The exports base must have been subtracted from the ordinal already.
141 * The loader_section must be locked while calling this function.
143 static FARPROC
find_ordinal_export( HMODULE module
, IMAGE_EXPORT_DIRECTORY
*exports
,
144 DWORD exp_size
, int ordinal
)
147 WORD
*ordinals
= get_rva( module
, exports
->AddressOfNameOrdinals
);
148 DWORD
*functions
= get_rva( module
, exports
->AddressOfFunctions
);
150 if (ordinal
>= exports
->NumberOfFunctions
)
152 TRACE(" ordinal %ld out of range!\n", ordinal
+ exports
->Base
);
155 if (!functions
[ordinal
]) return NULL
;
157 proc
= get_rva( module
, functions
[ordinal
] );
159 /* if the address falls into the export dir, it's a forward */
160 if (((char *)proc
>= (char *)exports
) && ((char *)proc
< (char *)exports
+ exp_size
))
161 return find_forwarded_export( module
, (char *)proc
);
165 /* try to find a name for it */
168 DWORD
*name
= get_rva( module
, exports
->AddressOfNames
);
169 if (name
) for (i
= 0; i
< exports
->NumberOfNames
; i
++)
171 if (ordinals
[i
] == ordinal
)
173 ename
= get_rva( module
, name
[i
] );
177 proc
= SNOOP_GetProcAddress( module
, ename
, ordinal
, proc
);
183 /*************************************************************************
186 * Find an exported function by name.
187 * The loader_section must be locked while calling this function.
189 static FARPROC
find_named_export( HMODULE module
, IMAGE_EXPORT_DIRECTORY
*exports
,
190 DWORD exp_size
, const char *name
, int hint
)
192 WORD
*ordinals
= get_rva( module
, exports
->AddressOfNameOrdinals
);
193 DWORD
*names
= get_rva( module
, exports
->AddressOfNames
);
194 int min
= 0, max
= exports
->NumberOfNames
- 1;
196 /* first check the hint */
197 if (hint
>= 0 && hint
<= max
)
199 char *ename
= get_rva( module
, names
[hint
] );
200 if (!strcmp( ename
, name
))
201 return find_ordinal_export( module
, exports
, exp_size
, ordinals
[hint
] );
204 /* then do a binary search */
207 int res
, pos
= (min
+ max
) / 2;
208 char *ename
= get_rva( module
, names
[pos
] );
209 if (!(res
= strcmp( ename
, name
)))
210 return find_ordinal_export( module
, exports
, exp_size
, ordinals
[pos
] );
211 if (res
> 0) max
= pos
- 1;
219 /*************************************************************************
222 * Import the dll specified by the given import descriptor.
223 * The loader_section must be locked while calling this function.
225 static WINE_MODREF
*import_dll( HMODULE module
, IMAGE_IMPORT_DESCRIPTOR
*descr
)
230 IMAGE_EXPORT_DIRECTORY
*exports
;
232 IMAGE_THUNK_DATA
*import_list
, *thunk_list
;
233 char *name
= get_rva( module
, descr
->Name
);
235 status
= load_dll( name
, 0, &wmImp
);
238 WINE_MODREF
*user
= get_modref( module
);
239 if (status
== STATUS_NO_SUCH_FILE
)
240 ERR("Module (file) %s (which is needed by %s) not found\n", name
, user
->filename
);
242 ERR("Loading module (file) %s (which is needed by %s) failed (error %ld).\n",
243 name
, user
->filename
, status
);
247 imp_mod
= wmImp
->ldr
.BaseAddress
;
248 if (!(exports
= RtlImageDirectoryEntryToData( imp_mod
, TRUE
,
249 IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
)))
252 thunk_list
= get_rva( module
, (DWORD
)descr
->FirstThunk
);
253 if (descr
->u
.OriginalFirstThunk
)
254 import_list
= get_rva( module
, (DWORD
)descr
->u
.OriginalFirstThunk
);
256 import_list
= thunk_list
;
258 while (import_list
->u1
.Ordinal
)
260 if (IMAGE_SNAP_BY_ORDINAL(import_list
->u1
.Ordinal
))
262 int ordinal
= IMAGE_ORDINAL(import_list
->u1
.Ordinal
);
264 TRACE("--- Ordinal %s,%d\n", name
, ordinal
);
265 thunk_list
->u1
.Function
= (PDWORD
)find_ordinal_export( imp_mod
, exports
, exp_size
,
266 ordinal
- exports
->Base
);
267 if (!thunk_list
->u1
.Function
)
269 WINE_MODREF
*user
= get_modref( module
);
270 ERR("No implementation for %s.%d imported from %s, setting to 0xdeadbeef\n",
271 name
, ordinal
, user
->filename
);
272 thunk_list
->u1
.Function
= (PDWORD
)0xdeadbeef;
275 else /* import by name */
277 IMAGE_IMPORT_BY_NAME
*pe_name
;
278 pe_name
= get_rva( module
, (DWORD
)import_list
->u1
.AddressOfData
);
279 TRACE("--- %s %s.%d\n", pe_name
->Name
, name
, pe_name
->Hint
);
280 thunk_list
->u1
.Function
= (PDWORD
)find_named_export( imp_mod
, exports
, exp_size
,
281 pe_name
->Name
, pe_name
->Hint
);
282 if (!thunk_list
->u1
.Function
)
284 WINE_MODREF
*user
= get_modref( module
);
285 ERR("No implementation for %s.%s imported from %s, setting to 0xdeadbeef\n",
286 name
, pe_name
->Name
, user
->filename
);
287 thunk_list
->u1
.Function
= (PDWORD
)0xdeadbeef;
297 /****************************************************************
300 * Fixup all imports of a given module.
301 * The loader_section must be locked while calling this function.
303 DWORD
PE_fixup_imports( WINE_MODREF
*wm
)
306 IMAGE_IMPORT_DESCRIPTOR
*imports
;
309 if (!(imports
= RtlImageDirectoryEntryToData( wm
->ldr
.BaseAddress
, TRUE
,
310 IMAGE_DIRECTORY_ENTRY_IMPORT
, &size
)))
313 nb_imports
= size
/ sizeof(*imports
);
314 for (i
= 0; i
< nb_imports
; i
++)
316 if (!imports
[i
].Name
)
322 if (!nb_imports
) return 0; /* no imports */
324 /* Allocate module dependency list */
325 wm
->nDeps
= nb_imports
;
326 wm
->deps
= RtlAllocateHeap( ntdll_get_process_heap(), 0, nb_imports
*sizeof(WINE_MODREF
*) );
328 /* load the imported modules. They are automatically
329 * added to the modref list of the process.
331 for (i
= 0; i
< nb_imports
; i
++)
333 if (!(wm
->deps
[i
] = import_dll( wm
->ldr
.BaseAddress
, &imports
[i
] ))) return 1;
339 /*************************************************************************
342 * Allocate a WINE_MODREF structure and add it to the process list
343 * The loader_section must be locked while calling this function.
345 WINE_MODREF
*MODULE_AllocModRef( HMODULE hModule
, LPCSTR filename
)
348 IMAGE_NT_HEADERS
*nt
= RtlImageNtHeader(hModule
);
350 DWORD long_len
= strlen( filename
);
351 DWORD short_len
= GetShortPathNameA( filename
, NULL
, 0 );
353 if ((wm
= RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY
,
354 sizeof(*wm
) + long_len
+ short_len
+ 1 )))
356 wm
->filename
= wm
->data
;
357 memcpy( wm
->filename
, filename
, long_len
+ 1 );
358 if ((wm
->modname
= strrchr( wm
->filename
, '\\' ))) wm
->modname
++;
359 else wm
->modname
= wm
->filename
;
361 wm
->short_filename
= wm
->filename
+ long_len
+ 1;
362 GetShortPathNameA( wm
->filename
, wm
->short_filename
, short_len
+ 1 );
363 if ((wm
->short_modname
= strrchr( wm
->short_filename
, '\\' ))) wm
->short_modname
++;
364 else wm
->short_modname
= wm
->short_filename
;
366 wm
->next
= MODULE_modref_list
;
367 if (wm
->next
) wm
->next
->prev
= wm
;
368 MODULE_modref_list
= wm
;
370 wm
->ldr
.InLoadOrderModuleList
.Flink
= NULL
;
371 wm
->ldr
.InLoadOrderModuleList
.Blink
= NULL
;
372 wm
->ldr
.InMemoryOrderModuleList
.Flink
= NULL
;
373 wm
->ldr
.InMemoryOrderModuleList
.Blink
= NULL
;
374 wm
->ldr
.InInitializationOrderModuleList
.Flink
= NULL
;
375 wm
->ldr
.InInitializationOrderModuleList
.Blink
= NULL
;
376 wm
->ldr
.BaseAddress
= hModule
;
377 wm
->ldr
.EntryPoint
= (nt
->OptionalHeader
.AddressOfEntryPoint
) ?
378 ((char *)hModule
+ nt
->OptionalHeader
.AddressOfEntryPoint
) : 0;
379 wm
->ldr
.SizeOfImage
= nt
->OptionalHeader
.SizeOfImage
;
380 RtlCreateUnicodeStringFromAsciiz( &wm
->ldr
.FullDllName
, wm
->filename
);
381 RtlCreateUnicodeStringFromAsciiz( &wm
->ldr
.BaseDllName
, wm
->modname
);
383 wm
->ldr
.LoadCount
= 0;
384 wm
->ldr
.TlsIndex
= -1;
385 wm
->ldr
.SectionHandle
= NULL
;
386 wm
->ldr
.CheckSum
= 0;
387 wm
->ldr
.TimeDateStamp
= 0;
389 if (!(nt
->FileHeader
.Characteristics
& IMAGE_FILE_DLL
))
391 if (!exe_modref
) exe_modref
= wm
;
392 else FIXME( "Trying to load second .EXE file: %s\n", filename
);
394 else wm
->ldr
.Flags
|= LDR_IMAGE_IS_DLL
;
399 /*************************************************************************
402 static BOOL
MODULE_InitDLL( WINE_MODREF
*wm
, DWORD type
, LPVOID lpReserved
)
404 static const char * const typeName
[] = { "PROCESS_DETACH", "PROCESS_ATTACH",
405 "THREAD_ATTACH", "THREAD_DETACH" };
407 DLLENTRYPROC entry
= wm
->ldr
.EntryPoint
;
408 void *module
= wm
->ldr
.BaseAddress
;
410 /* Skip calls for modules loaded with special load flags */
412 if (wm
->ldr
.Flags
& LDR_DONT_RESOLVE_REFS
) return TRUE
;
413 if (!entry
|| !(wm
->ldr
.Flags
& LDR_IMAGE_IS_DLL
)) return TRUE
;
415 TRACE("(%p (%s),%s,%p) - CALL\n", module
, wm
->modname
, typeName
[type
], lpReserved
);
418 DPRINTF("%04lx:Call PE DLL (proc=%p,module=%p,type=%ld,res=%p)\n",
419 GetCurrentThreadId(), entry
, module
, type
, lpReserved
);
421 retv
= entry( module
, type
, lpReserved
);
424 DPRINTF("%04lx:Ret PE DLL (proc=%p,module=%p,type=%ld,res=%p) retval=%x\n",
425 GetCurrentThreadId(), entry
, module
, type
, lpReserved
, retv
);
427 /* The state of the module list may have changed due to the call
428 to the dll. We cannot assume that this module has not been
430 TRACE("(%p,%s,%p) - RETURN %d\n", module
, typeName
[type
], lpReserved
, retv
);
436 /*************************************************************************
437 * MODULE_DllProcessAttach
439 * Send the process attach notification to all DLLs the given module
440 * depends on (recursively). This is somewhat complicated due to the fact that
442 * - we have to respect the module dependencies, i.e. modules implicitly
443 * referenced by another module have to be initialized before the module
444 * itself can be initialized
446 * - the initialization routine of a DLL can itself call LoadLibrary,
447 * thereby introducing a whole new set of dependencies (even involving
448 * the 'old' modules) at any time during the whole process
450 * (Note that this routine can be recursively entered not only directly
451 * from itself, but also via LoadLibrary from one of the called initialization
454 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
455 * the process *detach* notifications to be sent in the correct order.
456 * This must not only take into account module dependencies, but also
457 * 'hidden' dependencies created by modules calling LoadLibrary in their
458 * attach notification routine.
460 * The strategy is rather simple: we move a WINE_MODREF to the head of the
461 * list after the attach notification has returned. This implies that the
462 * detach notifications are called in the reverse of the sequence the attach
463 * notifications *returned*.
465 BOOL
MODULE_DllProcessAttach( WINE_MODREF
*wm
, LPVOID lpReserved
)
470 RtlEnterCriticalSection( &loader_section
);
479 /* prevent infinite recursion in case of cyclical dependencies */
480 if ( ( wm
->ldr
.Flags
& LDR_LOAD_IN_PROGRESS
)
481 || ( wm
->ldr
.Flags
& LDR_PROCESS_ATTACHED
) )
484 TRACE("(%s,%p) - START\n", wm
->modname
, lpReserved
);
486 /* Tag current MODREF to prevent recursive loop */
487 wm
->ldr
.Flags
|= LDR_LOAD_IN_PROGRESS
;
489 /* Recursively attach all DLLs this one depends on */
490 for ( i
= 0; retv
&& i
< wm
->nDeps
; i
++ )
492 retv
= MODULE_DllProcessAttach( wm
->deps
[i
], lpReserved
);
494 /* Call DLL entry point */
497 retv
= MODULE_InitDLL( wm
, DLL_PROCESS_ATTACH
, lpReserved
);
499 wm
->ldr
.Flags
|= LDR_PROCESS_ATTACHED
;
502 /* Re-insert MODREF at head of list */
503 if ( retv
&& wm
->prev
)
505 wm
->prev
->next
= wm
->next
;
506 if ( wm
->next
) wm
->next
->prev
= wm
->prev
;
509 wm
->next
= MODULE_modref_list
;
510 MODULE_modref_list
= wm
->next
->prev
= wm
;
513 /* Remove recursion flag */
514 wm
->ldr
.Flags
&= ~LDR_LOAD_IN_PROGRESS
;
516 TRACE("(%s,%p) - END\n", wm
->modname
, lpReserved
);
520 RtlLeaveCriticalSection( &loader_section
);
524 /*************************************************************************
525 * MODULE_DllProcessDetach
527 * Send DLL process detach notifications. See the comment about calling
528 * sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
529 * is set, only DLLs with zero refcount are notified.
531 void MODULE_DllProcessDetach( BOOL bForceDetach
, LPVOID lpReserved
)
535 RtlEnterCriticalSection( &loader_section
);
536 if (bForceDetach
) process_detaching
= 1;
539 for ( wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
541 /* Check whether to detach this DLL */
542 if ( !(wm
->ldr
.Flags
& LDR_PROCESS_ATTACHED
) )
544 if ( wm
->ldr
.LoadCount
> 0 && !bForceDetach
)
547 /* Call detach notification */
548 wm
->ldr
.Flags
&= ~LDR_PROCESS_ATTACHED
;
549 MODULE_InitDLL( wm
, DLL_PROCESS_DETACH
, lpReserved
);
551 /* Restart at head of WINE_MODREF list, as entries might have
552 been added and/or removed while performing the call ... */
557 RtlLeaveCriticalSection( &loader_section
);
560 /*************************************************************************
561 * MODULE_DllThreadAttach
563 * Send DLL thread attach notifications. These are sent in the
564 * reverse sequence of process detach notification.
567 void MODULE_DllThreadAttach( LPVOID lpReserved
)
571 /* don't do any attach calls if process is exiting */
572 if (process_detaching
) return;
573 /* FIXME: there is still a race here */
575 RtlEnterCriticalSection( &loader_section
);
579 for ( wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
583 for ( ; wm
; wm
= wm
->prev
)
585 if ( !(wm
->ldr
.Flags
& LDR_PROCESS_ATTACHED
) )
587 if ( wm
->ldr
.Flags
& LDR_NO_DLL_CALLS
)
590 MODULE_InitDLL( wm
, DLL_THREAD_ATTACH
, lpReserved
);
593 RtlLeaveCriticalSection( &loader_section
);
596 /******************************************************************
597 * LdrDisableThreadCalloutsForDll (NTDLL.@)
600 NTSTATUS WINAPI
LdrDisableThreadCalloutsForDll(HMODULE hModule
)
603 NTSTATUS ret
= STATUS_SUCCESS
;
605 RtlEnterCriticalSection( &loader_section
);
607 wm
= get_modref( hModule
);
609 ret
= STATUS_DLL_NOT_FOUND
;
611 wm
->ldr
.Flags
|= LDR_NO_DLL_CALLS
;
613 RtlLeaveCriticalSection( &loader_section
);
618 /******************************************************************
619 * LdrFindEntryForAddress (NTDLL.@)
621 * The loader_section must be locked while calling this function
623 NTSTATUS WINAPI
LdrFindEntryForAddress(const void* addr
, PLDR_MODULE
* mod
)
627 for ( wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
629 if ((const void *)wm
->ldr
.BaseAddress
<= addr
&&
630 (char *)addr
< (char*)wm
->ldr
.BaseAddress
+ wm
->ldr
.SizeOfImage
)
633 return STATUS_SUCCESS
;
636 return STATUS_NO_MORE_ENTRIES
;
639 /**********************************************************************
642 * Find a (loaded) win32 module depending on path
643 * LPCSTR path: [in] pathname of module/library to be found
645 * The loader_section must be locked while calling this function
647 * the module handle if found
650 WINE_MODREF
*MODULE_FindModule(LPCSTR path
)
653 char dllname
[260], *p
;
655 /* Append .DLL to name if no extension present */
656 strcpy( dllname
, path
);
657 if (!(p
= strrchr( dllname
, '.')) || strchr( p
, '/' ) || strchr( p
, '\\'))
658 strcat( dllname
, ".DLL" );
660 if ((wm
= cached_modref
) != NULL
)
662 if ( !FILE_strcasecmp( dllname
, wm
->modname
) ) return wm
;
663 if ( !FILE_strcasecmp( dllname
, wm
->filename
) ) return wm
;
664 if ( !FILE_strcasecmp( dllname
, wm
->short_modname
) ) return wm
;
665 if ( !FILE_strcasecmp( dllname
, wm
->short_filename
) ) return wm
;
668 for ( wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
670 if ( !FILE_strcasecmp( dllname
, wm
->modname
) ) break;
671 if ( !FILE_strcasecmp( dllname
, wm
->filename
) ) break;
672 if ( !FILE_strcasecmp( dllname
, wm
->short_modname
) ) break;
673 if ( !FILE_strcasecmp( dllname
, wm
->short_filename
) ) break;
680 /******************************************************************
681 * LdrLockLoaderLock (NTDLL.@)
683 * Note: flags are not implemented.
684 * Flag 0x01 is used to raise exceptions on errors.
685 * Flag 0x02 is used to avoid waiting on the section (does RtlTryEnterCriticalSection instead).
687 NTSTATUS WINAPI
LdrLockLoaderLock( ULONG flags
, ULONG
*result
, ULONG
*magic
)
689 if (flags
) FIXME( "flags %lx not supported\n", flags
);
691 if (result
) *result
= 1;
692 if (!magic
) return STATUS_INVALID_PARAMETER_3
;
693 RtlEnterCriticalSection( &loader_section
);
694 *magic
= GetCurrentThreadId();
695 return STATUS_SUCCESS
;
699 /******************************************************************
700 * LdrUnlockLoaderUnlock (NTDLL.@)
702 NTSTATUS WINAPI
LdrUnlockLoaderLock( ULONG flags
, ULONG magic
)
706 if (magic
!= GetCurrentThreadId()) return STATUS_INVALID_PARAMETER_2
;
707 RtlLeaveCriticalSection( &loader_section
);
709 return STATUS_SUCCESS
;
713 /******************************************************************
714 * LdrGetDllHandle (NTDLL.@)
718 NTSTATUS WINAPI
LdrGetDllHandle(ULONG x
, ULONG y
, PUNICODE_STRING name
, HMODULE
*base
)
723 if (x
!= 0 || y
!= 0)
724 FIXME("Unknown behavior, please report\n");
726 /* FIXME: we should store module name information as unicode */
727 RtlUnicodeStringToAnsiString( &str
, name
, TRUE
);
728 wm
= MODULE_FindModule( str
.Buffer
);
729 RtlFreeAnsiString( &str
);
734 return STATUS_DLL_NOT_FOUND
;
737 *base
= wm
->ldr
.BaseAddress
;
739 TRACE("%lx %lx %s -> %p\n", x
, y
, debugstr_us(name
), *base
);
741 return STATUS_SUCCESS
;
745 /******************************************************************
746 * LdrGetProcedureAddress (NTDLL.@)
748 NTSTATUS WINAPI
LdrGetProcedureAddress(HMODULE module
, PANSI_STRING name
, ULONG ord
, PVOID
*address
)
750 IMAGE_EXPORT_DIRECTORY
*exports
;
752 NTSTATUS ret
= STATUS_PROCEDURE_NOT_FOUND
;
754 RtlEnterCriticalSection( &loader_section
);
756 if ((exports
= RtlImageDirectoryEntryToData( module
, TRUE
,
757 IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
)))
759 void *proc
= name
? find_named_export( module
, exports
, exp_size
, name
->Buffer
, -1 )
760 : find_ordinal_export( module
, exports
, exp_size
, ord
- exports
->Base
);
764 ret
= STATUS_SUCCESS
;
769 /* check if the module itself is invalid to return the proper error */
770 if (!get_modref( module
)) ret
= STATUS_DLL_NOT_FOUND
;
773 RtlLeaveCriticalSection( &loader_section
);
778 /***********************************************************************
781 * helper for MODULE_LoadLibraryExA. Allocate space to hold the directory
782 * portion of the provided name and put the name in it.
785 static LPCSTR
allocate_lib_dir(LPCSTR libname
)
792 if ((p
= strrchr( pmax
, '\\' ))) pmax
= p
+ 1;
793 if ((p
= strrchr( pmax
, '/' ))) pmax
= p
+ 1; /* Naughty. MSDN says don't */
794 if (pmax
== libname
&& pmax
[0] && pmax
[1] == ':') pmax
+= 2;
796 length
= pmax
- libname
;
798 result
= RtlAllocateHeap (ntdll_get_process_heap(), 0, length
+1);
802 strncpy (result
, libname
, length
);
803 result
[length
] = '\0';
809 /***********************************************************************
810 * load_dll (internal)
812 * Load a PE style module according to the load order.
814 * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion
815 * on this function. When first called from LoadLibraryExA it will be
816 * NULL but thereafter it may point to a buffer containing the path
817 * portion of the library name. Note that the recursion all occurs
818 * within a Critical section (see LoadLibraryExA) so the use of a
819 * static is acceptable.
820 * (We have to use a static variable at some point anyway, to pass the
821 * information from BUILTIN32_dlopen through dlopen and the builtin's
822 * init function into load_library).
823 * allocated_libdir is TRUE in the stack frame that allocated libdir
825 static NTSTATUS
load_dll( LPCSTR libname
, DWORD flags
, WINE_MODREF
** pwm
)
828 enum loadorder_type loadorder
[LOADORDER_NTYPES
];
830 const char *filetype
= "";
832 BOOL allocated_libdir
= FALSE
;
833 static LPCSTR libdir
= NULL
; /* See above */
834 NTSTATUS nts
= STATUS_SUCCESS
;
837 if ( !libname
) return STATUS_DLL_NOT_FOUND
; /* FIXME ? */
839 filename
= RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH
+ 1 );
840 if ( !filename
) return STATUS_NO_MEMORY
;
841 *filename
= 0; /* Just in case we don't set it before goto error */
843 RtlEnterCriticalSection( &loader_section
);
845 if ((flags
& LOAD_WITH_ALTERED_SEARCH_PATH
) && FILE_contains_path(libname
))
847 if (!(libdir
= allocate_lib_dir(libname
)))
849 nts
= STATUS_NO_MEMORY
;
852 allocated_libdir
= TRUE
;
855 if (!libdir
|| allocated_libdir
)
856 found
= SearchPathA(NULL
, libname
, ".dll", MAX_PATH
, filename
, NULL
);
858 found
= DIR_SearchAlternatePath(libdir
, libname
, ".dll", MAX_PATH
, filename
, NULL
);
860 /* build the modules filename */
863 if (!MODULE_GetBuiltinPath( libname
, ".dll", filename
, MAX_PATH
))
865 nts
= STATUS_INTERNAL_ERROR
;
870 /* Check for already loaded module */
871 if (!(*pwm
= MODULE_FindModule(filename
)) && !FILE_contains_path(libname
))
873 LPSTR fn
= RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH
+ 1 );
876 /* since the default loading mechanism uses a more detailed algorithm
877 * than SearchPath (like using PATH, which can even be modified between
878 * two attempts of loading the same DLL), the look-up above (with
879 * SearchPath) can have put the file in system directory, whereas it
880 * has already been loaded but with a different path. So do a specific
881 * look-up with filename (without any path)
883 strcpy ( fn
, libname
);
884 /* if the filename doesn't have an extension append .DLL */
885 if (!strrchr( fn
, '.')) strcat( fn
, ".dll" );
886 if ((*pwm
= MODULE_FindModule( fn
)) != NULL
)
887 strcpy( filename
, fn
);
888 RtlFreeHeap( ntdll_get_process_heap(), 0, fn
);
893 (*pwm
)->ldr
.LoadCount
++;
895 if (((*pwm
)->ldr
.Flags
& LDR_DONT_RESOLVE_REFS
) &&
896 !(flags
& DONT_RESOLVE_DLL_REFERENCES
))
898 (*pwm
)->ldr
.Flags
&= ~LDR_DONT_RESOLVE_REFS
;
899 PE_fixup_imports( *pwm
);
901 TRACE("Already loaded module '%s' at %p, count=%d\n", filename
, (*pwm
)->ldr
.BaseAddress
, (*pwm
)->ldr
.LoadCount
);
902 if (allocated_libdir
)
904 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR
)libdir
);
907 RtlLeaveCriticalSection( &loader_section
);
908 RtlFreeHeap( ntdll_get_process_heap(), 0, filename
);
909 return STATUS_SUCCESS
;
912 MODULE_GetLoadOrder( loadorder
, filename
, TRUE
);
914 for (i
= 0; i
< LOADORDER_NTYPES
; i
++)
916 if (loadorder
[i
] == LOADORDER_INVALID
) break;
918 switch (loadorder
[i
])
921 TRACE("Trying native dll '%s'\n", filename
);
922 nts
= PE_LoadLibraryExA(filename
, flags
, pwm
);
927 TRACE("Trying built-in '%s'\n", filename
);
928 nts
= BUILTIN32_LoadLibraryExA(filename
, flags
, pwm
);
929 filetype
= "builtin";
933 nts
= STATUS_INTERNAL_ERROR
;
937 if (nts
== STATUS_SUCCESS
)
939 /* Initialize DLL just loaded */
940 TRACE("Loaded module '%s' (%s) at %p\n", filename
, filetype
, (*pwm
)->ldr
.BaseAddress
);
941 if (!TRACE_ON(module
))
942 TRACE_(loaddll
)("Loaded module '%s' : %s\n", filename
, filetype
);
943 /* Set the ldr.LoadCount here so that an attach failure will */
944 /* decrement the dependencies through the MODULE_FreeLibrary call. */
945 (*pwm
)->ldr
.LoadCount
= 1;
947 if (allocated_libdir
)
949 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR
)libdir
);
952 RtlLeaveCriticalSection( &loader_section
);
953 RtlFreeHeap( ntdll_get_process_heap(), 0, filename
);
957 if (nts
!= STATUS_NO_SUCH_FILE
)
959 WARN("Loading of %s DLL %s failed (status %ld).\n",
960 filetype
, filename
, nts
);
966 if (allocated_libdir
)
968 RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR
)libdir
);
971 RtlLeaveCriticalSection( &loader_section
);
972 WARN("Failed to load module '%s'; status=%ld\n", filename
, nts
);
973 RtlFreeHeap( ntdll_get_process_heap(), 0, filename
);
977 /******************************************************************
978 * LdrLoadDll (NTDLL.@)
980 NTSTATUS WINAPI
LdrLoadDll(LPCWSTR path_name
, DWORD flags
, PUNICODE_STRING libname
, HMODULE
* hModule
)
983 NTSTATUS nts
= STATUS_SUCCESS
;
986 RtlUnicodeStringToAnsiString(&str
, libname
, TRUE
);
988 RtlEnterCriticalSection( &loader_section
);
990 switch (nts
= load_dll( str
.Buffer
, flags
, &wm
))
993 if ( !MODULE_DllProcessAttach( wm
, NULL
) )
995 WARN("Attach failed for module '%s'.\n", str
.Buffer
);
996 LdrUnloadDll(wm
->ldr
.BaseAddress
);
997 nts
= STATUS_DLL_INIT_FAILED
;
1001 case STATUS_NO_SUCH_FILE
:
1002 nts
= STATUS_DLL_NOT_FOUND
;
1004 default: /* keep error code as it is (memory...) */
1008 *hModule
= (wm
) ? wm
->ldr
.BaseAddress
: NULL
;
1010 RtlLeaveCriticalSection( &loader_section
);
1012 RtlFreeAnsiString(&str
);
1017 /******************************************************************
1018 * LdrQueryProcessModuleInformation
1021 NTSTATUS WINAPI
LdrQueryProcessModuleInformation(PSYSTEM_MODULE_INFORMATION smi
,
1022 ULONG buf_size
, ULONG
* req_size
)
1024 SYSTEM_MODULE
* sm
= &smi
->Modules
[0];
1025 ULONG size
= sizeof(ULONG
);
1026 NTSTATUS nts
= STATUS_SUCCESS
;
1031 smi
->ModulesCount
= 0;
1033 RtlEnterCriticalSection( &loader_section
);
1034 for ( wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
1036 size
+= sizeof(*sm
);
1037 if (size
<= buf_size
)
1039 sm
->Reserved1
= 0; /* FIXME */
1040 sm
->Reserved2
= 0; /* FIXME */
1041 sm
->ImageBaseAddress
= wm
->ldr
.BaseAddress
;
1042 sm
->ImageSize
= wm
->ldr
.SizeOfImage
;
1043 sm
->Flags
= wm
->ldr
.Flags
;
1044 sm
->Id
= 0; /* FIXME */
1045 sm
->Rank
= 0; /* FIXME */
1046 sm
->Unknown
= 0; /* FIXME */
1048 str
.MaximumLength
= MAXIMUM_FILENAME_LENGTH
;
1049 str
.Buffer
= sm
->Name
;
1050 RtlUnicodeStringToAnsiString(&str
, &wm
->ldr
.FullDllName
, FALSE
);
1051 ptr
= strrchr(sm
->Name
, '\\');
1052 sm
->NameOffset
= (ptr
!= NULL
) ? (ptr
- (char*)sm
->Name
+ 1) : 0;
1054 smi
->ModulesCount
++;
1057 else nts
= STATUS_INFO_LENGTH_MISMATCH
;
1059 RtlLeaveCriticalSection( &loader_section
);
1061 if (req_size
) *req_size
= size
;
1066 /******************************************************************
1067 * LdrShutdownProcess (NTDLL.@)
1070 NTSTATUS WINAPI
LdrShutdownProcess(void)
1073 MODULE_DllProcessDetach( TRUE
, (LPVOID
)1 );
1074 return STATUS_SUCCESS
; /* FIXME */
1077 /******************************************************************
1078 * LdrShutdownThread (NTDLL.@)
1081 NTSTATUS WINAPI
LdrShutdownThread(void)
1086 /* don't do any detach calls if process is exiting */
1087 if (process_detaching
) return STATUS_SUCCESS
;
1088 /* FIXME: there is still a race here */
1090 RtlEnterCriticalSection( &loader_section
);
1092 for ( wm
= MODULE_modref_list
; wm
; wm
= wm
->next
)
1094 if ( !(wm
->ldr
.Flags
& LDR_PROCESS_ATTACHED
) )
1096 if ( wm
->ldr
.Flags
& LDR_NO_DLL_CALLS
)
1099 MODULE_InitDLL( wm
, DLL_THREAD_DETACH
, NULL
);
1102 RtlLeaveCriticalSection( &loader_section
);
1103 return STATUS_SUCCESS
; /* FIXME */
1106 /***********************************************************************
1107 * MODULE_FlushModrefs
1109 * Remove all unused modrefs and call the internal unloading routines
1110 * for the library type.
1112 * The loader_section must be locked while calling this function.
1114 static void MODULE_FlushModrefs(void)
1116 WINE_MODREF
*wm
, *next
;
1118 for (wm
= MODULE_modref_list
; wm
; wm
= next
)
1122 if (wm
->ldr
.LoadCount
)
1125 /* Unlink this modref from the chain */
1127 wm
->next
->prev
= wm
->prev
;
1129 wm
->prev
->next
= wm
->next
;
1130 if (wm
== MODULE_modref_list
)
1131 MODULE_modref_list
= wm
->next
;
1133 TRACE(" unloading %s\n", wm
->filename
);
1134 if (!TRACE_ON(module
))
1135 TRACE_(loaddll
)("Unloaded module '%s' : %s\n", wm
->filename
,
1136 wm
->dlhandle
? "builtin" : "native" );
1138 SERVER_START_REQ( unload_dll
)
1140 req
->base
= wm
->ldr
.BaseAddress
;
1141 wine_server_call( req
);
1145 if (wm
->dlhandle
) wine_dll_unload( wm
->dlhandle
);
1146 else NtUnmapViewOfSection( GetCurrentProcess(), wm
->ldr
.BaseAddress
);
1147 FreeLibrary16( wm
->hDummyMod
);
1148 if (cached_modref
== wm
) cached_modref
= NULL
;
1149 RtlFreeHeap( ntdll_get_process_heap(), 0, wm
->deps
);
1150 RtlFreeHeap( ntdll_get_process_heap(), 0, wm
);
1154 /***********************************************************************
1155 * MODULE_DecRefCount
1157 * The loader_section must be locked while calling this function.
1159 static void MODULE_DecRefCount( WINE_MODREF
*wm
)
1163 if ( wm
->ldr
.Flags
& LDR_UNLOAD_IN_PROGRESS
)
1166 if ( wm
->ldr
.LoadCount
<= 0 )
1169 --wm
->ldr
.LoadCount
;
1170 TRACE("(%s) ldr.LoadCount: %d\n", wm
->modname
, wm
->ldr
.LoadCount
);
1172 if ( wm
->ldr
.LoadCount
== 0 )
1174 wm
->ldr
.Flags
|= LDR_UNLOAD_IN_PROGRESS
;
1176 for ( i
= 0; i
< wm
->nDeps
; i
++ )
1178 MODULE_DecRefCount( wm
->deps
[i
] );
1180 wm
->ldr
.Flags
&= ~LDR_UNLOAD_IN_PROGRESS
;
1184 /******************************************************************
1185 * LdrUnloadDll (NTDLL.@)
1189 NTSTATUS WINAPI
LdrUnloadDll( HMODULE hModule
)
1191 NTSTATUS retv
= STATUS_SUCCESS
;
1193 TRACE("(%p)\n", hModule
);
1195 RtlEnterCriticalSection( &loader_section
);
1197 /* if we're stopping the whole process (and forcing the removal of all
1198 * DLLs) the library will be freed anyway
1200 if (!process_detaching
)
1205 if ((wm
= get_modref( hModule
)) != NULL
)
1207 TRACE("(%s) - START\n", wm
->modname
);
1209 /* Recursively decrement reference counts */
1210 MODULE_DecRefCount( wm
);
1212 /* Call process detach notifications */
1213 if ( free_lib_count
<= 1 )
1215 MODULE_DllProcessDetach( FALSE
, NULL
);
1216 MODULE_FlushModrefs();
1222 retv
= STATUS_DLL_NOT_FOUND
;
1227 RtlLeaveCriticalSection( &loader_section
);
1232 /***********************************************************************
1233 * RtlImageNtHeader (NTDLL.@)
1235 PIMAGE_NT_HEADERS WINAPI
RtlImageNtHeader(HMODULE hModule
)
1237 IMAGE_NT_HEADERS
*ret
;
1241 IMAGE_DOS_HEADER
*dos
= (IMAGE_DOS_HEADER
*)hModule
;
1244 if (dos
->e_magic
== IMAGE_DOS_SIGNATURE
)
1246 ret
= (IMAGE_NT_HEADERS
*)((char *)dos
+ dos
->e_lfanew
);
1247 if (ret
->Signature
!= IMAGE_NT_SIGNATURE
) ret
= NULL
;
1250 __EXCEPT(page_fault
)
1259 /***********************************************************************
1260 * RtlImageDirectoryEntryToData (NTDLL.@)
1262 PVOID WINAPI
RtlImageDirectoryEntryToData( HMODULE module
, BOOL image
, WORD dir
, ULONG
*size
)
1264 const IMAGE_NT_HEADERS
*nt
;
1267 if ((ULONG_PTR
)module
& 1) /* mapped as data file */
1269 module
= (HMODULE
)((ULONG_PTR
)module
& ~1);
1272 if (!(nt
= RtlImageNtHeader( module
))) return NULL
;
1273 if (dir
>= nt
->OptionalHeader
.NumberOfRvaAndSizes
) return NULL
;
1274 if (!(addr
= nt
->OptionalHeader
.DataDirectory
[dir
].VirtualAddress
)) return NULL
;
1275 *size
= nt
->OptionalHeader
.DataDirectory
[dir
].Size
;
1276 if (image
|| addr
< nt
->OptionalHeader
.SizeOfHeaders
) return (char *)module
+ addr
;
1278 /* not mapped as image, need to find the section containing the virtual address */
1279 return RtlImageRvaToVa( nt
, module
, addr
, NULL
);
1283 /***********************************************************************
1284 * RtlImageRvaToSection (NTDLL.@)
1286 PIMAGE_SECTION_HEADER WINAPI
RtlImageRvaToSection( const IMAGE_NT_HEADERS
*nt
,
1287 HMODULE module
, DWORD rva
)
1290 IMAGE_SECTION_HEADER
*sec
= (IMAGE_SECTION_HEADER
*)((char*)&nt
->OptionalHeader
+
1291 nt
->FileHeader
.SizeOfOptionalHeader
);
1292 for (i
= 0; i
< nt
->FileHeader
.NumberOfSections
; i
++, sec
++)
1294 if ((sec
->VirtualAddress
<= rva
) && (sec
->VirtualAddress
+ sec
->SizeOfRawData
> rva
))
1301 /***********************************************************************
1302 * RtlImageRvaToVa (NTDLL.@)
1304 PVOID WINAPI
RtlImageRvaToVa( const IMAGE_NT_HEADERS
*nt
, HMODULE module
,
1305 DWORD rva
, IMAGE_SECTION_HEADER
**section
)
1307 IMAGE_SECTION_HEADER
*sec
;
1309 if (section
&& *section
) /* try this section first */
1312 if ((sec
->VirtualAddress
<= rva
) && (sec
->VirtualAddress
+ sec
->SizeOfRawData
> rva
))
1315 if (!(sec
= RtlImageRvaToSection( nt
, module
, rva
))) return NULL
;
1317 if (section
) *section
= sec
;
1318 return (char *)module
+ sec
->PointerToRawData
+ (rva
- sec
->VirtualAddress
);