/* * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include "wine/port.h" #include #include #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif #include "wine/winbase16.h" #include "winerror.h" #include "winternl.h" #include "heap.h" #include "file.h" #include "module.h" #include "wine/debug.h" #include "wine/unicode.h" #include "wine/server.h" WINE_DEFAULT_DEBUG_CHANNEL(module); WINE_DECLARE_DEBUG_CHANNEL(win32); WINE_DECLARE_DEBUG_CHANNEL(loaddll); inline static HMODULE get_exe_module(void) { HANDLE *pdb = (HANDLE *)NtCurrentTeb()->process; return pdb[0x08 / sizeof(HANDLE)]; /* get dword at offset 0x08 in pdb */ } /*********************************************************************** * wait_input_idle * * Wrapper to call WaitForInputIdle USER function */ typedef DWORD (WINAPI *WaitForInputIdle_ptr)( HANDLE hProcess, DWORD dwTimeOut ); static DWORD wait_input_idle( HANDLE process, DWORD timeout ) { HMODULE mod = GetModuleHandleA( "user32.dll" ); if (mod) { WaitForInputIdle_ptr ptr = (WaitForInputIdle_ptr)GetProcAddress( mod, "WaitForInputIdle" ); if (ptr) return ptr( process, timeout ); } return 0; } /**************************************************************************** * DisableThreadLibraryCalls (KERNEL32.@) * * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set. */ BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule ) { NTSTATUS nts = LdrDisableThreadCalloutsForDll( hModule ); if (nts == STATUS_SUCCESS) return TRUE; SetLastError( RtlNtStatusToDosError( nts ) ); return FALSE; } /*********************************************************************** * MODULE_CreateDummyModule * * Create a dummy NE module for Win32 or Winelib. */ HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 ) { HMODULE16 hModule; NE_MODULE *pModule; SEGTABLEENTRY *pSegment; char *pStr,*s; unsigned int len; const char* basename; OFSTRUCT *ofs; int of_size, size; /* Extract base filename */ basename = strrchr(filename, '\\'); if (!basename) basename = filename; else basename++; len = strlen(basename); if ((s = strchr(basename, '.'))) len = s - basename; /* Allocate module */ of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName) + strlen(filename) + 1; size = sizeof(NE_MODULE) + /* loaded file info */ ((of_size + 3) & ~3) + /* segment table: DS,CS */ 2 * sizeof(SEGTABLEENTRY) + /* name table */ len + 2 + /* several empty tables */ 8; hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size ); if (!hModule) return (HMODULE16)11; /* invalid exe */ FarSetOwner16( hModule, hModule ); pModule = (NE_MODULE *)GlobalLock16( hModule ); /* Set all used entries */ pModule->magic = IMAGE_OS2_SIGNATURE; pModule->count = 1; pModule->next = 0; pModule->flags = 0; pModule->dgroup = 0; pModule->ss = 1; pModule->cs = 2; pModule->heap_size = 0; pModule->stack_size = 0; pModule->seg_count = 2; pModule->modref_count = 0; pModule->nrname_size = 0; pModule->fileinfo = sizeof(NE_MODULE); pModule->os_flags = NE_OSFLAGS_WINDOWS; pModule->self = hModule; pModule->module32 = module32; /* Set version and flags */ if (module32) { IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module32 ); pModule->expected_version = ((nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) | (nt->OptionalHeader.MinorSubsystemVersion & 0xff); pModule->flags |= NE_FFLAGS_WIN32; if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL) pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA; } /* Set loaded file information */ ofs = (OFSTRUCT *)(pModule + 1); memset( ofs, 0, of_size ); ofs->cBytes = of_size < 256 ? of_size : 255; /* FIXME */ strcpy( ofs->szPathName, filename ); pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3)); pModule->seg_table = (int)pSegment - (int)pModule; /* Data segment */ pSegment->size = 0; pSegment->flags = NE_SEGFLAGS_DATA; pSegment->minsize = 0x1000; pSegment++; /* Code segment */ pSegment->flags = 0; pSegment++; /* Module name */ pStr = (char *)pSegment; pModule->name_table = (int)pStr - (int)pModule; assert(len<256); *pStr = len; lstrcpynA( pStr+1, basename, len+1 ); pStr += len+2; /* All tables zero terminated */ pModule->res_table = pModule->import_table = pModule->entry_table = (int)pStr - (int)pModule; NE_RegisterModule( pModule ); return hModule; } /* Check whether a file is an OS/2 or a very old Windows executable * by testing on import of KERNEL. * * FIXME: is reading the module imports the only way of discerning * old Windows binaries from OS/2 ones ? At least it seems so... */ static enum binary_type MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz, const IMAGE_OS2_HEADER *ne) { DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR); enum binary_type 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 broken; /* 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 broken; 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; goto good; } } broken: ERR("Hmm, an error occurred. Is this binary file broken ?\n"); good: HeapFree( GetProcessHeap(), 0, modtab); HeapFree( GetProcessHeap(), 0, nametab); SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */ return ret; } /*********************************************************************** * MODULE_GetBinaryType */ enum binary_type MODULE_GetBinaryType( HANDLE hfile ) { union { struct { unsigned char magic[4]; unsigned char ignored[12]; unsigned short type; } elf; IMAGE_DOS_HEADER mz; } header; char magic[4]; DWORD len; /* Seek to the start of the file and read the header information. */ if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1) return BINARY_UNKNOWN; if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header)) return BINARY_UNKNOWN; if (!memcmp( header.elf.magic, "\177ELF", 4 )) { /* FIXME: we don't bother to check byte order, architecture, etc. */ switch(header.elf.type) { case 2: return BINARY_UNIX_EXE; case 3: return BINARY_UNIX_LIB; } return BINARY_UNKNOWN; } /* Not ELF, try DOS */ if (header.mz.e_magic == IMAGE_DOS_SIGNATURE) { /* 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. */ /* But before we do we will make sure that header * structure encompasses the "Offset to extended header" * field. */ if ((header.mz.e_cparhdr << 4) < sizeof(IMAGE_DOS_HEADER)) return BINARY_DOS; if (header.mz.e_crlc && (header.mz.e_lfarlc < sizeof(IMAGE_DOS_HEADER))) return BINARY_DOS; if (header.mz.e_lfanew < sizeof(IMAGE_DOS_HEADER)) return BINARY_DOS; if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1) return BINARY_DOS; if (!ReadFile( hfile, magic, sizeof(magic), &len, NULL ) || len != sizeof(magic)) return BINARY_DOS; /* Reading the magic field succeeded so * we will try to determine what type it is. */ if (!memcmp( magic, "PE\0\0", 4 )) { IMAGE_FILE_HEADER FileHeader; if (ReadFile( hfile, &FileHeader, sizeof(FileHeader), &len, NULL ) && len == sizeof(FileHeader)) { if (FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL; return BINARY_PE_EXE; } return BINARY_DOS; } if (!memcmp( 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. */ IMAGE_OS2_HEADER ne; if ( SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) != -1 && ReadFile( hfile, &ne, sizeof(ne), &len, NULL ) && len == sizeof(ne) ) { switch ( ne.ne_exetyp ) { case 2: return BINARY_WIN16; case 5: return BINARY_DOS; default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ne); } } /* Couldn't read header, so abort. */ return BINARY_DOS; } /* Unknown extended header, but this file is nonetheless DOS-executable. */ return BINARY_DOS; } return BINARY_UNKNOWN; } /*********************************************************************** * GetBinaryTypeA [KERNEL32.@] * GetBinaryType [KERNEL32.@] * * The GetBinaryType function determines whether a file is executable * or not and if it is it returns what type of executable it is. * The type of executable is a property that determines in which * subsystem an executable file runs under. * * Binary types returned: * SCS_32BIT_BINARY: A Win32 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 * * Returns TRUE if the file is an executable in which case * the value pointed by lpBinaryType is set. * Returns FALSE if the file is not an executable or if the function fails. * * To do so it opens the file and reads in the header information * if the extended header information is not present it will * assume that the file is a DOS executable. * If the extended header information is present it will * determine if the file is a 16 or 32 bit Windows executable * by check the flags in the header. * * Note that .COM and .PIF files are only recognized by their * file name extension; but Windows does it the same way ... */ BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType ) { BOOL ret = FALSE; HANDLE hfile; char *ptr; TRACE_(win32)("%s\n", lpApplicationName ); /* Sanity check. */ if ( lpApplicationName == NULL || lpBinaryType == NULL ) return FALSE; /* Open the file indicated by lpApplicationName for reading. */ hfile = CreateFileA( lpApplicationName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 ); if ( hfile == INVALID_HANDLE_VALUE ) return FALSE; /* Check binary type */ switch(MODULE_GetBinaryType( hfile )) { case BINARY_UNKNOWN: /* try to determine from file name */ ptr = strrchr( lpApplicationName, '.' ); if (!ptr) break; if (!FILE_strcasecmp( ptr, ".COM" )) { *lpBinaryType = SCS_DOS_BINARY; ret = TRUE; } else if (!FILE_strcasecmp( ptr, ".PIF" )) { *lpBinaryType = SCS_PIF_BINARY; ret = TRUE; } break; case BINARY_PE_EXE: case BINARY_PE_DLL: *lpBinaryType = 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; } /*********************************************************************** * GetBinaryTypeW [KERNEL32.@] */ BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType ) { BOOL ret = FALSE; LPSTR strNew = NULL; TRACE_(win32)("%s\n", debugstr_w(lpApplicationName) ); /* Sanity check. */ if ( lpApplicationName == NULL || lpBinaryType == NULL ) return FALSE; /* Convert the wide string to a ascii string. */ strNew = HEAP_strdupWtoA( GetProcessHeap(), 0, lpApplicationName ); if ( strNew != NULL ) { ret = GetBinaryTypeA( strNew, lpBinaryType ); /* Free the allocated string. */ HeapFree( GetProcessHeap(), 0, strNew ); } return ret; } /*********************************************************************** * WinExec (KERNEL.166) */ HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow ) { LPCSTR p, args = NULL; LPCSTR name_beg, name_end; LPSTR name, cmdline; int arglen; HINSTANCE16 ret; char buffer[MAX_PATH]; if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */ { name_beg = lpCmdLine+1; p = strchr ( lpCmdLine+1, '"' ); if (p) { name_end = p; args = strchr ( p, ' ' ); } else /* yes, even valid with trailing '"' missing */ name_end = lpCmdLine+strlen(lpCmdLine); } else { name_beg = lpCmdLine; args = strchr( lpCmdLine, ' ' ); name_end = args ? args : lpCmdLine+strlen(lpCmdLine); } if ((name_beg == lpCmdLine) && (!args)) { /* just use the original cmdline string as file name */ name = (LPSTR)lpCmdLine; } else { if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 ))) return ERROR_NOT_ENOUGH_MEMORY; memcpy( name, name_beg, name_end - name_beg ); name[name_end - name_beg] = '\0'; } if (args) { args++; arglen = strlen(args); cmdline = HeapAlloc( GetProcessHeap(), 0, 2 + arglen ); cmdline[0] = (BYTE)arglen; strcpy( cmdline + 1, args ); } else { cmdline = HeapAlloc( GetProcessHeap(), 0, 2 ); cmdline[0] = cmdline[1] = 0; } TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]); if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL )) { LOADPARAMS16 params; WORD showCmd[2]; showCmd[0] = 2; showCmd[1] = nCmdShow; params.hEnvironment = 0; params.cmdLine = MapLS( cmdline ); params.showCmd = MapLS( showCmd ); params.reserved = 0; ret = LoadModule16( buffer, ¶ms ); UnMapLS( params.cmdLine ); UnMapLS( params.showCmd ); } else ret = GetLastError(); HeapFree( GetProcessHeap(), 0, cmdline ); if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name ); if (ret == 21) /* 32-bit module */ { DWORD count; ReleaseThunkLock( &count ); ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) ); RestoreThunkLock( count ); } return ret; } /*********************************************************************** * WinExec (KERNEL32.@) */ UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow ) { PROCESS_INFORMATION info; STARTUPINFOA startup; char *cmdline; UINT ret; memset( &startup, 0, sizeof(startup) ); startup.cb = sizeof(startup); startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = nCmdShow; /* cmdline needs to be writeable for CreateProcess */ if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0; strcpy( cmdline, lpCmdLine ); if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &info )) { /* Give 30 seconds to the app to come up */ if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF) WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() ); ret = 33; /* Close off the handles */ CloseHandle( info.hThread ); CloseHandle( info.hProcess ); } else if ((ret = GetLastError()) >= 32) { FIXME("Strange error set by CreateProcess: %d\n", ret ); ret = 11; } HeapFree( GetProcessHeap(), 0, cmdline ); return ret; } /********************************************************************** * LoadModule (KERNEL32.@) */ HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock ) { LOADPARAMS *params = (LOADPARAMS *)paramBlock; PROCESS_INFORMATION info; STARTUPINFOA startup; HINSTANCE hInstance; LPSTR cmdline, p; char filename[MAX_PATH]; BYTE len; if (!name) return (HINSTANCE)ERROR_FILE_NOT_FOUND; if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) && !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL )) return (HINSTANCE)GetLastError(); len = (BYTE)params->lpCmdLine[0]; if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 ))) return (HINSTANCE)ERROR_NOT_ENOUGH_MEMORY; strcpy( cmdline, filename ); p = cmdline + strlen(cmdline); *p++ = ' '; memcpy( p, params->lpCmdLine + 1, len ); p[len] = 0; memset( &startup, 0, sizeof(startup) ); startup.cb = sizeof(startup); if (params->lpCmdShow) { startup.dwFlags = STARTF_USESHOWWINDOW; startup.wShowWindow = params->lpCmdShow[1]; } if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0, params->lpEnvAddress, NULL, &startup, &info )) { /* Give 30 seconds to the app to come up */ if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF ) WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() ); hInstance = (HINSTANCE)33; /* Close off the handles */ CloseHandle( info.hThread ); CloseHandle( info.hProcess ); } else if ((hInstance = (HINSTANCE)GetLastError()) >= (HINSTANCE)32) { FIXME("Strange error set by CreateProcess: %p\n", hInstance ); hInstance = (HINSTANCE)11; } HeapFree( GetProcessHeap(), 0, cmdline ); return hInstance; } /*********************************************************************** * GetModuleHandleA (KERNEL32.@) * GetModuleHandle32 (KERNEL.488) */ HMODULE WINAPI GetModuleHandleA(LPCSTR module) { NTSTATUS nts; HMODULE ret; UNICODE_STRING wstr; if (!module) return get_exe_module(); RtlCreateUnicodeStringFromAsciiz(&wstr, module); nts = LdrGetDllHandle(0, 0, &wstr, &ret); RtlFreeUnicodeString( &wstr ); if (nts != STATUS_SUCCESS) { ret = 0; SetLastError( RtlNtStatusToDosError( nts ) ); } return ret; } /*********************************************************************** * GetModuleHandleW (KERNEL32.@) */ HMODULE WINAPI GetModuleHandleW(LPCWSTR module) { NTSTATUS nts; HMODULE ret; UNICODE_STRING wstr; if (!module) return get_exe_module(); RtlInitUnicodeString( &wstr, module ); nts = LdrGetDllHandle( 0, 0, &wstr, &ret); if (nts != STATUS_SUCCESS) { SetLastError( RtlNtStatusToDosError( nts ) ); ret = 0; } return ret; } /*********************************************************************** * GetModuleFileNameA (KERNEL32.@) * GetModuleFileName32 (KERNEL.487) * * GetModuleFileNameA seems to *always* return the long path; * it's only GetModuleFileName16 that decides between short/long path * by checking if exe version >= 4.0. * (SDK docu doesn't mention this) */ DWORD WINAPI GetModuleFileNameA( HMODULE hModule, /* [in] module handle (32bit) */ LPSTR lpFileName, /* [out] filenamebuffer */ DWORD size ) /* [in] size of filenamebuffer */ { LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ); if (!filenameW) { SetLastError( ERROR_NOT_ENOUGH_MEMORY ); return 0; } GetModuleFileNameW( hModule, filenameW, size ); WideCharToMultiByte( CP_ACP, 0, filenameW, -1, lpFileName, size, NULL, NULL ); HeapFree( GetProcessHeap(), 0, filenameW ); return strlen( lpFileName ); } /*********************************************************************** * GetModuleFileNameW (KERNEL32.@) */ DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size ) { ULONG magic; lpFileName[0] = 0; LdrLockLoaderLock( 0, NULL, &magic ); if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32)) { /* 16-bit task - get current NE module name */ NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() ); if (pModule) { WCHAR path[MAX_PATH]; MultiByteToWideChar( CP_ACP, 0, NE_MODULE_NAME(pModule), -1, path, MAX_PATH ); GetLongPathNameW(path, lpFileName, size); } } else { LDR_MODULE* pldr; NTSTATUS nts; if (!hModule) hModule = get_exe_module(); nts = LdrFindEntryForAddress( hModule, &pldr ); if (nts == STATUS_SUCCESS) lstrcpynW(lpFileName, pldr->FullDllName.Buffer, size); else SetLastError( RtlNtStatusToDosError( nts ) ); } LdrUnlockLoaderLock( 0, magic ); TRACE( "%s\n", debugstr_w(lpFileName) ); return strlenW(lpFileName); } /****************************************************************** * load_library_as_datafile */ static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod) { static const WCHAR dotDLL[] = {'.','d','l','l',0}; WCHAR filenameW[MAX_PATH]; HANDLE hFile = INVALID_HANDLE_VALUE; HANDLE mapping; *hmod = 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 ); } if (hFile == INVALID_HANDLE_VALUE) return FALSE; switch (MODULE_GetBinaryType( hFile )) { case BINARY_PE_EXE: case BINARY_PE_DLL: mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); if (mapping) { *hmod = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 ); CloseHandle( mapping ); } break; default: break; } CloseHandle( hFile ); return *hmod != 0; } /****************************************************************** * 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. * */ HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags) { UNICODE_STRING wstr; NTSTATUS nts; HMODULE hModule; if (!libname) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } RtlCreateUnicodeStringFromAsciiz( &wstr, libname ); 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( wstr.Buffer, &hModule)) { RtlFreeUnicodeString( &wstr ); return (HMODULE)((ULONG_PTR)hModule + 1); } flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */ /* Fallback to normal behaviour */ } nts = LdrLoadDll(NULL, flags, &wstr, &hModule); if (nts != STATUS_SUCCESS) { hModule = 0; SetLastError( RtlNtStatusToDosError( nts ) ); } RtlFreeUnicodeString( &wstr ); return hModule; } /*********************************************************************** * LoadLibraryExW (KERNEL32.@) */ HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags) { UNICODE_STRING wstr; NTSTATUS nts; HMODULE hModule; if (!libnameW) { SetLastError(ERROR_INVALID_PARAMETER); return 0; } 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, &hModule)) return (HMODULE)((ULONG_PTR)hModule + 1); flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */ /* Fallback to normal behaviour */ } 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); } /*********************************************************************** * LoadLibraryW (KERNEL32.@) */ HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW) { return LoadLibraryExW(libnameW, 0, 0); } /*********************************************************************** * LoadLibrary32 (KERNEL.452) * LoadSystemLibrary32 (KERNEL.482) */ HMODULE WINAPI LoadLibrary32_16( LPCSTR libname ) { HMODULE hModule; DWORD count; ReleaseThunkLock( &count ); hModule = LoadLibraryA( libname ); RestoreThunkLock( count ); return hModule; } /*********************************************************************** * FreeLibrary (KERNEL32.@) * FreeLibrary32 (KERNEL.486) */ 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 */ char *ptr = (char *)hLibModule - 1; UnmapViewOfFile( ptr ); return TRUE; } if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE; else SetLastError( RtlNtStatusToDosError( nts ) ); return retv; } /*********************************************************************** * FreeLibraryAndExitThread (KERNEL32.@) */ VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode) { FreeLibrary(hLibModule); ExitThread(dwExitCode); } /*********************************************************************** * PrivateLoadLibrary (KERNEL32.@) * * FIXME: rough guesswork, don't know what "Private" means */ HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname) { return LoadLibrary16(libname); } /*********************************************************************** * PrivateFreeLibrary (KERNEL32.@) * * FIXME: rough guesswork, don't know what "Private" means */ void WINAPI PrivateFreeLibrary(HINSTANCE16 handle) { FreeLibrary16(handle); } /*********************************************************************** * GetProcAddress16 (KERNEL32.37) * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func) */ FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name ) { if (!hModule) { WARN("hModule may not be 0!\n"); return (FARPROC16)0; } if (HIWORD(hModule)) { WARN("hModule is Win32 handle (%p)\n", hModule ); return (FARPROC16)0; } return GetProcAddress16( LOWORD(hModule), name ); } /*********************************************************************** * GetProcAddress (KERNEL.50) */ FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, LPCSTR name ) { WORD ordinal; FARPROC16 ret; if (!hModule) hModule = GetCurrentTask(); hModule = GetExePtr( hModule ); if (HIWORD(name) != 0) { ordinal = NE_GetOrdinal( hModule, name ); TRACE("%04x '%s'\n", hModule, name ); } else { ordinal = LOWORD(name); TRACE("%04x %04x\n", hModule, ordinal ); } if (!ordinal) return (FARPROC16)0; ret = NE_GetEntryPoint( hModule, ordinal ); TRACE("returning %08x\n", (UINT)ret ); return ret; } /*********************************************************************** * GetProcAddress (KERNEL32.@) */ FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function ) { NTSTATUS nts; FARPROC fp; if (HIWORD(function)) { ANSI_STRING str; RtlInitAnsiString( &str, function ); nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp ); } else nts = LdrGetProcedureAddress( hModule, NULL, (DWORD)function, (void**)&fp ); if (nts != STATUS_SUCCESS) { SetLastError( RtlNtStatusToDosError( nts ) ); fp = NULL; } return fp; } /*********************************************************************** * GetProcAddress32 (KERNEL.453) */ FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function ) { /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */ return GetProcAddress( hModule, function ); } /*************************************************************************** * HasGPHandler (KERNEL.338) */ #include "pshpack1.h" typedef struct _GPHANDLERDEF { WORD selector; WORD rangeStart; WORD rangeEnd; WORD handler; } GPHANDLERDEF; #include "poppack.h" SEGPTR WINAPI HasGPHandler16( SEGPTR address ) { HMODULE16 hModule; int gpOrdinal; SEGPTR gpPtr; GPHANDLERDEF *gpHandler; if ( (hModule = FarGetOwner16( SELECTOROF(address) )) != 0 && (gpOrdinal = NE_GetOrdinal( hModule, "__GP" )) != 0 && (gpPtr = (SEGPTR)NE_GetEntryPointEx( hModule, gpOrdinal, FALSE )) != 0 && !IsBadReadPtr16( gpPtr, sizeof(GPHANDLERDEF) ) && (gpHandler = MapSL( gpPtr )) != NULL ) { while (gpHandler->selector) { if ( SELECTOROF(address) == gpHandler->selector && OFFSETOF(address) >= gpHandler->rangeStart && OFFSETOF(address) < gpHandler->rangeEnd ) return MAKESEGPTR( gpHandler->selector, gpHandler->handler ); gpHandler++; } } return 0; }