Moved WINE_MODREF.flags to WINE_MODREF.ldr.Flags, and make use of the
[wine] / loader / 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 <assert.h>
25 #include <fcntl.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #include "wine/winbase16.h"
34 #include "winerror.h"
35 #include "winternl.h"
36 #include "heap.h"
37 #include "file.h"
38 #include "module.h"
39
40 #include "wine/debug.h"
41 #include "wine/unicode.h"
42 #include "wine/server.h"
43
44 WINE_DEFAULT_DEBUG_CHANNEL(module);
45 WINE_DECLARE_DEBUG_CHANNEL(win32);
46 WINE_DECLARE_DEBUG_CHANNEL(loaddll);
47
48 inline static HMODULE get_exe_module(void)
49 {
50     HMODULE mod;
51     /* FIXME: should look into PEB */
52     LdrGetDllHandle( 0, 0, NULL, &mod );
53     return mod;
54 }
55
56 /***********************************************************************
57  *           wait_input_idle
58  *
59  * Wrapper to call WaitForInputIdle USER function
60  */
61 typedef DWORD (WINAPI *WaitForInputIdle_ptr)( HANDLE hProcess, DWORD dwTimeOut );
62
63 static DWORD wait_input_idle( HANDLE process, DWORD timeout )
64 {
65     HMODULE mod = GetModuleHandleA( "user32.dll" );
66     if (mod)
67     {
68         WaitForInputIdle_ptr ptr = (WaitForInputIdle_ptr)GetProcAddress( mod, "WaitForInputIdle" );
69         if (ptr) return ptr( process, timeout );
70     }
71     return 0;
72 }
73
74
75 /****************************************************************************
76  *              DisableThreadLibraryCalls (KERNEL32.@)
77  *
78  * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
79  */
80 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
81 {
82     NTSTATUS    nts = LdrDisableThreadCalloutsForDll( hModule );
83     if (nts == STATUS_SUCCESS) return TRUE;
84
85     SetLastError( RtlNtStatusToDosError( nts ) );
86     return FALSE;
87 }
88
89
90 /***********************************************************************
91  *           MODULE_CreateDummyModule
92  *
93  * Create a dummy NE module for Win32 or Winelib.
94  */
95 HMODULE16 MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 )
96 {
97     HMODULE16 hModule;
98     NE_MODULE *pModule;
99     SEGTABLEENTRY *pSegment;
100     char *pStr,*s;
101     unsigned int len;
102     const char* basename;
103     OFSTRUCT *ofs;
104     int of_size, size;
105
106     /* Extract base filename */
107     basename = strrchr(filename, '\\');
108     if (!basename) basename = filename;
109     else basename++;
110     len = strlen(basename);
111     if ((s = strchr(basename, '.'))) len = s - basename;
112
113     /* Allocate module */
114     of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
115                     + strlen(filename) + 1;
116     size = sizeof(NE_MODULE) +
117                  /* loaded file info */
118                  ((of_size + 3) & ~3) +
119                  /* segment table: DS,CS */
120                  2 * sizeof(SEGTABLEENTRY) +
121                  /* name table */
122                  len + 2 +
123                  /* several empty tables */
124                  8;
125
126     hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
127     if (!hModule) return (HMODULE16)11;  /* invalid exe */
128
129     FarSetOwner16( hModule, hModule );
130     pModule = (NE_MODULE *)GlobalLock16( hModule );
131
132     /* Set all used entries */
133     pModule->magic            = IMAGE_OS2_SIGNATURE;
134     pModule->count            = 1;
135     pModule->next             = 0;
136     pModule->flags            = 0;
137     pModule->dgroup           = 0;
138     pModule->ss               = 1;
139     pModule->cs               = 2;
140     pModule->heap_size        = 0;
141     pModule->stack_size       = 0;
142     pModule->seg_count        = 2;
143     pModule->modref_count     = 0;
144     pModule->nrname_size      = 0;
145     pModule->fileinfo         = sizeof(NE_MODULE);
146     pModule->os_flags         = NE_OSFLAGS_WINDOWS;
147     pModule->self             = hModule;
148     pModule->module32         = module32;
149
150     /* Set version and flags */
151     if (module32)
152     {
153         IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module32 );
154         pModule->expected_version = ((nt->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) |
155                                      (nt->OptionalHeader.MinorSubsystemVersion & 0xff);
156         pModule->flags |= NE_FFLAGS_WIN32;
157         if (nt->FileHeader.Characteristics & IMAGE_FILE_DLL)
158             pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA;
159     }
160
161     /* Set loaded file information */
162     ofs = (OFSTRUCT *)(pModule + 1);
163     memset( ofs, 0, of_size );
164     ofs->cBytes = of_size < 256 ? of_size : 255;   /* FIXME */
165     strcpy( ofs->szPathName, filename );
166
167     pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3));
168     pModule->seg_table = (int)pSegment - (int)pModule;
169     /* Data segment */
170     pSegment->size    = 0;
171     pSegment->flags   = NE_SEGFLAGS_DATA;
172     pSegment->minsize = 0x1000;
173     pSegment++;
174     /* Code segment */
175     pSegment->flags   = 0;
176     pSegment++;
177
178     /* Module name */
179     pStr = (char *)pSegment;
180     pModule->name_table = (int)pStr - (int)pModule;
181     assert(len<256);
182     *pStr = len;
183     lstrcpynA( pStr+1, basename, len+1 );
184     pStr += len+2;
185
186     /* All tables zero terminated */
187     pModule->res_table = pModule->import_table = pModule->entry_table =
188                 (int)pStr - (int)pModule;
189
190     NE_RegisterModule( pModule );
191     return hModule;
192 }
193
194
195 /* Check whether a file is an OS/2 or a very old Windows executable
196  * by testing on import of KERNEL.
197  *
198  * FIXME: is reading the module imports the only way of discerning
199  *        old Windows binaries from OS/2 ones ? At least it seems so...
200  */
201 static enum binary_type MODULE_Decide_OS2_OldWin(HANDLE hfile, const IMAGE_DOS_HEADER *mz,
202                                                  const IMAGE_OS2_HEADER *ne)
203 {
204     DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
205     enum binary_type ret = BINARY_OS216;
206     LPWORD modtab = NULL;
207     LPSTR nametab = NULL;
208     DWORD len;
209     int i;
210
211     /* read modref table */
212     if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
213       || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
214       || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
215       || (len != ne->ne_cmod*sizeof(WORD)) )
216         goto broken;
217
218     /* read imported names table */
219     if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
220       || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
221       || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
222       || (len != ne->ne_enttab - ne->ne_imptab) )
223         goto broken;
224
225     for (i=0; i < ne->ne_cmod; i++)
226     {
227         LPSTR module = &nametab[modtab[i]];
228         TRACE("modref: %.*s\n", module[0], &module[1]);
229         if (!(strncmp(&module[1], "KERNEL", module[0])))
230         { /* very old Windows file */
231             MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
232             ret = BINARY_WIN16;
233             goto good;
234         }
235     }
236
237 broken:
238     ERR("Hmm, an error occurred. Is this binary file broken ?\n");
239
240 good:
241     HeapFree( GetProcessHeap(), 0, modtab);
242     HeapFree( GetProcessHeap(), 0, nametab);
243     SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
244     return ret;
245 }
246
247 /***********************************************************************
248  *           MODULE_GetBinaryType
249  */
250 enum binary_type MODULE_GetBinaryType( HANDLE hfile )
251 {
252     union
253     {
254         struct
255         {
256             unsigned char magic[4];
257             unsigned char ignored[12];
258             unsigned short type;
259         } elf;
260         IMAGE_DOS_HEADER mz;
261     } header;
262
263     char magic[4];
264     DWORD len;
265
266     /* Seek to the start of the file and read the header information. */
267     if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1)
268         return BINARY_UNKNOWN;
269     if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header))
270         return BINARY_UNKNOWN;
271
272     if (!memcmp( header.elf.magic, "\177ELF", 4 ))
273     {
274         /* FIXME: we don't bother to check byte order, architecture, etc. */
275         switch(header.elf.type)
276         {
277         case 2: return BINARY_UNIX_EXE;
278         case 3: return BINARY_UNIX_LIB;
279         }
280         return BINARY_UNKNOWN;
281     }
282
283     /* Not ELF, try DOS */
284
285     if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
286     {
287         /* We do have a DOS image so we will now try to seek into
288          * the file by the amount indicated by the field
289          * "Offset to extended header" and read in the
290          * "magic" field information at that location.
291          * This will tell us if there is more header information
292          * to read or not.
293          */
294         /* But before we do we will make sure that header
295          * structure encompasses the "Offset to extended header"
296          * field.
297          */
298         if ((header.mz.e_cparhdr << 4) < sizeof(IMAGE_DOS_HEADER))
299             return BINARY_DOS;
300         if (header.mz.e_crlc && (header.mz.e_lfarlc < sizeof(IMAGE_DOS_HEADER)))
301             return BINARY_DOS;
302         if (header.mz.e_lfanew < sizeof(IMAGE_DOS_HEADER))
303             return BINARY_DOS;
304         if (SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) == -1)
305             return BINARY_DOS;
306         if (!ReadFile( hfile, magic, sizeof(magic), &len, NULL ) || len != sizeof(magic))
307             return BINARY_DOS;
308
309         /* Reading the magic field succeeded so
310          * we will try to determine what type it is.
311          */
312         if (!memcmp( magic, "PE\0\0", 4 ))
313         {
314             IMAGE_FILE_HEADER FileHeader;
315
316             if (ReadFile( hfile, &FileHeader, sizeof(FileHeader), &len, NULL ) && len == sizeof(FileHeader))
317             {
318                 if (FileHeader.Characteristics & IMAGE_FILE_DLL) return BINARY_PE_DLL;
319                 return BINARY_PE_EXE;
320             }
321             return BINARY_DOS;
322         }
323
324         if (!memcmp( magic, "NE", 2 ))
325         {
326             /* This is a Windows executable (NE) header.  This can
327              * mean either a 16-bit OS/2 or a 16-bit Windows or even a
328              * DOS program (running under a DOS extender).  To decide
329              * which, we'll have to read the NE header.
330              */
331             IMAGE_OS2_HEADER ne;
332             if (    SetFilePointer( hfile, header.mz.e_lfanew, NULL, SEEK_SET ) != -1
333                     && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
334                     && len == sizeof(ne) )
335             {
336                 switch ( ne.ne_exetyp )
337                 {
338                 case 2:  return BINARY_WIN16;
339                 case 5:  return BINARY_DOS;
340                 default: return MODULE_Decide_OS2_OldWin(hfile, &header.mz, &ne);
341                 }
342             }
343             /* Couldn't read header, so abort. */
344             return BINARY_DOS;
345         }
346
347         /* Unknown extended header, but this file is nonetheless DOS-executable. */
348         return BINARY_DOS;
349     }
350
351     return BINARY_UNKNOWN;
352 }
353
354 /***********************************************************************
355  *             GetBinaryTypeA                     [KERNEL32.@]
356  *             GetBinaryType                      [KERNEL32.@]
357  *
358  * The GetBinaryType function determines whether a file is executable
359  * or not and if it is it returns what type of executable it is.
360  * The type of executable is a property that determines in which
361  * subsystem an executable file runs under.
362  *
363  * Binary types returned:
364  * SCS_32BIT_BINARY: A Win32 based application
365  * SCS_DOS_BINARY: An MS-Dos based application
366  * SCS_WOW_BINARY: A Win16 based application
367  * SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
368  * SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
369  * SCS_OS216_BINARY: A 16bit OS/2 based application
370  *
371  * Returns TRUE if the file is an executable in which case
372  * the value pointed by lpBinaryType is set.
373  * Returns FALSE if the file is not an executable or if the function fails.
374  *
375  * To do so it opens the file and reads in the header information
376  * if the extended header information is not present it will
377  * assume that the file is a DOS executable.
378  * If the extended header information is present it will
379  * determine if the file is a 16 or 32 bit Windows executable
380  * by check the flags in the header.
381  *
382  * Note that .COM and .PIF files are only recognized by their
383  * file name extension; but Windows does it the same way ...
384  */
385 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
386 {
387     BOOL ret = FALSE;
388     HANDLE hfile;
389     char *ptr;
390
391     TRACE_(win32)("%s\n", lpApplicationName );
392
393     /* Sanity check.
394      */
395     if ( lpApplicationName == NULL || lpBinaryType == NULL )
396         return FALSE;
397
398     /* Open the file indicated by lpApplicationName for reading.
399      */
400     hfile = CreateFileA( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
401                          NULL, OPEN_EXISTING, 0, 0 );
402     if ( hfile == INVALID_HANDLE_VALUE )
403         return FALSE;
404
405     /* Check binary type
406      */
407     switch(MODULE_GetBinaryType( hfile ))
408     {
409     case BINARY_UNKNOWN:
410         /* try to determine from file name */
411         ptr = strrchr( lpApplicationName, '.' );
412         if (!ptr) break;
413         if (!FILE_strcasecmp( ptr, ".COM" ))
414         {
415             *lpBinaryType = SCS_DOS_BINARY;
416             ret = TRUE;
417         }
418         else if (!FILE_strcasecmp( ptr, ".PIF" ))
419         {
420             *lpBinaryType = SCS_PIF_BINARY;
421             ret = TRUE;
422         }
423         break;
424     case BINARY_PE_EXE:
425     case BINARY_PE_DLL:
426         *lpBinaryType = SCS_32BIT_BINARY;
427         ret = TRUE;
428         break;
429     case BINARY_WIN16:
430         *lpBinaryType = SCS_WOW_BINARY;
431         ret = TRUE;
432         break;
433     case BINARY_OS216:
434         *lpBinaryType = SCS_OS216_BINARY;
435         ret = TRUE;
436         break;
437     case BINARY_DOS:
438         *lpBinaryType = SCS_DOS_BINARY;
439         ret = TRUE;
440         break;
441     case BINARY_UNIX_EXE:
442     case BINARY_UNIX_LIB:
443         ret = FALSE;
444         break;
445     }
446
447     CloseHandle( hfile );
448     return ret;
449 }
450
451 /***********************************************************************
452  *             GetBinaryTypeW                      [KERNEL32.@]
453  */
454 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
455 {
456     BOOL ret = FALSE;
457     LPSTR strNew = NULL;
458
459     TRACE_(win32)("%s\n", debugstr_w(lpApplicationName) );
460
461     /* Sanity check.
462      */
463     if ( lpApplicationName == NULL || lpBinaryType == NULL )
464         return FALSE;
465
466     /* Convert the wide string to a ascii string.
467      */
468     strNew = HEAP_strdupWtoA( GetProcessHeap(), 0, lpApplicationName );
469
470     if ( strNew != NULL )
471     {
472         ret = GetBinaryTypeA( strNew, lpBinaryType );
473
474         /* Free the allocated string.
475          */
476         HeapFree( GetProcessHeap(), 0, strNew );
477     }
478
479     return ret;
480 }
481
482
483 /***********************************************************************
484  *           WinExec     (KERNEL.166)
485  */
486 HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
487 {
488     LPCSTR p, args = NULL;
489     LPCSTR name_beg, name_end;
490     LPSTR name, cmdline;
491     int arglen;
492     HINSTANCE16 ret;
493     char buffer[MAX_PATH];
494
495     if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */
496     {
497       name_beg = lpCmdLine+1;
498       p = strchr ( lpCmdLine+1, '"' );
499       if (p)
500       {
501           name_end = p;
502           args = strchr ( p, ' ' );
503       }
504       else /* yes, even valid with trailing '"' missing */
505           name_end = lpCmdLine+strlen(lpCmdLine);
506     }
507     else
508     {
509       name_beg = lpCmdLine;
510       args = strchr( lpCmdLine, ' ' );
511       name_end = args ? args : lpCmdLine+strlen(lpCmdLine);
512     }
513
514     if ((name_beg == lpCmdLine) && (!args))
515     { /* just use the original cmdline string as file name */
516         name = (LPSTR)lpCmdLine;
517     }
518     else
519     {
520         if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 )))
521             return ERROR_NOT_ENOUGH_MEMORY;
522         memcpy( name, name_beg, name_end - name_beg );
523         name[name_end - name_beg] = '\0';
524     }
525
526     if (args)
527     {
528         args++;
529         arglen = strlen(args);
530         cmdline = HeapAlloc( GetProcessHeap(), 0, 2 + arglen );
531         cmdline[0] = (BYTE)arglen;
532         strcpy( cmdline + 1, args );
533     }
534     else
535     {
536         cmdline = HeapAlloc( GetProcessHeap(), 0, 2 );
537         cmdline[0] = cmdline[1] = 0;
538     }
539
540     TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]);
541
542     if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL ))
543     {
544         LOADPARAMS16 params;
545         WORD showCmd[2];
546         showCmd[0] = 2;
547         showCmd[1] = nCmdShow;
548
549         params.hEnvironment = 0;
550         params.cmdLine = MapLS( cmdline );
551         params.showCmd = MapLS( showCmd );
552         params.reserved = 0;
553
554         ret = LoadModule16( buffer, &params );
555         UnMapLS( params.cmdLine );
556         UnMapLS( params.showCmd );
557     }
558     else ret = GetLastError();
559
560     HeapFree( GetProcessHeap(), 0, cmdline );
561     if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
562
563     if (ret == 21)  /* 32-bit module */
564     {
565         DWORD count;
566         ReleaseThunkLock( &count );
567         ret = LOWORD( WinExec( lpCmdLine, nCmdShow ) );
568         RestoreThunkLock( count );
569     }
570     return ret;
571 }
572
573 /***********************************************************************
574  *           WinExec   (KERNEL32.@)
575  */
576 UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
577 {
578     PROCESS_INFORMATION info;
579     STARTUPINFOA startup;
580     char *cmdline;
581     UINT ret;
582
583     memset( &startup, 0, sizeof(startup) );
584     startup.cb = sizeof(startup);
585     startup.dwFlags = STARTF_USESHOWWINDOW;
586     startup.wShowWindow = nCmdShow;
587
588     /* cmdline needs to be writeable for CreateProcess */
589     if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
590     strcpy( cmdline, lpCmdLine );
591
592     if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
593                         0, NULL, NULL, &startup, &info ))
594     {
595         /* Give 30 seconds to the app to come up */
596         if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF)
597             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
598         ret = 33;
599         /* Close off the handles */
600         CloseHandle( info.hThread );
601         CloseHandle( info.hProcess );
602     }
603     else if ((ret = GetLastError()) >= 32)
604     {
605         FIXME("Strange error set by CreateProcess: %d\n", ret );
606         ret = 11;
607     }
608     HeapFree( GetProcessHeap(), 0, cmdline );
609     return ret;
610 }
611
612 /**********************************************************************
613  *          LoadModule    (KERNEL32.@)
614  */
615 HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
616 {
617     LOADPARAMS *params = (LOADPARAMS *)paramBlock;
618     PROCESS_INFORMATION info;
619     STARTUPINFOA startup;
620     HINSTANCE hInstance;
621     LPSTR cmdline, p;
622     char filename[MAX_PATH];
623     BYTE len;
624
625     if (!name) return (HINSTANCE)ERROR_FILE_NOT_FOUND;
626
627     if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
628         !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
629         return (HINSTANCE)GetLastError();
630
631     len = (BYTE)params->lpCmdLine[0];
632     if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
633         return (HINSTANCE)ERROR_NOT_ENOUGH_MEMORY;
634
635     strcpy( cmdline, filename );
636     p = cmdline + strlen(cmdline);
637     *p++ = ' ';
638     memcpy( p, params->lpCmdLine + 1, len );
639     p[len] = 0;
640
641     memset( &startup, 0, sizeof(startup) );
642     startup.cb = sizeof(startup);
643     if (params->lpCmdShow)
644     {
645         startup.dwFlags = STARTF_USESHOWWINDOW;
646         startup.wShowWindow = params->lpCmdShow[1];
647     }
648
649     if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
650                         params->lpEnvAddress, NULL, &startup, &info ))
651     {
652         /* Give 30 seconds to the app to come up */
653         if (wait_input_idle( info.hProcess, 30000 ) ==  0xFFFFFFFF )
654             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
655         hInstance = (HINSTANCE)33;
656         /* Close off the handles */
657         CloseHandle( info.hThread );
658         CloseHandle( info.hProcess );
659     }
660     else if ((hInstance = (HINSTANCE)GetLastError()) >= (HINSTANCE)32)
661     {
662         FIXME("Strange error set by CreateProcess: %p\n", hInstance );
663         hInstance = (HINSTANCE)11;
664     }
665
666     HeapFree( GetProcessHeap(), 0, cmdline );
667     return hInstance;
668 }
669
670
671 /***********************************************************************
672  *              GetModuleHandleA         (KERNEL32.@)
673  *              GetModuleHandle32        (KERNEL.488)
674  */
675 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
676 {
677     NTSTATUS            nts;
678     HMODULE             ret;
679
680     if (module)
681     {
682         UNICODE_STRING      wstr;
683
684         RtlCreateUnicodeStringFromAsciiz(&wstr, module);
685         nts = LdrGetDllHandle(0, 0, &wstr, &ret);
686         RtlFreeUnicodeString( &wstr );
687     }
688     else
689         nts = LdrGetDllHandle(0, 0, NULL, &ret);
690     if (nts != STATUS_SUCCESS)
691     {
692         ret = 0;
693         SetLastError( RtlNtStatusToDosError( nts ) );
694     }
695
696     return ret;
697 }
698
699 /***********************************************************************
700  *              GetModuleHandleW (KERNEL32.@)
701  */
702 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
703 {
704     NTSTATUS            nts;
705     HMODULE             ret;
706
707     if (module)
708     {
709         UNICODE_STRING      wstr;
710
711         RtlInitUnicodeString( &wstr, module );
712         nts = LdrGetDllHandle( 0, 0, &wstr, &ret);
713     }
714     else
715         nts = LdrGetDllHandle( 0, 0, NULL, &ret);
716
717     if (nts != STATUS_SUCCESS)
718     {
719         SetLastError( RtlNtStatusToDosError( nts ) );
720         ret = 0;
721     }
722     return ret;
723 }
724
725
726 /***********************************************************************
727  *              GetModuleFileNameA      (KERNEL32.@)
728  *              GetModuleFileName32     (KERNEL.487)
729  *
730  * GetModuleFileNameA seems to *always* return the long path;
731  * it's only GetModuleFileName16 that decides between short/long path
732  * by checking if exe version >= 4.0.
733  * (SDK docu doesn't mention this)
734  */
735 DWORD WINAPI GetModuleFileNameA(
736         HMODULE hModule,        /* [in] module handle (32bit) */
737         LPSTR lpFileName,       /* [out] filenamebuffer */
738         DWORD size )            /* [in] size of filenamebuffer */
739 {
740     LPWSTR filenameW = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) );
741
742     if (!filenameW)
743     {
744         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
745         return 0;
746     }
747     GetModuleFileNameW( hModule, filenameW, size );
748     WideCharToMultiByte( CP_ACP, 0, filenameW, -1, lpFileName, size, NULL, NULL );
749     HeapFree( GetProcessHeap(), 0, filenameW );
750     return strlen( lpFileName );
751 }
752
753 /***********************************************************************
754  *              GetModuleFileNameW      (KERNEL32.@)
755  */
756 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName, DWORD size )
757 {
758     ULONG magic;
759
760     lpFileName[0] = 0;
761
762     LdrLockLoaderLock( 0, NULL, &magic );
763     if (!hModule && !(NtCurrentTeb()->tibflags & TEBF_WIN32))
764     {
765         /* 16-bit task - get current NE module name */
766         NE_MODULE *pModule = NE_GetPtr( GetCurrentTask() );
767         if (pModule)
768         {
769             WCHAR    path[MAX_PATH];
770
771             MultiByteToWideChar( CP_ACP, 0, NE_MODULE_NAME(pModule), -1, path, MAX_PATH );
772             GetLongPathNameW(path, lpFileName, size);
773         }
774     }
775     else
776     {
777         LDR_MODULE* pldr;
778         NTSTATUS    nts;
779
780         if (!hModule) hModule = get_exe_module();
781         nts = LdrFindEntryForAddress( hModule, &pldr );
782         if (nts == STATUS_SUCCESS) lstrcpynW(lpFileName, pldr->FullDllName.Buffer, size);
783         else SetLastError( RtlNtStatusToDosError( nts ) );
784
785     }
786     LdrUnlockLoaderLock( 0, magic );
787
788     TRACE( "%s\n", debugstr_w(lpFileName) );
789     return strlenW(lpFileName);
790 }
791
792 /******************************************************************
793  *              load_library_as_datafile
794  */
795 static BOOL load_library_as_datafile( LPCWSTR name, HMODULE* hmod)
796 {
797     static const WCHAR dotDLL[] = {'.','d','l','l',0};
798
799     WCHAR filenameW[MAX_PATH];
800     HANDLE hFile = INVALID_HANDLE_VALUE;
801     HANDLE mapping;
802
803     *hmod = 0;
804
805     if (SearchPathW( NULL, (LPCWSTR)name, dotDLL, sizeof(filenameW) / sizeof(filenameW[0]),
806                      filenameW, NULL ))
807     {
808         hFile = CreateFileW( filenameW, GENERIC_READ, FILE_SHARE_READ,
809                              NULL, OPEN_EXISTING, 0, 0 );
810     }
811     if (hFile == INVALID_HANDLE_VALUE) return FALSE;
812     switch (MODULE_GetBinaryType( hFile ))
813     {
814     case BINARY_PE_EXE:
815     case BINARY_PE_DLL:
816         mapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
817         if (mapping)
818         {
819             *hmod = MapViewOfFile( mapping, FILE_MAP_READ, 0, 0, 0 );
820             CloseHandle( mapping );
821         }
822         break;
823     default:
824         break;
825     }
826     CloseHandle( hFile );
827
828     return *hmod != 0;
829 }
830
831 /******************************************************************
832  *              LoadLibraryExA          (KERNEL32.@)
833  *
834  * The HFILE parameter is not used and marked reserved in the SDK. I can
835  * only guess that it should force a file to be mapped, but I rather
836  * ignore the parameter because it would be extremely difficult to
837  * integrate this with different types of module representations.
838  *
839  */
840 HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
841 {
842     UNICODE_STRING      wstr;
843     NTSTATUS            nts;
844     HMODULE             hModule;
845
846     if (!libname)
847     {
848         SetLastError(ERROR_INVALID_PARAMETER);
849         return 0;
850     }
851     RtlCreateUnicodeStringFromAsciiz( &wstr, libname );
852
853     if (flags & LOAD_LIBRARY_AS_DATAFILE)
854     {
855         /* The method in load_library_as_datafile allows searching for the
856          * 'native' libraries only
857          */
858         if (load_library_as_datafile( wstr.Buffer, &hModule))
859         {
860             RtlFreeUnicodeString( &wstr );
861             return (HMODULE)((ULONG_PTR)hModule + 1);
862         }
863         flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
864         /* Fallback to normal behaviour */
865     }
866
867     nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
868     if (nts != STATUS_SUCCESS)
869     {
870         hModule = 0;
871         SetLastError( RtlNtStatusToDosError( nts ) );
872     }
873     RtlFreeUnicodeString( &wstr );
874
875     return hModule;
876 }
877
878 /***********************************************************************
879  *           LoadLibraryExW       (KERNEL32.@)
880  */
881 HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW, HANDLE hfile, DWORD flags)
882 {
883     UNICODE_STRING      wstr;
884     NTSTATUS            nts;
885     HMODULE             hModule;
886
887     if (!libnameW)
888     {
889         SetLastError(ERROR_INVALID_PARAMETER);
890         return 0;
891     }
892
893     if (flags & LOAD_LIBRARY_AS_DATAFILE)
894     {
895         /* The method in load_library_as_datafile allows searching for the
896          * 'native' libraries only
897          */
898         if (load_library_as_datafile(libnameW, &hModule))
899             return (HMODULE)((ULONG_PTR)hModule + 1);
900         flags |= DONT_RESOLVE_DLL_REFERENCES; /* Just in case */
901         /* Fallback to normal behaviour */
902     }
903
904     RtlInitUnicodeString( &wstr, libnameW );
905     nts = LdrLoadDll(NULL, flags, &wstr, &hModule);
906     if (nts != STATUS_SUCCESS)
907     {
908         hModule = 0;
909         SetLastError( RtlNtStatusToDosError( nts ) );
910     }
911     return hModule;
912 }
913
914 /***********************************************************************
915  *           LoadLibraryA         (KERNEL32.@)
916  */
917 HMODULE WINAPI LoadLibraryA(LPCSTR libname)
918 {
919     return LoadLibraryExA(libname, 0, 0);
920 }
921
922 /***********************************************************************
923  *           LoadLibraryW         (KERNEL32.@)
924  */
925 HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
926 {
927     return LoadLibraryExW(libnameW, 0, 0);
928 }
929
930 /***********************************************************************
931  *           LoadLibrary32        (KERNEL.452)
932  *           LoadSystemLibrary32  (KERNEL.482)
933  */
934 HMODULE WINAPI LoadLibrary32_16( LPCSTR libname )
935 {
936     HMODULE hModule;
937     DWORD count;
938
939     ReleaseThunkLock( &count );
940     hModule = LoadLibraryA( libname );
941     RestoreThunkLock( count );
942     return hModule;
943 }
944
945 /***********************************************************************
946  *           FreeLibrary   (KERNEL32.@)
947  *           FreeLibrary32 (KERNEL.486)
948  */
949 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
950 {
951     BOOL                retv = FALSE;
952     NTSTATUS            nts;
953
954     if (!hLibModule)
955     {
956         SetLastError( ERROR_INVALID_HANDLE );
957         return FALSE;
958     }
959
960     if ((ULONG_PTR)hLibModule & 1)
961     {
962         /* this is a LOAD_LIBRARY_AS_DATAFILE module */
963         char *ptr = (char *)hLibModule - 1;
964         UnmapViewOfFile( ptr );
965         return TRUE;
966     }
967
968     if ((nts = LdrUnloadDll( hLibModule )) == STATUS_SUCCESS) retv = TRUE;
969     else SetLastError( RtlNtStatusToDosError( nts ) );
970
971     return retv;
972 }
973
974 /***********************************************************************
975  *           FreeLibraryAndExitThread (KERNEL32.@)
976  */
977 VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
978 {
979     FreeLibrary(hLibModule);
980     ExitThread(dwExitCode);
981 }
982
983 /***********************************************************************
984  *           PrivateLoadLibrary       (KERNEL32.@)
985  *
986  * FIXME: rough guesswork, don't know what "Private" means
987  */
988 HINSTANCE16 WINAPI PrivateLoadLibrary(LPCSTR libname)
989 {
990     return LoadLibrary16(libname);
991 }
992
993 /***********************************************************************
994  *           PrivateFreeLibrary       (KERNEL32.@)
995  *
996  * FIXME: rough guesswork, don't know what "Private" means
997  */
998 void WINAPI PrivateFreeLibrary(HINSTANCE16 handle)
999 {
1000     FreeLibrary16(handle);
1001 }
1002
1003
1004 /***********************************************************************
1005  *           GetProcAddress16   (KERNEL32.37)
1006  * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
1007  */
1008 FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name )
1009 {
1010     if (!hModule) {
1011         WARN("hModule may not be 0!\n");
1012         return (FARPROC16)0;
1013     }
1014     if (HIWORD(hModule))
1015     {
1016         WARN("hModule is Win32 handle (%p)\n", hModule );
1017         return (FARPROC16)0;
1018     }
1019     return GetProcAddress16( LOWORD(hModule), name );
1020 }
1021
1022 /***********************************************************************
1023  *           GetProcAddress   (KERNEL.50)
1024  */
1025 FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, LPCSTR name )
1026 {
1027     WORD ordinal;
1028     FARPROC16 ret;
1029
1030     if (!hModule) hModule = GetCurrentTask();
1031     hModule = GetExePtr( hModule );
1032
1033     if (HIWORD(name) != 0)
1034     {
1035         ordinal = NE_GetOrdinal( hModule, name );
1036         TRACE("%04x '%s'\n", hModule, name );
1037     }
1038     else
1039     {
1040         ordinal = LOWORD(name);
1041         TRACE("%04x %04x\n", hModule, ordinal );
1042     }
1043     if (!ordinal) return (FARPROC16)0;
1044
1045     ret = NE_GetEntryPoint( hModule, ordinal );
1046
1047     TRACE("returning %08x\n", (UINT)ret );
1048     return ret;
1049 }
1050
1051
1052 /***********************************************************************
1053  *           GetProcAddress             (KERNEL32.@)
1054  */
1055 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
1056 {
1057     NTSTATUS    nts;
1058     FARPROC     fp;
1059
1060     if (HIWORD(function))
1061     {
1062         ANSI_STRING     str;
1063
1064         RtlInitAnsiString( &str, function );
1065         nts = LdrGetProcedureAddress( hModule, &str, 0, (void**)&fp );
1066     }
1067     else
1068         nts = LdrGetProcedureAddress( hModule, NULL, (DWORD)function, (void**)&fp );
1069     if (nts != STATUS_SUCCESS)
1070     {
1071         SetLastError( RtlNtStatusToDosError( nts ) );
1072         fp = NULL;
1073     }
1074     return fp;
1075 }
1076
1077 /***********************************************************************
1078  *           GetProcAddress32                   (KERNEL.453)
1079  */
1080 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
1081 {
1082     /* FIXME: we used to disable snoop when returning proc for Win16 subsystem */
1083     return GetProcAddress( hModule, function );
1084 }
1085
1086 /***************************************************************************
1087  *              HasGPHandler                    (KERNEL.338)
1088  */
1089
1090 #include "pshpack1.h"
1091 typedef struct _GPHANDLERDEF
1092 {
1093     WORD selector;
1094     WORD rangeStart;
1095     WORD rangeEnd;
1096     WORD handler;
1097 } GPHANDLERDEF;
1098 #include "poppack.h"
1099
1100 SEGPTR WINAPI HasGPHandler16( SEGPTR address )
1101 {
1102     HMODULE16 hModule;
1103     int gpOrdinal;
1104     SEGPTR gpPtr;
1105     GPHANDLERDEF *gpHandler;
1106
1107     if (    (hModule = FarGetOwner16( SELECTOROF(address) )) != 0
1108          && (gpOrdinal = NE_GetOrdinal( hModule, "__GP" )) != 0
1109          && (gpPtr = (SEGPTR)NE_GetEntryPointEx( hModule, gpOrdinal, FALSE )) != 0
1110          && !IsBadReadPtr16( gpPtr, sizeof(GPHANDLERDEF) )
1111          && (gpHandler = MapSL( gpPtr )) != NULL )
1112     {
1113         while (gpHandler->selector)
1114         {
1115             if (    SELECTOROF(address) == gpHandler->selector
1116                  && OFFSETOF(address)   >= gpHandler->rangeStart
1117                  && OFFSETOF(address)   <  gpHandler->rangeEnd  )
1118                 return MAKESEGPTR( gpHandler->selector, gpHandler->handler );
1119             gpHandler++;
1120         }
1121     }
1122
1123     return 0;
1124 }