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