- Remove <string.h> from winnt.h.
[wine] / loader / module.c
1 /*
2  * Modules
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include "wine/winbase16.h"
15 #include "winerror.h"
16 #include "heap.h"
17 #include "file.h"
18 #include "module.h"
19 #include "debugtools.h"
20 #include "callback.h"
21 #include "loadorder.h"
22 #include "server.h"
23
24 DEFAULT_DEBUG_CHANNEL(module);
25 DECLARE_DEBUG_CHANNEL(win32);
26 DECLARE_DEBUG_CHANNEL(loaddll);
27
28 WINE_MODREF *MODULE_modref_list = NULL;
29
30 static WINE_MODREF *exe_modref;
31 static int free_lib_count;   /* recursion depth of FreeLibrary calls */
32 static int process_detaching;  /* set on process detach to avoid deadlocks with thread detach */
33
34 /*************************************************************************
35  *              MODULE32_LookupHMODULE
36  * looks for the referenced HMODULE in the current process
37  * NOTE: Assumes that the process critical section is held!
38  */
39 static WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hmod )
40 {
41     WINE_MODREF *wm;
42
43     if (!hmod) 
44         return exe_modref;
45
46     if (!HIWORD(hmod)) {
47         ERR("tried to lookup 0x%04x in win32 module handler!\n",hmod);
48         SetLastError( ERROR_INVALID_HANDLE );
49         return NULL;
50     }
51     for ( wm = MODULE_modref_list; wm; wm=wm->next )
52         if (wm->module == hmod)
53             return wm;
54     SetLastError( ERROR_INVALID_HANDLE );
55     return NULL;
56 }
57
58 /*************************************************************************
59  *              MODULE_AllocModRef
60  *
61  * Allocate a WINE_MODREF structure and add it to the process list
62  * NOTE: Assumes that the process critical section is held!
63  */
64 WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
65 {
66     WINE_MODREF *wm;
67     DWORD len;
68
69     if ((wm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) )))
70     {
71         wm->module = hModule;
72         wm->tlsindex = -1;
73
74         wm->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
75         if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
76         else wm->modname = wm->filename;
77
78         len = GetShortPathNameA( wm->filename, NULL, 0 );
79         wm->short_filename = (char *)HeapAlloc( GetProcessHeap(), 0, len+1 );
80         GetShortPathNameA( wm->filename, wm->short_filename, len+1 );
81         if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
82         else wm->short_modname = wm->short_filename;
83
84         wm->next = MODULE_modref_list;
85         if (wm->next) wm->next->prev = wm;
86         MODULE_modref_list = wm;
87
88         if (!(PE_HEADER(hModule)->FileHeader.Characteristics & IMAGE_FILE_DLL))
89         {
90             if (!exe_modref) exe_modref = wm;
91             else FIXME( "Trying to load second .EXE file: %s\n", filename );
92         }
93     }
94     return wm;
95 }
96
97 /*************************************************************************
98  *              MODULE_InitDLL
99  */
100 static BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
101 {
102     BOOL retv = TRUE;
103
104     static LPCSTR typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH", 
105                                  "THREAD_ATTACH", "THREAD_DETACH" };
106     assert( wm );
107
108     /* Skip calls for modules loaded with special load flags */
109
110     if (wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) return TRUE;
111
112     TRACE("(%s,%s,%p) - CALL\n", wm->modname, typeName[type], lpReserved );
113
114     /* Call the initialization routine */
115     retv = PE_InitDLL( wm->module, type, lpReserved );
116
117     /* The state of the module list may have changed due to the call
118        to PE_InitDLL. We cannot assume that this module has not been
119        deleted.  */
120     TRACE("(%p,%s,%p) - RETURN %d\n", wm, typeName[type], lpReserved, retv );
121
122     return retv;
123 }
124
125 /*************************************************************************
126  *              MODULE_DllProcessAttach
127  * 
128  * Send the process attach notification to all DLLs the given module
129  * depends on (recursively). This is somewhat complicated due to the fact that
130  *
131  * - we have to respect the module dependencies, i.e. modules implicitly
132  *   referenced by another module have to be initialized before the module
133  *   itself can be initialized
134  * 
135  * - the initialization routine of a DLL can itself call LoadLibrary,
136  *   thereby introducing a whole new set of dependencies (even involving
137  *   the 'old' modules) at any time during the whole process
138  *
139  * (Note that this routine can be recursively entered not only directly
140  *  from itself, but also via LoadLibrary from one of the called initialization
141  *  routines.)
142  *
143  * Furthermore, we need to rearrange the main WINE_MODREF list to allow
144  * the process *detach* notifications to be sent in the correct order.
145  * This must not only take into account module dependencies, but also 
146  * 'hidden' dependencies created by modules calling LoadLibrary in their
147  * attach notification routine.
148  *
149  * The strategy is rather simple: we move a WINE_MODREF to the head of the
150  * list after the attach notification has returned.  This implies that the
151  * detach notifications are called in the reverse of the sequence the attach
152  * notifications *returned*.
153  */
154 BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
155 {
156     BOOL retv = TRUE;
157     int i;
158
159     RtlAcquirePebLock();
160
161     if (!wm) wm = exe_modref;
162     assert( wm );
163
164     /* prevent infinite recursion in case of cyclical dependencies */
165     if (    ( wm->flags & WINE_MODREF_MARKER )
166          || ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) )
167         goto done;
168
169     TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
170
171     /* Tag current MODREF to prevent recursive loop */
172     wm->flags |= WINE_MODREF_MARKER;
173
174     /* Recursively attach all DLLs this one depends on */
175     for ( i = 0; retv && i < wm->nDeps; i++ )
176         if ( wm->deps[i] )
177             retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
178
179     /* Call DLL entry point */
180     if ( retv )
181     {
182         retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
183         if ( retv )
184             wm->flags |= WINE_MODREF_PROCESS_ATTACHED;
185     }
186
187     /* Re-insert MODREF at head of list */
188     if ( retv && wm->prev )
189     {
190         wm->prev->next = wm->next;
191         if ( wm->next ) wm->next->prev = wm->prev;
192
193         wm->prev = NULL;
194         wm->next = MODULE_modref_list;
195         MODULE_modref_list = wm->next->prev = wm;
196     }
197
198     /* Remove recursion flag */
199     wm->flags &= ~WINE_MODREF_MARKER;
200
201     TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
202
203  done:
204     RtlReleasePebLock();
205     return retv;
206 }
207
208 /*************************************************************************
209  *              MODULE_DllProcessDetach
210  * 
211  * Send DLL process detach notifications.  See the comment about calling 
212  * sequence at MODULE_DllProcessAttach.  Unless the bForceDetach flag
213  * is set, only DLLs with zero refcount are notified.
214  */
215 void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
216 {
217     WINE_MODREF *wm;
218
219     RtlAcquirePebLock();
220     if (bForceDetach) process_detaching = 1;
221     do
222     {
223         for ( wm = MODULE_modref_list; wm; wm = wm->next )
224         {
225             /* Check whether to detach this DLL */
226             if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
227                 continue;
228             if ( wm->refCount > 0 && !bForceDetach )
229                 continue;
230
231             /* Call detach notification */
232             wm->flags &= ~WINE_MODREF_PROCESS_ATTACHED;
233             MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
234
235             /* Restart at head of WINE_MODREF list, as entries might have
236                been added and/or removed while performing the call ... */
237             break;
238         }
239     } while ( wm );
240
241     RtlReleasePebLock();
242 }
243
244 /*************************************************************************
245  *              MODULE_DllThreadAttach
246  * 
247  * Send DLL thread attach notifications. These are sent in the
248  * reverse sequence of process detach notification.
249  *
250  */
251 void MODULE_DllThreadAttach( LPVOID lpReserved )
252 {
253     WINE_MODREF *wm;
254
255     /* don't do any attach calls if process is exiting */
256     if (process_detaching) return;
257     /* FIXME: there is still a race here */
258
259     RtlAcquirePebLock();
260
261     for ( wm = MODULE_modref_list; wm; wm = wm->next )
262         if ( !wm->next )
263             break;
264
265     for ( ; wm; wm = wm->prev )
266     {
267         if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
268             continue;
269         if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
270             continue;
271
272         MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
273     }
274
275     RtlReleasePebLock();
276 }
277
278 /*************************************************************************
279  *              MODULE_DllThreadDetach
280  * 
281  * Send DLL thread detach notifications. These are sent in the
282  * same sequence as process detach notification.
283  *
284  */
285 void MODULE_DllThreadDetach( LPVOID lpReserved )
286 {
287     WINE_MODREF *wm;
288
289     /* don't do any detach calls if process is exiting */
290     if (process_detaching) return;
291     /* FIXME: there is still a race here */
292
293     RtlAcquirePebLock();
294
295     for ( wm = MODULE_modref_list; wm; wm = wm->next )
296     {
297         if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
298             continue;
299         if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
300             continue;
301
302         MODULE_InitDLL( wm, DLL_THREAD_DETACH, lpReserved );
303     }
304
305     RtlReleasePebLock();
306 }
307
308 /****************************************************************************
309  *              DisableThreadLibraryCalls (KERNEL32.74)
310  *
311  * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
312  */
313 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
314 {
315     WINE_MODREF *wm;
316     BOOL retval = TRUE;
317
318     RtlAcquirePebLock();
319
320     wm = MODULE32_LookupHMODULE( hModule );
321     if ( !wm )
322         retval = FALSE;
323     else
324         wm->flags |= WINE_MODREF_NO_DLL_CALLS;
325
326     RtlReleasePebLock();
327
328     return retval;
329 }
330
331
332 /***********************************************************************
333  *           MODULE_CreateDummyModule
334  *
335  * Create a dummy NE module for Win32 or Winelib.
336  */
337 HMODULE MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 )
338 {
339     HMODULE hModule;
340     NE_MODULE *pModule;
341     SEGTABLEENTRY *pSegment;
342     char *pStr,*s;
343     unsigned int len;
344     const char* basename;
345     OFSTRUCT *ofs;
346     int of_size, size;
347
348     /* Extract base filename */
349     basename = strrchr(filename, '\\');
350     if (!basename) basename = filename;
351     else basename++;
352     len = strlen(basename);
353     if ((s = strchr(basename, '.'))) len = s - basename;
354
355     /* Allocate module */
356     of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
357                     + strlen(filename) + 1;
358     size = sizeof(NE_MODULE) +
359                  /* loaded file info */
360                  ((of_size + 3) & ~3) + 
361                  /* segment table: DS,CS */
362                  2 * sizeof(SEGTABLEENTRY) +
363                  /* name table */
364                  len + 2 +
365                  /* several empty tables */
366                  8;
367
368     hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
369     if (!hModule) return (HMODULE)11;  /* invalid exe */
370
371     FarSetOwner16( hModule, hModule );
372     pModule = (NE_MODULE *)GlobalLock16( hModule );
373
374     /* Set all used entries */
375     pModule->magic            = IMAGE_OS2_SIGNATURE;
376     pModule->count            = 1;
377     pModule->next             = 0;
378     pModule->flags            = 0;
379     pModule->dgroup           = 0;
380     pModule->ss               = 1;
381     pModule->cs               = 2;
382     pModule->heap_size        = 0;
383     pModule->stack_size       = 0;
384     pModule->seg_count        = 2;
385     pModule->modref_count     = 0;
386     pModule->nrname_size      = 0;
387     pModule->fileinfo         = sizeof(NE_MODULE);
388     pModule->os_flags         = NE_OSFLAGS_WINDOWS;
389     pModule->self             = hModule;
390     pModule->module32         = module32;
391
392     /* Set version and flags */
393     if (module32)
394     {
395         pModule->expected_version =
396             ((PE_HEADER(module32)->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) |
397              (PE_HEADER(module32)->OptionalHeader.MinorSubsystemVersion & 0xff);
398         pModule->flags |= NE_FFLAGS_WIN32;
399         if (PE_HEADER(module32)->FileHeader.Characteristics & IMAGE_FILE_DLL)
400             pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA;
401     }
402
403     /* Set loaded file information */
404     ofs = (OFSTRUCT *)(pModule + 1);
405     memset( ofs, 0, of_size );
406     ofs->cBytes = of_size < 256 ? of_size : 255;   /* FIXME */
407     strcpy( ofs->szPathName, filename );
408
409     pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + ((of_size + 3) & ~3));
410     pModule->seg_table = (int)pSegment - (int)pModule;
411     /* Data segment */
412     pSegment->size    = 0;
413     pSegment->flags   = NE_SEGFLAGS_DATA;
414     pSegment->minsize = 0x1000;
415     pSegment++;
416     /* Code segment */
417     pSegment->flags   = 0;
418     pSegment++;
419
420     /* Module name */
421     pStr = (char *)pSegment;
422     pModule->name_table = (int)pStr - (int)pModule;
423     assert(len<256);
424     *pStr = len;
425     lstrcpynA( pStr+1, basename, len+1 );
426     pStr += len+2;
427
428     /* All tables zero terminated */
429     pModule->res_table = pModule->import_table = pModule->entry_table =
430                 (int)pStr - (int)pModule;
431
432     NE_RegisterModule( pModule );
433     return hModule;
434 }
435
436
437 /**********************************************************************
438  *          MODULE_FindModule
439  *
440  * Find a (loaded) win32 module depending on path
441  *
442  * RETURNS
443  *      the module handle if found
444  *      0 if not
445  */
446 WINE_MODREF *MODULE_FindModule(
447         LPCSTR path     /* [in] pathname of module/library to be found */
448 ) {
449     WINE_MODREF *wm;
450     char dllname[260], *p;
451
452     /* Append .DLL to name if no extension present */
453     strcpy( dllname, path );
454     if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
455             strcat( dllname, ".DLL" );
456
457     for ( wm = MODULE_modref_list; wm; wm = wm->next )
458     {
459         if ( !FILE_strcasecmp( dllname, wm->modname ) )
460             break;
461         if ( !FILE_strcasecmp( dllname, wm->filename ) )
462             break;
463         if ( !FILE_strcasecmp( dllname, wm->short_modname ) )
464             break;
465         if ( !FILE_strcasecmp( dllname, wm->short_filename ) )
466             break;
467     }
468
469     return wm;
470 }
471
472
473 /* Check whether a file is an OS/2 or a very old Windows executable
474  * by testing on import of KERNEL.
475  *
476  * FIXME: is reading the module imports the only way of discerning
477  *        old Windows binaries from OS/2 ones ? At least it seems so...
478  */
479 static DWORD MODULE_Decide_OS2_OldWin(HANDLE hfile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne)
480 {
481     DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
482     DWORD type = SCS_OS216_BINARY;
483     LPWORD modtab = NULL;
484     LPSTR nametab = NULL;
485     DWORD len;
486     int i;
487
488     /* read modref table */
489     if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
490       || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
491       || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
492       || (len != ne->ne_cmod*sizeof(WORD)) )
493         goto broken;
494
495     /* read imported names table */
496     if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
497       || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
498       || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
499       || (len != ne->ne_enttab - ne->ne_imptab) )
500         goto broken;
501
502     for (i=0; i < ne->ne_cmod; i++)
503     {
504         LPSTR module = &nametab[modtab[i]];
505         TRACE("modref: %.*s\n", module[0], &module[1]);
506         if (!(strncmp(&module[1], "KERNEL", module[0])))
507         { /* very old Windows file */
508             MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
509             type = SCS_WOW_BINARY;
510             goto good;
511         }
512     }
513
514 broken:
515     ERR("Hmm, an error occurred. Is this binary file broken ?\n");
516
517 good:
518     HeapFree( GetProcessHeap(), 0, modtab);
519     HeapFree( GetProcessHeap(), 0, nametab);
520     SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
521     return type;
522 }
523
524 /***********************************************************************
525  *           MODULE_GetBinaryType
526  *
527  * The GetBinaryType function determines whether a file is executable
528  * or not and if it is it returns what type of executable it is.
529  * The type of executable is a property that determines in which
530  * subsystem an executable file runs under.
531  *
532  * Binary types returned:
533  * SCS_32BIT_BINARY: A Win32 based application
534  * SCS_DOS_BINARY: An MS-Dos based application
535  * SCS_WOW_BINARY: A Win16 based application
536  * SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
537  * SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
538  * SCS_OS216_BINARY: A 16bit OS/2 based application
539  *
540  * Returns TRUE if the file is an executable in which case
541  * the value pointed by lpBinaryType is set.
542  * Returns FALSE if the file is not an executable or if the function fails.
543  *
544  * To do so it opens the file and reads in the header information
545  * if the extended header information is not present it will
546  * assume that the file is a DOS executable.
547  * If the extended header information is present it will
548  * determine if the file is a 16 or 32 bit Windows executable
549  * by check the flags in the header.
550  *
551  * Note that .COM and .PIF files are only recognized by their
552  * file name extension; but Windows does it the same way ...
553  */
554 static BOOL MODULE_GetBinaryType( HANDLE hfile, LPCSTR filename, LPDWORD lpBinaryType )
555 {
556     IMAGE_DOS_HEADER mz_header;
557     char magic[4], *ptr;
558     DWORD len;
559
560     /* Seek to the start of the file and read the DOS header information.
561      */
562     if (    SetFilePointer( hfile, 0, NULL, SEEK_SET ) != -1  
563          && ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL )
564          && len == sizeof(mz_header) )
565     {
566         /* Now that we have the header check the e_magic field
567          * to see if this is a dos image.
568          */
569         if ( mz_header.e_magic == IMAGE_DOS_SIGNATURE )
570         {
571             BOOL lfanewValid = FALSE;
572             /* We do have a DOS image so we will now try to seek into
573              * the file by the amount indicated by the field
574              * "Offset to extended header" and read in the
575              * "magic" field information at that location.
576              * This will tell us if there is more header information
577              * to read or not.
578              */
579             /* But before we do we will make sure that header
580              * structure encompasses the "Offset to extended header"
581              * field.
582              */
583             if ( (mz_header.e_cparhdr<<4) >= sizeof(IMAGE_DOS_HEADER) )
584                 if ( ( mz_header.e_crlc == 0 ) ||
585                      ( mz_header.e_lfarlc >= sizeof(IMAGE_DOS_HEADER) ) )
586                     if (    mz_header.e_lfanew >= sizeof(IMAGE_DOS_HEADER)
587                          && SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ) != -1  
588                          && ReadFile( hfile, magic, sizeof(magic), &len, NULL )
589                          && len == sizeof(magic) )
590                         lfanewValid = TRUE;
591
592             if ( !lfanewValid )
593             {
594                 /* If we cannot read this "extended header" we will
595                  * assume that we have a simple DOS executable.
596                  */
597                 *lpBinaryType = SCS_DOS_BINARY;
598                 return TRUE;
599             }
600             else
601             {
602                 /* Reading the magic field succeeded so
603                  * we will try to determine what type it is.
604                  */
605                 if ( *(DWORD*)magic      == IMAGE_NT_SIGNATURE )
606                 {
607                     /* This is an NT signature.
608                      */
609                     *lpBinaryType = SCS_32BIT_BINARY;
610                     return TRUE;
611                 }
612                 else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
613                 {
614                     /* The IMAGE_OS2_SIGNATURE indicates that the
615                      * "extended header is a Windows executable (NE)
616                      * header."  This can mean either a 16-bit OS/2
617                      * or a 16-bit Windows or even a DOS program 
618                      * (running under a DOS extender).  To decide
619                      * which, we'll have to read the NE header.
620                      */
621
622                      IMAGE_OS2_HEADER ne;
623                      if (    SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ) != -1  
624                           && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
625                           && len == sizeof(ne) )
626                      {
627                          switch ( ne.ne_exetyp )
628                          {
629                          case 2:  *lpBinaryType = SCS_WOW_BINARY;   return TRUE;
630                          case 5:  *lpBinaryType = SCS_DOS_BINARY;   return TRUE;
631                          default: *lpBinaryType =
632                                   MODULE_Decide_OS2_OldWin(hfile, &mz_header, &ne);
633                                   return TRUE;
634                          }
635                      }
636                      /* Couldn't read header, so abort. */
637                      return FALSE;
638                 }
639                 else
640                 {
641                     /* Unknown extended header, but this file is nonetheless
642                        DOS-executable.
643                      */
644                     *lpBinaryType = SCS_DOS_BINARY;
645                     return TRUE;
646                 }
647             }
648         }
649     }
650
651     /* If we get here, we don't even have a correct MZ header.
652      * Try to check the file extension for known types ...
653      */
654     ptr = strrchr( filename, '.' );
655     if ( ptr && !strchr( ptr, '\\' ) && !strchr( ptr, '/' ) )
656     {
657         if ( !FILE_strcasecmp( ptr, ".COM" ) )
658         {
659             *lpBinaryType = SCS_DOS_BINARY;
660             return TRUE;
661         }
662
663         if ( !FILE_strcasecmp( ptr, ".PIF" ) )
664         {
665             *lpBinaryType = SCS_PIF_BINARY;
666             return TRUE;
667         }
668     }
669
670     return FALSE;
671 }
672
673 /***********************************************************************
674  *             GetBinaryTypeA                     [KERNEL32.280]
675  */
676 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
677 {
678     BOOL ret = FALSE;
679     HANDLE hfile;
680
681     TRACE_(win32)("%s\n", lpApplicationName );
682
683     /* Sanity check.
684      */
685     if ( lpApplicationName == NULL || lpBinaryType == NULL )
686         return FALSE;
687
688     /* Open the file indicated by lpApplicationName for reading.
689      */
690     hfile = CreateFileA( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
691                          NULL, OPEN_EXISTING, 0, 0 );
692     if ( hfile == INVALID_HANDLE_VALUE )
693         return FALSE;
694
695     /* Check binary type
696      */
697     ret = MODULE_GetBinaryType( hfile, lpApplicationName, lpBinaryType );
698
699     /* Close the file.
700      */
701     CloseHandle( hfile );
702
703     return ret;
704 }
705
706 /***********************************************************************
707  *             GetBinaryTypeW                      [KERNEL32.281]
708  */
709 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
710 {
711     BOOL ret = FALSE;
712     LPSTR strNew = NULL;
713
714     TRACE_(win32)("%s\n", debugstr_w(lpApplicationName) );
715
716     /* Sanity check.
717      */
718     if ( lpApplicationName == NULL || lpBinaryType == NULL )
719         return FALSE;
720
721     /* Convert the wide string to a ascii string.
722      */
723     strNew = HEAP_strdupWtoA( GetProcessHeap(), 0, lpApplicationName );
724
725     if ( strNew != NULL )
726     {
727         ret = GetBinaryTypeA( strNew, lpBinaryType );
728
729         /* Free the allocated string.
730          */
731         HeapFree( GetProcessHeap(), 0, strNew );
732     }
733
734     return ret;
735 }
736
737
738 /***********************************************************************
739  *           WinExec16   (KERNEL.166)
740  */
741 HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
742 {
743     LPCSTR p, args = NULL;
744     LPCSTR name_beg, name_end;
745     LPSTR name, cmdline;
746     int arglen;
747     HINSTANCE16 ret;
748     char buffer[MAX_PATH];
749
750     if (*lpCmdLine == '"') /* has to be only one and only at beginning ! */
751     {
752       name_beg = lpCmdLine+1;
753       p = strchr ( lpCmdLine+1, '"' );
754       if (p)
755       {
756           name_end = p;
757           args = strchr ( p, ' ' );
758       }
759       else /* yes, even valid with trailing '"' missing */
760           name_end = lpCmdLine+strlen(lpCmdLine);
761     }
762     else 
763     {
764       name_beg = lpCmdLine;
765       args = strchr( lpCmdLine, ' ' );
766       name_end = args ? args : lpCmdLine+strlen(lpCmdLine);
767     }
768
769     if ((name_beg == lpCmdLine) && (!args))
770     { /* just use the original cmdline string as file name */
771         name = (LPSTR)lpCmdLine;
772     }
773     else
774     {
775         if (!(name = HeapAlloc( GetProcessHeap(), 0, name_end - name_beg + 1 )))
776             return ERROR_NOT_ENOUGH_MEMORY;
777         memcpy( name, name_beg, name_end - name_beg );
778         name[name_end - name_beg] = '\0';
779     }
780
781     if (args)
782     {
783         args++;
784         arglen = strlen(args);
785         cmdline = SEGPTR_ALLOC( 2 + arglen );
786         cmdline[0] = (BYTE)arglen;
787         strcpy( cmdline + 1, args );
788     }
789     else
790     {
791         cmdline = SEGPTR_ALLOC( 2 );
792         cmdline[0] = cmdline[1] = 0;
793     }
794
795     TRACE("name: '%s', cmdline: '%.*s'\n", name, cmdline[0], &cmdline[1]);
796
797     if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL ))
798     {
799         LOADPARAMS16 params;
800         WORD *showCmd = SEGPTR_ALLOC( 2*sizeof(WORD) );
801         showCmd[0] = 2;
802         showCmd[1] = nCmdShow;
803
804         params.hEnvironment = 0;
805         params.cmdLine = SEGPTR_GET(cmdline);
806         params.showCmd = SEGPTR_GET(showCmd);
807         params.reserved = 0;
808
809         ret = LoadModule16( buffer, &params );
810
811         SEGPTR_FREE( showCmd );
812         SEGPTR_FREE( cmdline );
813     }
814     else ret = GetLastError();
815
816     if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
817
818     if (ret == 21)  /* 32-bit module */
819     {
820         DWORD count;
821         ReleaseThunkLock( &count );
822         ret = WinExec( lpCmdLine, nCmdShow );
823         RestoreThunkLock( count );
824     }
825     return ret;
826 }
827
828 /***********************************************************************
829  *           WinExec   (KERNEL32.566)
830  */
831 HINSTANCE WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
832 {
833     PROCESS_INFORMATION info;
834     STARTUPINFOA startup;
835     HINSTANCE hInstance;
836     char *cmdline;
837
838     memset( &startup, 0, sizeof(startup) );
839     startup.cb = sizeof(startup);
840     startup.dwFlags = STARTF_USESHOWWINDOW;
841     startup.wShowWindow = nCmdShow;
842
843     /* cmdline needs to be writeable for CreateProcess */
844     if (!(cmdline = HEAP_strdupA( GetProcessHeap(), 0, lpCmdLine ))) return 0;
845
846     if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
847                         0, NULL, NULL, &startup, &info ))
848     {
849         /* Give 30 seconds to the app to come up */
850         if (Callout.WaitForInputIdle &&
851             Callout.WaitForInputIdle( info.hProcess, 30000 ) == 0xFFFFFFFF)
852             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
853         hInstance = 33;
854         /* Close off the handles */
855         CloseHandle( info.hThread );
856         CloseHandle( info.hProcess );
857     }
858     else if ((hInstance = GetLastError()) >= 32)
859     {
860         FIXME("Strange error set by CreateProcess: %d\n", hInstance );
861         hInstance = 11;
862     }
863     HeapFree( GetProcessHeap(), 0, cmdline );
864     return hInstance;
865 }
866
867 /**********************************************************************
868  *          LoadModule    (KERNEL32.499)
869  */
870 HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock ) 
871 {
872     LOADPARAMS *params = (LOADPARAMS *)paramBlock;
873     PROCESS_INFORMATION info;
874     STARTUPINFOA startup;
875     HINSTANCE hInstance;
876     LPSTR cmdline, p;
877     char filename[MAX_PATH];
878     BYTE len;
879
880     if (!name) return ERROR_FILE_NOT_FOUND;
881
882     if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
883         !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
884         return GetLastError();
885
886     len = (BYTE)params->lpCmdLine[0];
887     if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
888         return ERROR_NOT_ENOUGH_MEMORY;
889
890     strcpy( cmdline, filename );
891     p = cmdline + strlen(cmdline);
892     *p++ = ' ';
893     memcpy( p, params->lpCmdLine + 1, len );
894     p[len] = 0;
895
896     memset( &startup, 0, sizeof(startup) );
897     startup.cb = sizeof(startup);
898     if (params->lpCmdShow)
899     {
900         startup.dwFlags = STARTF_USESHOWWINDOW;
901         startup.wShowWindow = params->lpCmdShow[1];
902     }
903     
904     if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
905                         params->lpEnvAddress, NULL, &startup, &info ))
906     {
907         /* Give 30 seconds to the app to come up */
908         if (Callout.WaitForInputIdle &&
909             Callout.WaitForInputIdle( info.hProcess, 30000 ) ==  0xFFFFFFFF )
910             WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
911         hInstance = 33;
912         /* Close off the handles */
913         CloseHandle( info.hThread );
914         CloseHandle( info.hProcess );
915     }
916     else if ((hInstance = GetLastError()) >= 32)
917     {
918         FIXME("Strange error set by CreateProcess: %d\n", hInstance );
919         hInstance = 11;
920     }
921
922     HeapFree( GetProcessHeap(), 0, cmdline );
923     return hInstance;
924 }
925
926
927 /*************************************************************************
928  *               get_file_name
929  *
930  * Helper for CreateProcess: retrieve the file name to load from the
931  * app name and command line. Store the file name in buffer, and
932  * return a possibly modified command line.
933  */
934 static LPSTR get_file_name( LPCSTR appname, LPSTR cmdline, LPSTR buffer, int buflen )
935 {
936     char *name, *pos, *ret = NULL;
937     const char *p;
938
939     /* if we have an app name, everything is easy */
940
941     if (appname)
942     {
943         /* use the unmodified app name as file name */
944         lstrcpynA( buffer, appname, buflen );
945         if (!(ret = cmdline))
946         {
947             /* no command-line, create one */
948             if ((ret = HeapAlloc( GetProcessHeap(), 0, strlen(appname) + 3 )))
949                 sprintf( ret, "\"%s\"", appname );
950         }
951         return ret;
952     }
953
954     if (!cmdline)
955     {
956         SetLastError( ERROR_INVALID_PARAMETER );
957         return NULL;
958     }
959
960     /* first check for a quoted file name */
961
962     if ((cmdline[0] == '"') && ((p = strchr( cmdline + 1, '"' ))))
963     {
964         int len = p - cmdline - 1;
965         /* extract the quoted portion as file name */
966         if (!(name = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) return NULL;
967         memcpy( name, cmdline + 1, len );
968         name[len] = 0;
969
970         if (SearchPathA( NULL, name, ".exe", buflen, buffer, NULL ) ||
971             SearchPathA( NULL, name, NULL, buflen, buffer, NULL ))
972             ret = cmdline;  /* no change necessary */
973         goto done;
974     }
975
976     /* now try the command-line word by word */
977
978     if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + 1 ))) return NULL;
979     pos = name;
980     p = cmdline;
981
982     while (*p)
983     {
984         do *pos++ = *p++; while (*p && *p != ' ');
985         *pos = 0;
986         TRACE("trying '%s'\n", name );
987         if (SearchPathA( NULL, name, ".exe", buflen, buffer, NULL ) ||
988             SearchPathA( NULL, name, NULL, buflen, buffer, NULL ))
989         {
990             ret = cmdline;
991             break;
992         }
993     }
994
995     if (!ret || !strchr( name, ' ' )) goto done;  /* no change necessary */
996
997     /* now build a new command-line with quotes */
998
999     if (!(ret = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + 3 ))) goto done;
1000     sprintf( ret, "\"%s\"%s", name, p );
1001
1002  done:
1003     HeapFree( GetProcessHeap(), 0, name );
1004     return ret;
1005 }
1006
1007
1008 /**********************************************************************
1009  *       CreateProcessA          (KERNEL32.171)
1010  */
1011 BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine, 
1012                             LPSECURITY_ATTRIBUTES lpProcessAttributes,
1013                             LPSECURITY_ATTRIBUTES lpThreadAttributes,
1014                             BOOL bInheritHandles, DWORD dwCreationFlags,
1015                             LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
1016                             LPSTARTUPINFOA lpStartupInfo,
1017                             LPPROCESS_INFORMATION lpProcessInfo )
1018 {
1019     BOOL retv = FALSE;
1020     HANDLE hFile;
1021     DWORD type;
1022     char name[MAX_PATH];
1023     LPSTR tidy_cmdline;
1024
1025     /* Process the AppName and/or CmdLine to get module name and path */
1026
1027     TRACE("app '%s' cmdline '%s'\n", lpApplicationName, lpCommandLine );
1028
1029     if (!(tidy_cmdline = get_file_name( lpApplicationName, lpCommandLine, name, sizeof(name) )))
1030         return FALSE;
1031
1032     /* Warn if unsupported features are used */
1033
1034     if (dwCreationFlags & DETACHED_PROCESS)
1035         FIXME("(%s,...): DETACHED_PROCESS ignored\n", name);
1036     if (dwCreationFlags & CREATE_NEW_CONSOLE)
1037         FIXME("(%s,...): CREATE_NEW_CONSOLE ignored\n", name);
1038     if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
1039         FIXME("(%s,...): NORMAL_PRIORITY_CLASS ignored\n", name);
1040     if (dwCreationFlags & IDLE_PRIORITY_CLASS)
1041         FIXME("(%s,...): IDLE_PRIORITY_CLASS ignored\n", name);
1042     if (dwCreationFlags & HIGH_PRIORITY_CLASS)
1043         FIXME("(%s,...): HIGH_PRIORITY_CLASS ignored\n", name);
1044     if (dwCreationFlags & REALTIME_PRIORITY_CLASS)
1045         FIXME("(%s,...): REALTIME_PRIORITY_CLASS ignored\n", name);
1046     if (dwCreationFlags & CREATE_NEW_PROCESS_GROUP)
1047         FIXME("(%s,...): CREATE_NEW_PROCESS_GROUP ignored\n", name);
1048     if (dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)
1049         FIXME("(%s,...): CREATE_UNICODE_ENVIRONMENT ignored\n", name);
1050     if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
1051         FIXME("(%s,...): CREATE_SEPARATE_WOW_VDM ignored\n", name);
1052     if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
1053         FIXME("(%s,...): CREATE_SHARED_WOW_VDM ignored\n", name);
1054     if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
1055         FIXME("(%s,...): CREATE_DEFAULT_ERROR_MODE ignored\n", name);
1056     if (dwCreationFlags & CREATE_NO_WINDOW)
1057         FIXME("(%s,...): CREATE_NO_WINDOW ignored\n", name);
1058     if (dwCreationFlags & PROFILE_USER)
1059         FIXME("(%s,...): PROFILE_USER ignored\n", name);
1060     if (dwCreationFlags & PROFILE_KERNEL)
1061         FIXME("(%s,...): PROFILE_KERNEL ignored\n", name);
1062     if (dwCreationFlags & PROFILE_SERVER)
1063         FIXME("(%s,...): PROFILE_SERVER ignored\n", name);
1064     if (lpStartupInfo->lpDesktop)
1065         FIXME("(%s,...): lpStartupInfo->lpDesktop %s ignored\n", 
1066                       name, lpStartupInfo->lpDesktop);
1067     if (lpStartupInfo->lpTitle)
1068         FIXME("(%s,...): lpStartupInfo->lpTitle %s ignored\n", 
1069                       name, lpStartupInfo->lpTitle);
1070     if (lpStartupInfo->dwFlags & STARTF_USECOUNTCHARS)
1071         FIXME("(%s,...): STARTF_USECOUNTCHARS (%ld,%ld) ignored\n", 
1072                       name, lpStartupInfo->dwXCountChars, lpStartupInfo->dwYCountChars);
1073     if (lpStartupInfo->dwFlags & STARTF_USEFILLATTRIBUTE)
1074         FIXME("(%s,...): STARTF_USEFILLATTRIBUTE %lx ignored\n", 
1075                       name, lpStartupInfo->dwFillAttribute);
1076     if (lpStartupInfo->dwFlags & STARTF_RUNFULLSCREEN)
1077         FIXME("(%s,...): STARTF_RUNFULLSCREEN ignored\n", name);
1078     if (lpStartupInfo->dwFlags & STARTF_FORCEONFEEDBACK)
1079         FIXME("(%s,...): STARTF_FORCEONFEEDBACK ignored\n", name);
1080     if (lpStartupInfo->dwFlags & STARTF_FORCEOFFFEEDBACK)
1081         FIXME("(%s,...): STARTF_FORCEOFFFEEDBACK ignored\n", name);
1082     if (lpStartupInfo->dwFlags & STARTF_USEHOTKEY)
1083         FIXME("(%s,...): STARTF_USEHOTKEY ignored\n", name);
1084
1085     /* Open file and determine executable type */
1086
1087     hFile = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0 );
1088     if (hFile == INVALID_HANDLE_VALUE) goto done;
1089
1090     if ( !MODULE_GetBinaryType( hFile, name, &type ) )
1091     {
1092         CloseHandle( hFile );
1093         retv = PROCESS_Create( 0, name, tidy_cmdline, lpEnvironment, 
1094                                lpProcessAttributes, lpThreadAttributes,
1095                                bInheritHandles, dwCreationFlags,
1096                                lpStartupInfo, lpProcessInfo, lpCurrentDirectory );
1097         goto done;
1098     }
1099
1100     /* Create process */
1101
1102     switch ( type )
1103     {
1104     case SCS_32BIT_BINARY:
1105     case SCS_WOW_BINARY:
1106     case SCS_DOS_BINARY:
1107         retv = PROCESS_Create( hFile, name, tidy_cmdline, lpEnvironment, 
1108                                lpProcessAttributes, lpThreadAttributes,
1109                                bInheritHandles, dwCreationFlags,
1110                                lpStartupInfo, lpProcessInfo, lpCurrentDirectory);
1111         break;
1112
1113     case SCS_PIF_BINARY:
1114     case SCS_POSIX_BINARY:
1115     case SCS_OS216_BINARY:
1116         FIXME("Unsupported executable type: %ld\n", type );
1117         /* fall through */
1118
1119     default:
1120         SetLastError( ERROR_BAD_FORMAT );
1121         break;
1122     }
1123     CloseHandle( hFile );
1124
1125  done:
1126     if (tidy_cmdline != lpCommandLine) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
1127     return retv;
1128 }
1129
1130 /**********************************************************************
1131  *       CreateProcessW          (KERNEL32.172)
1132  * NOTES
1133  *  lpReserved is not converted
1134  */
1135 BOOL WINAPI CreateProcessW( LPCWSTR lpApplicationName, LPWSTR lpCommandLine, 
1136                                 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1137                                 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1138                                 BOOL bInheritHandles, DWORD dwCreationFlags,
1139                                 LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
1140                                 LPSTARTUPINFOW lpStartupInfo,
1141                                 LPPROCESS_INFORMATION lpProcessInfo )
1142 {   BOOL ret;
1143     STARTUPINFOA StartupInfoA;
1144     
1145     LPSTR lpApplicationNameA = HEAP_strdupWtoA (GetProcessHeap(),0,lpApplicationName);
1146     LPSTR lpCommandLineA = HEAP_strdupWtoA (GetProcessHeap(),0,lpCommandLine);
1147     LPSTR lpCurrentDirectoryA = HEAP_strdupWtoA (GetProcessHeap(),0,lpCurrentDirectory);
1148
1149     memcpy (&StartupInfoA, lpStartupInfo, sizeof(STARTUPINFOA));
1150     StartupInfoA.lpDesktop = HEAP_strdupWtoA (GetProcessHeap(),0,lpStartupInfo->lpDesktop);
1151     StartupInfoA.lpTitle = HEAP_strdupWtoA (GetProcessHeap(),0,lpStartupInfo->lpTitle);
1152
1153     TRACE_(win32)("(%s,%s,...)\n", debugstr_w(lpApplicationName), debugstr_w(lpCommandLine));
1154
1155     if (lpStartupInfo->lpReserved)
1156       FIXME_(win32)("StartupInfo.lpReserved is used, please report (%s)\n", debugstr_w(lpStartupInfo->lpReserved));
1157       
1158     ret = CreateProcessA(  lpApplicationNameA,  lpCommandLineA, 
1159                              lpProcessAttributes, lpThreadAttributes,
1160                              bInheritHandles, dwCreationFlags,
1161                              lpEnvironment, lpCurrentDirectoryA,
1162                              &StartupInfoA, lpProcessInfo );
1163
1164     HeapFree( GetProcessHeap(), 0, lpCurrentDirectoryA );
1165     HeapFree( GetProcessHeap(), 0, lpCommandLineA );
1166     HeapFree( GetProcessHeap(), 0, StartupInfoA.lpDesktop );
1167     HeapFree( GetProcessHeap(), 0, StartupInfoA.lpTitle );
1168
1169     return ret;
1170 }
1171
1172 /***********************************************************************
1173  *              GetModuleHandleA         (KERNEL32.237)
1174  */
1175 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
1176 {
1177     WINE_MODREF *wm;
1178
1179     if ( module == NULL )
1180         wm = exe_modref;
1181     else
1182         wm = MODULE_FindModule( module );
1183
1184     return wm? wm->module : 0;
1185 }
1186
1187 /***********************************************************************
1188  *              GetModuleHandleW
1189  */
1190 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
1191 {
1192     HMODULE hModule;
1193     LPSTR modulea = HEAP_strdupWtoA( GetProcessHeap(), 0, module );
1194     hModule = GetModuleHandleA( modulea );
1195     HeapFree( GetProcessHeap(), 0, modulea );
1196     return hModule;
1197 }
1198
1199
1200 /***********************************************************************
1201  *              GetModuleFileNameA      (KERNEL32.235)
1202  *
1203  * GetModuleFileNameA seems to *always* return the long path;
1204  * it's only GetModuleFileName16 that decides between short/long path
1205  * by checking if exe version >= 4.0.
1206  * (SDK docu doesn't mention this)
1207  */
1208 DWORD WINAPI GetModuleFileNameA( 
1209         HMODULE hModule,        /* [in] module handle (32bit) */
1210         LPSTR lpFileName,       /* [out] filenamebuffer */
1211         DWORD size )            /* [in] size of filenamebuffer */
1212 {
1213     WINE_MODREF *wm;
1214
1215     RtlAcquirePebLock();
1216
1217     lpFileName[0] = 0;
1218     if ((wm = MODULE32_LookupHMODULE( hModule )))
1219         lstrcpynA( lpFileName, wm->filename, size );
1220
1221     RtlReleasePebLock();
1222     TRACE("%s\n", lpFileName );
1223     return strlen(lpFileName);
1224 }                   
1225  
1226
1227 /***********************************************************************
1228  *              GetModuleFileNameW      (KERNEL32.236)
1229  */
1230 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName,
1231                                    DWORD size )
1232 {
1233     LPSTR fnA = (char*)HeapAlloc( GetProcessHeap(), 0, size );
1234     DWORD res = GetModuleFileNameA( hModule, fnA, size );
1235     if (size > 0 && !MultiByteToWideChar( CP_ACP, 0, fnA, -1, lpFileName, size ))
1236         lpFileName[size-1] = 0;
1237     HeapFree( GetProcessHeap(), 0, fnA );
1238     return res;
1239 }
1240
1241
1242 /***********************************************************************
1243  *           LoadLibraryExA   (KERNEL32)
1244  */
1245 HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
1246 {
1247         WINE_MODREF *wm;
1248
1249         if(!libname)
1250         {
1251                 SetLastError(ERROR_INVALID_PARAMETER);
1252                 return 0;
1253         }
1254
1255         if (flags & LOAD_LIBRARY_AS_DATAFILE)
1256         {
1257             char filename[256];
1258             HANDLE hFile;
1259             HMODULE hmod = 0;
1260
1261             if (!SearchPathA( NULL, libname, ".dll", sizeof(filename), filename, NULL ))
1262                 return 0;
1263             /* FIXME: maybe we should use the hfile parameter instead */
1264             hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
1265                                  NULL, OPEN_EXISTING, 0, 0 );
1266             if (hFile != INVALID_HANDLE_VALUE)
1267             {
1268                 hmod = PE_LoadImage( hFile, filename, flags );
1269                 CloseHandle( hFile );
1270             }
1271             return hmod;
1272         }
1273
1274         RtlAcquirePebLock();
1275
1276         wm = MODULE_LoadLibraryExA( libname, hfile, flags );
1277         if ( wm )
1278         {
1279                 if ( !MODULE_DllProcessAttach( wm, NULL ) )
1280                 {
1281                         WARN_(module)("Attach failed for module '%s', \n", libname);
1282                         MODULE_FreeLibrary(wm);
1283                         SetLastError(ERROR_DLL_INIT_FAILED);
1284                         wm = NULL;
1285                 }
1286         }
1287
1288         RtlReleasePebLock();
1289         return wm ? wm->module : 0;
1290 }
1291
1292 /***********************************************************************
1293  *      MODULE_LoadLibraryExA   (internal)
1294  *
1295  * Load a PE style module according to the load order.
1296  *
1297  * The HFILE parameter is not used and marked reserved in the SDK. I can
1298  * only guess that it should force a file to be mapped, but I rather
1299  * ignore the parameter because it would be extremely difficult to
1300  * integrate this with different types of module represenations.
1301  *
1302  */
1303 WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
1304 {
1305         DWORD err = GetLastError();
1306         WINE_MODREF *pwm;
1307         int i;
1308         module_loadorder_t *plo;
1309         LPSTR filename, p;
1310         const char *filetype = "";
1311
1312         if ( !libname ) return NULL;
1313
1314         filename = HeapAlloc ( GetProcessHeap(), 0, MAX_PATH + 1 );
1315         if ( !filename ) return NULL;
1316
1317         /* build the modules filename */
1318         if (!SearchPathA( NULL, libname, ".dll", MAX_PATH, filename, NULL ))
1319         {
1320             if ( ! GetSystemDirectoryA ( filename, MAX_PATH ) ) 
1321                 goto error;
1322
1323             /* if the library name contains a path and can not be found, return an error. 
1324                exception: if the path is the system directory, proceed, so that modules, 
1325                which are not PE-modules can be loaded
1326
1327                if the library name does not contain a path and can not be found, assume the 
1328                system directory is meant */
1329             
1330             if ( ! FILE_strncasecmp ( filename, libname, strlen ( filename ) ))
1331                 strcpy ( filename, libname );
1332             else
1333             {
1334                 if ( strchr ( libname, '\\' ) || strchr ( libname, ':') || strchr ( libname, '/' ) ) 
1335                     goto error;
1336                 else 
1337                 {
1338                     strcat ( filename, "\\" );
1339                     strcat ( filename, libname );
1340                 }
1341             }
1342       
1343             /* if the filename doesn't have an extension append .DLL */
1344             if (!(p = strrchr( filename, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
1345                 strcat( filename, ".DLL" );
1346         }
1347
1348         RtlAcquirePebLock();
1349
1350         /* Check for already loaded module */
1351         if (!(pwm = MODULE_FindModule(filename)) && 
1352             /* no path in libpath */
1353             !strchr( libname, '\\' ) && !strchr( libname, ':') && !strchr( libname, '/' )) 
1354         {
1355             LPSTR       fn = HeapAlloc ( GetProcessHeap(), 0, MAX_PATH + 1 );
1356             if (fn)
1357             {
1358                 /* since the default loading mechanism uses a more detailed algorithm 
1359                  * than SearchPath (like using PATH, which can even be modified between
1360                  * two attempts of loading the same DLL), the look-up above (with
1361                  * SearchPath) can have put the file in system directory, whereas it
1362                  * has already been loaded but with a different path. So do a specific
1363                  * look-up with filename (without any path)
1364                  */
1365                 strcpy ( fn, libname );
1366                 /* if the filename doesn't have an extension append .DLL */
1367                 if (!strrchr( fn, '.')) strcat( fn, ".dll" );
1368                 if ((pwm = MODULE_FindModule( fn )) != NULL)
1369                    strcpy( filename, fn );
1370                 HeapFree( GetProcessHeap(), 0, fn );
1371             }
1372         }
1373         if (pwm)
1374         {
1375                 if(!(pwm->flags & WINE_MODREF_MARKER))
1376                         pwm->refCount++;
1377
1378                 if ((pwm->flags & WINE_MODREF_DONT_RESOLVE_REFS) &&
1379                     !(flags & DONT_RESOLVE_DLL_REFERENCES))
1380                 {
1381                     extern DWORD fixup_imports(WINE_MODREF *wm); /*FIXME*/
1382                     pwm->flags &= ~WINE_MODREF_DONT_RESOLVE_REFS;
1383                     fixup_imports( pwm );
1384                 }
1385                 TRACE("Already loaded module '%s' at 0x%08x, count=%d, \n", filename, pwm->module, pwm->refCount);
1386                 RtlReleasePebLock();
1387                 HeapFree ( GetProcessHeap(), 0, filename );
1388                 return pwm;
1389         }
1390
1391         plo = MODULE_GetLoadOrder(filename, TRUE);
1392
1393         for(i = 0; i < MODULE_LOADORDER_NTYPES; i++)
1394         {
1395                 SetLastError( ERROR_FILE_NOT_FOUND );
1396                 switch(plo->loadorder[i])
1397                 {
1398                 case MODULE_LOADORDER_DLL:
1399                         TRACE("Trying native dll '%s'\n", filename);
1400                         pwm = PE_LoadLibraryExA(filename, flags);
1401                         filetype = "native";
1402                         break;
1403
1404                 case MODULE_LOADORDER_SO:
1405                         TRACE("Trying so-library '%s'\n", filename);
1406                         pwm = ELF_LoadLibraryExA(filename, flags);
1407                         filetype = "so";
1408                         break;
1409
1410                 case MODULE_LOADORDER_BI:
1411                         TRACE("Trying built-in '%s'\n", filename);
1412                         pwm = BUILTIN32_LoadLibraryExA(filename, flags);
1413                         filetype = "builtin";
1414                         break;
1415
1416                 default:
1417                         ERR("Got invalid loadorder type %d (%s index %d)\n", plo->loadorder[i], plo->modulename, i);
1418                 /* Fall through */
1419
1420                 case MODULE_LOADORDER_INVALID:  /* We ignore this as it is an empty entry */
1421                         pwm = NULL;
1422                         break;
1423                 }
1424
1425                 if(pwm)
1426                 {
1427                         /* Initialize DLL just loaded */
1428                         TRACE("Loaded module '%s' at 0x%08x, \n", filename, pwm->module);
1429                         if (!TRACE_ON(module))
1430                             TRACE_(loaddll)("Loaded module '%s' : %s\n", filename, filetype);
1431                         /* Set the refCount here so that an attach failure will */
1432                         /* decrement the dependencies through the MODULE_FreeLibrary call. */
1433                         pwm->refCount++;
1434
1435                         RtlReleasePebLock();
1436                         SetLastError( err );  /* restore last error */
1437                         HeapFree ( GetProcessHeap(), 0, filename );
1438                         return pwm;
1439                 }
1440
1441                 if(GetLastError() != ERROR_FILE_NOT_FOUND)
1442                         break;
1443         }
1444
1445         RtlReleasePebLock();
1446  error:
1447         WARN("Failed to load module '%s'; error=0x%08lx, \n", filename, GetLastError());
1448         HeapFree ( GetProcessHeap(), 0, filename );
1449         return NULL;
1450 }
1451
1452 /***********************************************************************
1453  *           LoadLibraryA         (KERNEL32)
1454  */
1455 HMODULE WINAPI LoadLibraryA(LPCSTR libname) {
1456         return LoadLibraryExA(libname,0,0);
1457 }
1458
1459 /***********************************************************************
1460  *           LoadLibraryW         (KERNEL32)
1461  */
1462 HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
1463 {
1464     return LoadLibraryExW(libnameW,0,0);
1465 }
1466
1467 /***********************************************************************
1468  *           LoadLibrary32_16   (KERNEL.452)
1469  */
1470 HMODULE WINAPI LoadLibrary32_16( LPCSTR libname )
1471 {
1472     HMODULE hModule;
1473     DWORD count;
1474
1475     ReleaseThunkLock( &count );
1476     hModule = LoadLibraryA( libname );
1477     RestoreThunkLock( count );
1478     return hModule;
1479 }
1480
1481 /***********************************************************************
1482  *           LoadLibraryExW       (KERNEL32)
1483  */
1484 HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW,HANDLE hfile,DWORD flags)
1485 {
1486     LPSTR libnameA = HEAP_strdupWtoA( GetProcessHeap(), 0, libnameW );
1487     HMODULE ret = LoadLibraryExA( libnameA , hfile, flags );
1488
1489     HeapFree( GetProcessHeap(), 0, libnameA );
1490     return ret;
1491 }
1492
1493 /***********************************************************************
1494  *           MODULE_FlushModrefs
1495  *
1496  * NOTE: Assumes that the process critical section is held!
1497  *
1498  * Remove all unused modrefs and call the internal unloading routines
1499  * for the library type.
1500  */
1501 static void MODULE_FlushModrefs(void)
1502 {
1503         WINE_MODREF *wm, *next;
1504
1505         for(wm = MODULE_modref_list; wm; wm = next)
1506         {
1507                 next = wm->next;
1508
1509                 if(wm->refCount)
1510                         continue;
1511
1512                 /* Unlink this modref from the chain */
1513                 if(wm->next)
1514                         wm->next->prev = wm->prev;
1515                 if(wm->prev)
1516                         wm->prev->next = wm->next;
1517                 if(wm == MODULE_modref_list)
1518                         MODULE_modref_list = wm->next;
1519
1520                 TRACE(" unloading %s\n", wm->filename);
1521                 /* VirtualFree( (LPVOID)wm->module, 0, MEM_RELEASE ); */  /* FIXME */
1522                 /* if (wm->dlhandle) wine_dlclose( wm->dlhandle, NULL, 0 ); */  /* FIXME */
1523                 FreeLibrary16(wm->hDummyMod);
1524                 HeapFree( GetProcessHeap(), 0, wm->deps );
1525                 HeapFree( GetProcessHeap(), 0, wm->filename );
1526                 HeapFree( GetProcessHeap(), 0, wm->short_filename );
1527                 HeapFree( GetProcessHeap(), 0, wm );
1528         }
1529 }
1530
1531 /***********************************************************************
1532  *           FreeLibrary
1533  */
1534 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
1535 {
1536     BOOL retv = FALSE;
1537     WINE_MODREF *wm;
1538
1539     RtlAcquirePebLock();
1540     free_lib_count++;
1541
1542     wm = MODULE32_LookupHMODULE( hLibModule );
1543     if ( !wm || !hLibModule )
1544         SetLastError( ERROR_INVALID_HANDLE );
1545     else
1546         retv = MODULE_FreeLibrary( wm );
1547
1548     free_lib_count--;
1549     RtlReleasePebLock();
1550
1551     return retv;
1552 }
1553
1554 /***********************************************************************
1555  *           MODULE_DecRefCount
1556  *
1557  * NOTE: Assumes that the process critical section is held!
1558  */
1559 static void MODULE_DecRefCount( WINE_MODREF *wm )
1560 {
1561     int i;
1562
1563     if ( wm->flags & WINE_MODREF_MARKER )
1564         return;
1565
1566     if ( wm->refCount <= 0 )
1567         return;
1568
1569     --wm->refCount;
1570     TRACE("(%s) refCount: %d\n", wm->modname, wm->refCount );
1571
1572     if ( wm->refCount == 0 )
1573     {
1574         wm->flags |= WINE_MODREF_MARKER;
1575
1576         for ( i = 0; i < wm->nDeps; i++ )
1577             if ( wm->deps[i] )
1578                 MODULE_DecRefCount( wm->deps[i] );
1579
1580         wm->flags &= ~WINE_MODREF_MARKER;
1581     }
1582 }
1583
1584 /***********************************************************************
1585  *           MODULE_FreeLibrary
1586  *
1587  * NOTE: Assumes that the process critical section is held!
1588  */
1589 BOOL MODULE_FreeLibrary( WINE_MODREF *wm )
1590 {
1591     TRACE("(%s) - START\n", wm->modname );
1592
1593     /* Recursively decrement reference counts */
1594     MODULE_DecRefCount( wm );
1595
1596     /* Call process detach notifications */
1597     if ( free_lib_count <= 1 )
1598     {
1599         MODULE_DllProcessDetach( FALSE, NULL );
1600         SERVER_START_REQ
1601         {
1602             struct unload_dll_request *req = server_alloc_req( sizeof(*req), 0 );
1603             req->base = (void *)wm->module;
1604             server_call_noerr( REQ_UNLOAD_DLL );
1605         }
1606         SERVER_END_REQ;
1607         MODULE_FlushModrefs();
1608     }
1609
1610     TRACE("END\n");
1611
1612     return TRUE;
1613 }
1614
1615
1616 /***********************************************************************
1617  *           FreeLibraryAndExitThread
1618  */
1619 VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
1620 {
1621     FreeLibrary(hLibModule);
1622     ExitThread(dwExitCode);
1623 }
1624
1625 /***********************************************************************
1626  *           PrivateLoadLibrary       (KERNEL32)
1627  *
1628  * FIXME: rough guesswork, don't know what "Private" means
1629  */
1630 HINSTANCE WINAPI PrivateLoadLibrary(LPCSTR libname)
1631 {
1632         return (HINSTANCE)LoadLibrary16(libname);
1633 }
1634
1635
1636
1637 /***********************************************************************
1638  *           PrivateFreeLibrary       (KERNEL32)
1639  *
1640  * FIXME: rough guesswork, don't know what "Private" means
1641  */
1642 void WINAPI PrivateFreeLibrary(HINSTANCE handle)
1643 {
1644         FreeLibrary16((HINSTANCE16)handle);
1645 }
1646
1647
1648 /***********************************************************************
1649  *           WIN32_GetProcAddress16   (KERNEL32.36)
1650  * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
1651  */
1652 FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name )
1653 {
1654     if (!hModule) {
1655         WARN("hModule may not be 0!\n");
1656         return (FARPROC16)0;
1657     }
1658     if (HIWORD(hModule))
1659     {
1660         WARN("hModule is Win32 handle (%08x)\n", hModule );
1661         return (FARPROC16)0;
1662     }
1663     return GetProcAddress16( hModule, name );
1664 }
1665
1666 /***********************************************************************
1667  *           GetProcAddress16   (KERNEL.50)
1668  */
1669 FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, LPCSTR name )
1670 {
1671     WORD ordinal;
1672     FARPROC16 ret;
1673
1674     if (!hModule) hModule = GetCurrentTask();
1675     hModule = GetExePtr( hModule );
1676
1677     if (HIWORD(name) != 0)
1678     {
1679         ordinal = NE_GetOrdinal( hModule, name );
1680         TRACE("%04x '%s'\n", hModule, name );
1681     }
1682     else
1683     {
1684         ordinal = LOWORD(name);
1685         TRACE("%04x %04x\n", hModule, ordinal );
1686     }
1687     if (!ordinal) return (FARPROC16)0;
1688
1689     ret = NE_GetEntryPoint( hModule, ordinal );
1690
1691     TRACE("returning %08x\n", (UINT)ret );
1692     return ret;
1693 }
1694
1695
1696 /***********************************************************************
1697  *           GetProcAddress             (KERNEL32.257)
1698  */
1699 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
1700 {
1701     return MODULE_GetProcAddress( hModule, function, TRUE );
1702 }
1703
1704 /***********************************************************************
1705  *           GetProcAddress32                   (KERNEL.453)
1706  */
1707 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
1708 {
1709     return MODULE_GetProcAddress( hModule, function, FALSE );
1710 }
1711
1712 /***********************************************************************
1713  *           MODULE_GetProcAddress              (internal)
1714  */
1715 FARPROC MODULE_GetProcAddress( 
1716         HMODULE hModule,        /* [in] current module handle */
1717         LPCSTR function,        /* [in] function to be looked up */
1718         BOOL snoop )
1719 {
1720     WINE_MODREF *wm;
1721     FARPROC     retproc = 0;
1722
1723     if (HIWORD(function))
1724         TRACE_(win32)("(%08lx,%s)\n",(DWORD)hModule,function);
1725     else
1726         TRACE_(win32)("(%08lx,%p)\n",(DWORD)hModule,function);
1727
1728     RtlAcquirePebLock();
1729     if ((wm = MODULE32_LookupHMODULE( hModule )))
1730     {
1731         retproc = wm->find_export( wm, function, snoop );
1732         if (!retproc) SetLastError(ERROR_PROC_NOT_FOUND);
1733     }
1734     RtlReleasePebLock();
1735     return retproc;
1736 }
1737
1738
1739 /***************************************************************************
1740  *              HasGPHandler                    (KERNEL.338)
1741  */
1742
1743 #include "pshpack1.h"
1744 typedef struct _GPHANDLERDEF
1745 {
1746     WORD selector;
1747     WORD rangeStart;
1748     WORD rangeEnd;
1749     WORD handler;
1750 } GPHANDLERDEF;
1751 #include "poppack.h"
1752
1753 SEGPTR WINAPI HasGPHandler16( SEGPTR address )
1754 {
1755     HMODULE16 hModule;
1756     int gpOrdinal;
1757     SEGPTR gpPtr;
1758     GPHANDLERDEF *gpHandler;
1759    
1760     if (    (hModule = FarGetOwner16( SELECTOROF(address) )) != 0
1761          && (gpOrdinal = NE_GetOrdinal( hModule, "__GP" )) != 0
1762          && (gpPtr = (SEGPTR)NE_GetEntryPointEx( hModule, gpOrdinal, FALSE )) != 0
1763          && !IsBadReadPtr16( gpPtr, sizeof(GPHANDLERDEF) )
1764          && (gpHandler = MapSL( gpPtr )) != NULL )
1765     {
1766         while (gpHandler->selector)
1767         {
1768             if (    SELECTOROF(address) == gpHandler->selector
1769                  && OFFSETOF(address)   >= gpHandler->rangeStart
1770                  && OFFSETOF(address)   <  gpHandler->rangeEnd  )
1771                 return MAKESEGPTR( gpHandler->selector, gpHandler->handler );
1772             gpHandler++;
1773         }
1774     }
1775
1776     return 0;
1777 }
1778