/* * Modules * * Copyright 1995 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" #include "wine/port.h" #include #include #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif #include "ntstatus.h" #define WIN32_NO_STATUS #include "winerror.h" #include "windef.h" #include "winbase.h" #include "winternl.h" #include "kernel_private.h" #include "psapi.h" #include "wine/exception.h" #include "wine/list.h" #include "wine/debug.h" #include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(module); #define NE_FFLAGS_LIBMODULE 0x8000 struct dll_dir_entry { struct list entry; WCHAR dir[1]; }; static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from AddDllDirectory */ static WCHAR *dll_directory; /* extra path for SetDllDirectoryW */ static DWORD default_search_flags; /* default flags set by SetDefaultDllDirectories */ static CRITICAL_SECTION dlldir_section; static CRITICAL_SECTION_DEBUG critsect_debug = { 0, 0, &dlldir_section, { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") } }; static CRITICAL_SECTION dlldir_section = { &critsect_debug, -1, 0, 0, 0, 0 }; /**************************************************************************** * GetDllDirectoryA (KERNEL32.@) */ DWORD WINAPI GetDllDirectoryA( DWORD buf_len, LPSTR buffer ) { DWORD len; RtlEnterCriticalSection( &dlldir_section ); len = dll_directory ? FILE_name_WtoA( dll_directory, strlenW(dll_directory), NULL, 0 ) : 0; if (buffer && buf_len > len) { if (dll_directory) FILE_name_WtoA( dll_directory, -1, buffer, buf_len ); else *buffer = 0; } else { len++; /* for terminating null */ if (buffer) *buffer = 0; } RtlLeaveCriticalSection( &dlldir_section ); return len; } /**************************************************************************** * GetDllDirectoryW (KERNEL32.@) */ DWORD WINAPI GetDllDirectoryW( DWORD buf_len, LPWSTR buffer ) { DWORD len; RtlEnterCriticalSection( &dlldir_section ); len = dll_directory ? strlenW( dll_directory ) : 0; if (buffer && buf_len > len) { if (dll_directory) memcpy( buffer, dll_directory, (len + 1) * sizeof(WCHAR) ); else *buffer = 0; } else { len++; /* for terminating null */ if (buffer) *buffer = 0; } RtlLeaveCriticalSection( &dlldir_section ); return len; } /**************************************************************************** * SetDllDirectoryA (KERNEL32.@) */ BOOL WINAPI SetDllDirectoryA( LPCSTR dir ) { WCHAR *dirW; BOOL ret; if (!(dirW = FILE_name_AtoW( dir, TRUE ))) return FALSE; ret = SetDllDirectoryW( dirW ); HeapFree( GetProcessHeap(), 0, dirW ); return ret; } /**************************************************************************** * SetDllDirectoryW (KERNEL32.@) */ BOOL WINAPI SetDllDirectoryW( LPCWSTR dir ) { WCHAR *newdir = NULL; if (dir) { DWORD len = (strlenW(dir) + 1) * sizeof(WCHAR); if (!(newdir = HeapAlloc( GetProcessHeap(), 0, len ))) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return FALSE; } memcpy( newdir, dir, len ); } RtlEnterCriticalSection( &dlldir_section ); HeapFree( GetProcessHeap(), 0, dll_directory ); dll_directory = newdir; RtlLeaveCriticalSection( &dlldir_section ); return TRUE; } /**************************************************************************** * AddDllDirectory (KERNEL32.@) */ DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory( const WCHAR *dir ) { WCHAR path[MAX_PATH]; DWORD len; struct dll_dir_entry *ptr; DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir ); if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH) { SetLastError( ERROR_INVALID_PARAMETER ); return NULL; } if (!(len = GetFullPathNameW( dir, MAX_PATH, path, NULL ))) return NULL; if (GetFileAttributesW( path ) == INVALID_FILE_ATTRIBUTES) return NULL; if (!(ptr = HeapAlloc( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] )))) return NULL; memcpy( ptr->dir, path, len * sizeof(WCHAR) ); TRACE( "%s\n", debugstr_w( ptr->dir )); RtlEnterCriticalSection( &dlldir_section ); list_add_head( &dll_dir_list, &ptr->entry ); RtlLeaveCriticalSection( &dlldir_section ); return ptr; } /**************************************************************************** * RemoveDllDirectory (KERNEL32.@) */ BOOL WINAPI RemoveDllDirectory( DLL_DIRECTORY_COOKIE cookie ) { struct dll_dir_entry *ptr = cookie; TRACE( "%s\n", debugstr_w( ptr->dir )); RtlEnterCriticalSection( &dlldir_section ); list_remove( &ptr->entry ); HeapFree( GetProcessHeap(), 0, ptr ); RtlLeaveCriticalSection( &dlldir_section ); return TRUE; } /************************************************************************* * SetDefaultDllDirectories (KERNEL32.@) */ BOOL WINAPI SetDefaultDllDirectories( DWORD flags ) { /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */ const DWORD load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); if (!flags || (flags & ~load_library_search_flags)) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } default_search_flags = flags; return TRUE; } /**************************************************************************** * DisableThreadLibraryCalls (KERNEL32.@) * * Inform the module loader that thread notifications are not required for a dll. * * PARAMS * hModule [I] Module handle to skip calls for * * RETURNS * Success: TRUE. Thread attach and detach notifications will not be sent * to hModule. * Failure: FALSE. Use GetLastError() to determine the cause. * * NOTES * This is typically called from the dll entry point of a dll during process * attachment, for dlls that do not need to process thread notifications. */ BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule ) { NTSTATUS nts = LdrDisableThreadCalloutsForDll( hModule ); if (nts == STATUS_SUCCESS) return TRUE; SetLastError( RtlNtStatusToDosError( nts ) ); return FALSE; } /* Check whether a file is an OS/2 or a very old Windows executable * by testing on import of KERNEL. * * Reading the module imports is the only reasonable way of discerning * old Windows binaries from OS/2 ones. */ static DWORD MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz, const IMAGE_OS2_HEADER *ne) { DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR); DWORD ret = BINARY_OS216; LPWORD modtab = NULL; LPSTR nametab = NULL; DWORD len; int i; /* read modref table */ if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1) || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD)))) || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL))) || (len != ne->ne_cmod*sizeof(WORD)) ) goto done; /* read imported names table */ if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1) || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab))) || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL))) || (len != ne->ne_enttab - ne->ne_imptab) ) goto done; for (i=0; i < ne->ne_cmod; i++) { LPSTR module = &nametab[modtab[i]]; TRACE("modref: %.*s\n", module[0], &module[1]); if (!(strncmp(&module[1], "KERNEL", module[0]))) { /* very old Windows file */ MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n"); ret = BINARY_WIN16; break; } } done: HeapFree( GetProcessHeap(), 0, modtab); HeapFree( GetProcessHeap(), 0, nametab); SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */ return ret; } /*********************************************************************** * MODULE_GetBinaryType */ void MODULE_get_binary_info( HANDLE hfile, struct binary_info *info ) { union { struct { unsigned char magic[4]; unsigned char class; unsigned char data; unsigned char ignored1[10]; unsigned short type; unsigned short machine; unsigned char ignored2[8]; unsigned int phoff; unsigned char ignored3[12]; unsigned short phnum; } elf; struct { unsigned char magic[4]; unsigned char class; unsigned char data; unsigned char ignored1[10]; unsigned short type; unsigned short machine; unsigned char ignored2[12]; unsigned __int64 phoff; unsigned char ignored3[16]; unsigned short phnum; } elf64; struct { unsigned int magic; unsigned int cputype; unsigned int cpusubtype; unsigned int filetype; } macho; IMAGE_DOS_HEADER mz; } header; DWORD len; memset( info, 0, sizeof(*info) ); /* Seek to the start of the file and read the header information. */ if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1) return; if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header)) return; if (!memcmp( header.elf.magic, "\177ELF", 4 )) { #ifdef WORDS_BIGENDIAN BOOL byteswap = (header.elf.data == 1); #else BOOL byteswap = (header.elf.data == 2); #endif if (header.elf.class == 2) info->flags |= BINARY_FLAG_64BIT; if (byteswap) { header.elf.type = RtlUshortByteSwap( header.elf.type ); header.elf.machine = RtlUshortByteSwap( header.elf.machine ); } switch(header.elf.type) { case 2: info->type = BINARY_UNIX_EXE; break; case 3: { LARGE_INTEGER phoff; unsigned short phnum; unsigned int type; if (header.elf.class == 2) { phoff.QuadPart = byteswap ? RtlUlonglongByteSwap( header.elf64.phoff ) : header.elf64.phoff; phnum = byteswap ? RtlUshortByteSwap( header.elf64.phnum ) : header.elf64.phnum; } else { phoff.QuadPart = byteswap ? RtlUlongByteSwap( header.elf.phoff ) : header.elf.phoff; phnum = byteswap ? RtlUshortByteSwap( header.elf.phnum ) : header.elf.phnum; } while (phnum--) { if (SetFilePointerEx( hfile, phoff, NULL, FILE_BEGIN ) == -1) return; if (!ReadFile( hfile, &type, sizeof(type), &len, NULL ) || len < sizeof(type)) return; if (byteswap) type = RtlUlongByteSwap( type ); if (type == 3) { info->type = BINARY_UNIX_EXE; break; } phoff.QuadPart += (header.elf.class == 2) ? 56 : 32; } if (!info->type) info->type = BINARY_UNIX_LIB; break; } default: return; } switch(header.elf.machine) { case 3: info->arch = IMAGE_FILE_MACHINE_I386; break; case 20: info->arch = IMAGE_FILE_MACHINE_POWERPC; break; case 40: info->arch = IMAGE_FILE_MACHINE_ARMNT; break; case 50: info->arch = IMAGE_FILE_MACHINE_IA64; break; case 62: info->arch = IMAGE_FILE_MACHINE_AMD64; break; case 183: info->arch = IMAGE_FILE_MACHINE_ARM64; break; } } /* Mach-o File with Endian set to Big Endian or Little Endian */ else if (header.macho.magic == 0xfeedface || header.macho.magic == 0xcefaedfe || header.macho.magic == 0xfeedfacf || header.macho.magic == 0xcffaedfe) { if ((header.macho.cputype >> 24) == 1) info->flags |= BINARY_FLAG_64BIT; if (header.macho.magic == 0xcefaedfe || header.macho.magic == 0xcffaedfe) { header.macho.filetype = RtlUlongByteSwap( header.macho.filetype ); header.macho.cputype = RtlUlongByteSwap( header.macho.cputype ); } switch(header.macho.filetype) { case 2: info->type = BINARY_UNIX_EXE; break; case 8: info->type = BINARY_UNIX_LIB; break; } switch(header.macho.cputype) { case 0x00000007: info->arch = IMAGE_FILE_MACHINE_I386; break; case 0x01000007: info->arch = IMAGE_FILE_MACHINE_AMD64; break; case 0x0000000c: info->arch = IMAGE_FILE_MACHINE_ARMNT; break; case 0x0100000c: info->arch = IMAGE_FILE_MACHINE_ARM64; break; case 0x00000012: info->arch = IMAGE_FILE_MACHINE_POWERPC; break; } } /* Not ELF, try DOS */ else if (header.mz.e_magic == IMAGE_DOS_SIGNATURE) { union { IMAGE_OS2_HEADER os2; IMAGE_NT_HEADERS32 nt; IMAGE_NT_HEADERS64 nt64; } ext_header; /* We do have a DOS image so we will now try to seek into * the file by the amount indicated by the field * "Offset to extended header" and read in the * "magic" field information at that location. * This will tell us if there is more header information * to read or not. */ info->type = BINARY_DOS; info->arch = IMAGE_FILE_MACHINE_I386; if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1) return; if (!ReadFile( hfile, &ext_header, sizeof(ext_header), &len, NULL ) || len < 4) return; /* Reading the magic field succeeded so * we will try to determine what type it is. */ if (!memcmp( &ext_header.nt.Signature, "PE\0\0", 4 )) { if (len >= sizeof(ext_header.nt.FileHeader)) { static const char fakedll_signature[] = "Wine placeholder DLL"; char buffer[sizeof(fakedll_signature)]; info->type = BINARY_PE; info->arch = ext_header.nt.FileHeader.Machine; if (ext_header.nt.FileHeader.Characteristics & IMAGE_FILE_DLL) info->flags |= BINARY_FLAG_DLL; if (len < sizeof(ext_header)) /* clear remaining part of header if missing */ memset( (char *)&ext_header + len, 0, sizeof(ext_header) - len ); switch (ext_header.nt.OptionalHeader.Magic) { case IMAGE_NT_OPTIONAL_HDR32_MAGIC: info->res_start = ext_header.nt.OptionalHeader.ImageBase; info->res_end = info->res_start + ext_header.nt.OptionalHeader.SizeOfImage; break; case IMAGE_NT_OPTIONAL_HDR64_MAGIC: info->res_start = ext_header.nt64.OptionalHeader.ImageBase; info->res_end = info->res_start + ext_header.nt64.OptionalHeader.SizeOfImage; info->flags |= BINARY_FLAG_64BIT; break; } if (header.mz.e_lfanew >= sizeof(header.mz) + sizeof(fakedll_signature) && SetFilePointer( hfile, sizeof(header.mz), NULL, SEEK_SET ) == sizeof(header.mz) && ReadFile( hfile, buffer, sizeof(fakedll_signature), &len, NULL ) && len == sizeof(fakedll_signature) && !memcmp( buffer, fakedll_signature, sizeof(fakedll_signature) )) { info->flags |= BINARY_FLAG_FAKEDLL; } } } else if (!memcmp( &ext_header.os2.ne_magic, "NE", 2 )) { /* This is a Windows executable (NE) header. This can * mean either a 16-bit OS/2 or a 16-bit Windows or even a * DOS program (running under a DOS extender). To decide * which, we'll have to read the NE header. */ if (len >= sizeof(ext_header.os2)) { if (ext_header.os2.ne_flags & NE_FFLAGS_LIBMODULE) info->flags |= BINARY_FLAG_DLL; switch ( ext_header.os2.ne_exetyp ) { case 1: info->type = BINARY_OS216; break; /* OS/2 */ case 2: info->type = BINARY_WIN16; break; /* Windows */ case 3: info->type = BINARY_DOS; break; /* European MS-DOS 4.x */ case 4: info->type = BINARY_WIN16; break; /* Windows 386; FIXME: is this 32bit??? */ case 5: info->type = BINARY_DOS; break; /* BOSS, Borland Operating System Services */ /* other types, e.g. 0 is: "unknown" */ default: info->type = MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ext_header.os2); break; } } } } } /*********************************************************************** * GetBinaryTypeW [KERNEL32.@] * * Determine whether a file is executable, and if so, what kind. * * PARAMS * lpApplicationName [I] Path of the file to check * lpBinaryType [O] Destination for the binary type * * RETURNS * TRUE, if the file is an executable, in which case lpBinaryType is set. * FALSE, if the file is not an executable or if the function fails. * * NOTES * The type of executable is a property that determines which subsystem an * executable file runs under. lpBinaryType can be set to one of the following * values: * SCS_32BIT_BINARY: A Win32 based application * SCS_64BIT_BINARY: A Win64 based application * SCS_DOS_BINARY: An MS-Dos based application * SCS_WOW_BINARY: A Win16 based application * SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app * SCS_POSIX_BINARY: A POSIX based application ( Not implemented ) * SCS_OS216_BINARY: A 16bit OS/2 based application * * To find the binary type, this function reads in the files header information. * If extended header information is not present it will assume that the file * is a DOS executable. If extended header information is present it will * determine if the file is a 16, 32 or 64 bit Windows executable by checking the * flags in the header. * * ".com" and ".pif" files are only recognized by their file name extension, * as per native Windows. */ BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ) { BOOL ret = FALSE; HANDLE hfile; struct binary_info binary_info; TRACE("%s\n", debugstr_w(lpApplicationName) ); /* Sanity check. */ if ( lpApplicationName == NULL || lpBinaryType == NULL ) return FALSE; /* Open the file indicated by lpApplicationName for reading. */ hfile = CreateFileW( lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); if ( hfile == INVALID_HANDLE_VALUE ) return FALSE; /* Check binary type */ MODULE_get_binary_info( hfile, &binary_info ); switch (binary_info.type) { case BINARY_UNKNOWN: { static const WCHAR comW[] = { '.','C','O','M',0 }; static const WCHAR pifW[] = { '.','P','I','F',0 }; const WCHAR *ptr; /* try to determine from file name */ ptr = strrchrW( lpApplicationName, '.' ); if (!ptr) break; if (!strcmpiW( ptr, comW )) { *lpBinaryType = SCS_DOS_BINARY; ret = TRUE; } else if (!strcmpiW( ptr, pifW )) { *lpBinaryType = SCS_PIF_BINARY; ret = TRUE; } break; } case BINARY_PE: *lpBinaryType = (binary_info.flags & BINARY_FLAG_64BIT) ? SCS_64BIT_BINARY : SCS_32BIT_BINARY; ret = TRUE; break; case BINARY_WIN16: *lpBinaryType = SCS_WOW_BINARY; ret = TRUE; break; case BINARY_OS216: *lpBinaryType = SCS_OS216_BINARY; ret = TRUE; break; case BINARY_DOS: *lpBinaryType = SCS_DOS_BINARY; ret = TRUE; break; case BINARY_UNIX_EXE: case BINARY_UNIX_LIB: ret = FALSE; break; } CloseHandle( hfile ); return ret; } /*********************************************************************** * GetBinaryTypeA [KERNEL32.@] * GetBinaryType [KERNEL32.@] * * See GetBinaryTypeW. */ BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ) { ANSI_STRING app_nameA; NTSTATUS status; TRACE("%s\n", debugstr_a(lpApplicationName)); /* Sanity check. */ if ( lpApplicationName == NULL || lpBinaryType == NULL ) return FALSE; RtlInitAnsiString(&app_nameA, lpApplicationName); status = RtlAnsiStringToUnicodeString(&NtCurrentTeb()->StaticUnicodeString, &app_nameA, FALSE); if (!status) return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType); SetLastError(RtlNtStatusToDosError(status)); return FALSE; } /*********************************************************************** * GetModuleHandleExA (KERNEL32.@) */ BOOL WINAPI GetModuleHandleExA( DWORD flags, LPCSTR name, HMODULE *module ) { WCHAR *nameW; if (!name || (flags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)) return GetModuleHandleExW( flags, (LPCWSTR)name, module ); if (!(nameW = FILE_name_AtoW( name, FALSE ))) return FALSE; return GetModuleHandleExW( flags, nameW, module ); } /*********************************************************************** * GetModuleHandleExW (KERNEL32.@) */ BOOL WINAPI GetModuleHandleExW( DWORD flags, LPCWSTR name, HMODULE *module ) { NTSTATUS status = STATUS_SUCCESS; HMODULE ret; ULONG_PTR magic; BOOL lock; if (!module) { SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } /* if we are messing with the refcount, grab the loader lock */ lock = (flags & GET_MODULE_HANDLE_EX_FLAG_PIN) || !(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT); if (lock) LdrLockLoaderLock( 0, NULL, &magic ); if (!name) { ret = NtCurrentTeb()->Peb->ImageBaseAddress; } else if (flags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS) { void *dummy; if (!(ret = RtlPcToFileHeader( (void *)name, &dummy ))) status = STATUS_DLL_NOT_FOUND; } else { UNICODE_STRING wstr; RtlInitUnicodeString( &wstr, name ); status = LdrGetDllHandle( NULL, 0, &wstr, &ret ); } if (status == STATUS_SUCCESS) { if (flags & GET_MODULE_HANDLE_EX_FLAG_PIN) LdrAddRefDll( LDR_ADDREF_DLL_PIN, ret ); else if (!(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT)) LdrAddRefDll( 0, ret ); } else SetLastError( RtlNtStatusToDosError( status ) ); if (lock) LdrUnlockLoaderLock( 0, magic ); if (status == STATUS_SUCCESS) *module = ret; else *module = NULL; return (status == STATUS_SUCCESS); } /*********************************************************************** * GetModuleHandleA (KERNEL32.@) * * Get the handle of a dll loaded into the process address space. * * PARAMS * module [I] Name of the dll * * RETURNS * Success: A handle to the loaded dll. * Failure: A NULL handle. Use GetLastError() to determine the cause. */ HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR module) { HMODULE ret; GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, module, &ret ); return ret; } /*********************************************************************** * GetModuleHandleW (KERNEL32.@) * * Unicode version of GetModuleHandleA. */ HMODULE WINAPI GetModuleHandleW(LPCWSTR module) { HMODULE ret; GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, module, &ret ); return ret; } /*********************************************************************** * GetModuleFileNameA (KERNEL32.@) * * Get the file name of a loaded module from its handle. * * RETURNS * Success: The length of the file name, excluding the terminating NUL. * Failure: 0. Use GetLastError() to determine the cause. * * NOTES * This function always returns the long path of hModule * The function doesn't write a terminating '\0' if the buffer is too * small. */ DWORD WINAPI GetModuleFileNameA( HMODULE hModule, /* [in] Module handle (32 bit) */ LPSTR lpFileName, /* [out] Destination for file name */ DWORD size ) /* [in] Size of lpFileName in characters */ { LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ); DWORD len; if (!filenameW) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return 0; } if ((len = GetModuleFileNameW( hModule, filenameW, size ))) { len = FILE_name_WtoA( filenameW, len, lpFileName, size ); if (len < size) lpFileName[len] = '\0'; else SetLastError( ERROR_INSUFFICIENT_BUFFER ); } HeapFree( GetProcessHeap(), 0, filenameW ); return len; } /*********************************************************************** * GetModuleFileNameW (KERNEL32.@) * * Unicode version of GetModuleFileNameA. */ DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size ) { ULONG len = 0; ULONG_PTR magic; LDR_MODULE *pldr; NTSTATUS nts; WIN16_SUBSYSTEM_TIB *win16_tib; if (!hModule && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name) { len = min(size, win16_tib->exe_name->Length / sizeof(WCHAR)); memcpy( lpFileName, win16_tib->exe_name->Buffer, len * sizeof(WCHAR) ); if (len < size) lpFileName[len] = '\0'; goto done; } LdrLockLoaderLock( 0, NULL, &magic ); if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress; nts = LdrFindEntryForAddress( hModule, &pldr ); if (nts == STATUS_SUCCESS) { len = min(size, pldr->FullDllName.Length / sizeof(WCHAR)); memcpy(lpFileName, pldr->FullDllName.Buffer, len * sizeof(WCHAR)); if (len < size) { lpFileName[len] = '\0'; SetLastError( 0 ); } else SetLastError( ERROR_INSUFFICIENT_BUFFER ); } else SetLastError( RtlNtStatusToDosError( nts ) ); LdrUnlockLoaderLock( 0, magic ); done: TRACE( "%s\n", debugstr_wn(lpFileName, len) ); return len; } /*********************************************************************** * get_dll_system_path */ static const WCHAR *get_dll_system_path(void) { static WCHAR *cached_path; if (!cached_path) { WCHAR *p, *path; int len = 1; len += 2 * GetSystemDirectoryW( NULL, 0 ); len += GetWindowsDirectoryW( NULL, 0 ); p = path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ); GetSystemDirectoryW( p, path + len - p); p += strlenW(p); /* if system directory ends in "32" add 16-bit version too */ if (p[-2] == '3' && p[-1] == '2') { *p++ = ';'; GetSystemDirectoryW( p, path + len - p); p += strlenW(p) - 2; } *p++ = ';'; GetWindowsDirectoryW( p, path + len - p); cached_path = path; } return cached_path; } /*********************************************************************** * get_dll_safe_mode */ static BOOL get_dll_safe_mode(void) { static const WCHAR keyW[] = {'\\','R','e','g','i','s','t','r','y','\\', 'M','a','c','h','i','n','e','\\', 'S','y','s','t','e','m','\\', 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\', 'C','o','n','t','r','o','l','\\', 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0}; static const WCHAR valueW[] = {'S','a','f','e','D','l','l','S','e','a','r','c','h','M','o','d','e',0}; static int safe_mode = -1; if (safe_mode == -1) { char buffer[offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data[sizeof(DWORD)])]; KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer; OBJECT_ATTRIBUTES attr; UNICODE_STRING nameW; HANDLE hkey; DWORD size = sizeof(buffer); attr.Length = sizeof(attr); attr.RootDirectory = 0; attr.ObjectName = &nameW; attr.Attributes = 0; attr.SecurityDescriptor = NULL; attr.SecurityQualityOfService = NULL; safe_mode = 1; RtlInitUnicodeString( &nameW, keyW ); if (!NtOpenKey( &hkey, KEY_READ, &attr )) { RtlInitUnicodeString( &nameW, valueW ); if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, buffer, size, &size ) && info->Type == REG_DWORD && info->DataLength == sizeof(DWORD)) safe_mode = !!*(DWORD *)info->Data; NtClose( hkey ); } if (!safe_mode) TRACE( "SafeDllSearchMode disabled through the registry\n" ); } return safe_mode; } /****************************************************************** * get_module_path_end * * Returns the end of the directory component of the module path. */ static inline const WCHAR *get_module_path_end(const WCHAR *module) { const WCHAR *p; const WCHAR *mod_end = module; if (!module) return mod_end; if ((p = strrchrW( mod_end, '\\' ))) mod_end = p; if ((p = strrchrW( mod_end, '/' ))) mod_end = p; if (mod_end == module + 2 && module[1] == ':') mod_end++; if (mod_end == module && module[0] && module[1] == ':') mod_end += 2; return mod_end; } /****************************************************************** * append_path_len * * Append a counted string to the load path. Helper for MODULE_get_dll_load_path. */ static inline WCHAR *append_path_len( WCHAR *p, const WCHAR *str, DWORD len ) { if (!len) return p; memcpy( p, str, len * sizeof(WCHAR) ); p[len] = ';'; return p + len + 1; } /****************************************************************** * append_path * * Append a string to the load path. Helper for MODULE_get_dll_load_path. */ static inline WCHAR *append_path( WCHAR *p, const WCHAR *str ) { return append_path_len( p, str, strlenW(str) ); } /****************************************************************** * MODULE_get_dll_load_path * * Compute the load path to use for a given dll. * Returned pointer must be freed by caller. */ WCHAR *MODULE_get_dll_load_path( LPCWSTR module, int safe_mode ) { static const WCHAR pathW[] = {'P','A','T','H',0}; static const WCHAR dotW[] = {'.',0}; const WCHAR *system_path = get_dll_system_path(); const WCHAR *mod_end = NULL; UNICODE_STRING name, value; WCHAR *p, *ret; int len = 0, path_len = 0; /* adjust length for module name */ if (module) mod_end = get_module_path_end( module ); /* if module is NULL or doesn't contain a path, fall back to directory * process was loaded from */ if (module == mod_end) { module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; mod_end = get_module_path_end( module ); } len += (mod_end - module) + 1; len += strlenW( system_path ) + 2; /* get the PATH variable */ RtlInitUnicodeString( &name, pathW ); value.Length = 0; value.MaximumLength = 0; value.Buffer = NULL; if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL) path_len = value.Length; RtlEnterCriticalSection( &dlldir_section ); if (safe_mode == -1) safe_mode = get_dll_safe_mode(); if (dll_directory) len += strlenW(dll_directory) + 1; else len += 2; /* current directory */ if ((p = ret = HeapAlloc( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) ))) { if (module) p = append_path_len( p, module, mod_end - module ); if (dll_directory) p = append_path( p, dll_directory ); else if (!safe_mode) p = append_path( p, dotW ); p = append_path( p, system_path ); if (!dll_directory && safe_mode) p = append_path( p, dotW ); } RtlLeaveCriticalSection( &dlldir_section ); if (!ret) return NULL; value.Buffer = p; value.MaximumLength = path_len; while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL) { WCHAR *new_ptr; /* grow the buffer and retry */ path_len = value.Length; if (!(new_ptr = HeapReAlloc( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) ))) { HeapFree( GetProcessHeap(), 0, ret ); return NULL; } value.Buffer = new_ptr + (value.Buffer - ret); value.MaximumLength = path_len; ret = new_ptr; } value.Buffer[value.Length / sizeof(WCHAR)] = 0; return ret; } /****************************************************************** * get_dll_load_path_search_flags */ static WCHAR *get_dll_load_path_search_flags( LPCWSTR module, DWORD flags ) { const WCHAR *image = NULL, *mod_end, *image_end; struct dll_dir_entry *dir; WCHAR *p, *ret; int len = 1; if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS) flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32); if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR) { DWORD type = RtlDetermineDosPathNameType_U( module ); if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH) { SetLastError( ERROR_INVALID_PARAMETER ); return NULL; } mod_end = get_module_path_end( module ); len += (mod_end - module) + 1; } else module = NULL; RtlEnterCriticalSection( &dlldir_section ); if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR) { image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer; image_end = get_module_path_end( image ); len += (image_end - image) + 1; } if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS) { LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry ) len += strlenW( dir->dir ) + 1; if (dll_directory) len += strlenW(dll_directory) + 1; } if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += GetSystemDirectoryW( NULL, 0 ); if ((p = ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) { if (module) p = append_path_len( p, module, mod_end - module ); if (image) p = append_path_len( p, image, image_end - image ); if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS) { LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry ) p = append_path( p, dir->dir ); if (dll_directory) p = append_path( p, dll_directory ); } if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) GetSystemDirectoryW( p, ret + len - p ); else { if (p > ret) p--; *p = 0; } } RtlLeaveCriticalSection( &dlldir_section ); return ret; } /****************************************************************** * load_library_as_datafile */ static BOOL load_library_as_datafile( LPCWSTR name, HMODULE *hmod, DWORD flags ) { static const WCHAR dotDLL[] = {'.','d','l','l',0}; WCHAR filenameW[MAX_PATH]; HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE mapping; HMODULE module; DWORD sharing = FILE_SHARE_READ; *hmod = 0; if (!(flags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) sharing |= FILE_SHARE_WRITE; if (SearchPathW( NULL, name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]), filenameW, NULL )) { hFile = CreateFileW( filenameW, GENERIC_READ, sharing, NULL, OPEN_EXISTING, 0, 0 ); } if (hFile == INVALID_HANDLE_VALUE) return FALSE; mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); CloseHandle( hFile ); if (!mapping) return FALSE; module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); CloseHandle( mapping ); if (!module) return FALSE; /* make sure it's a valid PE file */ if (!RtlImageNtHeader(module)) { UnmapViewOfFile( module ); return FALSE; } *hmod = (HMODULE)((char *)module + 1); /* set low bit of handle to indicate datafile module */ return TRUE; } /****************************************************************** * load_library * * Helper for LoadLibraryExA/W. */ static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags ) { NTSTATUS nts; HMODULE hModule; WCHAR *load_path; const DWORD load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR | LOAD_LIBRARY_SEARCH_APPLICATION_DIR | LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_SYSTEM32 | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); const DWORD unsupported_flags = (LOAD_IGNORE_CODE_AUTHZ_LEVEL | LOAD_LIBRARY_AS_IMAGE_RESOURCE | LOAD_LIBRARY_REQUIRE_SIGNED_TARGET); if (!(flags & load_library_search_flags)) flags |= default_search_flags; if( flags & unsupported_flags) FIXME("unsupported flag(s) used (flags: 0x%08x)\n", flags); if (flags & load_library_search_flags) load_path = get_dll_load_path_search_flags( libname->Buffer, flags ); else load_path = MODULE_get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL, -1 ); if (!load_path) return 0; if (flags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) { ULONG_PTR magic; LdrLockLoaderLock( 0, NULL, &magic ); if (!LdrGetDllHandle( load_path, flags, libname, &hModule )) { LdrAddRefDll( 0, hModule ); LdrUnlockLoaderLock( 0, magic ); goto done; } LdrUnlockLoaderLock( 0, magic ); /* The method in load_library_as_datafile allows searching for the * 'native' libraries only */ if (load_library_as_datafile( libname->Buffer, &hModule, flags )) goto done; flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */ /* Fallback to normal behaviour */ } nts = LdrLoadDll( load_path, flags, libname, &hModule ); if (nts != STATUS_SUCCESS) { hModule = 0; if (nts == STATUS_DLL_NOT_FOUND && (GetVersion() & 0x80000000)) SetLastError( ERROR_DLL_NOT_FOUND ); else SetLastError( RtlNtStatusToDosError( nts ) ); } done: HeapFree( GetProcessHeap(), 0, load_path ); return hModule; } /****************************************************************** * LoadLibraryExA (KERNEL32.@) * * Load a dll file into the process address space. * * PARAMS * libname [I] Name of the file to load * hfile [I] Reserved, must be 0. * flags [I] Flags for loading the dll * * RETURNS * Success: A handle to the loaded dll. * Failure: A NULL handle. Use GetLastError() to determine the cause. * * NOTES * 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. */ HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) { WCHAR *libnameW; if (!(libnameW = FILE_name_AtoW( libname, FALSE ))) return 0; return LoadLibraryExW( libnameW, hfile, flags ); } /*********************************************************************** * LoadLibraryExW (KERNEL32.@) * * Unicode version of LoadLibraryExA. */ HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags) { UNICODE_STRING wstr; HMODULE res; if (!libnameW) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } RtlInitUnicodeString( &wstr, libnameW ); if (wstr.Buffer[wstr.Length/sizeof(WCHAR) - 1] != ' ') return load_library( &wstr, flags ); /* Library name has trailing spaces */ RtlCreateUnicodeString( &wstr, libnameW ); while (wstr.Length > sizeof(WCHAR) && wstr.Buffer[wstr.Length/sizeof(WCHAR) - 1] == ' ') { wstr.Length -= sizeof(WCHAR); } wstr.Buffer[wstr.Length/sizeof(WCHAR)] = '\0'; res = load_library( &wstr, flags ); RtlFreeUnicodeString( &wstr ); return res; } /*********************************************************************** * LoadLibraryA (KERNEL32.@) * * Load a dll file into the process address space. * * PARAMS * libname [I] Name of the file to load * * RETURNS * Success: A handle to the loaded dll. * Failure: A NULL handle. Use GetLastError() to determine the cause. * * NOTES * See LoadLibraryExA(). */ HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR libname) { return LoadLibraryExA(libname, 0, 0); } /*********************************************************************** * LoadLibraryW (KERNEL32.@) * * Unicode version of LoadLibraryA. */ HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryW(LPCWSTR libnameW) { return LoadLibraryExW(libnameW, 0, 0); } /*********************************************************************** * FreeLibrary (KERNEL32.@) * * Free a dll loaded into the process address space. * * PARAMS * hLibModule [I] Handle to the dll returned by LoadLibraryA(). * * RETURNS * Success: TRUE. The dll is removed if it is not still in use. * Failure: FALSE. Use GetLastError() to determine the cause. */ BOOL WINAPI DECLSPEC_HOTPATCH 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 */ char *ptr = (char *)hLibModule - 1; return UnmapViewOfFile( ptr ); } if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE; else SetLastError( RtlNtStatusToDosError( nts ) ); return retv; } /*********************************************************************** * GetProcAddress (KERNEL32.@) * * Find the address of an exported symbol in a loaded dll. * * PARAMS * hModule [I] Handle to the dll returned by LoadLibraryA(). * function [I] Name of the symbol, or an integer ordinal number < 16384 * * RETURNS * Success: A pointer to the symbol in the process address space. * Failure: NULL. Use GetLastError() to determine the cause. */ FARPROC get_proc_address( HMODULE hModule, LPCSTR function ) { NTSTATUS nts; FARPROC fp; if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress; if ((ULONG_PTR)function >> 16) { ANSI_STRING str; RtlInitAnsiString( &str, function ); nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp ); } else nts = LdrGetProcedureAddress( hModule, NULL, LOWORD(function), (void**)&fp ); if (nts != STATUS_SUCCESS) { SetLastError( RtlNtStatusToDosError( nts ) ); fp = NULL; } return fp; } #ifdef __x86_64__ /* * Work around a Delphi bug on x86_64. When delay loading a symbol, * Delphi saves rcx, rdx, r8 and r9 to the stack. It then calls * GetProcAddress(), pops the saved registers and calls the function. * This works fine if all of the parameters are ints. However, since * it does not save xmm0 - 3, it relies on GetProcAddress() preserving * these registers if the function takes floating point parameters. * This wrapper saves xmm0 - 3 to the stack. */ extern FARPROC get_proc_address_wrapper( HMODULE module, LPCSTR function ); __ASM_GLOBAL_FUNC( get_proc_address_wrapper, "pushq %rbp\n\t" __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") __ASM_CFI(".cfi_rel_offset %rbp,0\n\t") "movq %rsp,%rbp\n\t" __ASM_CFI(".cfi_def_cfa_register %rbp\n\t") "subq $0x40,%rsp\n\t" "movaps %xmm0,-0x10(%rbp)\n\t" "movaps %xmm1,-0x20(%rbp)\n\t" "movaps %xmm2,-0x30(%rbp)\n\t" "movaps %xmm3,-0x40(%rbp)\n\t" "call " __ASM_NAME("get_proc_address") "\n\t" "movaps -0x40(%rbp), %xmm3\n\t" "movaps -0x30(%rbp), %xmm2\n\t" "movaps -0x20(%rbp), %xmm1\n\t" "movaps -0x10(%rbp), %xmm0\n\t" "movq %rbp,%rsp\n\t" __ASM_CFI(".cfi_def_cfa_register %rsp\n\t") "popq %rbp\n\t" __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") __ASM_CFI(".cfi_same_value %rbp\n\t") "ret" ) #else /* __x86_64__ */ static inline FARPROC get_proc_address_wrapper( HMODULE module, LPCSTR function ) { return get_proc_address( module, function ); } #endif /* __x86_64__ */ FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function ) { return get_proc_address_wrapper( hModule, function ); } /*********************************************************************** * DelayLoadFailureHook (KERNEL32.@) */ FARPROC WINAPI DelayLoadFailureHook( LPCSTR name, LPCSTR function ) { ULONG_PTR args[2]; if ((ULONG_PTR)function >> 16) ERR( "failed to delay load %s.%s\n", name, function ); else ERR( "failed to delay load %s.%u\n", name, LOWORD(function) ); args[0] = (ULONG_PTR)name; args[1] = (ULONG_PTR)function; RaiseException( EXCEPTION_WINE_STUB, EH_NONCONTINUABLE, 2, args ); return NULL; } typedef struct { HANDLE process; PLIST_ENTRY head, current; LDR_MODULE ldr_module; } MODULE_ITERATOR; static BOOL init_module_iterator(MODULE_ITERATOR *iter, HANDLE process) { PROCESS_BASIC_INFORMATION pbi; PPEB_LDR_DATA ldr_data; NTSTATUS status; /* Get address of PEB */ status = NtQueryInformationProcess(process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL); if (status != STATUS_SUCCESS) { SetLastError(RtlNtStatusToDosError(status)); return FALSE; } /* Read address of LdrData from PEB */ if (!ReadProcessMemory(process, &pbi.PebBaseAddress->LdrData, &ldr_data, sizeof(ldr_data), NULL)) return FALSE; /* Read address of first module from LdrData */ if (!ReadProcessMemory(process, &ldr_data->InLoadOrderModuleList.Flink, &iter->current, sizeof(iter->current), NULL)) return FALSE; iter->head = &ldr_data->InLoadOrderModuleList; iter->process = process; return TRUE; } static int module_iterator_next(MODULE_ITERATOR *iter) { if (iter->current == iter->head) return 0; if (!ReadProcessMemory(iter->process, CONTAINING_RECORD(iter->current, LDR_MODULE, InLoadOrderModuleList), &iter->ldr_module, sizeof(iter->ldr_module), NULL)) return -1; iter->current = iter->ldr_module.InLoadOrderModuleList.Flink; return 1; } static BOOL get_ldr_module(HANDLE process, HMODULE module, LDR_MODULE *ldr_module) { MODULE_ITERATOR iter; INT ret; if (!init_module_iterator(&iter, process)) return FALSE; while ((ret = module_iterator_next(&iter)) > 0) /* When hModule is NULL we return the process image - which will be * the first module since our iterator uses InLoadOrderModuleList */ if (!module || module == iter.ldr_module.BaseAddress) { *ldr_module = iter.ldr_module; return TRUE; } if (ret == 0) SetLastError(ERROR_INVALID_HANDLE); return FALSE; } /*********************************************************************** * K32EnumProcessModules (KERNEL32.@) * * NOTES * Returned list is in load order. */ BOOL WINAPI K32EnumProcessModules(HANDLE process, HMODULE *lphModule, DWORD cb, DWORD *needed) { MODULE_ITERATOR iter; DWORD size = 0; INT ret; if (!init_module_iterator(&iter, process)) return FALSE; if (cb && !lphModule) { SetLastError(ERROR_NOACCESS); return FALSE; } while ((ret = module_iterator_next(&iter)) > 0) { if (cb >= sizeof(HMODULE)) { *lphModule++ = iter.ldr_module.BaseAddress; cb -= sizeof(HMODULE); } size += sizeof(HMODULE); } if (!needed) { SetLastError(ERROR_NOACCESS); return FALSE; } *needed = size; return ret == 0; } /*********************************************************************** * K32EnumProcessModulesEx (KERNEL32.@) * * NOTES * Returned list is in load order. */ BOOL WINAPI K32EnumProcessModulesEx(HANDLE process, HMODULE *lphModule, DWORD cb, DWORD *needed, DWORD filter) { FIXME("(%p, %p, %d, %p, %d) semi-stub\n", process, lphModule, cb, needed, filter); return K32EnumProcessModules(process, lphModule, cb, needed); } /*********************************************************************** * K32GetModuleBaseNameW (KERNEL32.@) */ DWORD WINAPI K32GetModuleBaseNameW(HANDLE process, HMODULE module, LPWSTR base_name, DWORD size) { LDR_MODULE ldr_module; if (!get_ldr_module(process, module, &ldr_module)) return 0; size = min(ldr_module.BaseDllName.Length / sizeof(WCHAR), size); if (!ReadProcessMemory(process, ldr_module.BaseDllName.Buffer, base_name, size * sizeof(WCHAR), NULL)) return 0; base_name[size] = 0; return size; } /*********************************************************************** * K32GetModuleBaseNameA (KERNEL32.@) */ DWORD WINAPI K32GetModuleBaseNameA(HANDLE process, HMODULE module, LPSTR base_name, DWORD size) { WCHAR *base_name_w; DWORD len, ret = 0; if(!base_name || !size) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } base_name_w = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * size); if(!base_name_w) return 0; len = K32GetModuleBaseNameW(process, module, base_name_w, size); TRACE("%d, %s\n", len, debugstr_w(base_name_w)); if (len) { ret = WideCharToMultiByte(CP_ACP, 0, base_name_w, len, base_name, size, NULL, NULL); if (ret < size) base_name[ret] = 0; } HeapFree(GetProcessHeap(), 0, base_name_w); return ret; } /*********************************************************************** * K32GetModuleFileNameExW (KERNEL32.@) */ DWORD WINAPI K32GetModuleFileNameExW(HANDLE process, HMODULE module, LPWSTR file_name, DWORD size) { LDR_MODULE ldr_module; DWORD len; if (!size) return 0; if(!get_ldr_module(process, module, &ldr_module)) return 0; len = ldr_module.FullDllName.Length / sizeof(WCHAR); if (!ReadProcessMemory(process, ldr_module.FullDllName.Buffer, file_name, min( len, size ) * sizeof(WCHAR), NULL)) return 0; if (len < size) { file_name[len] = 0; return len; } else { file_name[size - 1] = 0; return size; } } /*********************************************************************** * K32GetModuleFileNameExA (KERNEL32.@) */ DWORD WINAPI K32GetModuleFileNameExA(HANDLE process, HMODULE module, LPSTR file_name, DWORD size) { WCHAR *ptr; DWORD len; TRACE("(hProcess=%p, hModule=%p, %p, %d)\n", process, module, file_name, size); if (!file_name || !size) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; } if ( process == GetCurrentProcess() ) { len = GetModuleFileNameA( module, file_name, size ); if (size) file_name[size - 1] = '\0'; return len; } if (!(ptr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)))) return 0; len = K32GetModuleFileNameExW(process, module, ptr, size); if (!len) { file_name[0] = '\0'; } else { if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, file_name, size, NULL, NULL )) { file_name[size - 1] = 0; len = size; } else if (len < size) len = strlen( file_name ); } HeapFree(GetProcessHeap(), 0, ptr); return len; } /*********************************************************************** * K32GetModuleInformation (KERNEL32.@) */ BOOL WINAPI K32GetModuleInformation(HANDLE process, HMODULE module, MODULEINFO *modinfo, DWORD cb) { LDR_MODULE ldr_module; if (cb < sizeof(MODULEINFO)) { SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } if (!get_ldr_module(process, module, &ldr_module)) return FALSE; modinfo->lpBaseOfDll = ldr_module.BaseAddress; modinfo->SizeOfImage = ldr_module.SizeOfImage; modinfo->EntryPoint = ldr_module.EntryPoint; return TRUE; } #ifdef __i386__ /*********************************************************************** * __wine_dll_register_16 (KERNEL32.@) * * No longer used. */ void __wine_dll_register_16( const IMAGE_DOS_HEADER *header, const char *file_name ) { ERR( "loading old style 16-bit dll %s no longer supported\n", file_name ); } /*********************************************************************** * __wine_dll_unregister_16 (KERNEL32.@) * * No longer used. */ void __wine_dll_unregister_16( const IMAGE_DOS_HEADER *header ) { } #endif