diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c index 541c465a8cc..effc09ccf29 100644 --- a/dlls/ntdll/loader.c +++ b/dlls/ntdll/loader.c @@ -44,6 +44,48 @@ static WINE_EXCEPTION_FILTER(page_fault) } +/************************************************************************* + * MODULE_AllocModRef + * + * Allocate a WINE_MODREF structure and add it to the process list + * NOTE: Assumes that the process critical section is held! + */ +WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ) +{ + WINE_MODREF *wm; + + DWORD long_len = strlen( filename ); + DWORD short_len = GetShortPathNameA( filename, NULL, 0 ); + + if ((wm = RtlAllocateHeap( ntdll_get_process_heap(), HEAP_ZERO_MEMORY, + sizeof(*wm) + long_len + short_len + 1 ))) + { + wm->module = hModule; + wm->tlsindex = -1; + + wm->filename = wm->data; + memcpy( wm->filename, filename, long_len + 1 ); + if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++; + else wm->modname = wm->filename; + + wm->short_filename = wm->filename + long_len + 1; + GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 ); + if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++; + else wm->short_modname = wm->short_filename; + + wm->next = MODULE_modref_list; + if (wm->next) wm->next->prev = wm; + MODULE_modref_list = wm; + + if (!(RtlImageNtHeader(hModule)->FileHeader.Characteristics & IMAGE_FILE_DLL)) + { + if (!exe_modref) exe_modref = wm; + else FIXME( "Trying to load second .EXE file: %s\n", filename ); + } + } + return wm; +} + /****************************************************************** * LdrDisableThreadCalloutsForDll (NTDLL.@) * @@ -182,6 +224,245 @@ NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE base, PANSI_STRING name, ULONG or } +/*********************************************************************** + * allocate_lib_dir + * + * helper for MODULE_LoadLibraryExA. Allocate space to hold the directory + * portion of the provided name and put the name in it. + * + */ +static LPCSTR allocate_lib_dir(LPCSTR libname) +{ + LPCSTR p, pmax; + LPSTR result; + int length; + + pmax = libname; + if ((p = strrchr( pmax, '\\' ))) pmax = p + 1; + if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty. MSDN says don't */ + if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2; + + length = pmax - libname; + + result = RtlAllocateHeap (ntdll_get_process_heap(), 0, length+1); + + if (result) + { + strncpy (result, libname, length); + result [length] = '\0'; + } + + return result; +} + +/*********************************************************************** + * MODULE_LoadLibraryExA (internal) + * + * Load a PE style module according to the load order. + * + * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion + * on this function. When first called from LoadLibraryExA it will be + * NULL but thereafter it may point to a buffer containing the path + * portion of the library name. Note that the recursion all occurs + * within a Critical section (see LoadLibraryExA) so the use of a + * static is acceptable. + * (We have to use a static variable at some point anyway, to pass the + * information from BUILTIN32_dlopen through dlopen and the builtin's + * init function into load_library). + * allocated_libdir is TRUE in the stack frame that allocated libdir + */ +NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** pwm) +{ + int i; + enum loadorder_type loadorder[LOADORDER_NTYPES]; + LPSTR filename; + const char *filetype = ""; + DWORD found; + BOOL allocated_libdir = FALSE; + static LPCSTR libdir = NULL; /* See above */ + NTSTATUS nts = STATUS_SUCCESS; + + *pwm = NULL; + if ( !libname ) return STATUS_DLL_NOT_FOUND; /* FIXME ? */ + + filename = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 ); + if ( !filename ) return STATUS_NO_MEMORY; + *filename = 0; /* Just in case we don't set it before goto error */ + + RtlEnterCriticalSection( &loader_section ); + + if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname)) + { + if (!(libdir = allocate_lib_dir(libname))) + { + nts = STATUS_NO_MEMORY; + goto error; + } + allocated_libdir = TRUE; + } + + if (!libdir || allocated_libdir) + found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL); + else + found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL); + + /* build the modules filename */ + if (!found) + { + if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH )) + { + nts = STATUS_INTERNAL_ERROR; + goto error; + } + } + + /* Check for already loaded module */ + if (!(*pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname)) + { + LPSTR fn = RtlAllocateHeap ( ntdll_get_process_heap(), 0, MAX_PATH + 1 ); + if (fn) + { + /* since the default loading mechanism uses a more detailed algorithm + * than SearchPath (like using PATH, which can even be modified between + * two attempts of loading the same DLL), the look-up above (with + * SearchPath) can have put the file in system directory, whereas it + * has already been loaded but with a different path. So do a specific + * look-up with filename (without any path) + */ + strcpy ( fn, libname ); + /* if the filename doesn't have an extension append .DLL */ + if (!strrchr( fn, '.')) strcat( fn, ".dll" ); + if ((*pwm = MODULE_FindModule( fn )) != NULL) + strcpy( filename, fn ); + RtlFreeHeap( ntdll_get_process_heap(), 0, fn ); + } + } + if (*pwm) + { + (*pwm)->refCount++; + + if (((*pwm)->flags & WINE_MODREF_DONT_RESOLVE_REFS) && + !(flags & DONT_RESOLVE_DLL_REFERENCES)) + { + (*pwm)->flags &= ~WINE_MODREF_DONT_RESOLVE_REFS; + PE_fixup_imports( *pwm ); + } + TRACE("Already loaded module '%s' at %p, count=%d\n", filename, (*pwm)->module, (*pwm)->refCount); + if (allocated_libdir) + { + RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir ); + libdir = NULL; + } + RtlLeaveCriticalSection( &loader_section ); + RtlFreeHeap( ntdll_get_process_heap(), 0, filename ); + return STATUS_SUCCESS; + } + + MODULE_GetLoadOrder( loadorder, filename, TRUE); + + for (i = 0; i < LOADORDER_NTYPES; i++) + { + if (loadorder[i] == LOADORDER_INVALID) break; + + switch (loadorder[i]) + { + case LOADORDER_DLL: + TRACE("Trying native dll '%s'\n", filename); + nts = PE_LoadLibraryExA(filename, flags, pwm); + filetype = "native"; + break; + + case LOADORDER_BI: + TRACE("Trying built-in '%s'\n", filename); + nts = BUILTIN32_LoadLibraryExA(filename, flags, pwm); + filetype = "builtin"; + break; + + default: + nts = STATUS_INTERNAL_ERROR; + break; + } + + if (nts == STATUS_SUCCESS) + { + /* Initialize DLL just loaded */ + TRACE("Loaded module '%s' at %p\n", filename, (*pwm)->module); + if (!TRACE_ON(module)) + TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype); + /* Set the refCount here so that an attach failure will */ + /* decrement the dependencies through the MODULE_FreeLibrary call. */ + (*pwm)->refCount = 1; + + if (allocated_libdir) + { + RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir ); + libdir = NULL; + } + RtlLeaveCriticalSection( &loader_section ); + RtlFreeHeap( ntdll_get_process_heap(), 0, filename ); + return nts; + } + + if (nts != STATUS_NO_SUCH_FILE) + { + WARN("Loading of %s DLL %s failed (status %ld).\n", + filetype, filename, nts); + break; + } + } + + error: + if (allocated_libdir) + { + RtlFreeHeap( ntdll_get_process_heap(), 0, (LPSTR)libdir ); + libdir = NULL; + } + RtlLeaveCriticalSection( &loader_section ); + WARN("Failed to load module '%s'; status=%ld\n", filename, nts); + RtlFreeHeap( ntdll_get_process_heap(), 0, filename ); + return nts; +} + +/****************************************************************** + * LdrLoadDll (NTDLL.@) + */ +NTSTATUS WINAPI LdrLoadDll(LPCWSTR path_name, DWORD flags, PUNICODE_STRING libname, HMODULE* hModule) +{ + WINE_MODREF *wm; + NTSTATUS nts = STATUS_SUCCESS; + STRING str; + + RtlUnicodeStringToAnsiString(&str, libname, TRUE); + + RtlEnterCriticalSection( &loader_section ); + + switch (nts = MODULE_LoadLibraryExA( str.Buffer, flags, &wm )) + { + case STATUS_SUCCESS: + if ( !MODULE_DllProcessAttach( wm, NULL ) ) + { + WARN_(module)("Attach failed for module '%s'.\n", str.Buffer); + LdrUnloadDll(wm->module); + nts = STATUS_DLL_INIT_FAILED; + wm = NULL; + } + break; + case STATUS_NO_SUCH_FILE: + nts = STATUS_DLL_NOT_FOUND; + break; + default: /* keep error code as it is (memory...) */ + break; + } + + *hModule = (wm) ? wm->module : NULL; + + RtlLeaveCriticalSection( &loader_section ); + + RtlFreeAnsiString(&str); + + return nts; +} + /****************************************************************** * LdrShutdownProcess (NTDLL.@) * diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 64d848e63de..c48da1c55f7 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -42,7 +42,7 @@ @ stdcall LdrGetDllHandle(long long ptr ptr) LdrGetDllHandle @ stdcall LdrGetProcedureAddress(ptr ptr long ptr) LdrGetProcedureAddress @ stub LdrInitializeThunk -@ stub LdrLoadDll +@ stdcall LdrLoadDll(wstr long ptr ptr) LdrLoadDll @ stub LdrProcessRelocationBlock @ stub LdrQueryImageFileExecutionOptions @ stub LdrQueryProcessModuleInformation diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 38ebcb40c85..9c001468cba 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -21,6 +21,7 @@ #include "winnt.h" #include "winternl.h" +#include "module.h" #include "thread.h" /* debug helper */ @@ -29,11 +30,12 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes); /* module handling */ extern FARPROC MODULE_GetProcAddress( HMODULE hModule, LPCSTR function, int hint, BOOL snoop ); +extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ); +extern NTSTATUS MODULE_LoadLibraryExA( LPCSTR libname, DWORD flags, WINE_MODREF** ); static inline HANDLE ntdll_get_process_heap(void) { HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process; return pdb[0x18 / sizeof(HANDLE)]; /* get dword at offset 0x18 in pdb */ } - #endif diff --git a/include/module.h b/include/module.h index 195eaf57a6c..1679c9b9c49 100644 --- a/include/module.h +++ b/include/module.h @@ -25,6 +25,7 @@ #include "winbase.h" #include "wine/windef16.h" #include "wine/winbase16.h" +#include "winternl.h" /* In-memory module structure. See 'Windows Internals' p. 219 */ typedef struct _NE_MODULE @@ -193,11 +194,9 @@ enum binary_type }; /* module.c */ -extern WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ); extern BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved ); extern void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved ); extern void MODULE_DllThreadAttach( LPVOID lpReserved ); -extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HANDLE hfile, DWORD flags ); extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); extern HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 ); extern enum binary_type MODULE_GetBinaryType( HANDLE hfile ); @@ -254,7 +253,7 @@ extern DWORD PE_SizeofResource(HRSRC); extern HGLOBAL PE_LoadResource(HMODULE,HRSRC); /* loader/pe_image.c */ -extern WINE_MODREF *PE_LoadLibraryExA(LPCSTR, DWORD); +extern NTSTATUS PE_LoadLibraryExA(LPCSTR, DWORD, WINE_MODREF**); extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename, DWORD flags ); extern WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags, HANDLE hFile, BOOL builtin ); @@ -268,7 +267,7 @@ extern void MODULE_GetLoadOrder( enum loadorder_type plo[], const char *path, BO extern void MODULE_AddLoadOrderOption( const char *option ); /* relay32/builtin.c */ -extern WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags); +extern NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR name, DWORD flags, WINE_MODREF**); extern HMODULE BUILTIN32_LoadExeModule( HMODULE main ); extern void *BUILTIN32_dlopen( const char *name ); extern int BUILTIN32_dlclose( void *handle ); diff --git a/include/winternl.h b/include/winternl.h index e6a5e57ede0..4b352d18bd4 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1141,7 +1141,7 @@ typedef struct _LDR_MODULE LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; void* BaseAddress; - ULONG EntryPoint; + void* EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; @@ -1187,7 +1187,7 @@ NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE); NTSTATUS WINAPI LdrFindEntryForAddress(void*, PLDR_MODULE*); NTSTATUS WINAPI LdrGetDllHandle(ULONG, ULONG, PUNICODE_STRING, HMODULE*); NTSTATUS WINAPI LdrGetProcedureAddress(HMODULE, PANSI_STRING, ULONG, void**); -NTSTATUS WINAPI LdrLoadDll(LPCSTR, DWORD, PUNICODE_STRING, HMODULE*); +NTSTATUS WINAPI LdrLoadDll(LPCWSTR, DWORD, PUNICODE_STRING, HMODULE*); NTSTATUS WINAPI LdrShutdownThread(void); NTSTATUS WINAPI LdrShutdownProcess(void); NTSTATUS WINAPI LdrUnloadDll(HMODULE); diff --git a/loader/module.c b/loader/module.c index 649de9ce28b..95207b7ec53 100644 --- a/loader/module.c +++ b/loader/module.c @@ -95,48 +95,6 @@ WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hmod ) return NULL; } -/************************************************************************* - * MODULE_AllocModRef - * - * Allocate a WINE_MODREF structure and add it to the process list - * NOTE: Assumes that the process critical section is held! - */ -WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename ) -{ - WINE_MODREF *wm; - - DWORD long_len = strlen( filename ); - DWORD short_len = GetShortPathNameA( filename, NULL, 0 ); - - if ((wm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(*wm) + long_len + short_len + 1 ))) - { - wm->module = hModule; - wm->tlsindex = -1; - - wm->filename = wm->data; - memcpy( wm->filename, filename, long_len + 1 ); - if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++; - else wm->modname = wm->filename; - - wm->short_filename = wm->filename + long_len + 1; - GetShortPathNameA( wm->filename, wm->short_filename, short_len + 1 ); - if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++; - else wm->short_modname = wm->short_filename; - - wm->next = MODULE_modref_list; - if (wm->next) wm->next->prev = wm; - MODULE_modref_list = wm; - - if (!(RtlImageNtHeader(hModule)->FileHeader.Characteristics & IMAGE_FILE_DLL)) - { - if (!exe_modref) exe_modref = wm; - else FIXME( "Trying to load second .EXE file: %s\n", filename ); - } - } - return wm; -} - /************************************************************************* * MODULE_InitDLL */ @@ -1024,277 +982,146 @@ DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size return strlenW(lpFileName); } - -/*********************************************************************** - * LoadLibraryExA (KERNEL32.@) - */ -HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) -{ - WINE_MODREF *wm; - - if(!libname) - { - SetLastError(ERROR_INVALID_PARAMETER); - return 0; - } - - if (flags & LOAD_LIBRARY_AS_DATAFILE) - { - char filename[256]; - HMODULE hmod = 0; - - /* This method allows searching for the 'native' libraries only */ - if (SearchPathA( NULL, libname, ".dll", sizeof(filename), filename, NULL )) - { - /* FIXME: maybe we should use the hfile parameter instead */ - HANDLE hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ, - NULL, OPEN_EXISTING, 0, 0 ); - if (hFile != INVALID_HANDLE_VALUE) - { - HANDLE mapping; - switch (MODULE_GetBinaryType( hFile )) - { - case BINARY_PE_EXE: - case BINARY_PE_DLL: - mapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); - if (mapping) - { - hmod = (HMODULE)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); - CloseHandle( mapping ); - } - break; - default: - break; - } - CloseHandle( hFile ); - } - if (hmod) return (HMODULE)((ULONG_PTR)hmod + 1); - } - flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */ - /* Fallback to normal behaviour */ - } - - RtlEnterCriticalSection( &loader_section ); - - wm = MODULE_LoadLibraryExA( libname, hfile, flags ); - if ( wm ) - { - if ( !MODULE_DllProcessAttach( wm, NULL ) ) - { - WARN_(module)("Attach failed for module '%s'.\n", libname); - LdrUnloadDll(wm->module); - SetLastError(ERROR_DLL_INIT_FAILED); - wm = NULL; - } - } - - RtlLeaveCriticalSection( &loader_section ); - return wm ? wm->module : 0; -} - -/*********************************************************************** - * allocate_lib_dir +/****************************************************************** + * load_library_as_datafile * - * helper for MODULE_LoadLibraryExA. Allocate space to hold the directory - * portion of the provided name and put the name in it. * */ -static LPCSTR allocate_lib_dir(LPCSTR libname) +static BOOL load_library_as_datafile(const void* name, BOOL unicode, HMODULE* hmod) { - LPCSTR p, pmax; - LPSTR result; - int length; + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE mapping; + + *hmod = 0; - pmax = libname; - if ((p = strrchr( pmax, '\\' ))) pmax = p + 1; - if ((p = strrchr( pmax, '/' ))) pmax = p + 1; /* Naughty. MSDN says don't */ - if (pmax == libname && pmax[0] && pmax[1] == ':') pmax += 2; - - length = pmax - libname; - - result = HeapAlloc (GetProcessHeap(), 0, length+1); - - if (result) + if (unicode) { - strncpy (result, libname, length); - result [length] = '\0'; + WCHAR filenameW[MAX_PATH]; +static WCHAR dotDLL[] = {'.','d','l','l',0}; + + if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]), filenameW, NULL )) + { + hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, 0 ); + } + } + else + { + char filenameA[MAX_PATH]; + + if (SearchPathA( NULL, (const char*)name, ".dll", sizeof(filenameA), filenameA, NULL )) + { + hFile = CreateFileA( filenameA, GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, 0 ); + } } - return result; + if (hFile == INVALID_HANDLE_VALUE) return FALSE; + switch (MODULE_GetBinaryType( hFile )) + { + case BINARY_PE_EXE: + case BINARY_PE_DLL: + mapping = CreateFileMappingA( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); + if (mapping) + { + *hmod = (HMODULE)MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); + CloseHandle( mapping ); + } + break; + default: + break; + } + CloseHandle( hFile ); + + return *hmod != 0; } -/*********************************************************************** - * MODULE_LoadLibraryExA (internal) - * - * Load a PE style module according to the load order. +/****************************************************************** + * LoadLibraryExA (KERNEL32.@) * * The HFILE parameter is not used and marked reserved in the SDK. I can * only guess that it should force a file to be mapped, but I rather * ignore the parameter because it would be extremely difficult to * integrate this with different types of module representations. * - * libdir is used to support LOAD_WITH_ALTERED_SEARCH_PATH during the recursion - * on this function. When first called from LoadLibraryExA it will be - * NULL but thereafter it may point to a buffer containing the path - * portion of the library name. Note that the recursion all occurs - * within a Critical section (see LoadLibraryExA) so the use of a - * static is acceptable. - * (We have to use a static variable at some point anyway, to pass the - * information from BUILTIN32_dlopen through dlopen and the builtin's - * init function into load_library). - * allocated_libdir is TRUE in the stack frame that allocated libdir */ -WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HANDLE hfile, DWORD flags ) +HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) { - DWORD err = GetLastError(); - WINE_MODREF *pwm; - int i; - enum loadorder_type loadorder[LOADORDER_NTYPES]; - LPSTR filename; - const char *filetype = ""; - DWORD found; - BOOL allocated_libdir = FALSE; - static LPCSTR libdir = NULL; /* See above */ + UNICODE_STRING wstr; + NTSTATUS nts; + HMODULE hModule; - if ( !libname ) return NULL; + if (!libname) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } - filename = HeapAlloc ( GetProcessHeap(), 0, MAX_PATH + 1 ); - if ( !filename ) return NULL; - *filename = 0; /* Just in case we don't set it before goto error */ + if (flags & LOAD_LIBRARY_AS_DATAFILE) + { + /* The method in load_library_as_datafile allows searching for the + * 'native' libraries only + */ + if (load_library_as_datafile(libname, FALSE, &hModule)) + return (HMODULE)((ULONG_PTR)hModule + 1); + flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */ + /* Fallback to normal behaviour */ + } - RtlEnterCriticalSection( &loader_section ); + RtlCreateUnicodeStringFromAsciiz( &wstr, libname ); + nts = LdrLoadDll(NULL, flags, &wstr, &hModule); + if (nts != STATUS_SUCCESS) + { + hModule = 0; + SetLastError( RtlNtStatusToDosError( nts ) ); + } + RtlFreeUnicodeString( &wstr ); - if ((flags & LOAD_WITH_ALTERED_SEARCH_PATH) && FILE_contains_path(libname)) - { - if (!(libdir = allocate_lib_dir(libname))) goto error; - allocated_libdir = TRUE; - } + return hModule; +} - if (!libdir || allocated_libdir) - found = SearchPathA(NULL, libname, ".dll", MAX_PATH, filename, NULL); - else - found = DIR_SearchAlternatePath(libdir, libname, ".dll", MAX_PATH, filename, NULL); +/*********************************************************************** + * LoadLibraryExW (KERNEL32.@) + */ +HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags) +{ + UNICODE_STRING wstr; + NTSTATUS nts; + HMODULE hModule; - /* build the modules filename */ - if (!found) - { - if (!MODULE_GetBuiltinPath( libname, ".dll", filename, MAX_PATH )) goto error; - } + if (!libnameW) + { + SetLastError(ERROR_INVALID_PARAMETER); + return 0; + } - /* Check for already loaded module */ - if (!(pwm = MODULE_FindModule(filename)) && !FILE_contains_path(libname)) - { - LPSTR fn = HeapAlloc ( GetProcessHeap(), 0, MAX_PATH + 1 ); - if (fn) - { - /* since the default loading mechanism uses a more detailed algorithm - * than SearchPath (like using PATH, which can even be modified between - * two attempts of loading the same DLL), the look-up above (with - * SearchPath) can have put the file in system directory, whereas it - * has already been loaded but with a different path. So do a specific - * look-up with filename (without any path) - */ - strcpy ( fn, libname ); - /* if the filename doesn't have an extension append .DLL */ - if (!strrchr( fn, '.')) strcat( fn, ".dll" ); - if ((pwm = MODULE_FindModule( fn )) != NULL) - strcpy( filename, fn ); - HeapFree( GetProcessHeap(), 0, fn ); - } - } - if (pwm) - { - pwm->refCount++; + if (flags & LOAD_LIBRARY_AS_DATAFILE) + { + /* The method in load_library_as_datafile allows searching for the + * 'native' libraries only + */ + if (load_library_as_datafile(libnameW, TRUE, &hModule)) + return (HMODULE)((ULONG_PTR)hModule + 1); + flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */ + /* Fallback to normal behaviour */ + } - if ((pwm->flags & WINE_MODREF_DONT_RESOLVE_REFS) && - !(flags & DONT_RESOLVE_DLL_REFERENCES)) - { - pwm->flags &= ~WINE_MODREF_DONT_RESOLVE_REFS; - PE_fixup_imports( pwm ); - } - TRACE("Already loaded module '%s' at %p, count=%d\n", filename, pwm->module, pwm->refCount); - if (allocated_libdir) - { - HeapFree ( GetProcessHeap(), 0, (LPSTR)libdir ); - libdir = NULL; - } - RtlLeaveCriticalSection( &loader_section ); - HeapFree ( GetProcessHeap(), 0, filename ); - return pwm; - } - - MODULE_GetLoadOrder( loadorder, filename, TRUE); - - for(i = 0; i < LOADORDER_NTYPES; i++) - { - if (loadorder[i] == LOADORDER_INVALID) break; - SetLastError( ERROR_FILE_NOT_FOUND ); - - switch(loadorder[i]) - { - case LOADORDER_DLL: - TRACE("Trying native dll '%s'\n", filename); - pwm = PE_LoadLibraryExA(filename, flags); - filetype = "native"; - break; - - case LOADORDER_BI: - TRACE("Trying built-in '%s'\n", filename); - pwm = BUILTIN32_LoadLibraryExA(filename, flags); - filetype = "builtin"; - break; - - default: - pwm = NULL; - break; - } - - if(pwm) - { - /* Initialize DLL just loaded */ - TRACE("Loaded module '%s' at %p\n", filename, pwm->module); - if (!TRACE_ON(module)) - TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype); - /* Set the refCount here so that an attach failure will */ - /* decrement the dependencies through the MODULE_FreeLibrary call. */ - pwm->refCount = 1; - - if (allocated_libdir) - { - HeapFree ( GetProcessHeap(), 0, (LPSTR)libdir ); - libdir = NULL; - } - RtlLeaveCriticalSection( &loader_section ); - SetLastError( err ); /* restore last error */ - HeapFree ( GetProcessHeap(), 0, filename ); - return pwm; - } - - if(GetLastError() != ERROR_FILE_NOT_FOUND) - { - WARN("Loading of %s DLL %s failed (error %ld).\n", - filetype, filename, GetLastError()); - break; - } - } - - error: - if (allocated_libdir) - { - HeapFree ( GetProcessHeap(), 0, (LPSTR)libdir ); - libdir = NULL; - } - RtlLeaveCriticalSection( &loader_section ); - WARN("Failed to load module '%s'; error=%ld\n", filename, GetLastError()); - HeapFree ( GetProcessHeap(), 0, filename ); - return NULL; + RtlInitUnicodeString( &wstr, libnameW ); + nts = LdrLoadDll(NULL, flags, &wstr, &hModule); + if (nts != STATUS_SUCCESS) + { + hModule = 0; + SetLastError( RtlNtStatusToDosError( nts ) ); + } + return hModule; } /*********************************************************************** * LoadLibraryA (KERNEL32.@) */ -HMODULE WINAPI LoadLibraryA(LPCSTR libname) { - return LoadLibraryExA(libname,0,0); +HMODULE WINAPI LoadLibraryA(LPCSTR libname) +{ + return LoadLibraryExA(libname, 0, 0); } /*********************************************************************** @@ -1302,7 +1129,7 @@ HMODULE WINAPI LoadLibraryA(LPCSTR libname) { */ HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW) { - return LoadLibraryExW(libnameW,0,0); + return LoadLibraryExW(libnameW, 0, 0); } /*********************************************************************** @@ -1320,18 +1147,6 @@ HMODULE WINAPI LoadLibrary32_16( LPCSTR libname ) return hModule; } -/*********************************************************************** - * LoadLibraryExW (KERNEL32.@) - */ -HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW,HANDLE hfile,DWORD flags) -{ - LPSTR libnameA = HEAP_strdupWtoA( GetProcessHeap(), 0, libnameW ); - HMODULE ret = LoadLibraryExA( libnameA , hfile, flags ); - - HeapFree( GetProcessHeap(), 0, libnameA ); - return ret; -} - /*********************************************************************** * FreeLibrary (KERNEL32.@) * FreeLibrary32 (KERNEL.486) @@ -1341,6 +1156,12 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) BOOL retv = FALSE; NTSTATUS nts; + if (!hLibModule) + { + SetLastError( ERROR_INVALID_HANDLE ); + return FALSE; + } + if ((ULONG_PTR)hLibModule & 1) { /* this is a LOAD_LIBRARY_AS_DATAFILE module */ @@ -1348,13 +1169,6 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule) UnmapViewOfFile( ptr ); return TRUE; } - - if (!hLibModule) - { - SetLastError( ERROR_INVALID_HANDLE ); - RtlLeaveCriticalSection( &loader_section ); - return FALSE; - } if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE; else SetLastError( RtlNtStatusToDosError( nts ) ); @@ -1381,8 +1195,6 @@ HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname) return LoadLibrary16(libname); } - - /*********************************************************************** * PrivateFreeLibrary (KERNEL32.@) * diff --git a/loader/pe_image.c b/loader/pe_image.c index 5ae6dc846c0..e42a58f598c 100644 --- a/loader/pe_image.c +++ b/loader/pe_image.c @@ -257,7 +257,7 @@ DWORD PE_fixup_imports( WINE_MODREF *wm ) /* Allocate module dependency list */ wm->nDeps = i; - wm->deps = HeapAlloc( GetProcessHeap(), 0, i*sizeof(WINE_MODREF *) ); + wm->deps = RtlAllocateHeap( ntdll_get_process_heap(), 0, i*sizeof(WINE_MODREF *) ); /* load the imported modules. They are automatically * added to the modref list of the process. @@ -268,19 +268,24 @@ DWORD PE_fixup_imports( WINE_MODREF *wm ) IMAGE_IMPORT_BY_NAME *pe_name; PIMAGE_THUNK_DATA import_list,thunk_list; char *name = get_rva(wm->module, pe_imp->Name); + NTSTATUS nts; if (characteristics_detection && !pe_imp->u.Characteristics) break; - wmImp = MODULE_LoadLibraryExA( name, 0, 0 ); - if (!wmImp) { - if(GetLastError() == ERROR_FILE_NOT_FOUND) - ERR_(module)("Module (file) %s (which is needed by %s) not found\n", name, wm->filename); - else - ERR_(module)("Loading module (file) %s (which is needed by %s) failed (error %ld).\n", - name, wm->filename, GetLastError()); + nts = MODULE_LoadLibraryExA( name, 0, &wmImp ); + switch (nts) + { + case STATUS_SUCCESS: + break; + case STATUS_NO_SUCH_FILE: + ERR_(module)("Module (file) %s (which is needed by %s) not found\n", name, wm->filename); + return 1; + default: + ERR_(module)("Loading module (file) %s (which is needed by %s) failed (error %ld).\n", + name, wm->filename, GetLastError()); return 1; - } + } wm->deps[i++] = wmImp; /* FIXME: forwarder entries ... */ @@ -575,35 +580,38 @@ WINE_MODREF *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags, * The PE Library Loader frontend. * FIXME: handle the flags. */ -WINE_MODREF *PE_LoadLibraryExA (LPCSTR name, DWORD flags) +NTSTATUS PE_LoadLibraryExA (LPCSTR name, DWORD flags, WINE_MODREF** pwm) { HMODULE hModule32; - WINE_MODREF *wm; HANDLE hFile; hFile = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); - if ( hFile == INVALID_HANDLE_VALUE ) return NULL; + if ( hFile == INVALID_HANDLE_VALUE ) + { + /* keep it that way until we transform CreateFile into NtCreateFile */ + return (GetLastError() == ERROR_FILE_NOT_FOUND) ? + STATUS_NO_SUCH_FILE : STATUS_INTERNAL_ERROR; + } /* Load PE module */ hModule32 = PE_LoadImage( hFile, name, flags ); if (!hModule32) { CloseHandle( hFile ); - return NULL; + return STATUS_INTERNAL_ERROR; } /* Create 32-bit MODREF */ - if ( !(wm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) ) + if ( !(*pwm = PE_CreateModule( hModule32, name, flags, hFile, FALSE )) ) { ERR( "can't load %s\n", name ); CloseHandle( hFile ); - SetLastError( ERROR_OUTOFMEMORY ); - return NULL; + return STATUS_NO_MEMORY; /* FIXME */ } CloseHandle( hFile ); - return wm; + return STATUS_SUCCESS; } diff --git a/relay32/builtin32.c b/relay32/builtin32.c index 9f6e2b3c343..d9ba9fe89d6 100644 --- a/relay32/builtin32.c +++ b/relay32/builtin32.c @@ -147,9 +147,8 @@ static void load_library( void *base, const char *filename ) * Partly copied from the original PE_ version. * */ -WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags) +NTSTATUS BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags, WINE_MODREF** pwm) { - WINE_MODREF *wm; char dllname[20], *p; LPCSTR name; void *handle; @@ -159,29 +158,24 @@ WINE_MODREF *BUILTIN32_LoadLibraryExA(LPCSTR path, DWORD flags) if ((p = strrchr( name, '\\' ))) name = p + 1; if ((p = strrchr( name, '/' ))) name = p + 1; - if (strlen(name) >= sizeof(dllname)-4) goto error; + if (strlen(name) >= sizeof(dllname)-4) return STATUS_NO_SUCH_FILE; strcpy( dllname, name ); p = strrchr( dllname, '.' ); if (!p) strcat( dllname, ".dll" ); for (p = dllname; *p; p++) *p = FILE_tolower(*p); - if (!(handle = BUILTIN32_dlopen( dllname ))) goto error; + if (!(handle = BUILTIN32_dlopen( dllname ))) return STATUS_NO_SUCH_FILE; - if (!(wm = MODULE_FindModule( path ))) wm = MODULE_FindModule( dllname ); - if (!wm) + if (!((*pwm) = MODULE_FindModule( path ))) *pwm = MODULE_FindModule( dllname ); + if (!*pwm) { ERR( "loaded .so but dll %s still not found - 16-bit dll or version conflict.\n", dllname ); /* wine_dll_unload( handle );*/ - SetLastError( ERROR_BAD_EXE_FORMAT ); - return NULL; + return STATUS_INVALID_IMAGE_FORMAT; } - wm->dlhandle = handle; - return wm; - - error: - SetLastError( ERROR_FILE_NOT_FOUND ); - return NULL; + (*pwm)->dlhandle = handle; + return STATUS_SUCCESS; } /***********************************************************************