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