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