Removed too strict header check to enable execution of handcoded PE
[wine] / dlls / kernel / module.c
1 /*
2  * Modules
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #ifdef HAVE_SYS_TYPES_H
29 # include <sys/types.h>
30 #endif
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include "wine/winbase16.h"
35 #include "winerror.h"
36 #include "ntstatus.h"
37 #include "windef.h"
38 #include "winbase.h"
39 #include "winreg.h"
40 #include "winternl.h"
41 #include "thread.h"
42 #include "module.h"
43
44 #include "wine/debug.h"
45 #include "wine/unicode.h"
46 #include "wine/server.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(module);
49 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
50
51
52 /****************************************************************************
53  *              DisableThreadLibraryCalls (KERNEL32.@)
54  *
55  * Inform the module loader that thread notifications are not required for a dll.
56  *
57  * PARAMS
58  *  hModule [I] Module handle to skip calls for
59  *
60  * RETURNS
61  *  Success: TRUE. Thread attach and detach notifications will not be sent
62  *           to hModule.
63  *  Failure: FALSE. Use GetLastError() to determine the cause.
64  *
65  * NOTES
66  *  This is typically called from the dll entry point of a dll during process
67  *  attachment, for dlls that do not need to process thread notifications.
68  */
69 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
70 {
71     NTSTATUS    nts = LdrDisableThreadCalloutsForDll( hModule );
72     if (nts == STATUS_SUCCESS) return TRUE;
73
74     SetLastError( RtlNtStatusToDosError( nts ) );
75     return FALSE;
76 }
77
78
79 /* Check whether a file is an OS/2 or a very old Windows executable
80  * by testing on import of KERNEL.
81  *
82  * FIXME: is reading the module imports the only way of discerning
83  *        old Windows binaries from OS/2 ones ? At least it seems so...
84  */
85 static enum binary_type MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz,
86                                                  const IMAGE_OS2_HEADER *ne)
87 {
88     DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
89     enum binary_type ret = BINARY_OS216;
90     LPWORD modtab = NULL;
91     LPSTR nametab = NULL;
92     DWORD len;
93     int i;
94
95     /* read modref table */
96     if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
97       || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
98       || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
99       || (len != ne->ne_cmod*sizeof(WORD)) )
100         goto broken;
101
102     /* read imported names table */
103     if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
104       || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
105       || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
106       || (len != ne->ne_enttab - ne->ne_imptab) )
107         goto broken;
108
109     for (i=0; i < ne->ne_cmod; i++)
110     {
111         LPSTR module = &nametab[modtab[i]];
112         TRACE("modref: %.*s\n", module[0], &module[1]);
113         if (!(strncmp(&module[1], "KERNEL", module[0])))
114         { /* very old Windows file */
115             MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
116             ret = BINARY_WIN16;
117             goto good;
118         }
119     }
120
121 broken:
122     ERR("Hmm, an error occurred. Is this binary file broken ?\n");
123
124 good:
125     HeapFree( GetProcessHeap(), 0, modtab);
126     HeapFree( GetProcessHeap(), 0, nametab);
127     SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
128     return ret;
129 }
130
131 /***********************************************************************
132  *           MODULE_GetBinaryType
133  */
134 enum binary_type MODULE_GetBinaryType( HANDLE hfile )
135 {
136     union
137     {
138         struct
139         {
140             unsigned char magic[4];
141             unsigned char ignored[12];
142             unsigned short type;
143         } elf;
144         struct
145         {
146             unsigned long magic;
147             unsigned long cputype;
148             unsigned long cpusubtype;
149             unsigned long filetype;
150         } macho;
151         IMAGE_DOS_HEADER mz;
152     } header;
153
154     char magic[4];
155     DWORD len;
156
157     /* Seek to the start of the file and read the header information. */
158     if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1)
159         return BINARY_UNKNOWN;
160     if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header))
161         return BINARY_UNKNOWN;
162
163     if (!memcmp( header.elf.magic, "\177ELF", 4 ))
164     {
165         /* FIXME: we don't bother to check byte order, architecture, etc. */
166         switch(header.elf.type)
167         {
168         case 2: return BINARY_UNIX_EXE;
169         case 3: return BINARY_UNIX_LIB;
170         }
171         return BINARY_UNKNOWN;
172     }
173
174     /* Mach-o File with Endian set to Big Endian  or Little Endian*/
175     if (header.macho.magic == 0xfeedface || header.macho.magic == 0xecafdeef)
176     {
177         switch(header.macho.filetype)
178         {
179             case 0x8: /* MH_BUNDLE */ return BINARY_UNIX_LIB;
180         }
181         return BINARY_UNKNOWN;
182     }
183
184     /* Not ELF, try DOS */
185
186     if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
187     {
188         /* We do have a DOS image so we will now try to seek into
189          * the file by the amount indicated by the field
190          * "Offset to extended header" and read in the
191          * "magic" field information at that location.
192          * This will tell us if there is more header information
193          * to read or not.
194          */
195         if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
196             return BINARY_DOS;
197         if (!ReadFile( hfile, magic, sizeof(magic), &len, NULL ) || len != sizeof(magic))
198             return BINARY_DOS;
199
200         /* Reading the magic field succeeded so
201          * we will try to determine what type it is.
202          */
203         if (!memcmp( magic, "PE\0\0", 4 ))
204         {
205             IMAGE_FILE_HEADER FileHeader;
206
207             if (ReadFile( hfile, &FileHeader, sizeof(FileHeader), &len, NULL ) && len == sizeof(FileHeader))
208             {
209                 if (FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
210                 return BINARY_PE_EXE;
211             }
212             return BINARY_DOS;
213         }
214
215         if (!memcmp( magic, "NE", 2 ))
216         {
217             /* This is a Windows executable (NE) header.  This can
218              * mean either a 16-bit OS/2 or a 16-bit Windows or even a
219              * DOS program (running under a DOS extender).  To decide
220              * which, we'll have to read the NE header.
221              */
222             IMAGE_OS2_HEADER ne;
223             if (    SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) != -1
224                     && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
225                     && len == sizeof(ne) )
226             {
227                 switch ( ne.ne_exetyp )
228                 {
229                 case 2:  return BINARY_WIN16;
230                 case 5:  return BINARY_DOS;
231                 default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ne);
232                 }
233             }
234             /* Couldn't read header, so abort. */
235             return BINARY_DOS;
236         }
237
238         /* Unknown extended header, but this file is nonetheless DOS-executable. */
239         return BINARY_DOS;
240     }
241
242     return BINARY_UNKNOWN;
243 }
244
245 /***********************************************************************
246  *             GetBinaryTypeW                     [KERNEL32.@]
247  *
248  * Determine whether a file is executable, and if so, what kind.
249  *
250  * PARAMS
251  *  lpApplicationName [I] Path of the file to check
252  *  lpBinaryType      [O] Destination for the binary type
253  *
254  * RETURNS
255  *  TRUE, if the file is an executable, in which case lpBinaryType is set.
256  *  FALSE, if the file is not an executable or if the function fails.
257  *
258  * NOTES
259  *  The type of executable is a property that determines which subsytem an
260  *  executable file runs under. lpBinaryType can be set to one of the following
261  *  values:
262  *   SCS_32BIT_BINARY: A Win32 based application
263  *   SCS_DOS_BINARY: An MS-Dos based application
264  *   SCS_WOW_BINARY: A Win16 based application
265  *   SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
266  *   SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
267  *   SCS_OS216_BINARY: A 16bit OS/2 based application
268  *
269  *  To find the binary type, this function reads in the files header information.
270  *  If extended header information is not present it will assume that the file
271  *  is a DOS executable. If extended header information is present it will
272  *  determine if the file is a 16 or 32 bit Windows executable by checking the
273  *  flags in the header.
274  *
275  *  ".com" and ".pif" files are only recognized by their file name extension,
276  *  as per native Windows.
277  */
278 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
279 {
280     BOOL ret = FALSE;
281     HANDLE hfile;
282
283     TRACE("%s\n", debugstr_w(lpApplicationName) );
284
285     /* Sanity check.
286      */
287     if ( lpApplicationName == NULL || lpBinaryType == NULL )
288         return FALSE;
289
290     /* Open the file indicated by lpApplicationName for reading.
291      */
292     hfile = CreateFileW( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
293                          NULL, OPEN_EXISTING, 0, 0 );
294     if ( hfile == INVALID_HANDLE_VALUE )
295         return FALSE;
296
297     /* Check binary type
298      */
299     switch(MODULE_GetBinaryType( hfile ))
300     {
301     case BINARY_UNKNOWN:
302     {
303         static const WCHAR comW[] = { '.','C','O','M',0 };
304         static const WCHAR pifW[] = { '.','P','I','F',0 };
305         const WCHAR *ptr;
306
307         /* try to determine from file name */
308         ptr = strrchrW( lpApplicationName, '.' );
309         if (!ptr) break;
310         if (!strcmpiW( ptr, comW ))
311         {
312             *lpBinaryType = SCS_DOS_BINARY;
313             ret = TRUE;
314         }
315         else if (!strcmpiW( ptr, pifW ))
316         {
317             *lpBinaryType = SCS_PIF_BINARY;
318             ret = TRUE;
319         }
320         break;
321     }
322     case BINARY_PE_EXE:
323     case BINARY_PE_DLL:
324         *lpBinaryType = SCS_32BIT_BINARY;
325         ret = TRUE;
326         break;
327     case BINARY_WIN16:
328         *lpBinaryType = SCS_WOW_BINARY;
329         ret = TRUE;
330         break;
331     case BINARY_OS216:
332         *lpBinaryType = SCS_OS216_BINARY;
333         ret = TRUE;
334         break;
335     case BINARY_DOS:
336         *lpBinaryType = SCS_DOS_BINARY;
337         ret = TRUE;
338         break;
339     case BINARY_UNIX_EXE:
340     case BINARY_UNIX_LIB:
341         ret = FALSE;
342         break;
343     }
344
345     CloseHandle( hfile );
346     return ret;
347 }
348
349 /***********************************************************************
350  *             GetBinaryTypeA                     [KERNEL32.@]
351  *             GetBinaryType                      [KERNEL32.@]
352  */
353 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
354 {
355     ANSI_STRING app_nameA;
356     NTSTATUS status;
357
358     TRACE("%s\n", debugstr_a(lpApplicationName));
359
360     /* Sanity check.
361      */
362     if ( lpApplicationName == NULL || lpBinaryType == NULL )
363         return FALSE;
364
365     RtlInitAnsiString(&app_nameA, lpApplicationName);
366     status = RtlAnsiStringToUnicodeString(&NtCurrentTeb()->StaticUnicodeString,
367                                           &app_nameA, FALSE);
368     if (!status)
369         return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
370
371     SetLastError(RtlNtStatusToDosError(status));
372     return FALSE;
373 }
374
375
376 /***********************************************************************
377  *              GetModuleHandleA         (KERNEL32.@)
378  *              GetModuleHandle32        (KERNEL.488)
379  *
380  * Get the handle of a dll loaded into the process address space.
381  *
382  * PARAMS
383  *  module [I] Name of the dll
384  *
385  * RETURNS
386  *  Success: A handle to the loaded dll.
387  *  Failure: A NULL handle. Use GetLastError() to determine the cause.
388  */
389 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
390 {
391     NTSTATUS            nts;
392     HMODULE             ret;
393     UNICODE_STRING      wstr;
394
395     if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
396
397     RtlCreateUnicodeStringFromAsciiz(&wstr, module);
398     nts = LdrGetDllHandle(0, 0, &wstr, &ret);
399     RtlFreeUnicodeString( &wstr );
400     if (nts != STATUS_SUCCESS)
401     {
402         ret = 0;
403         SetLastError( RtlNtStatusToDosError( nts ) );
404     }
405     return ret;
406 }
407
408 /***********************************************************************
409  *              GetModuleHandleW (KERNEL32.@)
410  *
411  * Unicode version of GetModuleHandleA.
412  */
413 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
414 {
415     NTSTATUS            nts;
416     HMODULE             ret;
417     UNICODE_STRING      wstr;
418
419     if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
420
421     RtlInitUnicodeString( &wstr, module );
422     nts = LdrGetDllHandle( 0, 0, &wstr, &ret);
423     if (nts != STATUS_SUCCESS)
424     {
425         SetLastError( RtlNtStatusToDosError( nts ) );
426         ret = 0;
427     }
428     return ret;
429 }
430
431
432 /***********************************************************************
433  *              GetModuleFileNameA      (KERNEL32.@)
434  *              GetModuleFileName32     (KERNEL.487)
435  *
436  * Get the file name of a loaded module from its handle.
437  *
438  * RETURNS
439  *  Success: The length of the file name, excluding the terminating NUL.
440  *  Failure: 0. Use GetLastError() to determine the cause.
441  *
442  * NOTES
443  *  This function always returns the long path of hModule (as opposed to
444  *  GetModuleFileName16() which returns short paths when the modules version
445  *  field is < 4.0).
446  */
447 DWORD WINAPI GetModuleFileNameA(
448         HMODULE hModule,        /* [in] Module handle (32 bit) */
449         LPSTR lpFileName,       /* [out] Destination for file name */
450         DWORD size )            /* [in] Size of lpFileName in characters */
451 {
452     LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
453
454     if (!filenameW)
455     {
456         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
457         return 0;
458     }
459     GetModuleFileNameW( hModule, filenameW, size );
460     WideCharToMultiByte( CP_ACP, 0, filenameW, -1, lpFileName, size, NULL, NULL );
461     HeapFree( GetProcessHeap(), 0, filenameW );
462     return strlen( lpFileName );
463 }
464
465 /***********************************************************************
466  *              GetModuleFileNameW      (KERNEL32.@)
467  *
468  * Unicode version of GetModuleFileNameA.
469  */
470 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
471 {
472     ULONG magic;
473
474     lpFileName[0] = 0;
475
476     LdrLockLoaderLock( 0, NULL, &magic );
477     if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32))
478     {
479         /* 16-bit task - get current NE module name */
480         NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() );
481         if (pModule)
482         {
483             WCHAR    path[MAX_PATH];
484
485             MultiByteToWideChar( CP_ACP, 0, NE_MODULE_NAME(pModule), -1, path, MAX_PATH );
486             GetLongPathNameW(path, lpFileName, size);
487         }
488     }
489     else
490     {
491         LDR_MODULE* pldr;
492         NTSTATUS    nts;
493
494         if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
495         nts = LdrFindEntryForAddress( hModule, &pldr );
496         if (nts == STATUS_SUCCESS) lstrcpynW(lpFileName, pldr->FullDllName.Buffer, size);
497         else SetLastError( RtlNtStatusToDosError( nts ) );
498
499     }
500     LdrUnlockLoaderLock( 0, magic );
501
502     TRACE( "%s\n", debugstr_w(lpFileName) );
503     return strlenW(lpFileName);
504 }
505
506
507 /***********************************************************************
508  *           get_dll_system_path
509  */
510 static const WCHAR *get_dll_system_path(void)
511 {
512     static WCHAR *path;
513
514     if (!path)
515     {
516         WCHAR *p, *exe_name;
517         int len = 3;
518
519         exe_name = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
520         if (!(p = strrchrW( exe_name, '\\' ))) p = exe_name;
521         /* include trailing backslash only on drive root */
522         if (p == exe_name + 2 && exe_name[1] == ':') p++;
523         len += p - exe_name;
524         len += GetSystemDirectoryW( NULL, 0 );
525         len += GetWindowsDirectoryW( NULL, 0 );
526         path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
527         memcpy( path, exe_name, (p - exe_name) * sizeof(WCHAR) );
528         p = path + (p - exe_name);
529         *p++ = ';';
530         *p++ = '.';
531         *p++ = ';';
532         GetSystemDirectoryW( p, path + len - p);
533         p += strlenW(p);
534         *p++ = ';';
535         GetWindowsDirectoryW( p, path + len - p);
536     }
537     return path;
538 }
539
540
541 /******************************************************************
542  *              get_dll_load_path
543  *
544  * Compute the load path to use for a given dll.
545  * Returned pointer must be freed by caller.
546  */
547 static WCHAR *get_dll_load_path( LPCWSTR module )
548 {
549     static const WCHAR pathW[] = {'P','A','T','H',0};
550
551     const WCHAR *system_path = get_dll_system_path();
552     const WCHAR *mod_end = NULL;
553     UNICODE_STRING name, value;
554     WCHAR *p, *ret;
555     int len = 0, path_len = 0;
556
557     /* adjust length for module name */
558
559     if (module)
560     {
561         mod_end = module;
562         if ((p = strrchrW( mod_end, '\\' ))) mod_end = p;
563         if ((p = strrchrW( mod_end, '/' ))) mod_end = p;
564         if (mod_end == module + 2 && module[1] == ':') mod_end++;
565         if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
566         len += (mod_end - module);
567         system_path = strchrW( system_path, ';' );
568     }
569     len += strlenW( system_path ) + 2;
570
571     /* get the PATH variable */
572
573     RtlInitUnicodeString( &name, pathW );
574     value.Length = 0;
575     value.MaximumLength = 0;
576     value.Buffer = NULL;
577     if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
578         path_len = value.Length;
579
580     if (!(ret = HeapAlloc( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) ))) return NULL;
581     p = ret;
582     if (module)
583     {
584         memcpy( ret, module, (mod_end - module) * sizeof(WCHAR) );
585         p += (mod_end - module);
586     }
587     strcpyW( p, system_path );
588     p += strlenW(p);
589     *p++ = ';';
590     value.Buffer = p;
591     value.MaximumLength = path_len;
592
593     while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
594     {
595         WCHAR *new_ptr;
596
597         /* grow the buffer and retry */
598         path_len = value.Length;
599         if (!(new_ptr = HeapReAlloc( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
600         {
601             HeapFree( GetProcessHeap(), 0, ret );
602             return NULL;
603         }
604         value.Buffer = new_ptr + (value.Buffer - ret);
605         value.MaximumLength = path_len;
606         ret = new_ptr;
607     }
608     value.Buffer[value.Length / sizeof(WCHAR)] = 0;
609     return ret;
610 }
611
612
613 /******************************************************************
614  *              MODULE_InitLoadPath
615  *
616  * Create the initial dll load path.
617  */
618 void MODULE_InitLoadPath(void)
619 {
620     WCHAR *path = get_dll_load_path( NULL );
621     RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath, path );
622 }
623
624
625 /******************************************************************
626  *              load_library_as_datafile
627  */
628 static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
629 {
630     static const WCHAR dotDLL[] = {'.','d','l','l',0};
631
632     WCHAR filenameW[MAX_PATH];
633     HANDLE hFile = INVALID_HANDLE_VALUE;
634     HANDLE mapping;
635     HMODULE module;
636
637     *hmod = 0;
638
639     if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
640                      filenameW, NULL ))
641     {
642         hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
643                              NULL, OPEN_EXISTING, 0, 0 );
644     }
645     if (hFile == INVALID_HANDLE_VALUE) return FALSE;
646
647     mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
648     CloseHandle( hFile );
649     if (!mapping) return FALSE;
650
651     module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
652     CloseHandle( mapping );
653     if (!module) return FALSE;
654
655     /* make sure it's a valid PE file */
656     if (!RtlImageNtHeader(module))
657     {
658         UnmapViewOfFile( module );
659         return FALSE;
660     }
661     *hmod = (HMODULE)((char *)module + 1);  /* set low bit of handle to indicate datafile module */
662     return TRUE;
663 }
664
665
666 /******************************************************************
667  *              load_library
668  *
669  * Helper for LoadLibraryExA/W.
670  */
671 static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags )
672 {
673     NTSTATUS nts;
674     HMODULE hModule;
675     WCHAR *load_path;
676
677     if (flags & LOAD_LIBRARY_AS_DATAFILE)
678     {
679         /* The method in load_library_as_datafile allows searching for the
680          * 'native' libraries only
681          */
682         if (load_library_as_datafile( libname->Buffer, &hModule )) return hModule;
683         flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
684         /* Fallback to normal behaviour */
685     }
686
687     load_path = get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL );
688     nts = LdrLoadDll( load_path, flags, libname, &hModule );
689     HeapFree( GetProcessHeap(), 0, load_path );
690     if (nts != STATUS_SUCCESS)
691     {
692         hModule = 0;
693         SetLastError( RtlNtStatusToDosError( nts ) );
694     }
695     return hModule;
696 }
697
698
699 /******************************************************************
700  *              LoadLibraryExA          (KERNEL32.@)
701  *
702  * Load a dll file into the process address space.
703  *
704  * PARAMS
705  *  libname [I] Name of the file to load
706  *  hfile   [I] Reserved, must be 0.
707  *  flags   [I] Flags for loading the dll
708  *
709  * RETURNS
710  *  Success: A handle to the loaded dll.
711  *  Failure: A NULL handle. Use GetLastError() to determine the cause.
712  *
713  * NOTES
714  * The HFILE parameter is not used and marked reserved in the SDK. I can
715  * only guess that it should force a file to be mapped, but I rather
716  * ignore the parameter because it would be extremely difficult to
717  * integrate this with different types of module representations.
718  */
719 HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
720 {
721     UNICODE_STRING      wstr;
722     HMODULE             hModule;
723
724     if (!libname)
725     {
726         SetLastError(ERROR_INVALID_PARAMETER);
727         return 0;
728     }
729     RtlCreateUnicodeStringFromAsciiz( &wstr, libname );
730     hModule = load_library( &wstr, flags );
731     RtlFreeUnicodeString( &wstr );
732     return hModule;
733 }
734
735 /***********************************************************************
736  *           LoadLibraryExW       (KERNEL32.@)
737  *
738  * Unicode version of LoadLibraryExA.
739  */
740 HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
741 {
742     UNICODE_STRING      wstr;
743
744     if (!libnameW)
745     {
746         SetLastError(ERROR_INVALID_PARAMETER);
747         return 0;
748     }
749     RtlInitUnicodeString( &wstr, libnameW );
750     return load_library( &wstr, flags );
751 }
752
753 /***********************************************************************
754  *           LoadLibraryA         (KERNEL32.@)
755  *
756  * Load a dll file into the process address space.
757  *
758  * PARAMS
759  *  libname [I] Name of the file to load
760  *
761  * RETURNS
762  *  Success: A handle to the loaded dll.
763  *  Failure: A NULL handle. Use GetLastError() to determine the cause.
764  *
765  * NOTES
766  * See LoadLibraryExA().
767  */
768 HMODULE WINAPI LoadLibraryA(LPCSTR libname)
769 {
770     return LoadLibraryExA(libname, 0, 0);
771 }
772
773 /***********************************************************************
774  *           LoadLibraryW         (KERNEL32.@)
775  *
776  * Unicode version of LoadLibraryA.
777  */
778 HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
779 {
780     return LoadLibraryExW(libnameW, 0, 0);
781 }
782
783 /***********************************************************************
784  *           FreeLibrary   (KERNEL32.@)
785  *           FreeLibrary32 (KERNEL.486)
786  *
787  * Free a dll loaded into the process address space.
788  *
789  * PARAMS
790  *  hLibModule [I] Handle to the dll returned by LoadLibraryA().
791  *
792  * RETURNS
793  *  Success: TRUE. The dll is removed if it is not still in use.
794  *  Failure: FALSE. Use GetLastError() to determine the cause.
795  */
796 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
797 {
798     BOOL                retv = FALSE;
799     NTSTATUS            nts;
800
801     if (!hLibModule)
802     {
803         SetLastError( ERROR_INVALID_HANDLE );
804         return FALSE;
805     }
806
807     if ((ULONG_PTR)hLibModule & 1)
808     {
809         /* this is a LOAD_LIBRARY_AS_DATAFILE module */
810         char *ptr = (char *)hLibModule - 1;
811         UnmapViewOfFile( ptr );
812         return TRUE;
813     }
814
815     if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
816     else SetLastError( RtlNtStatusToDosError( nts ) );
817
818     return retv;
819 }
820
821 /***********************************************************************
822  *           GetProcAddress             (KERNEL32.@)
823  *
824  * Find the address of an exported symbol in a loaded dll.
825  *
826  * PARAMS
827  *  hModule  [I] Handle to the dll returned by LoadLibraryA().
828  *  function [I] Name of the symbol, or an integer ordinal number < 16384
829  *
830  * RETURNS
831  *  Success: A pointer to the symbol in the process address space.
832  *  Failure: NULL. Use GetLastError() to determine the cause.
833  */
834 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
835 {
836     NTSTATUS    nts;
837     FARPROC     fp;
838
839     if (HIWORD(function))
840     {
841         ANSI_STRING     str;
842
843         RtlInitAnsiString( &str, function );
844         nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp );
845     }
846     else
847         nts = LdrGetProcedureAddress( hModule, NULL, (DWORD)function, (void**)&fp );
848     if (nts != STATUS_SUCCESS)
849     {
850         SetLastError( RtlNtStatusToDosError( nts ) );
851         fp = NULL;
852     }
853     return fp;
854 }
855
856 /***********************************************************************
857  *           GetProcAddress32                   (KERNEL.453)
858  *
859  * Find the address of an exported symbol in a loaded dll.
860  *
861  * PARAMS
862  *  hModule  [I] Handle to the dll returned by LoadLibraryA().
863  *  function [I] Name of the symbol, or an integer ordinal number < 16384
864  *
865  * RETURNS
866  *  Success: A pointer to the symbol in the process address space.
867  *  Failure: NULL. Use GetLastError() to determine the cause.
868  */
869 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
870 {
871     /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
872     return GetProcAddress( hModule, function );
873 }