kernel32: Properly detect ELF binaries that are position independent executables.
[wine.git] / dlls / kernel32 / module.c
blobd068f2a996ffbbb7bddc1ed4ff2e865d02a361e4
1 /*
2 * Modules
4 * Copyright 1995 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include "ntstatus.h"
34 #define WIN32_NO_STATUS
35 #include "winerror.h"
36 #include "windef.h"
37 #include "winbase.h"
38 #include "winternl.h"
39 #include "kernel_private.h"
40 #include "psapi.h"
42 #include "wine/exception.h"
43 #include "wine/list.h"
44 #include "wine/debug.h"
45 #include "wine/unicode.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(module);
49 #define NE_FFLAGS_LIBMODULE 0x8000
51 struct dll_dir_entry
53 struct list entry;
54 WCHAR dir[1];
57 static struct list dll_dir_list = LIST_INIT( dll_dir_list ); /* extra dirs from AddDllDirectory */
58 static WCHAR *dll_directory; /* extra path for SetDllDirectoryW */
59 static DWORD default_search_flags; /* default flags set by SetDefaultDllDirectories */
61 static CRITICAL_SECTION dlldir_section;
62 static CRITICAL_SECTION_DEBUG critsect_debug =
64 0, 0, &dlldir_section,
65 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
66 0, 0, { (DWORD_PTR)(__FILE__ ": dlldir_section") }
68 static CRITICAL_SECTION dlldir_section = { &critsect_debug, -1, 0, 0, 0, 0 };
70 /****************************************************************************
71 * GetDllDirectoryA (KERNEL32.@)
73 DWORD WINAPI GetDllDirectoryA( DWORD buf_len, LPSTR buffer )
75 DWORD len;
77 RtlEnterCriticalSection( &dlldir_section );
78 len = dll_directory ? FILE_name_WtoA( dll_directory, strlenW(dll_directory), NULL, 0 ) : 0;
79 if (buffer && buf_len > len)
81 if (dll_directory) FILE_name_WtoA( dll_directory, -1, buffer, buf_len );
82 else *buffer = 0;
84 else
86 len++; /* for terminating null */
87 if (buffer) *buffer = 0;
89 RtlLeaveCriticalSection( &dlldir_section );
90 return len;
94 /****************************************************************************
95 * GetDllDirectoryW (KERNEL32.@)
97 DWORD WINAPI GetDllDirectoryW( DWORD buf_len, LPWSTR buffer )
99 DWORD len;
101 RtlEnterCriticalSection( &dlldir_section );
102 len = dll_directory ? strlenW( dll_directory ) : 0;
103 if (buffer && buf_len > len)
105 if (dll_directory) memcpy( buffer, dll_directory, (len + 1) * sizeof(WCHAR) );
106 else *buffer = 0;
108 else
110 len++; /* for terminating null */
111 if (buffer) *buffer = 0;
113 RtlLeaveCriticalSection( &dlldir_section );
114 return len;
118 /****************************************************************************
119 * SetDllDirectoryA (KERNEL32.@)
121 BOOL WINAPI SetDllDirectoryA( LPCSTR dir )
123 WCHAR *dirW;
124 BOOL ret;
126 if (!(dirW = FILE_name_AtoW( dir, TRUE ))) return FALSE;
127 ret = SetDllDirectoryW( dirW );
128 HeapFree( GetProcessHeap(), 0, dirW );
129 return ret;
133 /****************************************************************************
134 * SetDllDirectoryW (KERNEL32.@)
136 BOOL WINAPI SetDllDirectoryW( LPCWSTR dir )
138 WCHAR *newdir = NULL;
140 if (dir)
142 DWORD len = (strlenW(dir) + 1) * sizeof(WCHAR);
143 if (!(newdir = HeapAlloc( GetProcessHeap(), 0, len )))
145 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
146 return FALSE;
148 memcpy( newdir, dir, len );
151 RtlEnterCriticalSection( &dlldir_section );
152 HeapFree( GetProcessHeap(), 0, dll_directory );
153 dll_directory = newdir;
154 RtlLeaveCriticalSection( &dlldir_section );
155 return TRUE;
159 /****************************************************************************
160 * AddDllDirectory (KERNEL32.@)
162 DLL_DIRECTORY_COOKIE WINAPI AddDllDirectory( const WCHAR *dir )
164 WCHAR path[MAX_PATH];
165 DWORD len;
166 struct dll_dir_entry *ptr;
167 DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir );
169 if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
171 SetLastError( ERROR_INVALID_PARAMETER );
172 return NULL;
174 if (!(len = GetFullPathNameW( dir, MAX_PATH, path, NULL ))) return NULL;
175 if (GetFileAttributesW( path ) == INVALID_FILE_ATTRIBUTES) return NULL;
177 if (!(ptr = HeapAlloc( GetProcessHeap(), 0, offsetof(struct dll_dir_entry, dir[++len] )))) return NULL;
178 memcpy( ptr->dir, path, len * sizeof(WCHAR) );
179 TRACE( "%s\n", debugstr_w( ptr->dir ));
181 RtlEnterCriticalSection( &dlldir_section );
182 list_add_head( &dll_dir_list, &ptr->entry );
183 RtlLeaveCriticalSection( &dlldir_section );
184 return ptr;
188 /****************************************************************************
189 * RemoveDllDirectory (KERNEL32.@)
191 BOOL WINAPI RemoveDllDirectory( DLL_DIRECTORY_COOKIE cookie )
193 struct dll_dir_entry *ptr = cookie;
195 TRACE( "%s\n", debugstr_w( ptr->dir ));
197 RtlEnterCriticalSection( &dlldir_section );
198 list_remove( &ptr->entry );
199 HeapFree( GetProcessHeap(), 0, ptr );
200 RtlLeaveCriticalSection( &dlldir_section );
201 return TRUE;
205 /*************************************************************************
206 * SetDefaultDllDirectories (KERNEL32.@)
208 BOOL WINAPI SetDefaultDllDirectories( DWORD flags )
210 /* LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR doesn't make sense in default dirs */
211 const DWORD load_library_search_flags = (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
212 LOAD_LIBRARY_SEARCH_USER_DIRS |
213 LOAD_LIBRARY_SEARCH_SYSTEM32 |
214 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
216 if (!flags || (flags & ~load_library_search_flags))
218 SetLastError( ERROR_INVALID_PARAMETER );
219 return FALSE;
221 default_search_flags = flags;
222 return TRUE;
226 /****************************************************************************
227 * DisableThreadLibraryCalls (KERNEL32.@)
229 * Inform the module loader that thread notifications are not required for a dll.
231 * PARAMS
232 * hModule [I] Module handle to skip calls for
234 * RETURNS
235 * Success: TRUE. Thread attach and detach notifications will not be sent
236 * to hModule.
237 * Failure: FALSE. Use GetLastError() to determine the cause.
239 * NOTES
240 * This is typically called from the dll entry point of a dll during process
241 * attachment, for dlls that do not need to process thread notifications.
243 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
245 NTSTATUS nts = LdrDisableThreadCalloutsForDll( hModule );
246 if (nts == STATUS_SUCCESS) return TRUE;
248 SetLastError( RtlNtStatusToDosError( nts ) );
249 return FALSE;
253 /* Check whether a file is an OS/2 or a very old Windows executable
254 * by testing on import of KERNEL.
256 * Reading the module imports is the only reasonable way of discerning
257 * old Windows binaries from OS/2 ones.
259 static DWORD MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz, const IMAGE_OS2_HEADER *ne)
261 DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
262 DWORD ret = BINARY_OS216;
263 LPWORD modtab = NULL;
264 LPSTR nametab = NULL;
265 DWORD len;
266 int i;
268 /* read modref table */
269 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
270 || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
271 || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
272 || (len != ne->ne_cmod*sizeof(WORD)) )
273 goto done;
275 /* read imported names table */
276 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
277 || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
278 || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
279 || (len != ne->ne_enttab - ne->ne_imptab) )
280 goto done;
282 for (i=0; i < ne->ne_cmod; i++)
284 LPSTR module = &nametab[modtab[i]];
285 TRACE("modref: %.*s\n", module[0], &module[1]);
286 if (!(strncmp(&module[1], "KERNEL", module[0])))
287 { /* very old Windows file */
288 MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
289 ret = BINARY_WIN16;
290 break;
294 done:
295 HeapFree( GetProcessHeap(), 0, modtab);
296 HeapFree( GetProcessHeap(), 0, nametab);
297 SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
298 return ret;
301 /***********************************************************************
302 * MODULE_GetBinaryType
304 void MODULE_get_binary_info( HANDLE hfile, struct binary_info *info )
306 union
308 struct
310 unsigned char magic[4];
311 unsigned char class;
312 unsigned char data;
313 unsigned char ignored1[10];
314 unsigned short type;
315 unsigned short machine;
316 unsigned char ignored2[8];
317 unsigned int phoff;
318 unsigned char ignored3[12];
319 unsigned short phnum;
320 } elf;
321 struct
323 unsigned char magic[4];
324 unsigned char class;
325 unsigned char data;
326 unsigned char ignored1[10];
327 unsigned short type;
328 unsigned short machine;
329 unsigned char ignored2[12];
330 unsigned __int64 phoff;
331 unsigned char ignored3[16];
332 unsigned short phnum;
333 } elf64;
334 struct
336 unsigned int magic;
337 unsigned int cputype;
338 unsigned int cpusubtype;
339 unsigned int filetype;
340 } macho;
341 IMAGE_DOS_HEADER mz;
342 } header;
344 DWORD len;
346 memset( info, 0, sizeof(*info) );
348 /* Seek to the start of the file and read the header information. */
349 if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1) return;
350 if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header)) return;
352 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
354 #ifdef WORDS_BIGENDIAN
355 BOOL byteswap = (header.elf.data == 1);
356 #else
357 BOOL byteswap = (header.elf.data == 2);
358 #endif
359 if (header.elf.class == 2) info->flags |= BINARY_FLAG_64BIT;
360 if (byteswap)
362 header.elf.type = RtlUshortByteSwap( header.elf.type );
363 header.elf.machine = RtlUshortByteSwap( header.elf.machine );
365 switch(header.elf.type)
367 case 2:
368 info->type = BINARY_UNIX_EXE;
369 break;
370 case 3:
372 LARGE_INTEGER phoff;
373 unsigned short phnum;
374 unsigned int type;
375 if (header.elf.class == 2)
377 phoff.QuadPart = byteswap ? RtlUlonglongByteSwap( header.elf64.phoff ) : header.elf64.phoff;
378 phnum = byteswap ? RtlUshortByteSwap( header.elf64.phnum ) : header.elf64.phnum;
380 else
382 phoff.QuadPart = byteswap ? RtlUlongByteSwap( header.elf.phoff ) : header.elf.phoff;
383 phnum = byteswap ? RtlUshortByteSwap( header.elf.phnum ) : header.elf.phnum;
385 while (phnum--)
387 if (SetFilePointerEx( hfile, phoff, NULL, FILE_BEGIN ) == -1) return;
388 if (!ReadFile( hfile, &type, sizeof(type), &len, NULL ) || len < sizeof(type)) return;
389 if (byteswap) type = RtlUlongByteSwap( type );
390 if (type == 3)
392 info->type = BINARY_UNIX_EXE;
393 break;
395 phoff.QuadPart += (header.elf.class == 2) ? 56 : 32;
397 if (!info->type) info->type = BINARY_UNIX_LIB;
398 break;
400 default:
401 return;
403 switch(header.elf.machine)
405 case 3: info->arch = IMAGE_FILE_MACHINE_I386; break;
406 case 20: info->arch = IMAGE_FILE_MACHINE_POWERPC; break;
407 case 40: info->arch = IMAGE_FILE_MACHINE_ARMNT; break;
408 case 50: info->arch = IMAGE_FILE_MACHINE_IA64; break;
409 case 62: info->arch = IMAGE_FILE_MACHINE_AMD64; break;
410 case 183: info->arch = IMAGE_FILE_MACHINE_ARM64; break;
413 /* Mach-o File with Endian set to Big Endian or Little Endian */
414 else if (header.macho.magic == 0xfeedface || header.macho.magic == 0xcefaedfe ||
415 header.macho.magic == 0xfeedfacf || header.macho.magic == 0xcffaedfe)
417 if ((header.macho.cputype >> 24) == 1) info->flags |= BINARY_FLAG_64BIT;
418 if (header.macho.magic == 0xcefaedfe || header.macho.magic == 0xcffaedfe)
420 header.macho.filetype = RtlUlongByteSwap( header.macho.filetype );
421 header.macho.cputype = RtlUlongByteSwap( header.macho.cputype );
423 switch(header.macho.filetype)
425 case 2: info->type = BINARY_UNIX_EXE; break;
426 case 8: info->type = BINARY_UNIX_LIB; break;
428 switch(header.macho.cputype)
430 case 0x00000007: info->arch = IMAGE_FILE_MACHINE_I386; break;
431 case 0x01000007: info->arch = IMAGE_FILE_MACHINE_AMD64; break;
432 case 0x0000000c: info->arch = IMAGE_FILE_MACHINE_ARMNT; break;
433 case 0x0100000c: info->arch = IMAGE_FILE_MACHINE_ARM64; break;
434 case 0x00000012: info->arch = IMAGE_FILE_MACHINE_POWERPC; break;
437 /* Not ELF, try DOS */
438 else if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
440 union
442 IMAGE_OS2_HEADER os2;
443 IMAGE_NT_HEADERS32 nt;
444 IMAGE_NT_HEADERS64 nt64;
445 } ext_header;
447 /* We do have a DOS image so we will now try to seek into
448 * the file by the amount indicated by the field
449 * "Offset to extended header" and read in the
450 * "magic" field information at that location.
451 * This will tell us if there is more header information
452 * to read or not.
454 info->type = BINARY_DOS;
455 info->arch = IMAGE_FILE_MACHINE_I386;
456 if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1) return;
457 if (!ReadFile( hfile, &ext_header, sizeof(ext_header), &len, NULL ) || len < 4) return;
459 /* Reading the magic field succeeded so
460 * we will try to determine what type it is.
462 if (!memcmp( &ext_header.nt.Signature, "PE\0\0", 4 ))
464 if (len >= sizeof(ext_header.nt.FileHeader))
466 static const char fakedll_signature[] = "Wine placeholder DLL";
467 char buffer[sizeof(fakedll_signature)];
469 info->type = BINARY_PE;
470 info->arch = ext_header.nt.FileHeader.Machine;
471 if (ext_header.nt.FileHeader.Characteristics & IMAGE_FILE_DLL)
472 info->flags |= BINARY_FLAG_DLL;
473 if (len < sizeof(ext_header)) /* clear remaining part of header if missing */
474 memset( (char *)&ext_header + len, 0, sizeof(ext_header) - len );
475 switch (ext_header.nt.OptionalHeader.Magic)
477 case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
478 info->res_start = ext_header.nt.OptionalHeader.ImageBase;
479 info->res_end = info->res_start + ext_header.nt.OptionalHeader.SizeOfImage;
480 break;
481 case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
482 info->res_start = ext_header.nt64.OptionalHeader.ImageBase;
483 info->res_end = info->res_start + ext_header.nt64.OptionalHeader.SizeOfImage;
484 info->flags |= BINARY_FLAG_64BIT;
485 break;
488 if (header.mz.e_lfanew >= sizeof(header.mz) + sizeof(fakedll_signature) &&
489 SetFilePointer( hfile, sizeof(header.mz), NULL, SEEK_SET ) == sizeof(header.mz) &&
490 ReadFile( hfile, buffer, sizeof(fakedll_signature), &len, NULL ) &&
491 len == sizeof(fakedll_signature) &&
492 !memcmp( buffer, fakedll_signature, sizeof(fakedll_signature) ))
494 info->flags |= BINARY_FLAG_FAKEDLL;
498 else if (!memcmp( &ext_header.os2.ne_magic, "NE", 2 ))
500 /* This is a Windows executable (NE) header. This can
501 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
502 * DOS program (running under a DOS extender). To decide
503 * which, we'll have to read the NE header.
505 if (len >= sizeof(ext_header.os2))
507 if (ext_header.os2.ne_flags & NE_FFLAGS_LIBMODULE) info->flags |= BINARY_FLAG_DLL;
508 switch ( ext_header.os2.ne_exetyp )
510 case 1: info->type = BINARY_OS216; break; /* OS/2 */
511 case 2: info->type = BINARY_WIN16; break; /* Windows */
512 case 3: info->type = BINARY_DOS; break; /* European MS-DOS 4.x */
513 case 4: info->type = BINARY_WIN16; break; /* Windows 386; FIXME: is this 32bit??? */
514 case 5: info->type = BINARY_DOS; break; /* BOSS, Borland Operating System Services */
515 /* other types, e.g. 0 is: "unknown" */
516 default: info->type = MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ext_header.os2); break;
523 /***********************************************************************
524 * GetBinaryTypeW [KERNEL32.@]
526 * Determine whether a file is executable, and if so, what kind.
528 * PARAMS
529 * lpApplicationName [I] Path of the file to check
530 * lpBinaryType [O] Destination for the binary type
532 * RETURNS
533 * TRUE, if the file is an executable, in which case lpBinaryType is set.
534 * FALSE, if the file is not an executable or if the function fails.
536 * NOTES
537 * The type of executable is a property that determines which subsystem an
538 * executable file runs under. lpBinaryType can be set to one of the following
539 * values:
540 * SCS_32BIT_BINARY: A Win32 based application
541 * SCS_64BIT_BINARY: A Win64 based application
542 * SCS_DOS_BINARY: An MS-Dos based application
543 * SCS_WOW_BINARY: A Win16 based application
544 * SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
545 * SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
546 * SCS_OS216_BINARY: A 16bit OS/2 based application
548 * To find the binary type, this function reads in the files header information.
549 * If extended header information is not present it will assume that the file
550 * is a DOS executable. If extended header information is present it will
551 * determine if the file is a 16, 32 or 64 bit Windows executable by checking the
552 * flags in the header.
554 * ".com" and ".pif" files are only recognized by their file name extension,
555 * as per native Windows.
557 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
559 BOOL ret = FALSE;
560 HANDLE hfile;
561 struct binary_info binary_info;
563 TRACE("%s\n", debugstr_w(lpApplicationName) );
565 /* Sanity check.
567 if ( lpApplicationName == NULL || lpBinaryType == NULL )
568 return FALSE;
570 /* Open the file indicated by lpApplicationName for reading.
572 hfile = CreateFileW( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
573 NULL, OPEN_EXISTING, 0, 0 );
574 if ( hfile == INVALID_HANDLE_VALUE )
575 return FALSE;
577 /* Check binary type
579 MODULE_get_binary_info( hfile, &binary_info );
580 switch (binary_info.type)
582 case BINARY_UNKNOWN:
584 static const WCHAR comW[] = { '.','C','O','M',0 };
585 static const WCHAR pifW[] = { '.','P','I','F',0 };
586 const WCHAR *ptr;
588 /* try to determine from file name */
589 ptr = strrchrW( lpApplicationName, '.' );
590 if (!ptr) break;
591 if (!strcmpiW( ptr, comW ))
593 *lpBinaryType = SCS_DOS_BINARY;
594 ret = TRUE;
596 else if (!strcmpiW( ptr, pifW ))
598 *lpBinaryType = SCS_PIF_BINARY;
599 ret = TRUE;
601 break;
603 case BINARY_PE:
604 *lpBinaryType = (binary_info.flags & BINARY_FLAG_64BIT) ? SCS_64BIT_BINARY : SCS_32BIT_BINARY;
605 ret = TRUE;
606 break;
607 case BINARY_WIN16:
608 *lpBinaryType = SCS_WOW_BINARY;
609 ret = TRUE;
610 break;
611 case BINARY_OS216:
612 *lpBinaryType = SCS_OS216_BINARY;
613 ret = TRUE;
614 break;
615 case BINARY_DOS:
616 *lpBinaryType = SCS_DOS_BINARY;
617 ret = TRUE;
618 break;
619 case BINARY_UNIX_EXE:
620 case BINARY_UNIX_LIB:
621 ret = FALSE;
622 break;
625 CloseHandle( hfile );
626 return ret;
629 /***********************************************************************
630 * GetBinaryTypeA [KERNEL32.@]
631 * GetBinaryType [KERNEL32.@]
633 * See GetBinaryTypeW.
635 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
637 ANSI_STRING app_nameA;
638 NTSTATUS status;
640 TRACE("%s\n", debugstr_a(lpApplicationName));
642 /* Sanity check.
644 if ( lpApplicationName == NULL || lpBinaryType == NULL )
645 return FALSE;
647 RtlInitAnsiString(&app_nameA, lpApplicationName);
648 status = RtlAnsiStringToUnicodeString(&NtCurrentTeb()->StaticUnicodeString,
649 &app_nameA, FALSE);
650 if (!status)
651 return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
653 SetLastError(RtlNtStatusToDosError(status));
654 return FALSE;
657 /***********************************************************************
658 * GetModuleHandleExA (KERNEL32.@)
660 BOOL WINAPI GetModuleHandleExA( DWORD flags, LPCSTR name, HMODULE *module )
662 WCHAR *nameW;
664 if (!name || (flags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS))
665 return GetModuleHandleExW( flags, (LPCWSTR)name, module );
667 if (!(nameW = FILE_name_AtoW( name, FALSE ))) return FALSE;
668 return GetModuleHandleExW( flags, nameW, module );
671 /***********************************************************************
672 * GetModuleHandleExW (KERNEL32.@)
674 BOOL WINAPI GetModuleHandleExW( DWORD flags, LPCWSTR name, HMODULE *module )
676 NTSTATUS status = STATUS_SUCCESS;
677 HMODULE ret;
678 ULONG_PTR magic;
679 BOOL lock;
681 if (!module)
683 SetLastError( ERROR_INVALID_PARAMETER );
684 return FALSE;
687 /* if we are messing with the refcount, grab the loader lock */
688 lock = (flags & GET_MODULE_HANDLE_EX_FLAG_PIN) || !(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT);
689 if (lock)
690 LdrLockLoaderLock( 0, NULL, &magic );
692 if (!name)
694 ret = NtCurrentTeb()->Peb->ImageBaseAddress;
696 else if (flags & GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS)
698 void *dummy;
699 if (!(ret = RtlPcToFileHeader( (void *)name, &dummy ))) status = STATUS_DLL_NOT_FOUND;
701 else
703 UNICODE_STRING wstr;
704 RtlInitUnicodeString( &wstr, name );
705 status = LdrGetDllHandle( NULL, 0, &wstr, &ret );
708 if (status == STATUS_SUCCESS)
710 if (flags & GET_MODULE_HANDLE_EX_FLAG_PIN)
711 LdrAddRefDll( LDR_ADDREF_DLL_PIN, ret );
712 else if (!(flags & GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT))
713 LdrAddRefDll( 0, ret );
715 else SetLastError( RtlNtStatusToDosError( status ) );
717 if (lock)
718 LdrUnlockLoaderLock( 0, magic );
720 if (status == STATUS_SUCCESS) *module = ret;
721 else *module = NULL;
723 return (status == STATUS_SUCCESS);
726 /***********************************************************************
727 * GetModuleHandleA (KERNEL32.@)
729 * Get the handle of a dll loaded into the process address space.
731 * PARAMS
732 * module [I] Name of the dll
734 * RETURNS
735 * Success: A handle to the loaded dll.
736 * Failure: A NULL handle. Use GetLastError() to determine the cause.
738 HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR module)
740 HMODULE ret;
742 GetModuleHandleExA( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, module, &ret );
743 return ret;
746 /***********************************************************************
747 * GetModuleHandleW (KERNEL32.@)
749 * Unicode version of GetModuleHandleA.
751 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
753 HMODULE ret;
755 GetModuleHandleExW( GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, module, &ret );
756 return ret;
760 /***********************************************************************
761 * GetModuleFileNameA (KERNEL32.@)
763 * Get the file name of a loaded module from its handle.
765 * RETURNS
766 * Success: The length of the file name, excluding the terminating NUL.
767 * Failure: 0. Use GetLastError() to determine the cause.
769 * NOTES
770 * This function always returns the long path of hModule
771 * The function doesn't write a terminating '\0' if the buffer is too
772 * small.
774 DWORD WINAPI GetModuleFileNameA(
775 HMODULE hModule, /* [in] Module handle (32 bit) */
776 LPSTR lpFileName, /* [out] Destination for file name */
777 DWORD size ) /* [in] Size of lpFileName in characters */
779 LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
780 DWORD len;
782 if (!filenameW)
784 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
785 return 0;
787 if ((len = GetModuleFileNameW( hModule, filenameW, size )))
789 len = FILE_name_WtoA( filenameW, len, lpFileName, size );
790 if (len < size)
791 lpFileName[len] = '\0';
792 else
793 SetLastError( ERROR_INSUFFICIENT_BUFFER );
795 HeapFree( GetProcessHeap(), 0, filenameW );
796 return len;
799 /***********************************************************************
800 * GetModuleFileNameW (KERNEL32.@)
802 * Unicode version of GetModuleFileNameA.
804 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
806 ULONG len = 0;
807 ULONG_PTR magic;
808 LDR_MODULE *pldr;
809 NTSTATUS nts;
810 WIN16_SUBSYSTEM_TIB *win16_tib;
812 if (!hModule && ((win16_tib = NtCurrentTeb()->Tib.SubSystemTib)) && win16_tib->exe_name)
814 len = min(size, win16_tib->exe_name->Length / sizeof(WCHAR));
815 memcpy( lpFileName, win16_tib->exe_name->Buffer, len * sizeof(WCHAR) );
816 if (len < size) lpFileName[len] = '\0';
817 goto done;
820 LdrLockLoaderLock( 0, NULL, &magic );
822 if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
823 nts = LdrFindEntryForAddress( hModule, &pldr );
824 if (nts == STATUS_SUCCESS)
826 len = min(size, pldr->FullDllName.Length / sizeof(WCHAR));
827 memcpy(lpFileName, pldr->FullDllName.Buffer, len * sizeof(WCHAR));
828 if (len < size)
830 lpFileName[len] = '\0';
831 SetLastError( 0 );
833 else
834 SetLastError( ERROR_INSUFFICIENT_BUFFER );
836 else SetLastError( RtlNtStatusToDosError( nts ) );
838 LdrUnlockLoaderLock( 0, magic );
839 done:
840 TRACE( "%s\n", debugstr_wn(lpFileName, len) );
841 return len;
845 /***********************************************************************
846 * get_dll_system_path
848 static const WCHAR *get_dll_system_path(void)
850 static WCHAR *cached_path;
852 if (!cached_path)
854 WCHAR *p, *path;
855 int len = 1;
857 len += 2 * GetSystemDirectoryW( NULL, 0 );
858 len += GetWindowsDirectoryW( NULL, 0 );
859 p = path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
860 GetSystemDirectoryW( p, path + len - p);
861 p += strlenW(p);
862 /* if system directory ends in "32" add 16-bit version too */
863 if (p[-2] == '3' && p[-1] == '2')
865 *p++ = ';';
866 GetSystemDirectoryW( p, path + len - p);
867 p += strlenW(p) - 2;
869 *p++ = ';';
870 GetWindowsDirectoryW( p, path + len - p);
871 cached_path = path;
873 return cached_path;
876 /***********************************************************************
877 * get_dll_safe_mode
879 static BOOL get_dll_safe_mode(void)
881 static const WCHAR keyW[] = {'\\','R','e','g','i','s','t','r','y','\\',
882 'M','a','c','h','i','n','e','\\',
883 'S','y','s','t','e','m','\\',
884 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
885 'C','o','n','t','r','o','l','\\',
886 'S','e','s','s','i','o','n',' ','M','a','n','a','g','e','r',0};
887 static const WCHAR valueW[] = {'S','a','f','e','D','l','l','S','e','a','r','c','h','M','o','d','e',0};
889 static int safe_mode = -1;
891 if (safe_mode == -1)
893 char buffer[offsetof(KEY_VALUE_PARTIAL_INFORMATION, Data[sizeof(DWORD)])];
894 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
895 OBJECT_ATTRIBUTES attr;
896 UNICODE_STRING nameW;
897 HANDLE hkey;
898 DWORD size = sizeof(buffer);
900 attr.Length = sizeof(attr);
901 attr.RootDirectory = 0;
902 attr.ObjectName = &nameW;
903 attr.Attributes = 0;
904 attr.SecurityDescriptor = NULL;
905 attr.SecurityQualityOfService = NULL;
907 safe_mode = 1;
908 RtlInitUnicodeString( &nameW, keyW );
909 if (!NtOpenKey( &hkey, KEY_READ, &attr ))
911 RtlInitUnicodeString( &nameW, valueW );
912 if (!NtQueryValueKey( hkey, &nameW, KeyValuePartialInformation, buffer, size, &size ) &&
913 info->Type == REG_DWORD && info->DataLength == sizeof(DWORD))
914 safe_mode = !!*(DWORD *)info->Data;
915 NtClose( hkey );
917 if (!safe_mode) TRACE( "SafeDllSearchMode disabled through the registry\n" );
919 return safe_mode;
922 /******************************************************************
923 * get_module_path_end
925 * Returns the end of the directory component of the module path.
927 static inline const WCHAR *get_module_path_end(const WCHAR *module)
929 const WCHAR *p;
930 const WCHAR *mod_end = module;
931 if (!module) return mod_end;
933 if ((p = strrchrW( mod_end, '\\' ))) mod_end = p;
934 if ((p = strrchrW( mod_end, '/' ))) mod_end = p;
935 if (mod_end == module + 2 && module[1] == ':') mod_end++;
936 if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
938 return mod_end;
942 /******************************************************************
943 * append_path_len
945 * Append a counted string to the load path. Helper for MODULE_get_dll_load_path.
947 static inline WCHAR *append_path_len( WCHAR *p, const WCHAR *str, DWORD len )
949 if (!len) return p;
950 memcpy( p, str, len * sizeof(WCHAR) );
951 p[len] = ';';
952 return p + len + 1;
956 /******************************************************************
957 * append_path
959 * Append a string to the load path. Helper for MODULE_get_dll_load_path.
961 static inline WCHAR *append_path( WCHAR *p, const WCHAR *str )
963 return append_path_len( p, str, strlenW(str) );
967 /******************************************************************
968 * MODULE_get_dll_load_path
970 * Compute the load path to use for a given dll.
971 * Returned pointer must be freed by caller.
973 WCHAR *MODULE_get_dll_load_path( LPCWSTR module, int safe_mode )
975 static const WCHAR pathW[] = {'P','A','T','H',0};
976 static const WCHAR dotW[] = {'.',0};
978 const WCHAR *system_path = get_dll_system_path();
979 const WCHAR *mod_end = NULL;
980 UNICODE_STRING name, value;
981 WCHAR *p, *ret;
982 int len = 0, path_len = 0;
984 /* adjust length for module name */
986 if (module)
987 mod_end = get_module_path_end( module );
988 /* if module is NULL or doesn't contain a path, fall back to directory
989 * process was loaded from */
990 if (module == mod_end)
992 module = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
993 mod_end = get_module_path_end( module );
995 len += (mod_end - module) + 1;
997 len += strlenW( system_path ) + 2;
999 /* get the PATH variable */
1001 RtlInitUnicodeString( &name, pathW );
1002 value.Length = 0;
1003 value.MaximumLength = 0;
1004 value.Buffer = NULL;
1005 if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
1006 path_len = value.Length;
1008 RtlEnterCriticalSection( &dlldir_section );
1009 if (safe_mode == -1) safe_mode = get_dll_safe_mode();
1010 if (dll_directory) len += strlenW(dll_directory) + 1;
1011 else len += 2; /* current directory */
1012 if ((p = ret = HeapAlloc( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) )))
1014 if (module) p = append_path_len( p, module, mod_end - module );
1016 if (dll_directory) p = append_path( p, dll_directory );
1017 else if (!safe_mode) p = append_path( p, dotW );
1019 p = append_path( p, system_path );
1021 if (!dll_directory && safe_mode) p = append_path( p, dotW );
1023 RtlLeaveCriticalSection( &dlldir_section );
1024 if (!ret) return NULL;
1026 value.Buffer = p;
1027 value.MaximumLength = path_len;
1029 while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
1031 WCHAR *new_ptr;
1033 /* grow the buffer and retry */
1034 path_len = value.Length;
1035 if (!(new_ptr = HeapReAlloc( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
1037 HeapFree( GetProcessHeap(), 0, ret );
1038 return NULL;
1040 value.Buffer = new_ptr + (value.Buffer - ret);
1041 value.MaximumLength = path_len;
1042 ret = new_ptr;
1044 value.Buffer[value.Length / sizeof(WCHAR)] = 0;
1045 return ret;
1049 /******************************************************************
1050 * get_dll_load_path_search_flags
1052 static WCHAR *get_dll_load_path_search_flags( LPCWSTR module, DWORD flags )
1054 const WCHAR *image = NULL, *mod_end, *image_end;
1055 struct dll_dir_entry *dir;
1056 WCHAR *p, *ret;
1057 int len = 1;
1059 if (flags & LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)
1060 flags |= (LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
1061 LOAD_LIBRARY_SEARCH_USER_DIRS |
1062 LOAD_LIBRARY_SEARCH_SYSTEM32);
1064 if (flags & LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR)
1066 DWORD type = RtlDetermineDosPathNameType_U( module );
1067 if (type != ABSOLUTE_DRIVE_PATH && type != ABSOLUTE_PATH)
1069 SetLastError( ERROR_INVALID_PARAMETER );
1070 return NULL;
1072 mod_end = get_module_path_end( module );
1073 len += (mod_end - module) + 1;
1075 else module = NULL;
1077 RtlEnterCriticalSection( &dlldir_section );
1079 if (flags & LOAD_LIBRARY_SEARCH_APPLICATION_DIR)
1081 image = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
1082 image_end = get_module_path_end( image );
1083 len += (image_end - image) + 1;
1086 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
1088 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
1089 len += strlenW( dir->dir ) + 1;
1090 if (dll_directory) len += strlenW(dll_directory) + 1;
1093 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) len += GetSystemDirectoryW( NULL, 0 );
1095 if ((p = ret = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1097 if (module) p = append_path_len( p, module, mod_end - module );
1098 if (image) p = append_path_len( p, image, image_end - image );
1099 if (flags & LOAD_LIBRARY_SEARCH_USER_DIRS)
1101 LIST_FOR_EACH_ENTRY( dir, &dll_dir_list, struct dll_dir_entry, entry )
1102 p = append_path( p, dir->dir );
1103 if (dll_directory) p = append_path( p, dll_directory );
1105 if (flags & LOAD_LIBRARY_SEARCH_SYSTEM32) GetSystemDirectoryW( p, ret + len - p );
1106 else
1108 if (p > ret) p--;
1109 *p = 0;
1113 RtlLeaveCriticalSection( &dlldir_section );
1114 return ret;
1118 /******************************************************************
1119 * load_library_as_datafile
1121 static BOOL load_library_as_datafile( LPCWSTR name, HMODULE *hmod, DWORD flags )
1123 static const WCHAR dotDLL[] = {'.','d','l','l',0};
1125 WCHAR filenameW[MAX_PATH];
1126 HANDLE hFile = INVALID_HANDLE_VALUE;
1127 HANDLE mapping;
1128 HMODULE module;
1129 DWORD sharing = FILE_SHARE_READ;
1131 *hmod = 0;
1133 if (!(flags & LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE)) sharing |= FILE_SHARE_WRITE;
1135 if (SearchPathW( NULL, name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
1136 filenameW, NULL ))
1138 hFile = CreateFileW( filenameW, GENERIC_READ, sharing, NULL, OPEN_EXISTING, 0, 0 );
1140 if (hFile == INVALID_HANDLE_VALUE) return FALSE;
1142 mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
1143 CloseHandle( hFile );
1144 if (!mapping) return FALSE;
1146 module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
1147 CloseHandle( mapping );
1148 if (!module) return FALSE;
1150 /* make sure it's a valid PE file */
1151 if (!RtlImageNtHeader(module))
1153 UnmapViewOfFile( module );
1154 return FALSE;
1156 *hmod = (HMODULE)((char *)module + 1); /* set low bit of handle to indicate datafile module */
1157 return TRUE;
1161 /******************************************************************
1162 * load_library
1164 * Helper for LoadLibraryExA/W.
1166 static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags )
1168 NTSTATUS nts;
1169 HMODULE hModule;
1170 WCHAR *load_path;
1171 const DWORD load_library_search_flags = (LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR |
1172 LOAD_LIBRARY_SEARCH_APPLICATION_DIR |
1173 LOAD_LIBRARY_SEARCH_USER_DIRS |
1174 LOAD_LIBRARY_SEARCH_SYSTEM32 |
1175 LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
1176 const DWORD unsupported_flags = (LOAD_IGNORE_CODE_AUTHZ_LEVEL |
1177 LOAD_LIBRARY_AS_IMAGE_RESOURCE |
1178 LOAD_LIBRARY_REQUIRE_SIGNED_TARGET);
1180 if (!(flags & load_library_search_flags)) flags |= default_search_flags;
1182 if( flags & unsupported_flags)
1183 FIXME("unsupported flag(s) used (flags: 0x%08x)\n", flags);
1185 if (flags & load_library_search_flags)
1186 load_path = get_dll_load_path_search_flags( libname->Buffer, flags );
1187 else
1188 load_path = MODULE_get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL, -1 );
1189 if (!load_path) return 0;
1191 if (flags & (LOAD_LIBRARY_AS_DATAFILE | LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE))
1193 ULONG_PTR magic;
1195 LdrLockLoaderLock( 0, NULL, &magic );
1196 if (!LdrGetDllHandle( load_path, flags, libname, &hModule ))
1198 LdrAddRefDll( 0, hModule );
1199 LdrUnlockLoaderLock( 0, magic );
1200 goto done;
1202 LdrUnlockLoaderLock( 0, magic );
1204 /* The method in load_library_as_datafile allows searching for the
1205 * 'native' libraries only
1207 if (load_library_as_datafile( libname->Buffer, &hModule, flags )) goto done;
1208 flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
1209 /* Fallback to normal behaviour */
1212 nts = LdrLoadDll( load_path, flags, libname, &hModule );
1213 if (nts != STATUS_SUCCESS)
1215 hModule = 0;
1216 if (nts == STATUS_DLL_NOT_FOUND && (GetVersion() & 0x80000000))
1217 SetLastError( ERROR_DLL_NOT_FOUND );
1218 else
1219 SetLastError( RtlNtStatusToDosError( nts ) );
1221 done:
1222 HeapFree( GetProcessHeap(), 0, load_path );
1223 return hModule;
1227 /******************************************************************
1228 * LoadLibraryExA (KERNEL32.@)
1230 * Load a dll file into the process address space.
1232 * PARAMS
1233 * libname [I] Name of the file to load
1234 * hfile [I] Reserved, must be 0.
1235 * flags [I] Flags for loading the dll
1237 * RETURNS
1238 * Success: A handle to the loaded dll.
1239 * Failure: A NULL handle. Use GetLastError() to determine the cause.
1241 * NOTES
1242 * The HFILE parameter is not used and marked reserved in the SDK. I can
1243 * only guess that it should force a file to be mapped, but I rather
1244 * ignore the parameter because it would be extremely difficult to
1245 * integrate this with different types of module representations.
1247 HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
1249 WCHAR *libnameW;
1251 if (!(libnameW = FILE_name_AtoW( libname, FALSE ))) return 0;
1252 return LoadLibraryExW( libnameW, hfile, flags );
1255 /***********************************************************************
1256 * LoadLibraryExW (KERNEL32.@)
1258 * Unicode version of LoadLibraryExA.
1260 HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
1262 UNICODE_STRING wstr;
1263 HMODULE res;
1265 if (!libnameW)
1267 SetLastError(ERROR_INVALID_PARAMETER);
1268 return 0;
1270 RtlInitUnicodeString( &wstr, libnameW );
1271 if (wstr.Buffer[wstr.Length/sizeof(WCHAR) - 1] != ' ')
1272 return load_library( &wstr, flags );
1274 /* Library name has trailing spaces */
1275 RtlCreateUnicodeString( &wstr, libnameW );
1276 while (wstr.Length > sizeof(WCHAR) &&
1277 wstr.Buffer[wstr.Length/sizeof(WCHAR) - 1] == ' ')
1279 wstr.Length -= sizeof(WCHAR);
1281 wstr.Buffer[wstr.Length/sizeof(WCHAR)] = '\0';
1282 res = load_library( &wstr, flags );
1283 RtlFreeUnicodeString( &wstr );
1284 return res;
1287 /***********************************************************************
1288 * LoadLibraryA (KERNEL32.@)
1290 * Load a dll file into the process address space.
1292 * PARAMS
1293 * libname [I] Name of the file to load
1295 * RETURNS
1296 * Success: A handle to the loaded dll.
1297 * Failure: A NULL handle. Use GetLastError() to determine the cause.
1299 * NOTES
1300 * See LoadLibraryExA().
1302 HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryA(LPCSTR libname)
1304 return LoadLibraryExA(libname, 0, 0);
1307 /***********************************************************************
1308 * LoadLibraryW (KERNEL32.@)
1310 * Unicode version of LoadLibraryA.
1312 HMODULE WINAPI DECLSPEC_HOTPATCH LoadLibraryW(LPCWSTR libnameW)
1314 return LoadLibraryExW(libnameW, 0, 0);
1317 /***********************************************************************
1318 * FreeLibrary (KERNEL32.@)
1320 * Free a dll loaded into the process address space.
1322 * PARAMS
1323 * hLibModule [I] Handle to the dll returned by LoadLibraryA().
1325 * RETURNS
1326 * Success: TRUE. The dll is removed if it is not still in use.
1327 * Failure: FALSE. Use GetLastError() to determine the cause.
1329 BOOL WINAPI DECLSPEC_HOTPATCH FreeLibrary(HINSTANCE hLibModule)
1331 BOOL retv = FALSE;
1332 NTSTATUS nts;
1334 if (!hLibModule)
1336 SetLastError( ERROR_INVALID_HANDLE );
1337 return FALSE;
1340 if ((ULONG_PTR)hLibModule & 1)
1342 /* this is a LOAD_LIBRARY_AS_DATAFILE module */
1343 char *ptr = (char *)hLibModule - 1;
1344 return UnmapViewOfFile( ptr );
1347 if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
1348 else SetLastError( RtlNtStatusToDosError( nts ) );
1350 return retv;
1353 /***********************************************************************
1354 * GetProcAddress (KERNEL32.@)
1356 * Find the address of an exported symbol in a loaded dll.
1358 * PARAMS
1359 * hModule [I] Handle to the dll returned by LoadLibraryA().
1360 * function [I] Name of the symbol, or an integer ordinal number < 16384
1362 * RETURNS
1363 * Success: A pointer to the symbol in the process address space.
1364 * Failure: NULL. Use GetLastError() to determine the cause.
1366 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
1368 NTSTATUS nts;
1369 FARPROC fp;
1371 if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
1373 if ((ULONG_PTR)function >> 16)
1375 ANSI_STRING str;
1377 RtlInitAnsiString( &str, function );
1378 nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp );
1380 else
1381 nts = LdrGetProcedureAddress( hModule, NULL, LOWORD(function), (void**)&fp );
1382 if (nts != STATUS_SUCCESS)
1384 SetLastError( RtlNtStatusToDosError( nts ) );
1385 fp = NULL;
1387 return fp;
1390 /***********************************************************************
1391 * DelayLoadFailureHook (KERNEL32.@)
1393 FARPROC WINAPI DelayLoadFailureHook( LPCSTR name, LPCSTR function )
1395 ULONG_PTR args[2];
1397 if ((ULONG_PTR)function >> 16)
1398 ERR( "failed to delay load %s.%s\n", name, function );
1399 else
1400 ERR( "failed to delay load %s.%u\n", name, LOWORD(function) );
1401 args[0] = (ULONG_PTR)name;
1402 args[1] = (ULONG_PTR)function;
1403 RaiseException( EXCEPTION_WINE_STUB, EH_NONCONTINUABLE, 2, args );
1404 return NULL;
1407 typedef struct {
1408 HANDLE process;
1409 PLIST_ENTRY head, current;
1410 LDR_MODULE ldr_module;
1411 } MODULE_ITERATOR;
1413 static BOOL init_module_iterator(MODULE_ITERATOR *iter, HANDLE process)
1415 PROCESS_BASIC_INFORMATION pbi;
1416 PPEB_LDR_DATA ldr_data;
1417 NTSTATUS status;
1419 /* Get address of PEB */
1420 status = NtQueryInformationProcess(process, ProcessBasicInformation,
1421 &pbi, sizeof(pbi), NULL);
1422 if (status != STATUS_SUCCESS)
1424 SetLastError(RtlNtStatusToDosError(status));
1425 return FALSE;
1428 /* Read address of LdrData from PEB */
1429 if (!ReadProcessMemory(process, &pbi.PebBaseAddress->LdrData,
1430 &ldr_data, sizeof(ldr_data), NULL))
1431 return FALSE;
1433 /* Read address of first module from LdrData */
1434 if (!ReadProcessMemory(process,
1435 &ldr_data->InLoadOrderModuleList.Flink,
1436 &iter->current, sizeof(iter->current), NULL))
1437 return FALSE;
1439 iter->head = &ldr_data->InLoadOrderModuleList;
1440 iter->process = process;
1442 return TRUE;
1445 static int module_iterator_next(MODULE_ITERATOR *iter)
1447 if (iter->current == iter->head)
1448 return 0;
1450 if (!ReadProcessMemory(iter->process,
1451 CONTAINING_RECORD(iter->current, LDR_MODULE, InLoadOrderModuleList),
1452 &iter->ldr_module, sizeof(iter->ldr_module), NULL))
1453 return -1;
1455 iter->current = iter->ldr_module.InLoadOrderModuleList.Flink;
1456 return 1;
1459 static BOOL get_ldr_module(HANDLE process, HMODULE module, LDR_MODULE *ldr_module)
1461 MODULE_ITERATOR iter;
1462 INT ret;
1464 if (!init_module_iterator(&iter, process))
1465 return FALSE;
1467 while ((ret = module_iterator_next(&iter)) > 0)
1468 /* When hModule is NULL we return the process image - which will be
1469 * the first module since our iterator uses InLoadOrderModuleList */
1470 if (!module || module == iter.ldr_module.BaseAddress)
1472 *ldr_module = iter.ldr_module;
1473 return TRUE;
1476 if (ret == 0)
1477 SetLastError(ERROR_INVALID_HANDLE);
1479 return FALSE;
1482 /***********************************************************************
1483 * K32EnumProcessModules (KERNEL32.@)
1485 * NOTES
1486 * Returned list is in load order.
1488 BOOL WINAPI K32EnumProcessModules(HANDLE process, HMODULE *lphModule,
1489 DWORD cb, DWORD *needed)
1491 MODULE_ITERATOR iter;
1492 INT ret;
1494 if (!init_module_iterator(&iter, process))
1495 return FALSE;
1497 if ((cb && !lphModule) || !needed)
1499 SetLastError(ERROR_NOACCESS);
1500 return FALSE;
1503 *needed = 0;
1505 while ((ret = module_iterator_next(&iter)) > 0)
1507 if (cb >= sizeof(HMODULE))
1509 *lphModule++ = iter.ldr_module.BaseAddress;
1510 cb -= sizeof(HMODULE);
1512 *needed += sizeof(HMODULE);
1515 return ret == 0;
1518 /***********************************************************************
1519 * K32EnumProcessModulesEx (KERNEL32.@)
1521 * NOTES
1522 * Returned list is in load order.
1524 BOOL WINAPI K32EnumProcessModulesEx(HANDLE process, HMODULE *lphModule,
1525 DWORD cb, DWORD *needed, DWORD filter)
1527 FIXME("(%p, %p, %d, %p, %d) semi-stub\n",
1528 process, lphModule, cb, needed, filter);
1529 return K32EnumProcessModules(process, lphModule, cb, needed);
1532 /***********************************************************************
1533 * K32GetModuleBaseNameW (KERNEL32.@)
1535 DWORD WINAPI K32GetModuleBaseNameW(HANDLE process, HMODULE module,
1536 LPWSTR base_name, DWORD size)
1538 LDR_MODULE ldr_module;
1540 if (!get_ldr_module(process, module, &ldr_module))
1541 return 0;
1543 size = min(ldr_module.BaseDllName.Length / sizeof(WCHAR), size);
1544 if (!ReadProcessMemory(process, ldr_module.BaseDllName.Buffer,
1545 base_name, size * sizeof(WCHAR), NULL))
1546 return 0;
1548 base_name[size] = 0;
1549 return size;
1552 /***********************************************************************
1553 * K32GetModuleBaseNameA (KERNEL32.@)
1555 DWORD WINAPI K32GetModuleBaseNameA(HANDLE process, HMODULE module,
1556 LPSTR base_name, DWORD size)
1558 WCHAR *base_name_w;
1559 DWORD len, ret = 0;
1561 if(!base_name || !size) {
1562 SetLastError(ERROR_INVALID_PARAMETER);
1563 return 0;
1566 base_name_w = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * size);
1567 if(!base_name_w)
1568 return 0;
1570 len = K32GetModuleBaseNameW(process, module, base_name_w, size);
1571 TRACE("%d, %s\n", len, debugstr_w(base_name_w));
1572 if (len)
1574 ret = WideCharToMultiByte(CP_ACP, 0, base_name_w, len,
1575 base_name, size, NULL, NULL);
1576 if (ret < size) base_name[ret] = 0;
1578 HeapFree(GetProcessHeap(), 0, base_name_w);
1579 return ret;
1582 /***********************************************************************
1583 * K32GetModuleFileNameExW (KERNEL32.@)
1585 DWORD WINAPI K32GetModuleFileNameExW(HANDLE process, HMODULE module,
1586 LPWSTR file_name, DWORD size)
1588 LDR_MODULE ldr_module;
1589 DWORD len;
1591 if (!size) return 0;
1593 if(!get_ldr_module(process, module, &ldr_module))
1594 return 0;
1596 len = ldr_module.FullDllName.Length / sizeof(WCHAR);
1597 if (!ReadProcessMemory(process, ldr_module.FullDllName.Buffer,
1598 file_name, min( len, size ) * sizeof(WCHAR), NULL))
1599 return 0;
1601 if (len < size)
1603 file_name[len] = 0;
1604 return len;
1606 else
1608 file_name[size - 1] = 0;
1609 return size;
1613 /***********************************************************************
1614 * K32GetModuleFileNameExA (KERNEL32.@)
1616 DWORD WINAPI K32GetModuleFileNameExA(HANDLE process, HMODULE module,
1617 LPSTR file_name, DWORD size)
1619 WCHAR *ptr;
1620 DWORD len;
1622 TRACE("(hProcess=%p, hModule=%p, %p, %d)\n", process, module, file_name, size);
1624 if (!file_name || !size)
1626 SetLastError( ERROR_INVALID_PARAMETER );
1627 return 0;
1630 if ( process == GetCurrentProcess() )
1632 len = GetModuleFileNameA( module, file_name, size );
1633 if (size) file_name[size - 1] = '\0';
1634 return len;
1637 if (!(ptr = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR)))) return 0;
1639 len = K32GetModuleFileNameExW(process, module, ptr, size);
1640 if (!len)
1642 file_name[0] = '\0';
1644 else
1646 if (!WideCharToMultiByte( CP_ACP, 0, ptr, -1, file_name, size, NULL, NULL ))
1648 file_name[size - 1] = 0;
1649 len = size;
1651 else if (len < size) len = strlen( file_name );
1654 HeapFree(GetProcessHeap(), 0, ptr);
1655 return len;
1658 /***********************************************************************
1659 * K32GetModuleInformation (KERNEL32.@)
1661 BOOL WINAPI K32GetModuleInformation(HANDLE process, HMODULE module,
1662 MODULEINFO *modinfo, DWORD cb)
1664 LDR_MODULE ldr_module;
1666 if (cb < sizeof(MODULEINFO))
1668 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1669 return FALSE;
1672 if (!get_ldr_module(process, module, &ldr_module))
1673 return FALSE;
1675 modinfo->lpBaseOfDll = ldr_module.BaseAddress;
1676 modinfo->SizeOfImage = ldr_module.SizeOfImage;
1677 modinfo->EntryPoint = ldr_module.EntryPoint;
1678 return TRUE;
1681 #ifdef __i386__
1683 /***********************************************************************
1684 * __wine_dll_register_16 (KERNEL32.@)
1686 * No longer used.
1688 void __wine_dll_register_16( const IMAGE_DOS_HEADER *header, const char *file_name )
1690 ERR( "loading old style 16-bit dll %s no longer supported\n", file_name );
1694 /***********************************************************************
1695 * __wine_dll_unregister_16 (KERNEL32.@)
1697 * No longer used.
1699 void __wine_dll_unregister_16( const IMAGE_DOS_HEADER *header )
1703 #endif