Documentation updates.
[wine.git] / loader / module.c
blobf32e13bcbcfc46bbfb76b8c2fcd634383d855f24
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <sys/types.h>
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 "heap.h"
42 #include "thread.h"
43 #include "file.h"
44 #include "module.h"
46 #include "wine/debug.h"
47 #include "wine/unicode.h"
48 #include "wine/server.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(module);
51 WINE_DECLARE_DEBUG_CHANNEL(win32);
52 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
55 /****************************************************************************
56 * DisableThreadLibraryCalls (KERNEL32.@)
58 * Inform the module loader that thread notifications are not required for a dll.
60 * PARAMS
61 * hModule [I] Module handle to skip calls for
63 * RETURNS
64 * Success: TRUE. Thread attach and detach notifications will not be sent
65 * to hModule.
66 * Failure: FALSE. Use GetLastError() to determine the cause.
68 * NOTES
69 * This is typically called from the dll entry point of a dll during process
70 * attachment, for dlls that do not need to process thread notifications.
72 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
74 NTSTATUS nts = LdrDisableThreadCalloutsForDll( hModule );
75 if (nts == STATUS_SUCCESS) return TRUE;
77 SetLastError( RtlNtStatusToDosError( nts ) );
78 return FALSE;
82 /* Check whether a file is an OS/2 or a very old Windows executable
83 * by testing on import of KERNEL.
85 * FIXME: is reading the module imports the only way of discerning
86 * old Windows binaries from OS/2 ones ? At least it seems so...
88 static enum binary_type MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz,
89 const IMAGE_OS2_HEADER *ne)
91 DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
92 enum binary_type ret = BINARY_OS216;
93 LPWORD modtab = NULL;
94 LPSTR nametab = NULL;
95 DWORD len;
96 int i;
98 /* read modref table */
99 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
100 || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
101 || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
102 || (len != ne->ne_cmod*sizeof(WORD)) )
103 goto broken;
105 /* read imported names table */
106 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
107 || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
108 || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
109 || (len != ne->ne_enttab - ne->ne_imptab) )
110 goto broken;
112 for (i=0; i < ne->ne_cmod; i++)
114 LPSTR module = &nametab[modtab[i]];
115 TRACE("modref: %.*s\n", module[0], &module[1]);
116 if (!(strncmp(&module[1], "KERNEL", module[0])))
117 { /* very old Windows file */
118 MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
119 ret = BINARY_WIN16;
120 goto good;
124 broken:
125 ERR("Hmm, an error occurred. Is this binary file broken ?\n");
127 good:
128 HeapFree( GetProcessHeap(), 0, modtab);
129 HeapFree( GetProcessHeap(), 0, nametab);
130 SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
131 return ret;
134 /***********************************************************************
135 * MODULE_GetBinaryType
137 enum binary_type MODULE_GetBinaryType( HANDLE hfile )
139 union
141 struct
143 unsigned char magic[4];
144 unsigned char ignored[12];
145 unsigned short type;
146 } elf;
147 struct
149 unsigned long magic;
150 unsigned long cputype;
151 unsigned long cpusubtype;
152 unsigned long filetype;
153 } macho;
154 IMAGE_DOS_HEADER mz;
155 } header;
157 char magic[4];
158 DWORD len;
160 /* Seek to the start of the file and read the header information. */
161 if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1)
162 return BINARY_UNKNOWN;
163 if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header))
164 return BINARY_UNKNOWN;
166 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
168 /* FIXME: we don't bother to check byte order, architecture, etc. */
169 switch(header.elf.type)
171 case 2: return BINARY_UNIX_EXE;
172 case 3: return BINARY_UNIX_LIB;
174 return BINARY_UNKNOWN;
177 /* Mach-o File with Endian set to Big Endian or Little Endian*/
178 if (header.macho.magic == 0xfeedface || header.macho.magic == 0xecafdeef)
180 switch(header.macho.filetype)
182 case 0x8: /* MH_BUNDLE */ return BINARY_UNIX_LIB;
184 return BINARY_UNKNOWN;
187 /* Not ELF, try DOS */
189 if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
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.
198 /* But before we do we will make sure that header
199 * structure encompasses the "Offset to extended header"
200 * field.
202 if (header.mz.e_lfanew < sizeof(IMAGE_DOS_HEADER))
203 return BINARY_DOS;
204 if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
205 return BINARY_DOS;
206 if (!ReadFile( hfile, magic, sizeof(magic), &len, NULL ) || len != sizeof(magic))
207 return BINARY_DOS;
209 /* Reading the magic field succeeded so
210 * we will try to determine what type it is.
212 if (!memcmp( magic, "PE\0\0", 4 ))
214 IMAGE_FILE_HEADER FileHeader;
216 if (ReadFile( hfile, &FileHeader, sizeof(FileHeader), &len, NULL ) && len == sizeof(FileHeader))
218 if (FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
219 return BINARY_PE_EXE;
221 return BINARY_DOS;
224 if (!memcmp( magic, "NE", 2 ))
226 /* This is a Windows executable (NE) header. This can
227 * mean either a 16-bit OS/2 or a 16-bit Windows or even a
228 * DOS program (running under a DOS extender). To decide
229 * which, we'll have to read the NE header.
231 IMAGE_OS2_HEADER ne;
232 if ( SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) != -1
233 && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
234 && len == sizeof(ne) )
236 switch ( ne.ne_exetyp )
238 case 2: return BINARY_WIN16;
239 case 5: return BINARY_DOS;
240 default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ne);
243 /* Couldn't read header, so abort. */
244 return BINARY_DOS;
247 /* Unknown extended header, but this file is nonetheless DOS-executable. */
248 return BINARY_DOS;
251 return BINARY_UNKNOWN;
254 /***********************************************************************
255 * GetBinaryTypeA [KERNEL32.@]
256 * GetBinaryType [KERNEL32.@]
258 * Determine whether a file is executable, and if so, what kind.
260 * PARAMS
261 * lpApplicationName [I] Path of the file to check
262 * lpBinaryType [O] Destination for the binary type
264 * RETURNS
265 * TRUE, if the file is an executable, in which case lpBinaryType is set.
266 * FALSE, if the file is not an executable or if the function fails.
268 * NOTES
269 * The type of executable is a property that determines which subsytem an
270 * executable file runs under. lpBinaryType can be set to one of the following
271 * values:
272 * SCS_32BIT_BINARY: A Win32 based application
273 * SCS_DOS_BINARY: An MS-Dos based application
274 * SCS_WOW_BINARY: A Win16 based application
275 * SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
276 * SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
277 * SCS_OS216_BINARY: A 16bit OS/2 based application
279 * To find the binary type, this function reads in the files header information.
280 * If extended header information is not present it will assume that the file
281 * is a DOS executable. If extended header information is present it will
282 * determine if the file is a 16 or 32 bit Windows executable by checking the
283 * flags in the header.
285 * ".com" and ".pif" files are only recognized by their file name extension,
286 * as per native Windows.
288 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
290 BOOL ret = FALSE;
291 HANDLE hfile;
292 char *ptr;
294 TRACE_(win32)("%s\n", lpApplicationName );
296 /* Sanity check.
298 if ( lpApplicationName == NULL || lpBinaryType == NULL )
299 return FALSE;
301 /* Open the file indicated by lpApplicationName for reading.
303 hfile = CreateFileA( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
304 NULL, OPEN_EXISTING, 0, 0 );
305 if ( hfile == INVALID_HANDLE_VALUE )
306 return FALSE;
308 /* Check binary type
310 switch(MODULE_GetBinaryType( hfile ))
312 case BINARY_UNKNOWN:
313 /* try to determine from file name */
314 ptr = strrchr( lpApplicationName, '.' );
315 if (!ptr) break;
316 if (!FILE_strcasecmp( ptr, ".COM" ))
318 *lpBinaryType = SCS_DOS_BINARY;
319 ret = TRUE;
321 else if (!FILE_strcasecmp( ptr, ".PIF" ))
323 *lpBinaryType = SCS_PIF_BINARY;
324 ret = TRUE;
326 break;
327 case BINARY_PE_EXE:
328 case BINARY_PE_DLL:
329 *lpBinaryType = SCS_32BIT_BINARY;
330 ret = TRUE;
331 break;
332 case BINARY_WIN16:
333 *lpBinaryType = SCS_WOW_BINARY;
334 ret = TRUE;
335 break;
336 case BINARY_OS216:
337 *lpBinaryType = SCS_OS216_BINARY;
338 ret = TRUE;
339 break;
340 case BINARY_DOS:
341 *lpBinaryType = SCS_DOS_BINARY;
342 ret = TRUE;
343 break;
344 case BINARY_UNIX_EXE:
345 case BINARY_UNIX_LIB:
346 ret = FALSE;
347 break;
350 CloseHandle( hfile );
351 return ret;
354 /***********************************************************************
355 * GetBinaryTypeW [KERNEL32.@]
357 * Unicode version of GetBinaryTypeA.
359 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
361 BOOL ret = FALSE;
362 LPSTR strNew = NULL;
364 TRACE_(win32)("%s\n", debugstr_w(lpApplicationName) );
366 /* Sanity check.
368 if ( lpApplicationName == NULL || lpBinaryType == NULL )
369 return FALSE;
371 /* Convert the wide string to a ascii string.
373 strNew = HEAP_strdupWtoA( GetProcessHeap(), 0, lpApplicationName );
375 if ( strNew != NULL )
377 ret = GetBinaryTypeA( strNew, lpBinaryType );
379 /* Free the allocated string.
381 HeapFree( GetProcessHeap(), 0, strNew );
384 return ret;
388 /***********************************************************************
389 * GetModuleHandleA (KERNEL32.@)
390 * GetModuleHandle32 (KERNEL.488)
392 * Get the handle of a dll loaded into the process address space.
394 * PARAMS
395 * module [I] Name of the dll
397 * RETURNS
398 * Success: A handle to the loaded dll.
399 * Failure: A NULL handle. Use GetLastError() to determine the cause.
401 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
403 NTSTATUS nts;
404 HMODULE ret;
405 UNICODE_STRING wstr;
407 if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
409 RtlCreateUnicodeStringFromAsciiz(&wstr, module);
410 nts = LdrGetDllHandle(0, 0, &wstr, &ret);
411 RtlFreeUnicodeString( &wstr );
412 if (nts != STATUS_SUCCESS)
414 ret = 0;
415 SetLastError( RtlNtStatusToDosError( nts ) );
417 return ret;
420 /***********************************************************************
421 * GetModuleHandleW (KERNEL32.@)
423 * Unicode version of GetModuleHandleA.
425 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
427 NTSTATUS nts;
428 HMODULE ret;
429 UNICODE_STRING wstr;
431 if (!module) return NtCurrentTeb()->Peb->ImageBaseAddress;
433 RtlInitUnicodeString( &wstr, module );
434 nts = LdrGetDllHandle( 0, 0, &wstr, &ret);
435 if (nts != STATUS_SUCCESS)
437 SetLastError( RtlNtStatusToDosError( nts ) );
438 ret = 0;
440 return ret;
444 /***********************************************************************
445 * GetModuleFileNameA (KERNEL32.@)
446 * GetModuleFileName32 (KERNEL.487)
448 * Get the file name of a loaded module from its handle.
450 * RETURNS
451 * Success: The length of the file name, excluding the terminating NUL.
452 * Failure: 0. Use GetLastError() to determine the cause.
454 * NOTES
455 * This function always returns the long path of hModule (as opposed to
456 * GetModuleFileName16() which returns short paths when the modules version
457 * field is < 4.0).
459 DWORD WINAPI GetModuleFileNameA(
460 HMODULE hModule, /* [in] Module handle (32 bit) */
461 LPSTR lpFileName, /* [out] Destination for file name */
462 DWORD size ) /* [in] Size of lpFileName in characters */
464 LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
466 if (!filenameW)
468 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
469 return 0;
471 GetModuleFileNameW( hModule, filenameW, size );
472 WideCharToMultiByte( CP_ACP, 0, filenameW, -1, lpFileName, size, NULL, NULL );
473 HeapFree( GetProcessHeap(), 0, filenameW );
474 return strlen( lpFileName );
477 /***********************************************************************
478 * GetModuleFileNameW (KERNEL32.@)
480 * Unicode version of GetModuleFileNameA.
482 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
484 ULONG magic;
486 lpFileName[0] = 0;
488 LdrLockLoaderLock( 0, NULL, &magic );
489 if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32))
491 /* 16-bit task - get current NE module name */
492 NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() );
493 if (pModule)
495 WCHAR path[MAX_PATH];
497 MultiByteToWideChar( CP_ACP, 0, NE_MODULE_NAME(pModule), -1, path, MAX_PATH );
498 GetLongPathNameW(path, lpFileName, size);
501 else
503 LDR_MODULE* pldr;
504 NTSTATUS nts;
506 if (!hModule) hModule = NtCurrentTeb()->Peb->ImageBaseAddress;
507 nts = LdrFindEntryForAddress( hModule, &pldr );
508 if (nts == STATUS_SUCCESS) lstrcpynW(lpFileName, pldr->FullDllName.Buffer, size);
509 else SetLastError( RtlNtStatusToDosError( nts ) );
512 LdrUnlockLoaderLock( 0, magic );
514 TRACE( "%s\n", debugstr_w(lpFileName) );
515 return strlenW(lpFileName);
518 /******************************************************************
519 * load_library_as_datafile
521 static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
523 static const WCHAR dotDLL[] = {'.','d','l','l',0};
525 WCHAR filenameW[MAX_PATH];
526 HANDLE hFile = INVALID_HANDLE_VALUE;
527 HANDLE mapping;
528 HMODULE module;
530 *hmod = 0;
532 if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
533 filenameW, NULL ))
535 hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
536 NULL, OPEN_EXISTING, 0, 0 );
538 if (hFile == INVALID_HANDLE_VALUE) return FALSE;
540 mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
541 CloseHandle( hFile );
542 if (!mapping) return FALSE;
544 module = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
545 CloseHandle( mapping );
546 if (!module) return FALSE;
548 /* make sure it's a valid PE file */
549 if (!RtlImageNtHeader(module))
551 UnmapViewOfFile( module );
552 return FALSE;
554 *hmod = (HMODULE)((char *)module + 1); /* set low bit of handle to indicate datafile module */
555 return TRUE;
558 /******************************************************************
559 * LoadLibraryExA (KERNEL32.@)
561 * Load a dll file into the process address space.
563 * PARAMS
564 * libname [I] Name of the file to load
565 * hfile [I] Reserved, must be 0.
566 * flags [I] Flags for loading the dll
568 * RETURNS
569 * Success: A handle to the loaded dll.
570 * Failure: A NULL handle. Use GetLastError() to determine the cause.
572 * NOTES
573 * The HFILE parameter is not used and marked reserved in the SDK. I can
574 * only guess that it should force a file to be mapped, but I rather
575 * ignore the parameter because it would be extremely difficult to
576 * integrate this with different types of module representations.
578 HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
580 UNICODE_STRING wstr;
581 NTSTATUS nts;
582 HMODULE hModule;
584 if (!libname)
586 SetLastError(ERROR_INVALID_PARAMETER);
587 return 0;
589 RtlCreateUnicodeStringFromAsciiz( &wstr, libname );
591 if (flags & LOAD_LIBRARY_AS_DATAFILE)
593 /* The method in load_library_as_datafile allows searching for the
594 * 'native' libraries only
596 if (load_library_as_datafile( wstr.Buffer, &hModule))
598 RtlFreeUnicodeString( &wstr );
599 return hModule;
601 flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
602 /* Fallback to normal behaviour */
605 nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
606 if (nts != STATUS_SUCCESS)
608 hModule = 0;
609 SetLastError( RtlNtStatusToDosError( nts ) );
611 RtlFreeUnicodeString( &wstr );
613 return hModule;
616 /***********************************************************************
617 * LoadLibraryExW (KERNEL32.@)
619 * Unicode version of LoadLibraryExA.
621 HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
623 UNICODE_STRING wstr;
624 NTSTATUS nts;
625 HMODULE hModule;
627 if (!libnameW)
629 SetLastError(ERROR_INVALID_PARAMETER);
630 return 0;
633 if (flags & LOAD_LIBRARY_AS_DATAFILE)
635 /* The method in load_library_as_datafile allows searching for the
636 * 'native' libraries only
638 if (load_library_as_datafile(libnameW, &hModule)) return hModule;
639 flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
640 /* Fallback to normal behaviour */
643 RtlInitUnicodeString( &wstr, libnameW );
644 nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
645 if (nts != STATUS_SUCCESS)
647 hModule = 0;
648 SetLastError( RtlNtStatusToDosError( nts ) );
650 return hModule;
653 /***********************************************************************
654 * LoadLibraryA (KERNEL32.@)
656 * Load a dll file into the process address space.
658 * PARAMS
659 * libname [I] Name of the file to load
661 * RETURNS
662 * Success: A handle to the loaded dll.
663 * Failure: A NULL handle. Use GetLastError() to determine the cause.
665 * NOTES
666 * See LoadLibraryExA().
668 HMODULE WINAPI LoadLibraryA(LPCSTR libname)
670 return LoadLibraryExA(libname, 0, 0);
673 /***********************************************************************
674 * LoadLibraryW (KERNEL32.@)
676 * Unicode version of LoadLibraryA.
678 HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
680 return LoadLibraryExW(libnameW, 0, 0);
683 /***********************************************************************
684 * FreeLibrary (KERNEL32.@)
685 * FreeLibrary32 (KERNEL.486)
687 * Free a dll loaded into the process address space.
689 * PARAMS
690 * hLibModule [I] Handle to the dll returned by LoadLibraryA().
692 * RETURNS
693 * Success: TRUE. The dll is removed if it is not still in use.
694 * Failure: FALSE. Use GetLastError() to determine the cause.
696 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
698 BOOL retv = FALSE;
699 NTSTATUS nts;
701 if (!hLibModule)
703 SetLastError( ERROR_INVALID_HANDLE );
704 return FALSE;
707 if ((ULONG_PTR)hLibModule & 1)
709 /* this is a LOAD_LIBRARY_AS_DATAFILE module */
710 char *ptr = (char *)hLibModule - 1;
711 UnmapViewOfFile( ptr );
712 return TRUE;
715 if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
716 else SetLastError( RtlNtStatusToDosError( nts ) );
718 return retv;
721 /***********************************************************************
722 * GetProcAddress (KERNEL32.@)
724 * Find the address of an exported symbol in a loaded dll.
726 * PARAMS
727 * hModule [I] Handle to the dll returned by LoadLibraryA().
728 * function [I] Name of the symbol, or an integer ordinal number < 16384
730 * RETURNS
731 * Success: A pointer to the symbol in the process address space.
732 * Failure: NULL. Use GetLastError() to determine the cause.
734 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
736 NTSTATUS nts;
737 FARPROC fp;
739 if (HIWORD(function))
741 ANSI_STRING str;
743 RtlInitAnsiString( &str, function );
744 nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp );
746 else
747 nts = LdrGetProcedureAddress( hModule, NULL, (DWORD)function, (void**)&fp );
748 if (nts != STATUS_SUCCESS)
750 SetLastError( RtlNtStatusToDosError( nts ) );
751 fp = NULL;
753 return fp;
756 /***********************************************************************
757 * GetProcAddress32 (KERNEL.453)
759 * Find the address of an exported symbol in a loaded dll.
761 * PARAMS
762 * hModule [I] Handle to the dll returned by LoadLibraryA().
763 * function [I] Name of the symbol, or an integer ordinal number < 16384
765 * RETURNS
766 * Success: A pointer to the symbol in the process address space.
767 * Failure: NULL. Use GetLastError() to determine the cause.
769 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
771 /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
772 return GetProcAddress( hModule, function );