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