Authors: Alexandre Julliard <julliard@codeweavers.com> (for Corel), Albert den Haan...
[wine/hacks.git] / loader / module.c
blob2f3729181e2c46b3dba41fa56cb0e27db30838ab
1 /*
2 * Modules
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <fcntl.h>
9 #include <stdlib.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <unistd.h>
14 #include "windef.h"
15 #include "wine/winbase16.h"
16 #include "winerror.h"
17 #include "file.h"
18 #include "global.h"
19 #include "heap.h"
20 #include "module.h"
21 #include "snoop.h"
22 #include "neexe.h"
23 #include "dosexe.h"
24 #include "process.h"
25 #include "syslevel.h"
26 #include "thread.h"
27 #include "selectors.h"
28 #include "stackframe.h"
29 #include "task.h"
30 #include "debugtools.h"
31 #include "callback.h"
32 #include "loadorder.h"
33 #include "elfdll.h"
34 #include "server.h"
36 DEFAULT_DEBUG_CHANNEL(module);
37 DECLARE_DEBUG_CHANNEL(win32);
40 /*************************************************************************
41 * MODULE32_LookupHMODULE
42 * looks for the referenced HMODULE in the current process
43 * NOTE: Assumes that the process critical section is held!
45 static WINE_MODREF *MODULE32_LookupHMODULE( HMODULE hmod )
47 WINE_MODREF *wm;
49 if (!hmod)
50 return PROCESS_Current()->exe_modref;
52 if (!HIWORD(hmod)) {
53 ERR("tried to lookup 0x%04x in win32 module handler!\n",hmod);
54 SetLastError( ERROR_INVALID_HANDLE );
55 return NULL;
57 for ( wm = PROCESS_Current()->modref_list; wm; wm=wm->next )
58 if (wm->module == hmod)
59 return wm;
60 SetLastError( ERROR_INVALID_HANDLE );
61 return NULL;
64 /*************************************************************************
65 * MODULE_AllocModRef
67 * Allocate a WINE_MODREF structure and add it to the process list
68 * NOTE: Assumes that the process critical section is held!
70 WINE_MODREF *MODULE_AllocModRef( HMODULE hModule, LPCSTR filename )
72 WINE_MODREF *wm;
73 DWORD len;
75 if ((wm = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*wm) )))
77 wm->module = hModule;
78 wm->tlsindex = -1;
80 wm->filename = HEAP_strdupA( GetProcessHeap(), 0, filename );
81 if ((wm->modname = strrchr( wm->filename, '\\' ))) wm->modname++;
82 else wm->modname = wm->filename;
84 len = GetShortPathNameA( wm->filename, NULL, 0 );
85 wm->short_filename = (char *)HeapAlloc( GetProcessHeap(), 0, len+1 );
86 GetShortPathNameA( wm->filename, wm->short_filename, len+1 );
87 if ((wm->short_modname = strrchr( wm->short_filename, '\\' ))) wm->short_modname++;
88 else wm->short_modname = wm->short_filename;
90 wm->next = PROCESS_Current()->modref_list;
91 if (wm->next) wm->next->prev = wm;
92 PROCESS_Current()->modref_list = wm;
94 return wm;
97 /*************************************************************************
98 * MODULE_InitDLL
100 static BOOL MODULE_InitDLL( WINE_MODREF *wm, DWORD type, LPVOID lpReserved )
102 BOOL retv = TRUE;
104 static LPCSTR typeName[] = { "PROCESS_DETACH", "PROCESS_ATTACH",
105 "THREAD_ATTACH", "THREAD_DETACH" };
106 assert( wm );
108 /* Skip calls for modules loaded with special load flags */
110 if (wm->flags & WINE_MODREF_DONT_RESOLVE_REFS) return TRUE;
112 TRACE("(%s,%s,%p) - CALL\n", wm->modname, typeName[type], lpReserved );
114 /* Call the initialization routine */
115 retv = PE_InitDLL( wm->module, type, lpReserved );
117 /* The state of the module list may have changed due to the call
118 to PE_InitDLL. We cannot assume that this module has not been
119 deleted. */
120 TRACE("(%p,%s,%p) - RETURN %d\n", wm, typeName[type], lpReserved, retv );
122 return retv;
125 /*************************************************************************
126 * MODULE_DllProcessAttach
128 * Send the process attach notification to all DLLs the given module
129 * depends on (recursively). This is somewhat complicated due to the fact that
131 * - we have to respect the module dependencies, i.e. modules implicitly
132 * referenced by another module have to be initialized before the module
133 * itself can be initialized
135 * - the initialization routine of a DLL can itself call LoadLibrary,
136 * thereby introducing a whole new set of dependencies (even involving
137 * the 'old' modules) at any time during the whole process
139 * (Note that this routine can be recursively entered not only directly
140 * from itself, but also via LoadLibrary from one of the called initialization
141 * routines.)
143 * Furthermore, we need to rearrange the main WINE_MODREF list to allow
144 * the process *detach* notifications to be sent in the correct order.
145 * This must not only take into account module dependencies, but also
146 * 'hidden' dependencies created by modules calling LoadLibrary in their
147 * attach notification routine.
149 * The strategy is rather simple: we move a WINE_MODREF to the head of the
150 * list after the attach notification has returned. This implies that the
151 * detach notifications are called in the reverse of the sequence the attach
152 * notifications *returned*.
154 * NOTE: Assumes that the process critical section is held!
157 BOOL MODULE_DllProcessAttach( WINE_MODREF *wm, LPVOID lpReserved )
159 BOOL retv = TRUE;
160 int i;
161 assert( wm );
163 /* prevent infinite recursion in case of cyclical dependencies */
164 if ( ( wm->flags & WINE_MODREF_MARKER )
165 || ( wm->flags & WINE_MODREF_PROCESS_ATTACHED ) )
166 return retv;
168 TRACE("(%s,%p) - START\n", wm->modname, lpReserved );
170 /* Tag current MODREF to prevent recursive loop */
171 wm->flags |= WINE_MODREF_MARKER;
173 /* Recursively attach all DLLs this one depends on */
174 for ( i = 0; retv && i < wm->nDeps; i++ )
175 if ( wm->deps[i] )
176 retv = MODULE_DllProcessAttach( wm->deps[i], lpReserved );
178 /* Call DLL entry point */
179 if ( retv )
181 retv = MODULE_InitDLL( wm, DLL_PROCESS_ATTACH, lpReserved );
182 if ( retv )
183 wm->flags |= WINE_MODREF_PROCESS_ATTACHED;
186 /* Re-insert MODREF at head of list */
187 if ( retv && wm->prev )
189 wm->prev->next = wm->next;
190 if ( wm->next ) wm->next->prev = wm->prev;
192 wm->prev = NULL;
193 wm->next = PROCESS_Current()->modref_list;
194 PROCESS_Current()->modref_list = wm->next->prev = wm;
197 /* Remove recursion flag */
198 wm->flags &= ~WINE_MODREF_MARKER;
200 TRACE("(%s,%p) - END\n", wm->modname, lpReserved );
202 return retv;
205 /*************************************************************************
206 * MODULE_DllProcessDetach
208 * Send DLL process detach notifications. See the comment about calling
209 * sequence at MODULE_DllProcessAttach. Unless the bForceDetach flag
210 * is set, only DLLs with zero refcount are notified.
212 void MODULE_DllProcessDetach( BOOL bForceDetach, LPVOID lpReserved )
214 WINE_MODREF *wm;
216 EnterCriticalSection( &PROCESS_Current()->crit_section );
220 for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
222 /* Check whether to detach this DLL */
223 if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
224 continue;
225 if ( wm->refCount > 0 && !bForceDetach )
226 continue;
228 /* Call detach notification */
229 wm->flags &= ~WINE_MODREF_PROCESS_ATTACHED;
230 MODULE_InitDLL( wm, DLL_PROCESS_DETACH, lpReserved );
232 /* Restart at head of WINE_MODREF list, as entries might have
233 been added and/or removed while performing the call ... */
234 break;
236 } while ( wm );
238 LeaveCriticalSection( &PROCESS_Current()->crit_section );
241 /*************************************************************************
242 * MODULE_DllThreadAttach
244 * Send DLL thread attach notifications. These are sent in the
245 * reverse sequence of process detach notification.
248 void MODULE_DllThreadAttach( LPVOID lpReserved )
250 WINE_MODREF *wm;
252 EnterCriticalSection( &PROCESS_Current()->crit_section );
254 for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
255 if ( !wm->next )
256 break;
258 for ( ; wm; wm = wm->prev )
260 if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
261 continue;
262 if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
263 continue;
265 MODULE_InitDLL( wm, DLL_THREAD_ATTACH, lpReserved );
268 LeaveCriticalSection( &PROCESS_Current()->crit_section );
271 /*************************************************************************
272 * MODULE_DllThreadDetach
274 * Send DLL thread detach notifications. These are sent in the
275 * same sequence as process detach notification.
278 void MODULE_DllThreadDetach( LPVOID lpReserved )
280 WINE_MODREF *wm;
282 EnterCriticalSection( &PROCESS_Current()->crit_section );
284 for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
286 if ( !(wm->flags & WINE_MODREF_PROCESS_ATTACHED) )
287 continue;
288 if ( wm->flags & WINE_MODREF_NO_DLL_CALLS )
289 continue;
291 MODULE_InitDLL( wm, DLL_THREAD_DETACH, lpReserved );
294 LeaveCriticalSection( &PROCESS_Current()->crit_section );
297 /****************************************************************************
298 * DisableThreadLibraryCalls (KERNEL32.74)
300 * Don't call DllEntryPoint for DLL_THREAD_{ATTACH,DETACH} if set.
302 BOOL WINAPI DisableThreadLibraryCalls( HMODULE hModule )
304 WINE_MODREF *wm;
305 BOOL retval = TRUE;
307 EnterCriticalSection( &PROCESS_Current()->crit_section );
309 wm = MODULE32_LookupHMODULE( hModule );
310 if ( !wm )
311 retval = FALSE;
312 else
313 wm->flags |= WINE_MODREF_NO_DLL_CALLS;
315 LeaveCriticalSection( &PROCESS_Current()->crit_section );
317 return retval;
321 /***********************************************************************
322 * MODULE_CreateDummyModule
324 * Create a dummy NE module for Win32 or Winelib.
326 HMODULE MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 )
328 HMODULE hModule;
329 NE_MODULE *pModule;
330 SEGTABLEENTRY *pSegment;
331 char *pStr,*s;
332 unsigned int len;
333 const char* basename;
334 OFSTRUCT *ofs;
335 int of_size, size;
337 /* Extract base filename */
338 basename = strrchr(filename, '\\');
339 if (!basename) basename = filename;
340 else basename++;
341 len = strlen(basename);
342 if ((s = strchr(basename, '.'))) len = s - basename;
344 /* Allocate module */
345 of_size = sizeof(OFSTRUCT) - sizeof(ofs->szPathName)
346 + strlen(filename) + 1;
347 size = sizeof(NE_MODULE) +
348 /* loaded file info */
349 of_size +
350 /* segment table: DS,CS */
351 2 * sizeof(SEGTABLEENTRY) +
352 /* name table */
353 len + 2 +
354 /* several empty tables */
357 hModule = GlobalAlloc16( GMEM_MOVEABLE | GMEM_ZEROINIT, size );
358 if (!hModule) return (HMODULE)11; /* invalid exe */
360 FarSetOwner16( hModule, hModule );
361 pModule = (NE_MODULE *)GlobalLock16( hModule );
363 /* Set all used entries */
364 pModule->magic = IMAGE_OS2_SIGNATURE;
365 pModule->count = 1;
366 pModule->next = 0;
367 pModule->flags = 0;
368 pModule->dgroup = 0;
369 pModule->ss = 1;
370 pModule->cs = 2;
371 pModule->heap_size = 0;
372 pModule->stack_size = 0;
373 pModule->seg_count = 2;
374 pModule->modref_count = 0;
375 pModule->nrname_size = 0;
376 pModule->fileinfo = sizeof(NE_MODULE);
377 pModule->os_flags = NE_OSFLAGS_WINDOWS;
378 pModule->self = hModule;
379 pModule->module32 = module32;
381 /* Set version and flags */
382 if (module32)
384 pModule->expected_version =
385 ((PE_HEADER(module32)->OptionalHeader.MajorSubsystemVersion & 0xff) << 8 ) |
386 (PE_HEADER(module32)->OptionalHeader.MinorSubsystemVersion & 0xff);
387 pModule->flags |= NE_FFLAGS_WIN32;
388 if (PE_HEADER(module32)->FileHeader.Characteristics & IMAGE_FILE_DLL)
389 pModule->flags |= NE_FFLAGS_LIBMODULE | NE_FFLAGS_SINGLEDATA;
392 /* Set loaded file information */
393 ofs = (OFSTRUCT *)(pModule + 1);
394 memset( ofs, 0, of_size );
395 ofs->cBytes = of_size < 256 ? of_size : 255; /* FIXME */
396 strcpy( ofs->szPathName, filename );
398 pSegment = (SEGTABLEENTRY*)((char*)(pModule + 1) + of_size);
399 pModule->seg_table = (int)pSegment - (int)pModule;
400 /* Data segment */
401 pSegment->size = 0;
402 pSegment->flags = NE_SEGFLAGS_DATA;
403 pSegment->minsize = 0x1000;
404 pSegment++;
405 /* Code segment */
406 pSegment->flags = 0;
407 pSegment++;
409 /* Module name */
410 pStr = (char *)pSegment;
411 pModule->name_table = (int)pStr - (int)pModule;
412 assert(len<256);
413 *pStr = len;
414 lstrcpynA( pStr+1, basename, len+1 );
415 pStr += len+2;
417 /* All tables zero terminated */
418 pModule->res_table = pModule->import_table = pModule->entry_table =
419 (int)pStr - (int)pModule;
421 NE_RegisterModule( pModule );
422 return hModule;
426 /**********************************************************************
427 * MODULE_FindModule32
429 * Find a (loaded) win32 module depending on path
431 * RETURNS
432 * the module handle if found
433 * 0 if not
435 WINE_MODREF *MODULE_FindModule(
436 LPCSTR path /* [in] pathname of module/library to be found */
438 WINE_MODREF *wm;
439 char dllname[260], *p;
441 /* Append .DLL to name if no extension present */
442 strcpy( dllname, path );
443 if (!(p = strrchr( dllname, '.')) || strchr( p, '/' ) || strchr( p, '\\'))
444 strcat( dllname, ".DLL" );
446 for ( wm = PROCESS_Current()->modref_list; wm; wm = wm->next )
448 if ( !strcasecmp( dllname, wm->modname ) )
449 break;
450 if ( !strcasecmp( dllname, wm->filename ) )
451 break;
452 if ( !strcasecmp( dllname, wm->short_modname ) )
453 break;
454 if ( !strcasecmp( dllname, wm->short_filename ) )
455 break;
458 return wm;
462 /* Check whether a file is an OS/2 or a very old Windows executable
463 * by testing on import of KERNEL.
465 * FIXME: is reading the module imports the only way of discerning
466 * old Windows binaries from OS/2 ones ? At least it seems so...
468 static DWORD MODULE_Decide_OS2_OldWin(HANDLE hfile, IMAGE_DOS_HEADER *mz, IMAGE_OS2_HEADER *ne)
470 DWORD currpos = SetFilePointer( hfile, 0, NULL, SEEK_CUR);
471 DWORD type = SCS_OS216_BINARY;
472 LPWORD modtab = NULL;
473 LPSTR nametab = NULL;
474 DWORD len;
475 int i;
477 /* read modref table */
478 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_modtab, NULL, SEEK_SET ) == -1)
479 || (!(modtab = HeapAlloc( GetProcessHeap(), 0, ne->ne_cmod*sizeof(WORD))))
480 || (!(ReadFile(hfile, modtab, ne->ne_cmod*sizeof(WORD), &len, NULL)))
481 || (len != ne->ne_cmod*sizeof(WORD)) )
482 goto broken;
484 /* read imported names table */
485 if ( (SetFilePointer( hfile, mz->e_lfanew + ne->ne_imptab, NULL, SEEK_SET ) == -1)
486 || (!(nametab = HeapAlloc( GetProcessHeap(), 0, ne->ne_enttab - ne->ne_imptab)))
487 || (!(ReadFile(hfile, nametab, ne->ne_enttab - ne->ne_imptab, &len, NULL)))
488 || (len != ne->ne_enttab - ne->ne_imptab) )
489 goto broken;
491 for (i=0; i < ne->ne_cmod; i++)
493 LPSTR module = &nametab[modtab[i]];
494 TRACE("modref: %.*s\n", module[0], &module[1]);
495 if (!(strncmp(&module[1], "KERNEL", module[0])))
496 { /* very old Windows file */
497 MESSAGE("This seems to be a very old (pre-3.0) Windows executable. Expect crashes, especially if this is a real-mode binary !\n");
498 type = SCS_WOW_BINARY;
499 goto good;
503 broken:
504 ERR("Hmm, an error occurred. Is this binary file broken ?\n");
506 good:
507 HeapFree( GetProcessHeap(), 0, modtab);
508 HeapFree( GetProcessHeap(), 0, nametab);
509 SetFilePointer( hfile, currpos, NULL, SEEK_SET); /* restore filepos */
510 return type;
513 /***********************************************************************
514 * MODULE_GetBinaryType
516 * The GetBinaryType function determines whether a file is executable
517 * or not and if it is it returns what type of executable it is.
518 * The type of executable is a property that determines in which
519 * subsystem an executable file runs under.
521 * Binary types returned:
522 * SCS_32BIT_BINARY: A Win32 based application
523 * SCS_DOS_BINARY: An MS-Dos based application
524 * SCS_WOW_BINARY: A Win16 based application
525 * SCS_PIF_BINARY: A PIF file that executes an MS-Dos based app
526 * SCS_POSIX_BINARY: A POSIX based application ( Not implemented )
527 * SCS_OS216_BINARY: A 16bit OS/2 based application
529 * Returns TRUE if the file is an executable in which case
530 * the value pointed by lpBinaryType is set.
531 * Returns FALSE if the file is not an executable or if the function fails.
533 * To do so it opens the file and reads in the header information
534 * if the extended header information is not present it will
535 * assume that the file is a DOS executable.
536 * If the extended header information is present it will
537 * determine if the file is a 16 or 32 bit Windows executable
538 * by check the flags in the header.
540 * Note that .COM and .PIF files are only recognized by their
541 * file name extension; but Windows does it the same way ...
543 BOOL MODULE_GetBinaryType( HANDLE hfile, LPCSTR filename, LPDWORD lpBinaryType )
545 IMAGE_DOS_HEADER mz_header;
546 char magic[4], *ptr;
547 DWORD len;
549 /* Seek to the start of the file and read the DOS header information.
551 if ( SetFilePointer( hfile, 0, NULL, SEEK_SET ) != -1
552 && ReadFile( hfile, &mz_header, sizeof(mz_header), &len, NULL )
553 && len == sizeof(mz_header) )
555 /* Now that we have the header check the e_magic field
556 * to see if this is a dos image.
558 if ( mz_header.e_magic == IMAGE_DOS_SIGNATURE )
560 BOOL lfanewValid = FALSE;
561 /* We do have a DOS image so we will now try to seek into
562 * the file by the amount indicated by the field
563 * "Offset to extended header" and read in the
564 * "magic" field information at that location.
565 * This will tell us if there is more header information
566 * to read or not.
568 /* But before we do we will make sure that header
569 * structure encompasses the "Offset to extended header"
570 * field.
572 if ( (mz_header.e_cparhdr<<4) >= sizeof(IMAGE_DOS_HEADER) )
573 if ( ( mz_header.e_crlc == 0 ) ||
574 ( mz_header.e_lfarlc >= sizeof(IMAGE_DOS_HEADER) ) )
575 if ( mz_header.e_lfanew >= sizeof(IMAGE_DOS_HEADER)
576 && SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ) != -1
577 && ReadFile( hfile, magic, sizeof(magic), &len, NULL )
578 && len == sizeof(magic) )
579 lfanewValid = TRUE;
581 if ( !lfanewValid )
583 /* If we cannot read this "extended header" we will
584 * assume that we have a simple DOS executable.
586 *lpBinaryType = SCS_DOS_BINARY;
587 return TRUE;
589 else
591 /* Reading the magic field succeeded so
592 * we will try to determine what type it is.
594 if ( *(DWORD*)magic == IMAGE_NT_SIGNATURE )
596 /* This is an NT signature.
598 *lpBinaryType = SCS_32BIT_BINARY;
599 return TRUE;
601 else if ( *(WORD*)magic == IMAGE_OS2_SIGNATURE )
603 /* The IMAGE_OS2_SIGNATURE indicates that the
604 * "extended header is a Windows executable (NE)
605 * header." This can mean either a 16-bit OS/2
606 * or a 16-bit Windows or even a DOS program
607 * (running under a DOS extender). To decide
608 * which, we'll have to read the NE header.
611 IMAGE_OS2_HEADER ne;
612 if ( SetFilePointer( hfile, mz_header.e_lfanew, NULL, SEEK_SET ) != -1
613 && ReadFile( hfile, &ne, sizeof(ne), &len, NULL )
614 && len == sizeof(ne) )
616 switch ( ne.ne_exetyp )
618 case 2: *lpBinaryType = SCS_WOW_BINARY; return TRUE;
619 case 5: *lpBinaryType = SCS_DOS_BINARY; return TRUE;
620 default: *lpBinaryType =
621 MODULE_Decide_OS2_OldWin(hfile, &mz_header, &ne);
622 return TRUE;
625 /* Couldn't read header, so abort. */
626 return FALSE;
628 else
630 /* Unknown extended header, but this file is nonetheless
631 DOS-executable.
633 *lpBinaryType = SCS_DOS_BINARY;
634 return TRUE;
640 /* If we get here, we don't even have a correct MZ header.
641 * Try to check the file extension for known types ...
643 ptr = strrchr( filename, '.' );
644 if ( ptr && !strchr( ptr, '\\' ) && !strchr( ptr, '/' ) )
646 if ( !strcasecmp( ptr, ".COM" ) )
648 *lpBinaryType = SCS_DOS_BINARY;
649 return TRUE;
652 if ( !strcasecmp( ptr, ".PIF" ) )
654 *lpBinaryType = SCS_PIF_BINARY;
655 return TRUE;
659 return FALSE;
662 /***********************************************************************
663 * GetBinaryTypeA [KERNEL32.280]
665 BOOL WINAPI GetBinaryTypeA( LPCSTR lpApplicationName, LPDWORD lpBinaryType )
667 BOOL ret = FALSE;
668 HANDLE hfile;
670 TRACE_(win32)("%s\n", lpApplicationName );
672 /* Sanity check.
674 if ( lpApplicationName == NULL || lpBinaryType == NULL )
675 return FALSE;
677 /* Open the file indicated by lpApplicationName for reading.
679 hfile = CreateFileA( lpApplicationName, GENERIC_READ, FILE_SHARE_READ,
680 NULL, OPEN_EXISTING, 0, -1 );
681 if ( hfile == INVALID_HANDLE_VALUE )
682 return FALSE;
684 /* Check binary type
686 ret = MODULE_GetBinaryType( hfile, lpApplicationName, lpBinaryType );
688 /* Close the file.
690 CloseHandle( hfile );
692 return ret;
695 /***********************************************************************
696 * GetBinaryTypeW [KERNEL32.281]
698 BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
700 BOOL ret = FALSE;
701 LPSTR strNew = NULL;
703 TRACE_(win32)("%s\n", debugstr_w(lpApplicationName) );
705 /* Sanity check.
707 if ( lpApplicationName == NULL || lpBinaryType == NULL )
708 return FALSE;
710 /* Convert the wide string to a ascii string.
712 strNew = HEAP_strdupWtoA( GetProcessHeap(), 0, lpApplicationName );
714 if ( strNew != NULL )
716 ret = GetBinaryTypeA( strNew, lpBinaryType );
718 /* Free the allocated string.
720 HeapFree( GetProcessHeap(), 0, strNew );
723 return ret;
727 /***********************************************************************
728 * WinExec16 (KERNEL.166)
730 HINSTANCE16 WINAPI WinExec16( LPCSTR lpCmdLine, UINT16 nCmdShow )
732 LPCSTR p = NULL;
733 LPSTR name, cmdline;
734 int len;
735 HINSTANCE16 ret;
736 char buffer[MAX_PATH];
738 if ( ( *lpCmdLine == '"' ) && ( p = strchr ( lpCmdLine+1, '"' ) ) )
739 p = strchr ( p, ' ' );
740 else
741 p = strchr( lpCmdLine, ' ' );
742 if ( p )
744 if (!(name = HeapAlloc( GetProcessHeap(), 0, p - lpCmdLine + 1 )))
745 return ERROR_NOT_ENOUGH_MEMORY;
746 memcpy( name, lpCmdLine, p - lpCmdLine );
747 name[p - lpCmdLine] = 0;
748 p++;
749 len = strlen(p);
750 cmdline = SEGPTR_ALLOC( len + 2 );
751 cmdline[0] = (BYTE)len;
752 strcpy( cmdline + 1, p );
754 else
756 name = (LPSTR)lpCmdLine;
757 cmdline = SEGPTR_ALLOC(2);
758 cmdline[0] = cmdline[1] = 0;
761 if (SearchPathA( NULL, name, ".exe", sizeof(buffer), buffer, NULL ))
763 LOADPARAMS16 params;
764 WORD *showCmd = SEGPTR_ALLOC( 2*sizeof(WORD) );
765 showCmd[0] = 2;
766 showCmd[1] = nCmdShow;
768 params.hEnvironment = 0;
769 params.cmdLine = SEGPTR_GET(cmdline);
770 params.showCmd = SEGPTR_GET(showCmd);
771 params.reserved = 0;
773 ret = LoadModule16( buffer, &params );
775 SEGPTR_FREE( showCmd );
776 SEGPTR_FREE( cmdline );
778 else ret = GetLastError();
780 if (name != lpCmdLine) HeapFree( GetProcessHeap(), 0, name );
782 if (ret == 21) /* 32-bit module */
784 SYSLEVEL_ReleaseWin16Lock();
785 ret = WinExec( lpCmdLine, nCmdShow );
786 SYSLEVEL_RestoreWin16Lock();
788 return ret;
791 /***********************************************************************
792 * WinExec (KERNEL32.566)
794 HINSTANCE WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
796 PROCESS_INFORMATION info;
797 STARTUPINFOA startup;
798 HINSTANCE hInstance;
799 char *cmdline;
801 memset( &startup, 0, sizeof(startup) );
802 startup.cb = sizeof(startup);
803 startup.dwFlags = STARTF_USESHOWWINDOW;
804 startup.wShowWindow = nCmdShow;
806 /* cmdline needs to be writeable for CreateProcess */
807 if (!(cmdline = HEAP_strdupA( GetProcessHeap(), 0, lpCmdLine ))) return 0;
809 if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
810 0, NULL, NULL, &startup, &info ))
812 /* Give 30 seconds to the app to come up */
813 if (Callout.WaitForInputIdle ( info.hProcess, 30000 ) == 0xFFFFFFFF)
814 WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
815 hInstance = 33;
816 /* Close off the handles */
817 CloseHandle( info.hThread );
818 CloseHandle( info.hProcess );
820 else if ((hInstance = GetLastError()) >= 32)
822 FIXME("Strange error set by CreateProcess: %d\n", hInstance );
823 hInstance = 11;
825 HeapFree( GetProcessHeap(), 0, cmdline );
826 return hInstance;
829 /**********************************************************************
830 * LoadModule (KERNEL32.499)
832 HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
834 LOADPARAMS *params = (LOADPARAMS *)paramBlock;
835 PROCESS_INFORMATION info;
836 STARTUPINFOA startup;
837 HINSTANCE hInstance;
838 LPSTR cmdline, p;
839 char filename[MAX_PATH];
840 BYTE len;
842 if (!name) return ERROR_FILE_NOT_FOUND;
844 if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
845 !SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
846 return GetLastError();
848 len = (BYTE)params->lpCmdLine[0];
849 if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
850 return ERROR_NOT_ENOUGH_MEMORY;
852 strcpy( cmdline, filename );
853 p = cmdline + strlen(cmdline);
854 *p++ = ' ';
855 memcpy( p, params->lpCmdLine + 1, len );
856 p[len] = 0;
858 memset( &startup, 0, sizeof(startup) );
859 startup.cb = sizeof(startup);
860 if (params->lpCmdShow)
862 startup.dwFlags = STARTF_USESHOWWINDOW;
863 startup.wShowWindow = params->lpCmdShow[1];
866 if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
867 params->lpEnvAddress, NULL, &startup, &info ))
869 /* Give 30 seconds to the app to come up */
870 if ( Callout.WaitForInputIdle ( info.hProcess, 30000 ) == 0xFFFFFFFF )
871 WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
872 hInstance = 33;
873 /* Close off the handles */
874 CloseHandle( info.hThread );
875 CloseHandle( info.hProcess );
877 else if ((hInstance = GetLastError()) >= 32)
879 FIXME("Strange error set by CreateProcess: %d\n", hInstance );
880 hInstance = 11;
883 HeapFree( GetProcessHeap(), 0, cmdline );
884 return hInstance;
888 /*************************************************************************
889 * get_file_name
891 * Helper for CreateProcess: retrieve the file name to load from the
892 * app name and command line. Store the file name in buffer, and
893 * return a possibly modified command line.
895 static LPSTR get_file_name( LPCSTR appname, LPSTR cmdline, LPSTR buffer, int buflen )
897 char *name, *pos, *ret = NULL;
898 const char *p;
900 /* if we have an app name, everything is easy */
902 if (appname)
904 /* use the unmodified app name as file name */
905 lstrcpynA( buffer, appname, buflen );
906 if (!(ret = cmdline))
908 /* no command-line, create one */
909 if ((ret = HeapAlloc( GetProcessHeap(), 0, strlen(appname) + 3 )))
910 sprintf( ret, "\"%s\"", appname );
912 return ret;
915 if (!cmdline)
917 SetLastError( ERROR_INVALID_PARAMETER );
918 return NULL;
921 /* first check for a quoted file name */
923 if ((cmdline[0] == '"') && ((p = strchr( cmdline + 1, '"' ))))
925 int len = p - cmdline - 1;
926 /* extract the quoted portion as file name */
927 if (!(name = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) return NULL;
928 memcpy( name, cmdline + 1, len );
929 name[len] = 0;
931 if (SearchPathA( NULL, name, ".exe", buflen, buffer, NULL ) ||
932 SearchPathA( NULL, name, NULL, buflen, buffer, NULL ))
933 ret = cmdline; /* no change necessary */
934 goto done;
937 /* now try the command-line word by word */
939 if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + 1 ))) return NULL;
940 pos = name;
941 p = cmdline;
943 while (*p)
945 do *pos++ = *p++; while (*p && *p != ' ');
946 *pos = 0;
947 TRACE("trying '%s'\n", name );
948 if (SearchPathA( NULL, name, ".exe", buflen, buffer, NULL ) ||
949 SearchPathA( NULL, name, NULL, buflen, buffer, NULL ))
951 ret = cmdline;
952 break;
956 if (!ret || !strchr( name, ' ' )) goto done; /* no change necessary */
958 /* now build a new command-line with quotes */
960 if (!(ret = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + 3 ))) goto done;
961 sprintf( ret, "\"%s\"%s", name, p );
963 done:
964 HeapFree( GetProcessHeap(), 0, name );
965 return ret;
969 /**********************************************************************
970 * CreateProcessA (KERNEL32.171)
972 BOOL WINAPI CreateProcessA( LPCSTR lpApplicationName, LPSTR lpCommandLine,
973 LPSECURITY_ATTRIBUTES lpProcessAttributes,
974 LPSECURITY_ATTRIBUTES lpThreadAttributes,
975 BOOL bInheritHandles, DWORD dwCreationFlags,
976 LPVOID lpEnvironment, LPCSTR lpCurrentDirectory,
977 LPSTARTUPINFOA lpStartupInfo,
978 LPPROCESS_INFORMATION lpProcessInfo )
980 BOOL retv = FALSE;
981 HANDLE hFile;
982 DWORD type;
983 char name[MAX_PATH];
984 LPSTR tidy_cmdline;
986 /* Process the AppName and/or CmdLine to get module name and path */
988 TRACE("app '%s' cmdline '%s'\n", lpApplicationName, lpCommandLine );
990 if (!(tidy_cmdline = get_file_name( lpApplicationName, lpCommandLine, name, sizeof(name) )))
991 return FALSE;
993 /* Warn if unsupported features are used */
995 if (dwCreationFlags & DETACHED_PROCESS)
996 FIXME("(%s,...): DETACHED_PROCESS ignored\n", name);
997 if (dwCreationFlags & CREATE_NEW_CONSOLE)
998 FIXME("(%s,...): CREATE_NEW_CONSOLE ignored\n", name);
999 if (dwCreationFlags & NORMAL_PRIORITY_CLASS)
1000 FIXME("(%s,...): NORMAL_PRIORITY_CLASS ignored\n", name);
1001 if (dwCreationFlags & IDLE_PRIORITY_CLASS)
1002 FIXME("(%s,...): IDLE_PRIORITY_CLASS ignored\n", name);
1003 if (dwCreationFlags & HIGH_PRIORITY_CLASS)
1004 FIXME("(%s,...): HIGH_PRIORITY_CLASS ignored\n", name);
1005 if (dwCreationFlags & REALTIME_PRIORITY_CLASS)
1006 FIXME("(%s,...): REALTIME_PRIORITY_CLASS ignored\n", name);
1007 if (dwCreationFlags & CREATE_NEW_PROCESS_GROUP)
1008 FIXME("(%s,...): CREATE_NEW_PROCESS_GROUP ignored\n", name);
1009 if (dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)
1010 FIXME("(%s,...): CREATE_UNICODE_ENVIRONMENT ignored\n", name);
1011 if (dwCreationFlags & CREATE_SEPARATE_WOW_VDM)
1012 FIXME("(%s,...): CREATE_SEPARATE_WOW_VDM ignored\n", name);
1013 if (dwCreationFlags & CREATE_SHARED_WOW_VDM)
1014 FIXME("(%s,...): CREATE_SHARED_WOW_VDM ignored\n", name);
1015 if (dwCreationFlags & CREATE_DEFAULT_ERROR_MODE)
1016 FIXME("(%s,...): CREATE_DEFAULT_ERROR_MODE ignored\n", name);
1017 if (dwCreationFlags & CREATE_NO_WINDOW)
1018 FIXME("(%s,...): CREATE_NO_WINDOW ignored\n", name);
1019 if (dwCreationFlags & PROFILE_USER)
1020 FIXME("(%s,...): PROFILE_USER ignored\n", name);
1021 if (dwCreationFlags & PROFILE_KERNEL)
1022 FIXME("(%s,...): PROFILE_KERNEL ignored\n", name);
1023 if (dwCreationFlags & PROFILE_SERVER)
1024 FIXME("(%s,...): PROFILE_SERVER ignored\n", name);
1025 if (lpStartupInfo->lpDesktop)
1026 FIXME("(%s,...): lpStartupInfo->lpDesktop %s ignored\n",
1027 name, lpStartupInfo->lpDesktop);
1028 if (lpStartupInfo->lpTitle)
1029 FIXME("(%s,...): lpStartupInfo->lpTitle %s ignored\n",
1030 name, lpStartupInfo->lpTitle);
1031 if (lpStartupInfo->dwFlags & STARTF_USECOUNTCHARS)
1032 FIXME("(%s,...): STARTF_USECOUNTCHARS (%ld,%ld) ignored\n",
1033 name, lpStartupInfo->dwXCountChars, lpStartupInfo->dwYCountChars);
1034 if (lpStartupInfo->dwFlags & STARTF_USEFILLATTRIBUTE)
1035 FIXME("(%s,...): STARTF_USEFILLATTRIBUTE %lx ignored\n",
1036 name, lpStartupInfo->dwFillAttribute);
1037 if (lpStartupInfo->dwFlags & STARTF_RUNFULLSCREEN)
1038 FIXME("(%s,...): STARTF_RUNFULLSCREEN ignored\n", name);
1039 if (lpStartupInfo->dwFlags & STARTF_FORCEONFEEDBACK)
1040 FIXME("(%s,...): STARTF_FORCEONFEEDBACK ignored\n", name);
1041 if (lpStartupInfo->dwFlags & STARTF_FORCEOFFFEEDBACK)
1042 FIXME("(%s,...): STARTF_FORCEOFFFEEDBACK ignored\n", name);
1043 if (lpStartupInfo->dwFlags & STARTF_USEHOTKEY)
1044 FIXME("(%s,...): STARTF_USEHOTKEY ignored\n", name);
1046 /* Open file and determine executable type */
1048 hFile = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, -1 );
1049 if (hFile == INVALID_HANDLE_VALUE) goto done;
1051 if ( !MODULE_GetBinaryType( hFile, name, &type ) )
1053 CloseHandle( hFile );
1054 retv = PROCESS_Create( -1, name, tidy_cmdline, lpEnvironment,
1055 lpProcessAttributes, lpThreadAttributes,
1056 bInheritHandles, dwCreationFlags,
1057 lpStartupInfo, lpProcessInfo, lpCurrentDirectory );
1058 goto done;
1061 /* Create process */
1063 switch ( type )
1065 case SCS_32BIT_BINARY:
1066 case SCS_WOW_BINARY:
1067 case SCS_DOS_BINARY:
1068 retv = PROCESS_Create( hFile, name, tidy_cmdline, lpEnvironment,
1069 lpProcessAttributes, lpThreadAttributes,
1070 bInheritHandles, dwCreationFlags,
1071 lpStartupInfo, lpProcessInfo, lpCurrentDirectory);
1072 break;
1074 case SCS_PIF_BINARY:
1075 case SCS_POSIX_BINARY:
1076 case SCS_OS216_BINARY:
1077 FIXME("Unsupported executable type: %ld\n", type );
1078 /* fall through */
1080 default:
1081 SetLastError( ERROR_BAD_FORMAT );
1082 break;
1084 CloseHandle( hFile );
1086 done:
1087 if (tidy_cmdline != lpCommandLine) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
1088 return retv;
1091 /**********************************************************************
1092 * CreateProcessW (KERNEL32.172)
1093 * NOTES
1094 * lpReserved is not converted
1096 BOOL WINAPI CreateProcessW( LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
1097 LPSECURITY_ATTRIBUTES lpProcessAttributes,
1098 LPSECURITY_ATTRIBUTES lpThreadAttributes,
1099 BOOL bInheritHandles, DWORD dwCreationFlags,
1100 LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory,
1101 LPSTARTUPINFOW lpStartupInfo,
1102 LPPROCESS_INFORMATION lpProcessInfo )
1103 { BOOL ret;
1104 STARTUPINFOA StartupInfoA;
1106 LPSTR lpApplicationNameA = HEAP_strdupWtoA (GetProcessHeap(),0,lpApplicationName);
1107 LPSTR lpCommandLineA = HEAP_strdupWtoA (GetProcessHeap(),0,lpCommandLine);
1108 LPSTR lpCurrentDirectoryA = HEAP_strdupWtoA (GetProcessHeap(),0,lpCurrentDirectory);
1110 memcpy (&StartupInfoA, lpStartupInfo, sizeof(STARTUPINFOA));
1111 StartupInfoA.lpDesktop = HEAP_strdupWtoA (GetProcessHeap(),0,lpStartupInfo->lpDesktop);
1112 StartupInfoA.lpTitle = HEAP_strdupWtoA (GetProcessHeap(),0,lpStartupInfo->lpTitle);
1114 TRACE_(win32)("(%s,%s,...)\n", debugstr_w(lpApplicationName), debugstr_w(lpCommandLine));
1116 if (lpStartupInfo->lpReserved)
1117 FIXME_(win32)("StartupInfo.lpReserved is used, please report (%s)\n", debugstr_w(lpStartupInfo->lpReserved));
1119 ret = CreateProcessA( lpApplicationNameA, lpCommandLineA,
1120 lpProcessAttributes, lpThreadAttributes,
1121 bInheritHandles, dwCreationFlags,
1122 lpEnvironment, lpCurrentDirectoryA,
1123 &StartupInfoA, lpProcessInfo );
1125 HeapFree( GetProcessHeap(), 0, lpCurrentDirectoryA );
1126 HeapFree( GetProcessHeap(), 0, lpCommandLineA );
1127 HeapFree( GetProcessHeap(), 0, StartupInfoA.lpDesktop );
1128 HeapFree( GetProcessHeap(), 0, StartupInfoA.lpTitle );
1130 return ret;
1133 /***********************************************************************
1134 * GetModuleHandleA (KERNEL32.237)
1136 HMODULE WINAPI GetModuleHandleA(LPCSTR module)
1138 WINE_MODREF *wm;
1140 if ( module == NULL )
1141 wm = PROCESS_Current()->exe_modref;
1142 else
1143 wm = MODULE_FindModule( module );
1145 return wm? wm->module : 0;
1148 /***********************************************************************
1149 * GetModuleHandleW
1151 HMODULE WINAPI GetModuleHandleW(LPCWSTR module)
1153 HMODULE hModule;
1154 LPSTR modulea = HEAP_strdupWtoA( GetProcessHeap(), 0, module );
1155 hModule = GetModuleHandleA( modulea );
1156 HeapFree( GetProcessHeap(), 0, modulea );
1157 return hModule;
1161 /***********************************************************************
1162 * GetModuleFileNameA (KERNEL32.235)
1164 * GetModuleFileNameA seems to *always* return the long path;
1165 * it's only GetModuleFileName16 that decides between short/long path
1166 * by checking if exe version >= 4.0.
1167 * (SDK docu doesn't mention this)
1169 DWORD WINAPI GetModuleFileNameA(
1170 HMODULE hModule, /* [in] module handle (32bit) */
1171 LPSTR lpFileName, /* [out] filenamebuffer */
1172 DWORD size ) /* [in] size of filenamebuffer */
1174 WINE_MODREF *wm;
1176 EnterCriticalSection( &PROCESS_Current()->crit_section );
1178 lpFileName[0] = 0;
1179 if ((wm = MODULE32_LookupHMODULE( hModule )))
1180 lstrcpynA( lpFileName, wm->filename, size );
1182 LeaveCriticalSection( &PROCESS_Current()->crit_section );
1183 TRACE("%s\n", lpFileName );
1184 return strlen(lpFileName);
1188 /***********************************************************************
1189 * GetModuleFileNameW (KERNEL32.236)
1191 DWORD WINAPI GetModuleFileNameW( HMODULE hModule, LPWSTR lpFileName,
1192 DWORD size )
1194 LPSTR fnA = (char*)HeapAlloc( GetProcessHeap(), 0, size );
1195 DWORD res = GetModuleFileNameA( hModule, fnA, size );
1196 lstrcpynAtoW( lpFileName, fnA, size );
1197 HeapFree( GetProcessHeap(), 0, fnA );
1198 return res;
1202 /***********************************************************************
1203 * LoadLibraryExA (KERNEL32)
1205 HMODULE WINAPI LoadLibraryExA(LPCSTR libname, HANDLE hfile, DWORD flags)
1207 WINE_MODREF *wm;
1209 if(!libname)
1211 SetLastError(ERROR_INVALID_PARAMETER);
1212 return 0;
1215 if (flags & LOAD_LIBRARY_AS_DATAFILE)
1217 char filename[256];
1218 HFILE hFile;
1219 HMODULE hmod = 0;
1221 if (!SearchPathA( NULL, libname, ".dll", sizeof(filename), filename, NULL ))
1222 return 0;
1223 /* FIXME: maybe we should use the hfile parameter instead */
1224 hFile = CreateFileA( filename, GENERIC_READ, FILE_SHARE_READ,
1225 NULL, OPEN_EXISTING, 0, -1 );
1226 if (hFile != INVALID_HANDLE_VALUE)
1228 hmod = PE_LoadImage( hFile, filename, flags );
1229 CloseHandle( hFile );
1231 return hmod;
1234 EnterCriticalSection(&PROCESS_Current()->crit_section);
1236 wm = MODULE_LoadLibraryExA( libname, hfile, flags );
1237 if ( wm )
1239 if ( !MODULE_DllProcessAttach( wm, NULL ) )
1241 WARN_(module)("Attach failed for module '%s', \n", libname);
1242 MODULE_FreeLibrary(wm);
1243 SetLastError(ERROR_DLL_INIT_FAILED);
1244 wm = NULL;
1248 LeaveCriticalSection(&PROCESS_Current()->crit_section);
1250 return wm ? wm->module : 0;
1253 /***********************************************************************
1254 * MODULE_LoadLibraryExA (internal)
1256 * Load a PE style module according to the load order.
1258 * The HFILE parameter is not used and marked reserved in the SDK. I can
1259 * only guess that it should force a file to be mapped, but I rather
1260 * ignore the parameter because it would be extremely difficult to
1261 * integrate this with different types of module represenations.
1264 WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags )
1266 DWORD err = GetLastError();
1267 WINE_MODREF *pwm;
1268 int i;
1269 module_loadorder_t *plo;
1271 EnterCriticalSection(&PROCESS_Current()->crit_section);
1273 /* Check for already loaded module */
1274 if((pwm = MODULE_FindModule(libname)))
1276 if(!(pwm->flags & WINE_MODREF_MARKER))
1277 pwm->refCount++;
1279 if ((pwm->flags & WINE_MODREF_DONT_RESOLVE_REFS) &&
1280 !(flags & DONT_RESOLVE_DLL_REFERENCES))
1282 extern DWORD fixup_imports(WINE_MODREF *wm); /*FIXME*/
1283 pwm->flags &= ~WINE_MODREF_DONT_RESOLVE_REFS;
1284 fixup_imports( pwm );
1286 TRACE("Already loaded module '%s' at 0x%08x, count=%d, \n", libname, pwm->module, pwm->refCount);
1287 LeaveCriticalSection(&PROCESS_Current()->crit_section);
1288 return pwm;
1291 plo = MODULE_GetLoadOrder(libname);
1293 for(i = 0; i < MODULE_LOADORDER_NTYPES; i++)
1295 SetLastError( ERROR_FILE_NOT_FOUND );
1296 switch(plo->loadorder[i])
1298 case MODULE_LOADORDER_DLL:
1299 TRACE("Trying native dll '%s'\n", libname);
1300 pwm = PE_LoadLibraryExA(libname, flags);
1301 break;
1303 case MODULE_LOADORDER_ELFDLL:
1304 TRACE("Trying elfdll '%s'\n", libname);
1305 if (!(pwm = BUILTIN32_LoadLibraryExA(libname, flags)))
1306 pwm = ELFDLL_LoadLibraryExA(libname, flags);
1307 break;
1309 case MODULE_LOADORDER_SO:
1310 TRACE("Trying so-library '%s'\n", libname);
1311 if (!(pwm = BUILTIN32_LoadLibraryExA(libname, flags)))
1312 pwm = ELF_LoadLibraryExA(libname, flags);
1313 break;
1315 case MODULE_LOADORDER_BI:
1316 TRACE("Trying built-in '%s'\n", libname);
1317 pwm = BUILTIN32_LoadLibraryExA(libname, flags);
1318 break;
1320 default:
1321 ERR("Got invalid loadorder type %d (%s index %d)\n", plo->loadorder[i], plo->modulename, i);
1322 /* Fall through */
1324 case MODULE_LOADORDER_INVALID: /* We ignore this as it is an empty entry */
1325 pwm = NULL;
1326 break;
1329 if(pwm)
1331 /* Initialize DLL just loaded */
1332 TRACE("Loaded module '%s' at 0x%08x, \n", libname, pwm->module);
1334 /* Set the refCount here so that an attach failure will */
1335 /* decrement the dependencies through the MODULE_FreeLibrary call. */
1336 pwm->refCount++;
1338 LeaveCriticalSection(&PROCESS_Current()->crit_section);
1339 SetLastError( err ); /* restore last error */
1340 return pwm;
1343 if(GetLastError() != ERROR_FILE_NOT_FOUND)
1344 break;
1347 WARN("Failed to load module '%s'; error=0x%08lx, \n", libname, GetLastError());
1348 LeaveCriticalSection(&PROCESS_Current()->crit_section);
1349 return NULL;
1352 /***********************************************************************
1353 * LoadLibraryA (KERNEL32)
1355 HMODULE WINAPI LoadLibraryA(LPCSTR libname) {
1356 return LoadLibraryExA(libname,0,0);
1359 /***********************************************************************
1360 * LoadLibraryW (KERNEL32)
1362 HMODULE WINAPI LoadLibraryW(LPCWSTR libnameW)
1364 return LoadLibraryExW(libnameW,0,0);
1367 /***********************************************************************
1368 * LoadLibrary32_16 (KERNEL.452)
1370 HMODULE WINAPI LoadLibrary32_16( LPCSTR libname )
1372 HMODULE hModule;
1374 SYSLEVEL_ReleaseWin16Lock();
1375 hModule = LoadLibraryA( libname );
1376 SYSLEVEL_RestoreWin16Lock();
1378 return hModule;
1381 /***********************************************************************
1382 * LoadLibraryExW (KERNEL32)
1384 HMODULE WINAPI LoadLibraryExW(LPCWSTR libnameW,HANDLE hfile,DWORD flags)
1386 LPSTR libnameA = HEAP_strdupWtoA( GetProcessHeap(), 0, libnameW );
1387 HMODULE ret = LoadLibraryExA( libnameA , hfile, flags );
1389 HeapFree( GetProcessHeap(), 0, libnameA );
1390 return ret;
1393 /***********************************************************************
1394 * MODULE_FlushModrefs
1396 * NOTE: Assumes that the process critical section is held!
1398 * Remove all unused modrefs and call the internal unloading routines
1399 * for the library type.
1401 static void MODULE_FlushModrefs(void)
1403 WINE_MODREF *wm, *next;
1405 for(wm = PROCESS_Current()->modref_list; wm; wm = next)
1407 next = wm->next;
1409 if(wm->refCount)
1410 continue;
1412 /* Unlink this modref from the chain */
1413 if(wm->next)
1414 wm->next->prev = wm->prev;
1415 if(wm->prev)
1416 wm->prev->next = wm->next;
1417 if(wm == PROCESS_Current()->modref_list)
1418 PROCESS_Current()->modref_list = wm->next;
1420 TRACE(" unloading %s\n", wm->filename);
1421 /* VirtualFree( (LPVOID)wm->module, 0, MEM_RELEASE ); */ /* FIXME */
1422 /* if (wm->dlhandle) dlclose( wm->dlhandle ); */ /* FIXME */
1423 HeapFree( GetProcessHeap(), 0, wm->filename );
1424 HeapFree( GetProcessHeap(), 0, wm->short_filename );
1425 HeapFree( GetProcessHeap(), 0, wm );
1429 /***********************************************************************
1430 * FreeLibrary
1432 BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
1434 BOOL retv = FALSE;
1435 WINE_MODREF *wm;
1437 EnterCriticalSection( &PROCESS_Current()->crit_section );
1438 PROCESS_Current()->free_lib_count++;
1440 wm = MODULE32_LookupHMODULE( hLibModule );
1441 if ( !wm || !hLibModule )
1442 SetLastError( ERROR_INVALID_HANDLE );
1443 else
1444 retv = MODULE_FreeLibrary( wm );
1446 PROCESS_Current()->free_lib_count--;
1447 LeaveCriticalSection( &PROCESS_Current()->crit_section );
1449 return retv;
1452 /***********************************************************************
1453 * MODULE_DecRefCount
1455 * NOTE: Assumes that the process critical section is held!
1457 static void MODULE_DecRefCount( WINE_MODREF *wm )
1459 int i;
1461 if ( wm->flags & WINE_MODREF_MARKER )
1462 return;
1464 if ( wm->refCount <= 0 )
1465 return;
1467 --wm->refCount;
1468 TRACE("(%s) refCount: %d\n", wm->modname, wm->refCount );
1470 if ( wm->refCount == 0 )
1472 wm->flags |= WINE_MODREF_MARKER;
1474 for ( i = 0; i < wm->nDeps; i++ )
1475 if ( wm->deps[i] )
1476 MODULE_DecRefCount( wm->deps[i] );
1478 wm->flags &= ~WINE_MODREF_MARKER;
1482 /***********************************************************************
1483 * MODULE_FreeLibrary
1485 * NOTE: Assumes that the process critical section is held!
1487 BOOL MODULE_FreeLibrary( WINE_MODREF *wm )
1489 TRACE("(%s) - START\n", wm->modname );
1491 /* Recursively decrement reference counts */
1492 MODULE_DecRefCount( wm );
1494 /* Call process detach notifications */
1495 if ( PROCESS_Current()->free_lib_count <= 1 )
1497 struct unload_dll_request *req = get_req_buffer();
1499 MODULE_DllProcessDetach( FALSE, NULL );
1500 req->base = (void *)wm->module;
1501 server_call_noerr( REQ_UNLOAD_DLL );
1503 MODULE_FlushModrefs();
1506 TRACE("END\n");
1508 return TRUE;
1512 /***********************************************************************
1513 * FreeLibraryAndExitThread
1515 VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
1517 FreeLibrary(hLibModule);
1518 ExitThread(dwExitCode);
1521 /***********************************************************************
1522 * PrivateLoadLibrary (KERNEL32)
1524 * FIXME: rough guesswork, don't know what "Private" means
1526 HINSTANCE WINAPI PrivateLoadLibrary(LPCSTR libname)
1528 return (HINSTANCE)LoadLibrary16(libname);
1533 /***********************************************************************
1534 * PrivateFreeLibrary (KERNEL32)
1536 * FIXME: rough guesswork, don't know what "Private" means
1538 void WINAPI PrivateFreeLibrary(HINSTANCE handle)
1540 FreeLibrary16((HINSTANCE16)handle);
1544 /***********************************************************************
1545 * WIN32_GetProcAddress16 (KERNEL32.36)
1546 * Get procaddress in 16bit module from win32... (kernel32 undoc. ordinal func)
1548 FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hModule, LPCSTR name )
1550 WORD ordinal;
1551 FARPROC16 ret;
1553 if (!hModule) {
1554 WARN("hModule may not be 0!\n");
1555 return (FARPROC16)0;
1557 if (HIWORD(hModule))
1559 WARN("hModule is Win32 handle (%08x)\n", hModule );
1560 return (FARPROC16)0;
1562 hModule = GetExePtr( hModule );
1563 if (HIWORD(name)) {
1564 ordinal = NE_GetOrdinal( hModule, name );
1565 TRACE("%04x '%s'\n", hModule, name );
1566 } else {
1567 ordinal = LOWORD(name);
1568 TRACE("%04x %04x\n", hModule, ordinal );
1570 if (!ordinal) return (FARPROC16)0;
1571 ret = NE_GetEntryPoint( hModule, ordinal );
1572 TRACE("returning %08x\n",(UINT)ret);
1573 return ret;
1576 /***********************************************************************
1577 * GetProcAddress16 (KERNEL.50)
1579 FARPROC16 WINAPI GetProcAddress16( HMODULE16 hModule, SEGPTR name )
1581 WORD ordinal;
1582 FARPROC16 ret;
1584 if (!hModule) hModule = GetCurrentTask();
1585 hModule = GetExePtr( hModule );
1587 if (HIWORD(name) != 0)
1589 ordinal = NE_GetOrdinal( hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1590 TRACE("%04x '%s'\n", hModule, (LPSTR)PTR_SEG_TO_LIN(name) );
1592 else
1594 ordinal = LOWORD(name);
1595 TRACE("%04x %04x\n", hModule, ordinal );
1597 if (!ordinal) return (FARPROC16)0;
1599 ret = NE_GetEntryPoint( hModule, ordinal );
1601 TRACE("returning %08x\n", (UINT)ret );
1602 return ret;
1606 /***********************************************************************
1607 * GetProcAddress (KERNEL32.257)
1609 FARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR function )
1611 return MODULE_GetProcAddress( hModule, function, TRUE );
1614 /***********************************************************************
1615 * GetProcAddress32 (KERNEL.453)
1617 FARPROC WINAPI GetProcAddress32_16( HMODULE hModule, LPCSTR function )
1619 return MODULE_GetProcAddress( hModule, function, FALSE );
1622 /***********************************************************************
1623 * MODULE_GetProcAddress (internal)
1625 FARPROC MODULE_GetProcAddress(
1626 HMODULE hModule, /* [in] current module handle */
1627 LPCSTR function, /* [in] function to be looked up */
1628 BOOL snoop )
1630 WINE_MODREF *wm;
1631 FARPROC retproc = 0;
1633 if (HIWORD(function))
1634 TRACE_(win32)("(%08lx,%s)\n",(DWORD)hModule,function);
1635 else
1636 TRACE_(win32)("(%08lx,%p)\n",(DWORD)hModule,function);
1638 EnterCriticalSection( &PROCESS_Current()->crit_section );
1639 if ((wm = MODULE32_LookupHMODULE( hModule )))
1641 retproc = wm->find_export( wm, function, snoop );
1642 if (!retproc) SetLastError(ERROR_PROC_NOT_FOUND);
1644 LeaveCriticalSection( &PROCESS_Current()->crit_section );
1645 return retproc;
1649 /***************************************************************************
1650 * HasGPHandler (KERNEL.338)
1653 #include "pshpack1.h"
1654 typedef struct _GPHANDLERDEF
1656 WORD selector;
1657 WORD rangeStart;
1658 WORD rangeEnd;
1659 WORD handler;
1660 } GPHANDLERDEF;
1661 #include "poppack.h"
1663 SEGPTR WINAPI HasGPHandler16( SEGPTR address )
1665 HMODULE16 hModule;
1666 int gpOrdinal;
1667 SEGPTR gpPtr;
1668 GPHANDLERDEF *gpHandler;
1670 if ( (hModule = FarGetOwner16( SELECTOROF(address) )) != 0
1671 && (gpOrdinal = NE_GetOrdinal( hModule, "__GP" )) != 0
1672 && (gpPtr = (SEGPTR)NE_GetEntryPointEx( hModule, gpOrdinal, FALSE )) != 0
1673 && !IsBadReadPtr16( gpPtr, sizeof(GPHANDLERDEF) )
1674 && (gpHandler = PTR_SEG_TO_LIN( gpPtr )) != NULL )
1676 while (gpHandler->selector)
1678 if ( SELECTOROF(address) == gpHandler->selector
1679 && OFFSETOF(address) >= gpHandler->rangeStart
1680 && OFFSETOF(address) < gpHandler->rangeEnd )
1681 return PTR_SEG_OFF_TO_SEGPTR( gpHandler->selector,
1682 gpHandler->handler );
1683 gpHandler++;
1687 return 0;