Ulrich Weigand <[EMAIL PROTECTED]> writes: > this is another attempt at finally merging WineLib and the emulator by making > wine itself a WineLib app. I've tried to preserve the option of running native > USER by adding support for running a WineLib app in a 16-bit task; I've tried > to keep the impact on the startup code as light as possible ... > > What do you think? I don't think we want to do it exactly this way. I'd like to move to a model of 1 wine process == 1 win32 process, as opposed to the current model of multiple win32 processes inside 1 wine process. What this means is for Win32 the main exe will directly be the PE binary, i.e. there will not be a separate initial process that will then spawn the PE binary. For Win16 there will be a WOW monitor process that will manage a bunch of Win16 tasks, and the tasks will be Win32 threads, not processes; the WOW monitor could even be a normal Winelib app exec'ed by Wine. I have included below my current address separation patch so that you can see what I mean. This one is a bit extreme in that it starts even Win16 processes each in a separate address space (kind of a hard-coded CREATE_SEPARATE_WOW_VDM flag). And it probably breaks native USER pretty badly... -- Alexandre Julliard [EMAIL PROTECTED] ---------------------------------------------------------------- Index: dlls/x11drv/x11drv_main.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/x11drv_main.c,v retrieving revision 1.9 diff -u -r1.9 x11drv_main.c --- dlls/x11drv/x11drv_main.c 2000/05/03 18:10:47 1.9 +++ dlls/x11drv/x11drv_main.c 2000/05/05 15:13:28 @@ -135,7 +135,7 @@ TSXStringListToTextProperty( &name, 1, &window_name ); TSXSetWMProperties( display, root_window, &window_name, &window_name, - Options.argv, Options.argc, size_hints, wm_hints, class_hints ); + NULL, 0, size_hints, wm_hints, class_hints ); XA_WM_DELETE_WINDOW = TSXInternAtom( display, "WM_DELETE_WINDOW", False ); TSXSetWMProtocols( display, root_window, &XA_WM_DELETE_WINDOW, 1 ); TSXFree( size_hints ); Index: include/main.h =================================================================== RCS file: /home/wine/wine/include/main.h,v retrieving revision 1.16 diff -u -r1.16 main.h --- include/main.h 2000/04/15 21:00:56 1.16 +++ include/main.h 2000/05/05 15:13:28 @@ -7,8 +7,8 @@ #include "windef.h" -extern BOOL MAIN_MainInit( int argc, char *argv[], BOOL win32 ); -extern BOOL MAIN_WineInit( int argc, char *argv[] ); +extern BOOL MAIN_MainInit( char *argv[] ); +extern void MAIN_WineInit(void); extern int MAIN_GetLanguageID(char*lang, char*country, char*charset, char*dialect); extern void MAIN_ParseDebugOptions(const char *options); extern void MAIN_ParseLanguageOption( const char *arg ); Index: include/module.h =================================================================== RCS file: /home/wine/wine/include/module.h,v retrieving revision 1.41 diff -u -r1.41 module.h --- include/module.h 2000/04/28 20:26:35 1.41 +++ include/module.h 2000/05/05 15:13:28 @@ -183,6 +183,7 @@ extern WINE_MODREF *MODULE_LoadLibraryExA( LPCSTR libname, HFILE hfile, DWORD flags ); extern BOOL MODULE_FreeLibrary( WINE_MODREF *wm ); extern WINE_MODREF *MODULE_FindModule( LPCSTR path ); +extern BOOL MODULE_GetBinaryType( HANDLE hfile, LPCSTR filename, LPDWORD lpBinaryType +); extern HMODULE MODULE_CreateDummyModule( LPCSTR filename, HMODULE module32 ); extern FARPROC16 WINAPI WIN32_GetProcAddress16( HMODULE hmodule, LPCSTR name ); extern SEGPTR WINAPI HasGPHandler16( SEGPTR address ); @@ -201,6 +202,7 @@ extern FARPROC16 NE_GetEntryPointEx( HMODULE16 hModule, WORD ordinal, BOOL16 snoop ); extern BOOL16 NE_SetEntryPoint( HMODULE16 hModule, WORD ordinal, WORD offset ); extern HANDLE NE_OpenFile( NE_MODULE *pModule ); +extern HMODULE16 NE_LoadExeHeader( LPCSTR filename ); extern BOOL NE_CreateProcess( HANDLE hFile, LPCSTR filename, LPCSTR cmd_line, LPCSTR env, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, BOOL inherit, DWORD flags, LPSTARTUPINFOA startup, Index: include/options.h =================================================================== RCS file: /home/wine/wine/include/options.h,v retrieving revision 1.23 diff -u -r1.23 options.h --- include/options.h 2000/04/13 19:29:11 1.23 +++ include/options.h 2000/05/05 15:13:28 @@ -55,8 +55,6 @@ struct options { - int argc; - char **argv; char * desktopGeometry; /* NULL when no desktop */ char * display; /* display name */ char *dllFlags; /* -dll flags (hack for Winelib support) */ @@ -70,7 +68,7 @@ extern const char *argv0; extern void OPTIONS_Usage(void) WINE_NORETURN; -extern void OPTIONS_ParseOptions( int argc, char *argv[] ); +extern void OPTIONS_ParseOptions( char *argv[] ); /* Profile functions */ Index: include/pe_image.h =================================================================== RCS file: /home/wine/wine/include/pe_image.h,v retrieving revision 1.24 diff -u -r1.24 pe_image.h --- include/pe_image.h 2000/05/03 18:43:11 1.24 +++ include/pe_image.h 2000/05/05 15:13:28 @@ -41,11 +41,6 @@ extern HMODULE PE_LoadImage( HANDLE hFile, LPCSTR filename ); extern struct _wine_modref *PE_CreateModule( HMODULE hModule, LPCSTR filename, DWORD flags, BOOL builtin ); -extern BOOL PE_CreateProcess( HANDLE hFile, LPCSTR filename, LPCSTR cmd_line, LPCSTR env, - LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, - BOOL inherit, DWORD flags, LPSTARTUPINFOA startup, - LPPROCESS_INFORMATION info ); - extern void PE_InitTls(void); extern BOOL PE_InitDLL(struct _wine_modref *wm, DWORD type, LPVOID lpReserved); Index: include/process.h =================================================================== RCS file: /home/wine/wine/include/process.h,v retrieving revision 1.45 diff -u -r1.45 process.h --- include/process.h 2000/05/03 18:42:40 1.45 +++ include/process.h 2000/05/05 15:13:28 @@ -153,7 +153,9 @@ extern void ENV_FreeEnvironment( PDB *pdb ); /* scheduler/process.c */ -extern BOOL PROCESS_Init( BOOL win32 ); +extern BOOL PROCESS_Init(void); +extern void PROCESS_InitWine( int argc, char *argv[] ) WINE_NORETURN; +extern void PROCESS_InitWinelib( int argc, char *argv[] ) WINE_NORETURN; extern PDB *PROCESS_IdToPDB( DWORD id ); extern void PROCESS_CallUserSignalProc( UINT uCode, HMODULE hModule ); extern PDB *PROCESS_Create( struct _NE_MODULE *pModule, HFILE hFile, @@ -161,7 +163,7 @@ LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, BOOL inherit, DWORD flags, STARTUPINFOA *startup, PROCESS_INFORMATION *info ); -extern BOOL PROCESS_CreateUnixProcess( LPCSTR filename, LPCSTR cmd_line, LPCSTR env, +extern BOOL PROCESS_CreateUnixProcess( HFILE hFile, LPCSTR filename, LPCSTR cmd_line, +LPCSTR env, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, BOOL inherit, DWORD flags, LPSTARTUPINFOA startup, LPPROCESS_INFORMATION info ); Index: loader/main.c =================================================================== RCS file: /home/wine/wine/loader/main.c,v retrieving revision 1.69 diff -u -r1.69 main.c --- loader/main.c 2000/05/01 16:24:22 1.69 +++ loader/main.c 2000/05/05 15:13:28 @@ -60,19 +60,17 @@ /*********************************************************************** * Main initialisation routine */ -BOOL MAIN_MainInit( int argc, char *argv[], BOOL win32 ) +BOOL MAIN_MainInit( char *argv[] ) { /* store the program name */ argv0 = argv[0]; /* Create the initial process */ - if (!PROCESS_Init( win32 )) return 0; + if (!PROCESS_Init()) return FALSE; - /* Initialize syslevel handling */ - SYSLEVEL_Init(); - /* Parse command line arguments */ - MAIN_WineInit( argc, argv ); + OPTIONS_ParseOptions( argv ); + MAIN_WineInit(); /* Load the configuration file */ if (!PROFILE_LoadWineIni()) return FALSE; Index: loader/module.c =================================================================== RCS file: /home/wine/wine/loader/module.c,v retrieving revision 1.89 diff -u -r1.89 module.c --- loader/module.c 2000/05/01 16:24:23 1.89 +++ loader/module.c 2000/05/05 15:13:30 @@ -39,36 +39,7 @@ DEFAULT_DEBUG_CHANNEL(module); DECLARE_DEBUG_CHANNEL(win32); -/************************************************************************* - * MODULE_WalkModref - * Walk MODREFs for input process ID - */ -void MODULE_WalkModref( DWORD id ) -{ - int i; - WINE_MODREF *zwm, *prev = NULL; - PDB *pdb = PROCESS_IdToPDB( id ); - if (!pdb) { - MESSAGE("Invalid process id (pid)\n"); - return; - } - - MESSAGE("Modref list for process pdb=%p\n", pdb); - MESSAGE("Modref next prev handle deps flags name\n"); - for ( zwm = pdb->modref_list; zwm; zwm = zwm->next) { - MESSAGE("%p %p %p %04x %5d %04x %s\n", zwm, zwm->next, zwm->prev, - zwm->module, zwm->nDeps, zwm->flags, zwm->modname); - for ( i = 0; i < zwm->nDeps; i++ ) { - if ( zwm->deps[i] ) - MESSAGE(" %d %p %s\n", i, zwm->deps[i], zwm->deps[i]->modname); - } - if (prev != zwm->prev) - MESSAGE(" --> modref corrupt, previous pointer wrong!!\n"); - prev = zwm; - } -} - /************************************************************************* * MODULE32_LookupHMODULE * looks for the referenced HMODULE in the current process @@ -502,8 +473,7 @@ * Note that .COM and .PIF files are only recognized by their * file name extension; but Windows does it the same way ... */ -static BOOL MODULE_GetBinaryType( HANDLE hfile, LPCSTR filename, - LPDWORD lpBinaryType ) +BOOL MODULE_GetBinaryType( HANDLE hfile, LPCSTR filename, LPDWORD lpBinaryType ) { IMAGE_DOS_HEADER mz_header; char magic[4], *ptr; @@ -905,6 +875,8 @@ /* Process the AppName and/or CmdLine to get module name and path */ + ERR("app '%s' cmdline '%s'\n", lpApplicationName, lpCommandLine ); + if (!(tidy_cmdline = get_file_name( lpApplicationName, lpCommandLine, name, sizeof(name) ))) return FALSE; @@ -972,8 +944,7 @@ if ( !MODULE_GetBinaryType( hFile, name, &type ) ) { CloseHandle( hFile ); - /* FIXME: Try Unix executable only when appropriate! */ - retv = PROCESS_CreateUnixProcess( name, tidy_cmdline, lpEnvironment, + retv = PROCESS_CreateUnixProcess( -1, name, tidy_cmdline, lpEnvironment, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpStartupInfo, lpProcessInfo ); @@ -985,12 +956,15 @@ switch ( type ) { case SCS_32BIT_BINARY: - retv = PE_CreateProcess( hFile, name, tidy_cmdline, lpEnvironment, - lpProcessAttributes, lpThreadAttributes, - bInheritHandles, dwCreationFlags, - lpStartupInfo, lpProcessInfo ); + case SCS_WOW_BINARY: + case SCS_DOS_BINARY: + retv = PROCESS_CreateUnixProcess( hFile, name, tidy_cmdline, lpEnvironment, + lpProcessAttributes, lpThreadAttributes, + bInheritHandles, dwCreationFlags, + lpStartupInfo, lpProcessInfo ); break; +#if 0 case SCS_DOS_BINARY: retv = MZ_CreateProcess( hFile, name, tidy_cmdline, lpEnvironment, lpProcessAttributes, lpThreadAttributes, @@ -1004,6 +978,7 @@ bInheritHandles, dwCreationFlags, lpStartupInfo, lpProcessInfo ); break; +#endif case SCS_PIF_BINARY: case SCS_POSIX_BINARY: Index: loader/pe_image.c =================================================================== RCS file: /home/wine/wine/loader/pe_image.c,v retrieving revision 1.60 diff -u -r1.60 pe_image.c --- loader/pe_image.c 2000/05/03 18:43:11 1.60 +++ loader/pe_image.c 2000/05/05 15:13:31 @@ -571,6 +571,7 @@ filename, aoep, lowest_va ); +#if 0 /* FIXME: Hack! While we don't really support shared sections yet, * this checks for those special cases where the whole DLL * consists only of shared sections and is mapped into the @@ -598,7 +599,7 @@ return sharedMod; } } - +#endif /* Allocate memory for module */ load_addr = nt->OptionalHeader.ImageBase; @@ -980,53 +981,6 @@ HeapFree( GetProcessHeap(), 0, wm->filename ); HeapFree( GetProcessHeap(), 0, wm->short_filename ); HeapFree( GetProcessHeap(), 0, wm ); -} - -/***************************************************************************** - * Load the PE main .EXE. All other loading is done by PE_LoadLibraryExA - * FIXME: this function should use PE_LoadLibraryExA, but currently can't - * due to the PROCESS_Create stuff. - */ -BOOL PE_CreateProcess( HANDLE hFile, LPCSTR filename, LPCSTR cmd_line, LPCSTR env, - LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, - BOOL inherit, DWORD flags, LPSTARTUPINFOA startup, - LPPROCESS_INFORMATION info ) -{ - HMODULE16 hModule16; - HMODULE hModule32; - NE_MODULE *pModule; - - /* Load file */ - if ( (hModule32 = PE_LoadImage( hFile, filename )) < 32 ) - { - SetLastError( hModule32 ); - return FALSE; - } -#if 0 - if (PE_HEADER(hModule32)->FileHeader.Characteristics & IMAGE_FILE_DLL) - { - SetLastError( 20 ); /* FIXME: not the right error code */ - return FALSE; - } -#endif - - /* Create 16-bit dummy module */ - if ( (hModule16 = MODULE_CreateDummyModule( filename, hModule32 )) < 32 ) - { - SetLastError( hModule16 ); - return FALSE; - } - pModule = (NE_MODULE *)GlobalLock16( hModule16 ); - - /* Create new process */ - if ( !PROCESS_Create( pModule, hFile, cmd_line, env, - psa, tsa, inherit, flags, startup, info ) ) - return FALSE; - - /* Note: PE_CreateModule and the remaining process initialization will - be done in the context of the new process, in TASK_CallToStart */ - - return TRUE; } Index: loader/ne/module.c =================================================================== RCS file: /home/wine/wine/loader/ne/module.c,v retrieving revision 1.67 diff -u -r1.67 module.c --- loader/ne/module.c 2000/04/18 11:58:25 1.67 +++ loader/ne/module.c 2000/05/05 15:13:32 @@ -392,7 +392,7 @@ /*********************************************************************** * NE_LoadExeHeader */ -static HMODULE16 NE_LoadExeHeader( LPCSTR filename ) +HMODULE16 NE_LoadExeHeader( LPCSTR filename ) { IMAGE_DOS_HEADER mz_header; IMAGE_OS2_HEADER ne_header; Index: misc/main.c =================================================================== RCS file: /home/wine/wine/misc/main.c,v retrieving revision 1.65 diff -u -r1.65 main.c --- misc/main.c 2000/04/13 19:29:11 1.65 +++ misc/main.c 2000/05/05 15:13:33 @@ -81,21 +81,6 @@ WORD WINE_LanguageId = 0x409; /* english as default */ -struct options Options = -{ /* default options */ - 0, /* argc */ - NULL, /* argv */ - NULL, /* desktopGeometry */ - NULL, /* display */ - NULL, /* dllFlags */ - FALSE, /* synchronous */ - 0, /* language */ - FALSE, /* Managed windows */ - NULL /* Alternate config file name */ -}; - -const char *argv0; - /*********************************************************************** * MAIN_ParseDebugOptions * @@ -641,7 +626,7 @@ * * Wine initialisation and command-line parsing */ -BOOL MAIN_WineInit( int argc, char *argv[] ) +void MAIN_WineInit(void) { struct timeval tv; @@ -667,10 +652,7 @@ gettimeofday( &tv, NULL); MSG_WineStartTicks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); - OPTIONS_ParseOptions( argc, argv ); - atexit(called_at_exit); - return TRUE; } /*********************************************************************** Index: misc/options.c =================================================================== RCS file: /home/wine/wine/misc/options.c,v retrieving revision 1.4 diff -u -r1.4 options.c --- misc/options.c 2000/04/15 21:00:56 1.4 +++ misc/options.c 2000/05/05 15:13:33 @@ -27,6 +27,20 @@ int _ARGC; char **_ARGV; +/* default options */ +struct options Options = +{ + NULL, /* desktopGeometry */ + NULL, /* display */ + NULL, /* dllFlags */ + FALSE, /* synchronous */ + 0, /* language */ + FALSE, /* Managed windows */ + NULL /* Alternate config file name */ +}; + +const char *argv0; + static void do_config( const char *arg ); static void do_desktop( const char *arg ); static void do_display( const char *arg ); @@ -116,10 +130,9 @@ Options.configFileName = strdup( arg ); } -static inline void remove_options( int *argc, char *argv[], int pos, int count ) +static inline void remove_options( char *argv[], int pos, int count ) { while ((argv[pos] = argv[pos+count])) pos++; - *argc -= count; } /*********************************************************************** @@ -128,7 +141,7 @@ void OPTIONS_Usage(void) { const struct option *opt; - MESSAGE( "Usage: %s [options] \"program_name [arguments]\"\n\n", argv0 ); + MESSAGE( "Usage: %s [options] program_name [arguments]\n\n", argv0 ); MESSAGE( "Options:\n" ); for (opt = option_table; opt->longname; opt++) MESSAGE( " %s\n", opt->usage ); ExitProcess(0); @@ -137,7 +150,7 @@ /*********************************************************************** * OPTIONS_ParseOptions */ -void OPTIONS_ParseOptions( int argc, char *argv[] ) +void OPTIONS_ParseOptions( char *argv[] ) { const struct option *opt; int i; @@ -163,12 +176,12 @@ if (opt->has_arg && argv[i+1]) { opt->func( argv[i+1] ); - remove_options( &argc, argv, i, 2 ); + remove_options( argv, i, 2 ); } else { opt->func( "" ); - remove_options( &argc, argv, i, 1 ); + remove_options( argv, i, 1 ); } i--; } @@ -178,7 +191,7 @@ { if (!strcmp( argv[i], "--" )) { - remove_options( &argc, argv, i, 1 ); + remove_options( argv, i, 1 ); break; } if (argv[i][0] == '-') @@ -187,8 +200,10 @@ OPTIONS_Usage(); } } - Options.argc = argc; - Options.argv = argv; - _ARGC = argc; + + /* count the resulting arguments */ + for (i = 0; argv[i]; i++) ; + + _ARGC = i; _ARGV = argv; } Index: miscemu/main.c =================================================================== RCS file: /home/wine/wine/miscemu/main.c,v retrieving revision 1.45 diff -u -r1.45 main.c --- miscemu/main.c 2000/05/01 21:21:31 1.45 +++ miscemu/main.c 2000/05/05 15:13:33 @@ -3,129 +3,13 @@ * */ -#include <stdlib.h> -#include <assert.h> -#include "wine/winbase16.h" -#include "callback.h" -#include "main.h" -#include "miscemu.h" -#include "module.h" -#include "options.h" #include "process.h" -#include "thread.h" -#include "task.h" -#include "stackframe.h" -#include "wine/exception.h" -#include "debugtools.h" -static BOOL exec_program( LPCSTR cmdline ) -{ - HINSTANCE handle = WinExec( cmdline, SW_SHOWNORMAL ); - if (handle < 32) - { - MESSAGE( "%s: can't exec '%s': ", argv0, cmdline ); - switch (handle) - { - case 2: MESSAGE("file not found\n" ); break; - case 11: MESSAGE("invalid exe file\n" ); break; - default: MESSAGE("error=%d\n", handle ); break; - } - } - return (handle >= 32); -} - -/*********************************************************************** - * Main loop of initial task - */ -void MAIN_EmulatorRun( void ) -{ - char startProg[256], defProg[256]; - int i, tasks = 0; - MSG msg; - char szGraphicsDriver[MAX_PATH]; - - if (PROFILE_GetWineIniString( "Wine", "GraphicsDriver", - "x11drv", szGraphicsDriver, sizeof(szGraphicsDriver))) - { - if (!LoadLibraryA( szGraphicsDriver )) ExitProcess(1); - } - - /* Load system DLLs into the initial process (and initialize them) */ - if ( !LoadLibrary16("GDI.EXE" ) || !LoadLibraryA("GDI32.DLL" ) - || !LoadLibrary16("USER.EXE") || !LoadLibraryA("USER32.DLL")) - ExitProcess( 1 ); - - /* Get pointers to USER routines called by KERNEL */ - THUNK_InitCallout(); - - /* Call FinalUserInit routine */ - Callout.FinalUserInit16(); - - /* Call InitApp for initial task */ - Callout.InitApp16( MapHModuleLS( 0 ) ); - - /* Add the Startup Program to the run list */ - PROFILE_GetWineIniString( "programs", "Startup", "", - startProg, sizeof(startProg) ); - if (startProg[0]) tasks += exec_program( startProg ); - - /* Add the Default Program if no program on the command line */ - if (!Options.argv[1]) - { - PROFILE_GetWineIniString( "programs", "Default", "", - defProg, sizeof(defProg) ); - if (defProg[0]) tasks += exec_program( defProg ); - else if (!tasks && !startProg[0]) OPTIONS_Usage(); - } - else - { - /* Load and run executables given on command line */ - for (i = 1; Options.argv[i]; i++) - { - tasks += exec_program( Options.argv[i] ); - } - } - if (!tasks) ExitProcess( 0 ); - - /* Start message loop for desktop window */ - - while ( GetNumTasks16() > 1 && Callout.GetMessageA( &msg, 0, 0, 0 ) ) - { - Callout.TranslateMessage( &msg ); - Callout.DispatchMessageA( &msg ); - } - - ExitProcess( 0 ); -} - - /********************************************************************** * main */ int main( int argc, char *argv[] ) { - NE_MODULE *pModule; - - /* Initialize everything */ - if (!MAIN_MainInit( argc, argv, FALSE )) return 1; - - if (!THREAD_InitStack( NtCurrentTeb(), 0, TRUE )) return 1; - SIGNAL_Init(); /* reinitialize signal stack */ - - /* Initialize KERNEL */ - if (!LoadLibraryA( "KERNEL32" )) return FALSE; - - /* Create initial task */ - if ( !(pModule = NE_GetPtr( GetModuleHandle16( "KERNEL" ) )) ) return 1; - if ( !TASK_Create( pModule, FALSE ) ) return 1; - - /* Switch to initial task */ - PostEvent16( PROCESS_Current()->task ); - TASK_Reschedule(); - - /* Switch stacks and jump to MAIN_EmulatorRun */ - CALL32_Init( &IF1632_CallLargeStack, MAIN_EmulatorRun, NtCurrentTeb()->stack_top ); - - MESSAGE( "main: Should never happen: returned from CALL32_Init()\n" ); - return 0; + PROCESS_InitWine( argc, argv ); + return 1; /* not reached */ } Index: scheduler/process.c =================================================================== RCS file: /home/wine/wine/scheduler/process.c,v retrieving revision 1.93 diff -u -r1.93 process.c --- scheduler/process.c 2000/05/03 18:42:41 1.93 +++ scheduler/process.c 2000/05/05 15:13:34 @@ -39,6 +39,8 @@ static ENVDB initial_envdb; static STARTUPINFOA initial_startup; +static char **main_exe_argv; +static char main_exe_name[MAX_PATH]; static HFILE main_exe_file = -1; static PDB *PROCESS_First; @@ -258,7 +260,7 @@ /*********************************************************************** * PROCESS_Init */ -BOOL PROCESS_Init( BOOL win32 ) +BOOL PROCESS_Init(void) { struct init_process_request *req; PDB *pdb = PROCESS_Current(); @@ -276,12 +278,6 @@ initial_envdb.startup_info = &initial_startup; PROCESS_First = pdb; - if (!win32) - { - pdb->flags = PDB32_WIN16_PROC; - NtCurrentTeb()->tibflags &= ~TEBF_WIN32; - } - /* Setup the server connection */ NtCurrentTeb()->socket = CLIENT_InitServer(); if (CLIENT_InitThread()) return FALSE; @@ -293,6 +289,7 @@ req->ppid = getppid(); if (server_call( REQ_INIT_PROCESS )) return FALSE; main_exe_file = req->exe_file; + lstrcpynA( main_exe_name, req->filename, sizeof(main_exe_name) ); initial_startup.dwFlags = req->start_flags; initial_startup.wShowWindow = req->cmd_show; initial_envdb.hStdin = initial_startup.hStdInput = req->hstdin; @@ -328,6 +325,9 @@ InitializeCriticalSection( &pdb->crit_section ); InitializeCriticalSection( &initial_envdb.section ); + /* Initialize syslevel handling */ + SYSLEVEL_Init(); + return TRUE; } @@ -337,7 +337,7 @@ * * Load system DLLs into the initial process (and initialize them) */ -static inline int load_system_dlls(void) +static int load_system_dlls(void) { char driver[MAX_PATH]; @@ -355,49 +355,6 @@ if (!LoadLibrary16("USER.EXE")) return 0; if (!LoadLibraryA("USER32.DLL")) return 0; - return 1; -} - - -/*********************************************************************** - * start_process - * - * Startup routine of a new Win32 process. Runs on the new process stack. - */ -static void start_process(void) -{ - struct init_process_done_request *req = get_req_buffer(); - int debugged; - HMODULE16 hModule16; - UINT cmdShow = SW_SHOWNORMAL; - LPTHREAD_START_ROUTINE entry; - PDB *pdb = PROCESS_Current(); - HMODULE main_module = pdb->exe_modref->module; - - /* Increment EXE refcount */ - pdb->exe_modref->refCount++; - - /* Retrieve entry point address */ - entry = (LPTHREAD_START_ROUTINE)RVA_PTR( main_module, OptionalHeader.AddressOfEntryPoint ); - - /* Create 16-bit dummy module */ - if ((hModule16 = MODULE_CreateDummyModule( pdb->exe_modref->filename, main_module )) < 32) - ExitProcess( hModule16 ); - - if (pdb->env_db->startup_info->dwFlags & STARTF_USESHOWWINDOW) - cmdShow = pdb->env_db->startup_info->wShowWindow; - if (!TASK_Create( (NE_MODULE *)GlobalLock16( hModule16 ), cmdShow )) goto error; - - /* Signal the parent process to continue */ - req->module = (void *)main_module; - req->entry = entry; - server_call( REQ_INIT_PROCESS_DONE ); - debugged = req->debugged; - - if (pdb->flags & PDB32_CONSOLE_PROC) AllocConsole(); - - /* Load the system dlls */ - if (!load_system_dlls()) goto error; /* Get pointers to USER routines called by KERNEL */ THUNK_InitCallout(); @@ -413,133 +370,363 @@ * 16-bit stack must be set up, which it is only after TASK_Create * in the case of a 16-bit process. Thus, we send the signal here. */ - PROCESS_CallUserSignalProc( USIG_PROCESS_CREATE, 0 ); PROCESS_CallUserSignalProc( USIG_THREAD_INIT, 0 ); PROCESS_CallUserSignalProc( USIG_PROCESS_INIT, 0 ); PROCESS_CallUserSignalProc( USIG_PROCESS_LOADED, 0 ); - EnterCriticalSection( &pdb->crit_section ); - PE_InitTls(); - MODULE_DllProcessAttach( pdb->exe_modref, (LPVOID)1 ); - LeaveCriticalSection( &pdb->crit_section ); + return 1; +} - /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 apps */ - if (pdb->flags & PDB32_CONSOLE_PROC) - PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 ); - TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry ); - if (debugged) DbgBreakPoint(); - /* FIXME: should use _PEB as parameter for NT 3.5 programs ! - * Dunno about other OSs */ - ExitProcess( entry(NULL) ); +/*********************************************************************** + * build_command_line + * + * Build the command-line of a process from the argv array. + */ +static inline char *build_command_line( char **argv ) +{ + int len, quote; + char *cmdline, *p, **arg; - error: - ExitProcess( GetLastError() ); + for (arg = argv, len = 0; *arg; arg++) len += strlen(*arg) + 1; + if ((quote = (strchr( argv[0], ' ' ) != NULL))) len += 2; + if (!(p = cmdline = HeapAlloc( GetProcessHeap(), 0, len ))) return NULL; + arg = argv; + if (quote) + { + *p++ = '\"'; + strcpy( p, *arg ); + p += strlen(p); + *p++ = '\"'; + *p++ = ' '; + arg++; + } + while (*arg) + { + strcpy( p, *arg ); + p += strlen(p); + *p++ = ' '; + arg++; + } + if (p > cmdline) p--; /* remove last space */ + *p = 0; + return cmdline; } /*********************************************************************** - * PROCESS_Init32 + * start_process * - * Initialisation of a new Win32 process. + * Startup routine of a new Win32 process. Runs on the new process stack. */ -void PROCESS_Init32( HFILE hFile, LPCSTR filename, LPCSTR cmd_line ) +static void start_process(void) { - HMODULE main_module; - PDB *pdb = PROCESS_Current(); + __TRY + { + struct init_process_done_request *req = get_req_buffer(); + int debugged; + HMODULE16 hModule16; + UINT cmdShow = SW_SHOWNORMAL; + LPTHREAD_START_ROUTINE entry; + PDB *pdb = PROCESS_Current(); + HMODULE main_module = pdb->exe_modref->module; + + /* Increment EXE refcount */ + pdb->exe_modref->refCount++; + + /* build command line */ + if (!(pdb->env_db->cmd_line = build_command_line( main_exe_argv ))) goto +error; + + /* Retrieve entry point address */ + entry = (LPTHREAD_START_ROUTINE)RVA_PTR( main_module, +OptionalHeader.AddressOfEntryPoint ); + + /* Create 16-bit dummy module */ + if ((hModule16 = MODULE_CreateDummyModule( pdb->exe_modref->filename, +main_module )) < 32) + ExitProcess( hModule16 ); + + if (pdb->env_db->startup_info->dwFlags & STARTF_USESHOWWINDOW) + cmdShow = pdb->env_db->startup_info->wShowWindow; + if (!TASK_Create( (NE_MODULE *)GlobalLock16( hModule16 ), cmdShow )) goto +error; + + /* Signal the parent process to continue */ + req->module = (void *)main_module; + req->entry = entry; + server_call( REQ_INIT_PROCESS_DONE ); + debugged = req->debugged; + + if (pdb->flags & PDB32_CONSOLE_PROC) AllocConsole(); + + /* Load the system dlls */ + if (!load_system_dlls()) goto error; + + EnterCriticalSection( &pdb->crit_section ); + PE_InitTls(); + MODULE_DllProcessAttach( pdb->exe_modref, (LPVOID)1 ); + LeaveCriticalSection( &pdb->crit_section ); + + /* Call UserSignalProc ( USIG_PROCESS_RUNNING ... ) only for non-GUI win32 +apps */ + if (pdb->flags & PDB32_CONSOLE_PROC) + PROCESS_CallUserSignalProc( USIG_PROCESS_RUNNING, 0 ); + + TRACE_(relay)( "Starting Win32 process (entryproc=%p)\n", entry ); + if (debugged) DbgBreakPoint(); + /* FIXME: should use _PEB as parameter for NT 3.5 programs ! + * Dunno about other OSs */ + ExitProcess( entry(NULL) ); - pdb->env_db->cmd_line = HEAP_strdupA( GetProcessHeap(), 0, cmd_line ); + error: + ExitProcess( GetLastError() ); + } + __EXCEPT(UnhandledExceptionFilter) + { + TerminateThread( GetCurrentThread(), GetExceptionCode() ); + } + __ENDTRY +} + + +/*********************************************************************** + * PROCESS_Start32 + * + * Startup routine of a new Win32 process once the main module has been loaded. + */ +static void PROCESS_Start32( HMODULE main_module, LPCSTR filename ) +{ /* load main module */ - if ((main_module = PE_LoadImage( hFile, filename )) < 32) - ExitProcess( main_module ); -#if 0 if (PE_HEADER(main_module)->FileHeader.Characteristics & IMAGE_FILE_DLL) { - SetLastError( 20 ); /* FIXME: not the right error code */ - goto error; + SetLastError( ERROR_BAD_EXE_FORMAT ); + return; } -#endif /* Create 32-bit MODREF */ - if (!PE_CreateModule( main_module, filename, 0, FALSE )) goto error; + if (!PE_CreateModule( main_module, filename, 0, FALSE )) return; /* allocate main thread stack */ if (!THREAD_InitStack( NtCurrentTeb(), PE_HEADER(main_module)->OptionalHeader.SizeOfStackReserve, TRUE )) - goto error; + return; SIGNAL_Init(); /* reinitialize signal stack */ /* switch to the new stack */ CALL32_Init( &IF1632_CallLargeStack, start_process, NtCurrentTeb()->stack_top ); - error: - ExitProcess( GetLastError() ); } /*********************************************************************** - * PROCESS_InitWinelib + * start_process16 * - * Initialisation of a new Winelib process. + * Startup routine of a new Win16 process. Runs on the new process stack. */ -void PROCESS_InitWinelib( int argc, char *argv[] ) +static void start_process16(void) { - PDB *pdb; - HMODULE main_module; - LPCSTR filename; - LPSTR cmdline, p; - int i, len = 0; + __TRY + { + struct init_process_done_request *req = get_req_buffer(); + UINT cmdShow = SW_SHOWNORMAL; + PDB *pdb = PROCESS_Current(); + NE_MODULE *pModule = NE_GetPtr( pdb->module ); + + pdb->flags |= PDB32_WIN16_PROC; + NtCurrentTeb()->tibflags &= ~TEBF_WIN32; + + /* build command line */ + if (!(pdb->env_db->cmd_line = build_command_line( main_exe_argv ))) goto +error; - if (!MAIN_MainInit( argc, argv, TRUE )) exit(1); - pdb = PROCESS_Current(); + if (pdb->env_db->startup_info->dwFlags & STARTF_USESHOWWINDOW) + cmdShow = pdb->env_db->startup_info->wShowWindow; + if (!TASK_Create( pModule, cmdShow )) goto error; + + /* Signal the parent process to continue */ + req->module = NULL; + req->entry = NULL; + server_call( REQ_INIT_PROCESS_DONE ); - /* build command-line */ - for (i = 0; Options.argv[i]; i++) len += strlen(Options.argv[i]) + 1; - if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, len ))) goto error; - for (p = cmdline, i = 0; Options.argv[i]; i++) + /* Load the system dlls */ + if (!load_system_dlls()) goto error; + + /* Load all process modules */ + if (!NE_InitProcess( pModule )) goto error; + + TRACE_(relay)( "Starting Win16 process\n" ); + TASK_CallToStart(); + + error: + ExitProcess( GetLastError() ); + + } + __EXCEPT(UnhandledExceptionFilter) { - strcpy( p, Options.argv[i] ); - p += strlen(p); - *p++ = ' '; + TerminateThread( GetCurrentThread(), GetExceptionCode() ); } - if (p > cmdline) p--; - *p = 0; - pdb->env_db->cmd_line = cmdline; + __ENDTRY +} - /* create 32-bit module for main exe */ - if ((main_module = BUILTIN32_LoadExeModule( &filename )) < 32 ) goto error; - /* Create 32-bit MODREF */ - if (!PE_CreateModule( main_module, filename, 0, FALSE )) goto error; +/*********************************************************************** + * PROCESS_Start16 + * + * Startup routine of a new Win16 process once the main module has been loaded. + */ +static void PROCESS_Start16( HMODULE16 main_module, LPCSTR filename ) +{ + NE_MODULE *pModule; + + if (!(pModule = NE_GetPtr( main_module )) || (pModule->flags & +NE_FFLAGS_LIBMODULE)) + { + SetLastError( ERROR_BAD_FORMAT ); + return; + } /* allocate main thread stack */ - if (!THREAD_InitStack( NtCurrentTeb(), - PE_HEADER(main_module)->OptionalHeader.SizeOfStackReserve, TRUE )) - goto error; + if (!THREAD_InitStack( NtCurrentTeb(), 0, FALSE )) return; SIGNAL_Init(); /* reinitialize signal stack */ + /* Pass module to new process (FIXME: hack) */ + PROCESS_Current()->module = main_module; + /* switch to the new stack */ - CALL32_Init( &IF1632_CallLargeStack, start_process, NtCurrentTeb()->stack_top ); + CALL32_Init( &IF1632_CallLargeStack, start_process16, NtCurrentTeb()->stack_top ); +} + + +/*********************************************************************** + * PROCESS_InitWine + * + * Wine initialisation: load and start the main exe file. + */ +void PROCESS_InitWine( int argc, char *argv[] ) +{ + DWORD type; + + /* Initialize everything */ + if (!MAIN_MainInit( argv )) exit(1); + + main_exe_argv = ++argv; /* remove argv[0] (wine itself) */ + + if (!main_exe_name[0]) + { + if (!argv[0]) OPTIONS_Usage(); + + /* open the exe file */ + if (!SearchPathA( NULL, argv[0], ".exe", sizeof(main_exe_name), +main_exe_name, NULL ) && + !SearchPathA( NULL, argv[0], NULL, sizeof(main_exe_name), main_exe_name, +NULL )) + { + MESSAGE( "%s: cannot find '%s'\n", argv0, argv[0] ); + goto error; + } + } + + if (main_exe_file == INVALID_HANDLE_VALUE) + { + if ((main_exe_file = CreateFileA( main_exe_name, GENERIC_READ, +FILE_SHARE_READ, + NULL, OPEN_EXISTING, 0, -1 )) == +INVALID_HANDLE_VALUE) + { + MESSAGE( "%s: cannot open '%s'\n", argv0, main_exe_name ); + goto error; + } + } + + if (!MODULE_GetBinaryType( main_exe_file, main_exe_name, &type )) + { + MESSAGE( "%s: unrecognized executable '%s'\n", argv0, main_exe_name ); + goto error; + } + + switch (type) + { + case SCS_32BIT_BINARY: + { + HMODULE main_module = PE_LoadImage( main_exe_file, main_exe_name ); + if (main_module) PROCESS_Start32( main_module, main_exe_name ); + } + break; + + case SCS_WOW_BINARY: + { + HMODULE16 main_module; + + SYSLEVEL_EnterWin16Lock(); + + /* Load module */ + if ((main_module = NE_LoadExeHeader( main_exe_name )) >= 32) + { + MESSAGE("starting win16 process %s\n", main_exe_name ); + PROCESS_Start16( main_module, main_exe_name ); + } + else SetLastError( main_module ); + + SYSLEVEL_LeaveWin16Lock(); + } + break; + + case SCS_DOS_BINARY: + FIXME( "DOS binaries support is broken at the moment; feel free to fix +it...\n" ); + SetLastError( ERROR_BAD_FORMAT ); + break; + + case SCS_PIF_BINARY: + case SCS_POSIX_BINARY: + case SCS_OS216_BINARY: + default: + MESSAGE( "%s: unrecognized executable '%s'\n", argv0, main_exe_name ); + SetLastError( ERROR_BAD_FORMAT ); + break; + } error: ExitProcess( GetLastError() ); } /*********************************************************************** + * PROCESS_InitWinelib + * + * Initialisation of a new Winelib process. + */ +void PROCESS_InitWinelib( int argc, char *argv[] ) +{ + HMODULE main_module; + LPCSTR filename; + + if (!MAIN_MainInit( argv )) exit(1); + + main_exe_argv = argv; + + /* create 32-bit module for main exe */ + if (!(main_module = BUILTIN32_LoadExeModule( &filename ))) ExitProcess( +GetLastError() ); + + PROCESS_Start32( main_module, filename ); + ExitProcess( GetLastError() ); +} + + +/*********************************************************************** * build_argv * * Build an argv array from a command-line. * The command-line is modified to insert nulls. + * 'reserved' is the number of args to reserve before the first one. */ -static char **build_argv( char *cmdline, char *argv0 ) +static char **build_argv( char *cmdline, int reserved ) { char **argv; - int count = 1; + int count = reserved + 1; char *p = cmdline; + /* if first word is quoted store it as a single arg */ + if (*cmdline == '\"') + { + if ((p = strchr( cmdline + 1, '\"' ))) + { + p++; + count++; + } + else p = cmdline; + } while (*p) { while (*p && isspace(*p)) p++; @@ -547,12 +734,20 @@ count++; while (*p && !isspace(*p)) p++; } - if (argv0) count++; + if ((argv = malloc( count * sizeof(*argv) ))) { - char **argvptr = argv; - if (argv0) *argvptr++ = argv0; + char **argvptr = argv + reserved; p = cmdline; + if (*cmdline == '\"') + { + if ((p = strchr( cmdline + 1, '\"' ))) + { + *argvptr++ = cmdline + 1; + *p++ = 0; + } + else p = cmdline; + } while (*p) { while (*p && isspace(*p)) *p++ = 0; @@ -654,7 +849,8 @@ * * Fork and exec a new Unix process, checking for errors. */ -static int fork_and_exec( const char *filename, const char *cmdline, const char *env ) +static int fork_and_exec( const char *filename, const char *cmdline, + const char *env, int use_wine ) { int fd[2]; int pid, err; @@ -667,10 +863,18 @@ fcntl( fd[1], F_SETFD, 1 ); /* set close on exec */ if (!(pid = fork())) /* child */ { - char **argv = build_argv( (char *)cmdline, NULL ); + char **argv = build_argv( (char *)cmdline, use_wine ? 2 : 0 ); char **envp = build_envp( env ); close( fd[0] ); - if (argv && envp) execve( filename, argv, envp ); + if (argv && envp) + { + if (use_wine) + { + argv[1] = "--"; + exec_wine_binary( argv, envp ); + } + else execve( filename, argv, envp ); + } err = errno; write( fd[1], &err, sizeof(err) ); _exit(1); @@ -689,8 +893,12 @@ /*********************************************************************** * PROCESS_CreateUnixProcess + * + * Create a new Unix process. If hFile is a valid handle we have a PE file, + * and then exec a new copy of wine to load it; otherwise we simply exec + * the specified filename. */ -BOOL PROCESS_CreateUnixProcess( LPCSTR filename, LPCSTR cmd_line, LPCSTR env, +BOOL PROCESS_CreateUnixProcess( HFILE hFile, LPCSTR filename, LPCSTR cmd_line, LPCSTR +env, LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa, BOOL inherit, DWORD flags, LPSTARTUPINFOA startup, LPPROCESS_INFORMATION info ) @@ -711,7 +919,7 @@ req->inherit_all = inherit; req->create_flags = flags; req->start_flags = startup->dwFlags; - req->exe_file = -1; + req->exe_file = hFile; if (startup->dwFlags & STARTF_USESTDHANDLES) { req->hstdin = startup->hStdInput; @@ -731,7 +939,8 @@ /* fork and execute */ - pid = fork_and_exec( unixfilename, cmd_line, env ? env : GetEnvironmentStringsA() ); + pid = fork_and_exec( unixfilename, cmd_line, + env ? env : GetEnvironmentStringsA(), (hFile != -1) ); wait_req->cancel = (pid == -1); wait_req->pinherit = (psa && (psa->nLength >= sizeof(*psa)) && psa->bInheritHandle); @@ -1052,9 +1261,7 @@ req->handle = GetCurrentProcess(); req->exit_code = status; server_call( REQ_TERMINATE_PROCESS ); - /* FIXME: need separate address spaces for that */ - /* exit( status ); */ - SYSDEPS_ExitThread( status ); + exit( status ); } /*********************************************************************** @@ -1091,7 +1298,11 @@ DWORD x, y; TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset ); - if ( !process ) return 0; + if ( !process ) + { + ERR("%d: process %lx not accessible\n", offset, dwProcessID); + return 0; + } switch ( offset ) { @@ -1167,7 +1378,11 @@ PDB *process = PROCESS_IdToPDB( dwProcessID ); TRACE_(win32)("(%ld, %d)\n", dwProcessID, offset ); - if ( !process ) return; + if ( !process ) + { + ERR("%d: process %lx not accessible\n", offset, dwProcessID); + return; + } switch ( offset ) {