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