Deal with kernels that don't have IsValidLanguageGroup.
[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         /* But before we do we will make sure that header
196          * structure encompasses the "Offset to extended header"
197          * field.
198          */
199         if (header.mz.e_lfanew < sizeof(IMAGE_DOS_HEADER))
200             return BINARY_DOS;
201         if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
202             return BINARY_DOS;
203         if (!ReadFile( hfile, magic, sizeof(magic), &len, NULL ) || len != sizeof(magic))
204             return BINARY_DOS;
205
206         /* Reading the magic field succeeded so
207          * we will try to determine what type it is.
208          */
209         if (!memcmp( magic, "PE\0\0", 4 ))
210         {
211             IMAGE_FILE_HEADER FileHeader;
212
213             if (ReadFile( hfile, &FileHeader, sizeof(FileHeader), &len, NULL ) && len == sizeof(FileHeader))
214             {
215                 if (FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
216                 return BINARY_PE_EXE;
217             }
218             return BINARY_DOS;
219         }
220
221         if (!memcmp( magic, "NE", 2 ))
222         {
223             /* This is a Windows executable (NE) header.  This can
224              * mean either a 16-bit OS/2 or a 16-bit Windows or even a
225              * DOS program (running under a DOS extender).  To decide
226              * which, we'll have to read the NE header.
227              */
228             IMAGE_OS2_HEADER ne;
229             if (    SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) != -1
230                     && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
231                     && len == sizeof(ne) )
232             {
233                 switch ( ne.ne_exetyp )
234                 {
235                 case 2:  return BINARY_WIN16;
236                 case 5:  return BINARY_DOS;
237                 default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ne);
238                 }
239             }
240             /* Couldn't read header, so abort. */
241             return BINARY_DOS;
242         }
243
244         /* Unknown extended header, but this file is nonetheless DOS-executable. */
245         return BINARY_DOS;
246     }
247
248     return BINARY_UNKNOWN;
249 }
250
251 /***********************************************************************
252  *             GetBinaryTypeW                     [KERNEL32.@]
253  *
254  * Determine whether a file is executable, and if so, what kind.
255  *
256  * PARAMS
257  *  lpApplicationName [I] Path of the file to check
258  *  lpBinaryType      [O] Destination for the binary type
259  *
260  * RETURNS
261  *  TRUE, if the file is an executable, in which case lpBinaryType is set.
262  *  FALSE, if the file is not an executable or if the function fails.
263  *
264  * NOTES
265  *  The type of executable is a property that determines which subsytem an
266  *  executable file runs under. lpBinaryType can be set to one of the following
267  *  values:
268  *   SCS_32BIT_BINARY: A Win32 based application
269  *   SCS_DOS_BINARY: An MS-Dos based application
270  *   SCS_WOW_BINARY: A Win16 based application
271  *   SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
272  *   SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
273  *   SCS_OS216_BINARY: A 16bit OS/2 based application
274  *
275  *  To find the binary type, this function reads in the files header information.
276  *  If extended header information is not present it will assume that the file
277  *  is a DOS executable. If extended header information is present it will
278  *  determine if the file is a 16 or 32 bit Windows executable by checking the
279  *  flags in the header.
280  *
281  *  ".com" and ".pif" files are only recognized by their file name extension,
282  *  as per native Windows.
283  */
284 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
285 {
286     BOOL ret = FALSE;
287     HANDLE hfile;
288
289     TRACE("%s\n", debugstr_w(lpApplicationName) );
290
291     /* Sanity check.
292      */
293     if ( lpApplicationName == NULL || lpBinaryType == NULL )
294         return FALSE;
295
296     /* Open the file indicated by lpApplicationName for reading.
297      */
298     hfile = CreateFileW( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
299                          NULL, OPEN_EXISTING, 0, 0 );
300     if ( hfile == INVALID_HANDLE_VALUE )
301         return FALSE;
302
303     /* Check binary type
304      */
305     switch(MODULE_GetBinaryType( hfile ))
306     {
307     case BINARY_UNKNOWN:
308     {
309         static const WCHAR comW[] = { '.','C','O','M',0 };
310         static const WCHAR pifW[] = { '.','P','I','F',0 };
311         const WCHAR *ptr;
312
313         /* try to determine from file name */
314         ptr = strrchrW( lpApplicationName, '.' );
315         if (!ptr) break;
316         if (!strcmpiW( ptr, comW ))
317         {
318             *lpBinaryType = SCS_DOS_BINARY;
319             ret = TRUE;
320         }
321         else if (!strcmpiW( ptr, pifW ))
322         {
323             *lpBinaryType = SCS_PIF_BINARY;
324             ret = TRUE;
325         }
326         break;
327     }
328     case BINARY_PE_EXE:
329     case BINARY_PE_DLL:
330         *lpBinaryType = SCS_32BIT_BINARY;
331         ret = TRUE;
332         break;
333     case BINARY_WIN16:
334         *lpBinaryType = SCS_WOW_BINARY;
335         ret = TRUE;
336         break;
337     case BINARY_OS216:
338         *lpBinaryType = SCS_OS216_BINARY;
339         ret = TRUE;
340         break;
341     case BINARY_DOS:
342         *lpBinaryType = SCS_DOS_BINARY;
343         ret = TRUE;
344         break;
345     case BINARY_UNIX_EXE:
346     case BINARY_UNIX_LIB:
347         ret = FALSE;
348         break;
349     }
350
351     CloseHandle( hfile );
352     return ret;
353 }
354
355 /***********************************************************************
356  *             GetBinaryTypeA                     [KERNEL32.@]
357  *             GetBinaryType                      [KERNEL32.@]
358  */
359 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
360 {
361     ANSI_STRING app_nameA;
362     NTSTATUS status;
363
364     TRACE("%s\n", debugstr_a(lpApplicationName));
365
366     /* Sanity check.
367      */
368     if ( lpApplicationName == NULL || lpBinaryType == NULL )
369         return FALSE;
370
371     RtlInitAnsiString(&app_nameA, lpApplicationName);
372     status = RtlAnsiStringToUnicodeString(&NtCurrentTeb()->StaticUnicodeString,
373                                           &app_nameA, FALSE);
374     if (!status)
375         return GetBinaryTypeW(NtCurrentTeb()->StaticUnicodeString.Buffer, lpBinaryType);
376
377     SetLastError(RtlNtStatusToDosError(status));
378     return FALSE;
379 }
380
381
382 /***********************************************************************
383  *              GetModuleHandleA         (KERNEL32.@)
384  *              GetModuleHandle32        (KERNEL.488)
385  *
386  * Get the handle of a dll loaded into the process address space.
387  *
388  * PARAMS
389  *  module [I] Name of the dll
390  *
391  * RETURNS
392  *  Success: A handle to the loaded dll.
393  *  Failure: A NULL handle. Use GetLastError() to determine the cause.
394  */
395 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
396 {
397     NTSTATUS            nts;
398     HMODULE             ret;
399     UNICODE_STRING      wstr;
400
401     if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
402
403     RtlCreateUnicodeStringFromAsciiz(&wstr, module);
404     nts = LdrGetDllHandle(0, 0, &wstr, &ret);
405     RtlFreeUnicodeString( &wstr );
406     if (nts != STATUS_SUCCESS)
407     {
408         ret = 0;
409         SetLastError( RtlNtStatusToDosError( nts ) );
410     }
411     return ret;
412 }
413
414 /***********************************************************************
415  *              GetModuleHandleW (KERNEL32.@)
416  *
417  * Unicode version of GetModuleHandleA.
418  */
419 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
420 {
421     NTSTATUS            nts;
422     HMODULE             ret;
423     UNICODE_STRING      wstr;
424
425     if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
426
427     RtlInitUnicodeString( &wstr, module );
428     nts = LdrGetDllHandle( 0, 0, &wstr, &ret);
429     if (nts != STATUS_SUCCESS)
430     {
431         SetLastError( RtlNtStatusToDosError( nts ) );
432         ret = 0;
433     }
434     return ret;
435 }
436
437
438 /***********************************************************************
439  *              GetModuleFileNameA      (KERNEL32.@)
440  *              GetModuleFileName32     (KERNEL.487)
441  *
442  * Get the file name of a loaded module from its handle.
443  *
444  * RETURNS
445  *  Success: The length of the file name, excluding the terminating NUL.
446  *  Failure: 0. Use GetLastError() to determine the cause.
447  *
448  * NOTES
449  *  This function always returns the long path of hModule (as opposed to
450  *  GetModuleFileName16() which returns short paths when the modules version
451  *  field is < 4.0).
452  */
453 DWORD WINAPI GetModuleFileNameA(
454         HMODULE hModule,        /* [in] Module handle (32 bit) */
455         LPSTR lpFileName,       /* [out] Destination for file name */
456         DWORD size )            /* [in] Size of lpFileName in characters */
457 {
458     LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
459
460     if (!filenameW)
461     {
462         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
463         return 0;
464     }
465     GetModuleFileNameW( hModule, filenameW, size );
466     WideCharToMultiByte( CP_ACP, 0, filenameW, -1, lpFileName, size, NULL, NULL );
467     HeapFree( GetProcessHeap(), 0, filenameW );
468     return strlen( lpFileName );
469 }
470
471 /***********************************************************************
472  *              GetModuleFileNameW      (KERNEL32.@)
473  *
474  * Unicode version of GetModuleFileNameA.
475  */
476 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
477 {
478     ULONG magic;
479
480     lpFileName[0] = 0;
481
482     LdrLockLoaderLock( 0, NULL, &magic );
483     if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32))
484     {
485         /* 16-bit task - get current NE module name */
486         NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() );
487         if (pModule)
488         {
489             WCHAR    path[MAX_PATH];
490
491             MultiByteToWideChar( CP_ACP, 0, NE_MODULE_NAME(pModule), -1, path, MAX_PATH );
492             GetLongPathNameW(path, lpFileName, size);
493         }
494     }
495     else
496     {
497         LDR_MODULE* pldr;
498         NTSTATUS    nts;
499
500         if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
501         nts = LdrFindEntryForAddress( hModule, &pldr );
502         if (nts == STATUS_SUCCESS) lstrcpynW(lpFileName, pldr->FullDllName.Buffer, size);
503         else SetLastError( RtlNtStatusToDosError( nts ) );
504
505     }
506     LdrUnlockLoaderLock( 0, magic );
507
508     TRACE( "%s\n", debugstr_w(lpFileName) );
509     return strlenW(lpFileName);
510 }
511
512
513 /***********************************************************************
514  *           get_dll_system_path
515  */
516 static const WCHAR *get_dll_system_path(void)
517 {
518     static WCHAR *path;
519
520     if (!path)
521     {
522         WCHAR *p, *exe_name;
523         int len = 3;
524
525         exe_name = NtCurrentTeb()->Peb->ProcessParameters->ImagePathName.Buffer;
526         if (!(p = strrchrW( exe_name, '\\' ))) p = exe_name;
527         /* include trailing backslash only on drive root */
528         if (p == exe_name + 2 && exe_name[1] == ':') p++;
529         len += p - exe_name;
530         len += GetSystemDirectoryW( NULL, 0 );
531         len += GetWindowsDirectoryW( NULL, 0 );
532         path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
533         memcpy( path, exe_name, (p - exe_name) * sizeof(WCHAR) );
534         p = path + (p - exe_name);
535         *p++ = ';';
536         *p++ = '.';
537         *p++ = ';';
538         GetSystemDirectoryW( p, path + len - p);
539         p += strlenW(p);
540         *p++ = ';';
541         GetWindowsDirectoryW( p, path + len - p);
542     }
543     return path;
544 }
545
546
547 /******************************************************************
548  *              get_dll_load_path
549  *
550  * Compute the load path to use for a given dll.
551  * Returned pointer must be freed by caller.
552  */
553 static WCHAR *get_dll_load_path( LPCWSTR module )
554 {
555     static const WCHAR pathW[] = {'P','A','T','H',0};
556
557     const WCHAR *system_path = get_dll_system_path();
558     const WCHAR *mod_end = NULL;
559     UNICODE_STRING name, value;
560     WCHAR *p, *ret;
561     int len = 0, path_len = 0;
562
563     /* adjust length for module name */
564
565     if (module)
566     {
567         mod_end = module;
568         if ((p = strrchrW( mod_end, '\\' ))) mod_end = p;
569         if ((p = strrchrW( mod_end, '/' ))) mod_end = p;
570         if (mod_end == module + 2 && module[1] == ':') mod_end++;
571         if (mod_end == module && module[0] && module[1] == ':') mod_end += 2;
572         len += (mod_end - module);
573         system_path = strchrW( system_path, ';' );
574     }
575     len += strlenW( system_path ) + 2;
576
577     /* get the PATH variable */
578
579     RtlInitUnicodeString( &name, pathW );
580     value.Length = 0;
581     value.MaximumLength = 0;
582     value.Buffer = NULL;
583     if (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
584         path_len = value.Length;
585
586     if (!(ret = HeapAlloc( GetProcessHeap(), 0, path_len + len * sizeof(WCHAR) ))) return NULL;
587     p = ret;
588     if (module)
589     {
590         memcpy( ret, module, (mod_end - module) * sizeof(WCHAR) );
591         p += (mod_end - module);
592     }
593     strcpyW( p, system_path );
594     p += strlenW(p);
595     *p++ = ';';
596     value.Buffer = p;
597     value.MaximumLength = path_len;
598
599     while (RtlQueryEnvironmentVariable_U( NULL, &name, &value ) == STATUS_BUFFER_TOO_SMALL)
600     {
601         WCHAR *new_ptr;
602
603         /* grow the buffer and retry */
604         path_len = value.Length;
605         if (!(new_ptr = HeapReAlloc( GetProcessHeap(), 0, ret, path_len + len * sizeof(WCHAR) )))
606         {
607             HeapFree( GetProcessHeap(), 0, ret );
608             return NULL;
609         }
610         value.Buffer = new_ptr + (value.Buffer - ret);
611         value.MaximumLength = path_len;
612         ret = new_ptr;
613     }
614     value.Buffer[value.Length / sizeof(WCHAR)] = 0;
615     return ret;
616 }
617
618
619 /******************************************************************
620  *              MODULE_InitLoadPath
621  *
622  * Create the initial dll load path.
623  */
624 void MODULE_InitLoadPath(void)
625 {
626     WCHAR *path = get_dll_load_path( NULL );
627     RtlInitUnicodeString( &NtCurrentTeb()->Peb->ProcessParameters->DllPath, path );
628 }
629
630
631 /******************************************************************
632  *              load_library_as_datafile
633  */
634 static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
635 {
636     static const WCHAR dotDLL[] = {'.','d','l','l',0};
637
638     WCHAR filenameW[MAX_PATH];
639     HANDLE hFile = INVALID_HANDLE_VALUE;
640     HANDLE mapping;
641     HMODULE module;
642
643     *hmod = 0;
644
645     if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
646                      filenameW, NULL ))
647     {
648         hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
649                              NULL, OPEN_EXISTING, 0, 0 );
650     }
651     if (hFile == INVALID_HANDLE_VALUE) return FALSE;
652
653     mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
654     CloseHandle( hFile );
655     if (!mapping) return FALSE;
656
657     module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
658     CloseHandle( mapping );
659     if (!module) return FALSE;
660
661     /* make sure it's a valid PE file */
662     if (!RtlImageNtHeader(module))
663     {
664         UnmapViewOfFile( module );
665         return FALSE;
666     }
667     *hmod = (HMODULE)((char *)module + 1);  /* set low bit of handle to indicate datafile module */
668     return TRUE;
669 }
670
671
672 /******************************************************************
673  *              load_library
674  *
675  * Helper for LoadLibraryExA/W.
676  */
677 static HMODULE load_library( const UNICODE_STRING *libname, DWORD flags )
678 {
679     NTSTATUS nts;
680     HMODULE hModule;
681     WCHAR *load_path;
682
683     if (flags & LOAD_LIBRARY_AS_DATAFILE)
684     {
685         /* The method in load_library_as_datafile allows searching for the
686          * 'native' libraries only
687          */
688         if (load_library_as_datafile( libname->Buffer, &hModule )) return hModule;
689         flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
690         /* Fallback to normal behaviour */
691     }
692
693     load_path = get_dll_load_path( flags & LOAD_WITH_ALTERED_SEARCH_PATH ? libname->Buffer : NULL );
694     nts = LdrLoadDll( load_path, flags, libname, &hModule );
695     HeapFree( GetProcessHeap(), 0, load_path );
696     if (nts != STATUS_SUCCESS)
697     {
698         hModule = 0;
699         SetLastError( RtlNtStatusToDosError( nts ) );
700     }
701     return hModule;
702 }
703
704
705 /******************************************************************
706  *              LoadLibraryExA          (KERNEL32.@)
707  *
708  * Load a dll file into the process address space.
709  *
710  * PARAMS
711  *  libname [I] Name of the file to load
712  *  hfile   [I] Reserved, must be 0.
713  *  flags   [I] Flags for loading the dll
714  *
715  * RETURNS
716  *  Success: A handle to the loaded dll.
717  *  Failure: A NULL handle. Use GetLastError() to determine the cause.
718  *
719  * NOTES
720  * The HFILE parameter is not used and marked reserved in the SDK. I can
721  * only guess that it should force a file to be mapped, but I rather
722  * ignore the parameter because it would be extremely difficult to
723  * integrate this with different types of module representations.
724  */
725 HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
726 {
727     UNICODE_STRING      wstr;
728     HMODULE             hModule;
729
730     if (!libname)
731     {
732         SetLastError(ERROR_INVALID_PARAMETER);
733         return 0;
734     }
735     RtlCreateUnicodeStringFromAsciiz( &wstr, libname );
736     hModule = load_library( &wstr, flags );
737     RtlFreeUnicodeString( &wstr );
738     return hModule;
739 }
740
741 /***********************************************************************
742  *           LoadLibraryExW       (KERNEL32.@)
743  *
744  * Unicode version of LoadLibraryExA.
745  */
746 HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
747 {
748     UNICODE_STRING      wstr;
749
750     if (!libnameW)
751     {
752         SetLastError(ERROR_INVALID_PARAMETER);
753         return 0;
754     }
755     RtlInitUnicodeString( &wstr, libnameW );
756     return load_library( &wstr, flags );
757 }
758
759 /***********************************************************************
760  *           LoadLibraryA         (KERNEL32.@)
761  *
762  * Load a dll file into the process address space.
763  *
764  * PARAMS
765  *  libname [I] Name of the file to load
766  *
767  * RETURNS
768  *  Success: A handle to the loaded dll.
769  *  Failure: A NULL handle. Use GetLastError() to determine the cause.
770  *
771  * NOTES
772  * See LoadLibraryExA().
773  */
774 HMODULE WINAPI LoadLibraryA(LPCSTR libname)
775 {
776     return LoadLibraryExA(libname, 0, 0);
777 }
778
779 /***********************************************************************
780  *           LoadLibraryW         (KERNEL32.@)
781  *
782  * Unicode version of LoadLibraryA.
783  */
784 HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
785 {
786     return LoadLibraryExW(libnameW, 0, 0);
787 }
788
789 /***********************************************************************
790  *           FreeLibrary   (KERNEL32.@)
791  *           FreeLibrary32 (KERNEL.486)
792  *
793  * Free a dll loaded into the process address space.
794  *
795  * PARAMS
796  *  hLibModule [I] Handle to the dll returned by LoadLibraryA().
797  *
798  * RETURNS
799  *  Success: TRUE. The dll is removed if it is not still in use.
800  *  Failure: FALSE. Use GetLastError() to determine the cause.
801  */
802 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
803 {
804     BOOL                retv = FALSE;
805     NTSTATUS            nts;
806
807     if (!hLibModule)
808     {
809         SetLastError( ERROR_INVALID_HANDLE );
810         return FALSE;
811     }
812
813     if ((ULONG_PTR)hLibModule & 1)
814     {
815         /* this is a LOAD_LIBRARY_AS_DATAFILE module */
816         char *ptr = (char *)hLibModule - 1;
817         UnmapViewOfFile( ptr );
818         return TRUE;
819     }
820
821     if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
822     else SetLastError( RtlNtStatusToDosError( nts ) );
823
824     return retv;
825 }
826
827 /***********************************************************************
828  *           GetProcAddress             (KERNEL32.@)
829  *
830  * Find the address of an exported symbol in a loaded dll.
831  *
832  * PARAMS
833  *  hModule  [I] Handle to the dll returned by LoadLibraryA().
834  *  function [I] Name of the symbol, or an integer ordinal number < 16384
835  *
836  * RETURNS
837  *  Success: A pointer to the symbol in the process address space.
838  *  Failure: NULL. Use GetLastError() to determine the cause.
839  */
840 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
841 {
842     NTSTATUS    nts;
843     FARPROC     fp;
844
845     if (HIWORD(function))
846     {
847         ANSI_STRING     str;
848
849         RtlInitAnsiString( &str, function );
850         nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp );
851     }
852     else
853         nts = LdrGetProcedureAddress( hModule, NULL, (DWORD)function, (void**)&fp );
854     if (nts != STATUS_SUCCESS)
855     {
856         SetLastError( RtlNtStatusToDosError( nts ) );
857         fp = NULL;
858     }
859     return fp;
860 }
861
862 /***********************************************************************
863  *           GetProcAddress32                   (KERNEL.453)
864  *
865  * Find the address of an exported symbol in a loaded dll.
866  *
867  * PARAMS
868  *  hModule  [I] Handle to the dll returned by LoadLibraryA().
869  *  function [I] Name of the symbol, or an integer ordinal number < 16384
870  *
871  * RETURNS
872  *  Success: A pointer to the symbol in the process address space.
873  *  Failure: NULL. Use GetLastError() to determine the cause.
874  */
875 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
876 {
877     /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
878     return GetProcAddress( hModule, function );
879 }