New loading scheme for Winelib apps, makes them behave like builtin
dlls and takes load order into account. Install them in dlldir.
Improved MODULE_GetBinaryType to recognize ELF binaries.
Added a wrapper script to setup the environment when running directly
from inside the source tree.
diff --git a/scheduler/process.c b/scheduler/process.c
index f192f3b..b6e885c 100644
--- a/scheduler/process.c
+++ b/scheduler/process.c
@@ -36,6 +36,7 @@
#include "drive.h"
#include "module.h"
#include "file.h"
+#include "heap.h"
#include "thread.h"
#include "winerror.h"
#include "wincon.h"
@@ -236,6 +237,118 @@
proc( uCode, GetCurrentProcessId(), dwFlags, hModule );
}
+
+/***********************************************************************
+ * get_basename
+ */
+inline static const char *get_basename( const char *name )
+{
+ char *p;
+
+ if ((p = strrchr( name, '/' ))) name = p + 1;
+ if ((p = strrchr( name, '\\' ))) name = p + 1;
+ return name;
+}
+
+
+/***********************************************************************
+ * open_exe_file
+ *
+ * Open an exe file, taking load order into account.
+ * Returns the file handle or 0 for a builtin exe.
+ */
+static HANDLE open_exe_file( const char *name )
+{
+ enum loadorder_type loadorder[LOADORDER_NTYPES];
+ HANDLE handle;
+ int i;
+
+ SetLastError( ERROR_FILE_NOT_FOUND );
+ MODULE_GetLoadOrder( loadorder, name, TRUE );
+
+ for(i = 0; i < LOADORDER_NTYPES; i++)
+ {
+ if (loadorder[i] == LOADORDER_INVALID) break;
+ switch(loadorder[i])
+ {
+ case LOADORDER_DLL:
+ TRACE( "Trying native exe %s\n", debugstr_a(name) );
+ if ((handle = CreateFileA( name, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE)
+ return handle;
+ if (GetLastError() != ERROR_FILE_NOT_FOUND) return INVALID_HANDLE_VALUE;
+ break;
+ case LOADORDER_BI:
+ TRACE( "Trying built-in exe %s\n", debugstr_a(name) );
+ if (wine_dll_load_main_exe( get_basename(name), NULL, 0, 1 )) return 0;
+ break;
+ default:
+ break;
+ }
+ }
+ return INVALID_HANDLE_VALUE;
+}
+
+
+/***********************************************************************
+ * find_exe_file
+ *
+ * Open an exe file, and return the full name and file handle.
+ * Returns FALSE if file could not be found.
+ * If file exists but cannot be opened, returns TRUE and set handle to INVALID_HANDLE_VALUE.
+ * If file is a builtin exe, returns TRUE and sets handle to 0.
+ */
+static BOOL find_exe_file( const char *name, char *buffer, int buflen, HANDLE *handle )
+{
+ enum loadorder_type loadorder[LOADORDER_NTYPES];
+ int i;
+
+ TRACE("looking for %s\n", debugstr_a(name) );
+
+ if (SearchPathA( NULL, name, ".exe", buflen, buffer, NULL ))
+ {
+ *handle = open_exe_file( buffer );
+ return TRUE;
+ }
+
+ /* no such file in path, try builtin with .exe extension */
+
+ lstrcpynA( buffer, get_basename(name), buflen );
+ if (!strchr( buffer, '.' ))
+ {
+ char *p = buffer + strlen(buffer);
+ lstrcpynA( p, ".exe", buflen - (p - buffer) );
+ }
+
+ MODULE_GetLoadOrder( loadorder, buffer, TRUE );
+ for (i = 0; i < LOADORDER_NTYPES; i++)
+ {
+ if (loadorder[i] == LOADORDER_BI)
+ {
+ TRACE( "Trying built-in exe %s\n", debugstr_a(buffer) );
+ if (wine_dll_load_main_exe( buffer, NULL, 0, 1 ))
+ {
+ *handle = 0;
+ return TRUE;
+ }
+ break;
+ }
+ if (loadorder[i] == LOADORDER_INVALID) break;
+ }
+
+ /* no builtin found, try native without extension in case it is a Unix app */
+
+ if (SearchPathA( NULL, name, NULL, buflen, buffer, NULL ))
+ {
+ TRACE( "Trying native/Unix binary %s\n", debugstr_a(buffer) );
+ if ((*handle = CreateFileA( buffer, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, 0, 0 )) != INVALID_HANDLE_VALUE)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
/***********************************************************************
* process_init
*
@@ -266,16 +379,13 @@
{
req->ldt_copy = &wine_ldt_copy;
req->ppid = getppid();
- wine_server_set_reply( req, main_exe_name, sizeof(main_exe_name)-1 );
if ((ret = !wine_server_call_err( req )))
{
- size_t len = wine_server_reply_size( reply );
- main_exe_name[len] = 0;
- main_exe_file = reply->exe_file;
- main_create_flags = reply->create_flags;
- info_size = reply->info_size;
- info = reply->info;
- server_startticks = reply->server_start;
+ main_exe_file = reply->exe_file;
+ main_create_flags = reply->create_flags;
+ info_size = reply->info_size;
+ info = reply->info;
+ server_startticks = reply->server_start;
current_startupinfo.hStdInput = reply->hstdin;
current_startupinfo.hStdOutput = reply->hstdout;
current_startupinfo.hStdError = reply->hstderr;
@@ -419,112 +529,92 @@
/***********************************************************************
- * open_winelib_app
- *
- * Try to open the Winelib app .so file based on argv[0] or WINEPRELOAD.
- */
-void *open_winelib_app( char *argv[] )
-{
- void *ret = NULL;
- char *tmp;
- const char *name;
- char errStr[100];
-
- if ((name = getenv( "WINEPRELOAD" )))
- {
- if (!(ret = wine_dll_load_main_exe( name, 0, errStr, sizeof(errStr) )))
- {
- MESSAGE( "%s: could not load '%s' as specified in the WINEPRELOAD environment variable: %s\n",
- argv[0], name, errStr );
- ExitProcess(1);
- }
- }
- else
- {
- const char *argv0 = main_exe_name;
- if (!*argv0)
- {
- /* if argv[0] is "wine", don't try to load anything */
- argv0 = argv[0];
- if (!(name = strrchr( argv0, '/' ))) name = argv0;
- else name++;
- if (!strcmp( name, "wine" )) return NULL;
- }
- /* now try argv[0] with ".so" appended */
- if ((tmp = HeapAlloc( GetProcessHeap(), 0, strlen(argv0) + 8 )))
- {
- strcpy( tmp, argv0 );
- strcat( tmp, ".exe.so" );
- /* search in PATH only if there was no '/' in argv[0] */
- ret = wine_dll_load_main_exe( tmp, (name == argv0), errStr, sizeof(errStr) );
- if (!ret && !argv[1] && !main_exe_name[0])
- {
- /* if no argv[1], this will be better than displaying usage */
- MESSAGE( "%s: could not load library '%s' as Winelib application: %s\n",
- argv[0], tmp, errStr );
- ExitProcess(1);
- }
- HeapFree( GetProcessHeap(), 0, tmp );
- }
- }
- return ret;
-}
-
-/***********************************************************************
* PROCESS_InitWine
*
* Wine initialisation: load and start the main exe file.
*/
void PROCESS_InitWine( int argc, char *argv[], LPSTR win16_exe_name, HANDLE *win16_exe_file )
{
+ char error[100];
DWORD stack_size = 0;
/* Initialize everything */
if (!process_init( argv )) exit(1);
- if (open_winelib_app( argv )) goto found; /* try to open argv[0] as a winelib app */
-
argv++; /* remove argv[0] (wine itself) */
+ TRACE( "starting process name=%s file=%x argv[0]=%s\n",
+ debugstr_a(main_exe_name), main_exe_file, debugstr_a(argv[0]) );
+
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))
+ if (!find_exe_file( argv[0], main_exe_name, sizeof(main_exe_name), &main_exe_file ))
{
MESSAGE( "%s: cannot find '%s'\n", argv0, argv[0] );
- goto error;
+ ExitProcess(1);
}
- }
-
- if (!main_exe_file)
- {
- if ((main_exe_file = CreateFileA( main_exe_name, GENERIC_READ, FILE_SHARE_READ,
- NULL, OPEN_EXISTING, 0, 0)) == INVALID_HANDLE_VALUE)
+ if (main_exe_file == INVALID_HANDLE_VALUE)
{
MESSAGE( "%s: cannot open '%s'\n", argv0, main_exe_name );
- goto error;
+ ExitProcess(1);
}
}
- /* first try Win32 format; this will fail if the file is not a PE binary */
- if ((current_process.module = PE_LoadImage( main_exe_file, main_exe_name, 0 )))
+ if (!main_exe_file) /* no file handle -> Winelib app */
{
- if (PE_HEADER(current_process.module)->FileHeader.Characteristics & IMAGE_FILE_DLL)
- ExitProcess( ERROR_BAD_EXE_FORMAT );
- goto found;
+ TRACE( "starting Winelib app %s\n", debugstr_a(main_exe_name) );
+ if (wine_dll_load_main_exe( get_basename(main_exe_name), error, sizeof(error), 0 ))
+ goto found;
+ MESSAGE( "%s: cannot open builtin library for '%s': %s\n", argv0, main_exe_name, error );
+ ExitProcess(1);
}
- /* it must be 16-bit or DOS format */
- NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
- current_process.flags |= PDB32_WIN16_PROC;
- strcpy( win16_exe_name, main_exe_name );
- main_exe_name[0] = 0;
- *win16_exe_file = main_exe_file;
- main_exe_file = 0;
- _EnterWin16Lock();
+ switch( MODULE_GetBinaryType( main_exe_file ))
+ {
+ case BINARY_UNKNOWN:
+ MESSAGE( "%s: cannot determine executable type for '%s'\n", argv0, main_exe_name );
+ ExitProcess(1);
+ case BINARY_PE_EXE:
+ TRACE( "starting Win32 binary %s\n", debugstr_a(main_exe_name) );
+ if ((current_process.module = PE_LoadImage( main_exe_file, main_exe_name, 0 ))) goto found;
+ MESSAGE( "%s: could not load '%s' as Win32 binary\n", argv0, main_exe_name );
+ ExitProcess(1);
+ case BINARY_PE_DLL:
+ MESSAGE( "%s: '%s' is a DLL, not an executable\n", argv0, main_exe_name );
+ ExitProcess(1);
+ case BINARY_WIN16:
+ case BINARY_DOS:
+ TRACE( "starting Win16/DOS binary %s\n", debugstr_a(main_exe_name) );
+ NtCurrentTeb()->tibflags &= ~TEBF_WIN32;
+ current_process.flags |= PDB32_WIN16_PROC;
+ strcpy( win16_exe_name, main_exe_name );
+ main_exe_name[0] = 0;
+ *win16_exe_file = main_exe_file;
+ main_exe_file = 0;
+ _EnterWin16Lock();
+ goto found;
+ case BINARY_OS216:
+ MESSAGE( "%s: '%s' is an OS/2 binary, not supported\n", argv0, main_exe_name );
+ ExitProcess(1);
+ case BINARY_UNIX_EXE:
+ MESSAGE( "%s: '%s' is a Unix binary, not supported\n", argv0, main_exe_name );
+ ExitProcess(1);
+ case BINARY_UNIX_LIB:
+ {
+ DOS_FULL_NAME full_name;
+ const char *name = main_exe_name;
+
+ TRACE( "starting Winelib app %s\n", debugstr_a(main_exe_name) );
+ if (DOSFS_GetFullName( name, TRUE, &full_name )) name = full_name.long_name;
+ CloseHandle( main_exe_file );
+ main_exe_file = 0;
+ if (wine_dlopen( name, RTLD_NOW, error, sizeof(error) )) goto found;
+ MESSAGE( "%s: could not load '%s': %s\n", argv0, main_exe_name, error );
+ ExitProcess(1);
+ }
+ }
found:
/* build command line */
@@ -680,7 +770,6 @@
{
if (memcmp( p, "PATH=", 5 ) &&
memcmp( p, "HOME=", 5 ) &&
- memcmp( p, "WINEPRELOAD=", 12 ) &&
memcmp( p, "WINEPREFIX=", 11 )) *envptr++ = (char *)p;
}
*envptr = 0;
@@ -734,10 +823,6 @@
}
}
free( argv[0] );
-
- /* finally try the current directory */
- argv[0] = "./wine";
- execve( argv[0], argv, envp );
}
@@ -796,43 +881,21 @@
/***********************************************************************
- * PROCESS_Create
+ * create_process
*
* Create a new process. If hFile is a valid handle we have an exe
- * file, and we exec a new copy of wine to load it; otherwise we
- * simply exec the specified filename as a Unix process.
+ * file, otherwise it is a Winelib app.
*/
-BOOL PROCESS_Create( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env,
- LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
- BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
- LPPROCESS_INFORMATION info, LPCSTR lpCurrentDirectory )
+static BOOL create_process( HANDLE hFile, LPCSTR filename, LPSTR cmd_line, LPCSTR env,
+ LPSECURITY_ATTRIBUTES psa, LPSECURITY_ATTRIBUTES tsa,
+ BOOL inherit, DWORD flags, LPSTARTUPINFOA startup,
+ LPPROCESS_INFORMATION info, LPCSTR unixdir )
{
BOOL ret;
- const char *unixfilename = NULL;
- const char *unixdir = NULL;
- DOS_FULL_NAME full_dir, full_name;
HANDLE load_done_evt = 0;
HANDLE process_info;
startup_info_t startup_info;
- info->hThread = info->hProcess = 0;
- info->dwProcessId = info->dwThreadId = 0;
-
- if (lpCurrentDirectory)
- {
- if (DOSFS_GetFullName( lpCurrentDirectory, TRUE, &full_dir ))
- unixdir = full_dir.long_name;
- }
- else
- {
- char buf[MAX_PATH];
- if (GetCurrentDirectoryA(sizeof(buf),buf))
- {
- if (DOSFS_GetFullName( buf, TRUE, &full_dir ))
- unixdir = full_dir.long_name;
- }
- }
-
/* fill the startup info structure */
startup_info.size = sizeof(startup_info);
@@ -874,20 +937,11 @@
req->hstderr = GetStdHandle( STD_ERROR_HANDLE );
}
- if (!hFile) /* unix process */
- {
- unixfilename = filename;
- if (DOSFS_GetFullName( filename, TRUE, &full_name ))
- unixfilename = full_name.long_name;
- nameptr = unixfilename;
- }
- else /* new wine process */
- {
- if (GetLongPathNameA( filename, buf, MAX_PATH ))
- nameptr = buf;
- else
- nameptr = filename;
- }
+ if (GetLongPathNameA( filename, buf, MAX_PATH ))
+ nameptr = buf;
+ else
+ nameptr = filename;
+
startup_info.filename_len = strlen(nameptr);
wine_server_add_data( req, &startup_info, sizeof(startup_info) );
wine_server_add_data( req, nameptr, startup_info.filename_len );
@@ -903,7 +957,7 @@
/* fork and execute */
- if (fork_and_exec( unixfilename, cmd_line, env, unixdir ) == -1)
+ if (fork_and_exec( NULL, cmd_line, env, unixdir ) == -1)
{
CloseHandle( process_info );
return FALSE;
@@ -956,6 +1010,260 @@
}
+/*************************************************************************
+ * get_file_name
+ *
+ * Helper for CreateProcess: retrieve the file name to load from the
+ * app name and command line. Store the file name in buffer, and
+ * return a possibly modified command line.
+ * Also returns a handle to the opened file if it's a Windows binary.
+ */
+static LPSTR get_file_name( LPCSTR appname, LPSTR cmdline, LPSTR buffer,
+ int buflen, HANDLE *handle )
+{
+ char *name, *pos, *ret = NULL;
+ const char *p;
+
+ /* if we have an app name, everything is easy */
+
+ if (appname)
+ {
+ /* use the unmodified app name as file name */
+ lstrcpynA( buffer, appname, buflen );
+ *handle = open_exe_file( buffer );
+ if (!(ret = cmdline))
+ {
+ /* no command-line, create one */
+ if ((ret = HeapAlloc( GetProcessHeap(), 0, strlen(appname) + 3 )))
+ sprintf( ret, "\"%s\"", appname );
+ }
+ return ret;
+ }
+
+ if (!cmdline)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return NULL;
+ }
+
+ /* first check for a quoted file name */
+
+ if ((cmdline[0] == '"') && ((p = strchr( cmdline + 1, '"' ))))
+ {
+ int len = p - cmdline - 1;
+ /* extract the quoted portion as file name */
+ if (!(name = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) return NULL;
+ memcpy( name, cmdline + 1, len );
+ name[len] = 0;
+
+ if (find_exe_file( name, buffer, buflen, handle ))
+ ret = cmdline; /* no change necessary */
+ goto done;
+ }
+
+ /* now try the command-line word by word */
+
+ if (!(name = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + 1 ))) return NULL;
+ pos = name;
+ p = cmdline;
+
+ while (*p)
+ {
+ do *pos++ = *p++; while (*p && *p != ' ');
+ *pos = 0;
+ if (find_exe_file( name, buffer, buflen, handle ))
+ {
+ ret = cmdline;
+ break;
+ }
+ }
+
+ if (!ret || !strchr( name, ' ' )) goto done; /* no change necessary */
+
+ /* now build a new command-line with quotes */
+
+ if (!(ret = HeapAlloc( GetProcessHeap(), 0, strlen(cmdline) + 3 ))) goto done;
+ sprintf( ret, "\"%s\"%s", name, p );
+
+ done:
+ HeapFree( GetProcessHeap(), 0, name );
+ return ret;
+}
+
+
+/**********************************************************************
+ * CreateProcessA (KERNEL32.@)
+ */
+BOOL WINAPI CreateProcessA( LPCSTR app_name, LPSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
+ LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit,
+ DWORD flags, LPVOID env, LPCSTR cur_dir,
+ LPSTARTUPINFOA startup_info, LPPROCESS_INFORMATION info )
+{
+ BOOL retv = FALSE;
+ HANDLE hFile = 0;
+ const char *unixdir = NULL;
+ DOS_FULL_NAME full_dir;
+ char name[MAX_PATH];
+ LPSTR tidy_cmdline;
+
+ /* Process the AppName and/or CmdLine to get module name and path */
+
+ TRACE("app %s cmdline %s\n", debugstr_a(app_name), debugstr_a(cmd_line) );
+
+ if (!(tidy_cmdline = get_file_name( app_name, cmd_line, name, sizeof(name), &hFile )))
+ return FALSE;
+ if (hFile == INVALID_HANDLE_VALUE) goto done;
+
+ /* Warn if unsupported features are used */
+
+ if (flags & NORMAL_PRIORITY_CLASS)
+ FIXME("(%s,...): NORMAL_PRIORITY_CLASS ignored\n", name);
+ if (flags & IDLE_PRIORITY_CLASS)
+ FIXME("(%s,...): IDLE_PRIORITY_CLASS ignored\n", name);
+ if (flags & HIGH_PRIORITY_CLASS)
+ FIXME("(%s,...): HIGH_PRIORITY_CLASS ignored\n", name);
+ if (flags & REALTIME_PRIORITY_CLASS)
+ FIXME("(%s,...): REALTIME_PRIORITY_CLASS ignored\n", name);
+ if (flags & CREATE_NEW_PROCESS_GROUP)
+ FIXME("(%s,...): CREATE_NEW_PROCESS_GROUP ignored\n", name);
+ if (flags & CREATE_UNICODE_ENVIRONMENT)
+ FIXME("(%s,...): CREATE_UNICODE_ENVIRONMENT ignored\n", name);
+ if (flags & CREATE_SEPARATE_WOW_VDM)
+ FIXME("(%s,...): CREATE_SEPARATE_WOW_VDM ignored\n", name);
+ if (flags & CREATE_SHARED_WOW_VDM)
+ FIXME("(%s,...): CREATE_SHARED_WOW_VDM ignored\n", name);
+ if (flags & CREATE_DEFAULT_ERROR_MODE)
+ FIXME("(%s,...): CREATE_DEFAULT_ERROR_MODE ignored\n", name);
+ if (flags & CREATE_NO_WINDOW)
+ FIXME("(%s,...): CREATE_NO_WINDOW ignored\n", name);
+ if (flags & PROFILE_USER)
+ FIXME("(%s,...): PROFILE_USER ignored\n", name);
+ if (flags & PROFILE_KERNEL)
+ FIXME("(%s,...): PROFILE_KERNEL ignored\n", name);
+ if (flags & PROFILE_SERVER)
+ FIXME("(%s,...): PROFILE_SERVER ignored\n", name);
+ if (startup_info->lpDesktop)
+ FIXME("(%s,...): startup_info->lpDesktop %s ignored\n",
+ name, debugstr_a(startup_info->lpDesktop));
+ if (startup_info->dwFlags & STARTF_RUNFULLSCREEN)
+ FIXME("(%s,...): STARTF_RUNFULLSCREEN ignored\n", name);
+ if (startup_info->dwFlags & STARTF_FORCEONFEEDBACK)
+ FIXME("(%s,...): STARTF_FORCEONFEEDBACK ignored\n", name);
+ if (startup_info->dwFlags & STARTF_FORCEOFFFEEDBACK)
+ FIXME("(%s,...): STARTF_FORCEOFFFEEDBACK ignored\n", name);
+ if (startup_info->dwFlags & STARTF_USEHOTKEY)
+ FIXME("(%s,...): STARTF_USEHOTKEY ignored\n", name);
+
+ if (cur_dir)
+ {
+ if (DOSFS_GetFullName( cur_dir, TRUE, &full_dir ))
+ unixdir = full_dir.long_name;
+ }
+ else
+ {
+ char buf[MAX_PATH];
+ if (GetCurrentDirectoryA(sizeof(buf),buf))
+ {
+ if (DOSFS_GetFullName( buf, TRUE, &full_dir )) unixdir = full_dir.long_name;
+ }
+ }
+
+ info->hThread = info->hProcess = 0;
+ info->dwProcessId = info->dwThreadId = 0;
+
+ /* Determine executable type */
+
+ if (!hFile) /* builtin exe */
+ {
+ TRACE( "starting %s as Winelib app\n", debugstr_a(name) );
+ retv = create_process( 0, name, tidy_cmdline, env, process_attr, thread_attr,
+ inherit, flags, startup_info, info, unixdir );
+ goto done;
+ }
+
+ switch( MODULE_GetBinaryType( hFile ))
+ {
+ case BINARY_PE_EXE:
+ case BINARY_WIN16:
+ case BINARY_DOS:
+ TRACE( "starting %s as Windows binary\n", debugstr_a(name) );
+ retv = create_process( hFile, name, tidy_cmdline, env, process_attr, thread_attr,
+ inherit, flags, startup_info, info, unixdir );
+ break;
+ case BINARY_OS216:
+ FIXME( "%s is OS/2 binary, not supported\n", debugstr_a(name) );
+ SetLastError( ERROR_BAD_EXE_FORMAT );
+ break;
+ case BINARY_PE_DLL:
+ TRACE( "not starting %s since it is a dll\n", debugstr_a(name) );
+ SetLastError( ERROR_BAD_EXE_FORMAT );
+ break;
+ case BINARY_UNIX_LIB:
+ TRACE( "%s is a Unix library, starting as Winelib app\n", debugstr_a(name) );
+ retv = create_process( hFile, name, tidy_cmdline, env, process_attr, thread_attr,
+ inherit, flags, startup_info, info, unixdir );
+ break;
+ case BINARY_UNIX_EXE:
+ case BINARY_UNKNOWN:
+ {
+ /* unknown file, try as unix executable */
+
+ DOS_FULL_NAME full_name;
+ const char *unixfilename = name;
+
+ TRACE( "starting %s as Unix binary\n", debugstr_a(name) );
+ if (DOSFS_GetFullName( name, TRUE, &full_name )) unixfilename = full_name.long_name;
+ retv = (fork_and_exec( unixfilename, tidy_cmdline, env, unixdir ) != -1);
+ }
+ break;
+ }
+ CloseHandle( hFile );
+
+ done:
+ if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
+ return retv;
+}
+
+
+/**********************************************************************
+ * CreateProcessW (KERNEL32.@)
+ * NOTES
+ * lpReserved is not converted
+ */
+BOOL WINAPI CreateProcessW( LPCWSTR app_name, LPWSTR cmd_line, LPSECURITY_ATTRIBUTES process_attr,
+ LPSECURITY_ATTRIBUTES thread_attr, BOOL inherit, DWORD flags,
+ LPVOID env, LPCWSTR cur_dir, LPSTARTUPINFOW startup_info,
+ LPPROCESS_INFORMATION info )
+{
+ BOOL ret;
+ STARTUPINFOA StartupInfoA;
+
+ LPSTR app_nameA = HEAP_strdupWtoA (GetProcessHeap(),0,app_name);
+ LPSTR cmd_lineA = HEAP_strdupWtoA (GetProcessHeap(),0,cmd_line);
+ LPSTR cur_dirA = HEAP_strdupWtoA (GetProcessHeap(),0,cur_dir);
+
+ memcpy (&StartupInfoA, startup_info, sizeof(STARTUPINFOA));
+ StartupInfoA.lpDesktop = HEAP_strdupWtoA (GetProcessHeap(),0,startup_info->lpDesktop);
+ StartupInfoA.lpTitle = HEAP_strdupWtoA (GetProcessHeap(),0,startup_info->lpTitle);
+
+ TRACE_(win32)("(%s,%s,...)\n", debugstr_w(app_name), debugstr_w(cmd_line));
+
+ if (startup_info->lpReserved)
+ FIXME_(win32)("StartupInfo.lpReserved is used, please report (%s)\n",
+ debugstr_w(startup_info->lpReserved));
+
+ ret = CreateProcessA( app_nameA, cmd_lineA, process_attr, thread_attr,
+ inherit, flags, env, cur_dirA, &StartupInfoA, info );
+
+ HeapFree( GetProcessHeap(), 0, cur_dirA );
+ HeapFree( GetProcessHeap(), 0, cmd_lineA );
+ HeapFree( GetProcessHeap(), 0, StartupInfoA.lpDesktop );
+ HeapFree( GetProcessHeap(), 0, StartupInfoA.lpTitle );
+
+ return ret;
+}
+
+
/***********************************************************************
* ExitProcess (KERNEL32.@)
*/