[PATCH v3 0/3] MR11608: cmd: Implement start command as a builtin
Mostly the code is just copied from start.exe implementation, there are some modifications to prevent some dynamically allocated strings from being leaked. Mostly I tried to use static size arrays as much as possible. -- v3: cmd: Implement start builtin inside cmd. https://gitlab.winehq.org/wine/wine/-/merge_requests/11608
From: Santino Mazza <smazza@codeweavers.com> --- programs/cmd/tests/test_builtins.bat | 1 + programs/cmd/tests/test_builtins.bat.exp | 1 + programs/cmd/tests/test_builtins.cmd | 1 + programs/cmd/tests/test_builtins.cmd.exp | 1 + 4 files changed, 4 insertions(+) diff --git a/programs/cmd/tests/test_builtins.bat b/programs/cmd/tests/test_builtins.bat index 7711aa917e3..73a76e7d585 100644 --- a/programs/cmd/tests/test_builtins.bat +++ b/programs/cmd/tests/test_builtins.bat @@ -96,6 +96,7 @@ mkdir foo & cd foo set "FOO_PATH=%cd%" > NUL cd .. call :setError 666 & (start /B /WAIT /d "%FOO_PATH%" cmd /s /c "if /I \"%%cd%%\"==\"%FOO_PATH%\" (exit 0) else (exit 1)" >nul &&echo !errorlevel!) +call :setError 666 & (start /B /WAIT /D"C:\"/bad cmd.exe /c "exit /b 1024" >NUL &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!) rd /q /s foo echo --- success/failure for TYPE command mkdir foo & cd foo diff --git a/programs/cmd/tests/test_builtins.bat.exp b/programs/cmd/tests/test_builtins.bat.exp index 77ca71c8778..4952fe4dda3 100644 --- a/programs/cmd/tests/test_builtins.bat.exp +++ b/programs/cmd/tests/test_builtins.bat.exp @@ -63,6 +63,7 @@ foo@space@ SUCCESS 1024 @todo_wine@SUCCESS 666 0 +@todo_wine@FAILURE 1 --- success/failure for TYPE command FAILURE 1 SUCCESS 0 diff --git a/programs/cmd/tests/test_builtins.cmd b/programs/cmd/tests/test_builtins.cmd index 4ca987a8b05..cdb92a150ea 100644 --- a/programs/cmd/tests/test_builtins.cmd +++ b/programs/cmd/tests/test_builtins.cmd @@ -679,6 +679,7 @@ mkdir foo & cd foo set "FOO_PATH=%cd%" > NUL cd .. call :setError 666 & (start /B /WAIT /d "%FOO_PATH%" cmd /s /c "if /I \"%%cd%%\"==\"%FOO_PATH%\" (exit 0) else (exit 1)" >nul &&echo !errorlevel!) +call :setError 666 & (start /B /WAIT /D"C:\"/bad cmd.exe /c "exit /b 1024" >NUL &&echo SUCCESS !errorlevel!||echo FAILURE !errorlevel!) rd /q /s foo echo --- success/failure for TYPE command mkdir foo & cd foo diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index c7015c61b7a..d2f076a2dc7 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -582,6 +582,7 @@ foo@space@ SUCCESS 1024 @todo_wine@SUCCESS 666 0 +@todo_wine@FAILURE 1 --- success/failure for TYPE command FAILURE 1 SUCCESS 0 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11608
From: Santino Mazza <smazza@codeweavers.com> --- programs/cmd/wcmd.h | 11 +++++++++++ programs/cmd/wcmdmain.c | 19 +++++-------------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index c8d0d03e9e6..dd912ea33c7 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -233,6 +233,17 @@ enum read_parse_line WCMD_ReadAndParseLine(CMD_NODE **output); void node_dispose_tree(CMD_NODE *cmds); RETURN_CODE node_execute(CMD_NODE *node); +struct search_command +{ + WCHAR path[MAX_PATH]; + BOOL has_path; /* if input has path part (ie cannot be a builtin command) */ + BOOL has_extension; /* if extension was given to input */ + BOOL is_command_file; /* when has_path is set, tells whether its a command file, or an external executable */ + int cmd_index; /* potential index to builtin command */ +}; + +RETURN_CODE WCMD_search_command(WCHAR *command, struct search_command *sc, BOOL fast); + RETURN_CODE WCMD_call_batch(const WCHAR *, WCHAR *); RETURN_CODE WCMD_call_command(WCHAR *command); RETURN_CODE WCMD_run_builtin_command(int cmd_index, WCHAR *cmd); diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 511d181c117..7f47a69b57c 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -1885,15 +1885,6 @@ static RETURN_CODE run_command_file(const WCHAR *file, WCHAR *full_cmdline) return return_code; } -struct search_command -{ - WCHAR path[MAX_PATH]; - BOOL has_path; /* if input has path part (ie cannot be a builtin command) */ - BOOL has_extension; /* if extension was given to input */ - BOOL is_command_file; /* when has_path is set, tells whether its a command file, or an external executable */ - int cmd_index; /* potential index to builtin command */ -}; - static BOOL search_in_pathext(WCHAR *path) { static struct @@ -1972,7 +1963,7 @@ static BOOL search_in_pathext(WCHAR *path) return TRUE; } -static RETURN_CODE search_command(WCHAR *command, struct search_command *sc, BOOL fast) +RETURN_CODE WCMD_search_command(WCHAR *command, struct search_command *sc, BOOL fast) { WCHAR temp[MAX_PATH]; WCHAR pathtosearch[MAXSTRING]; @@ -2407,7 +2398,7 @@ static RETURN_CODE execute_single_command(const WCHAR *command) TRACE("Command: '%s'\n", wine_dbgstr_w(cmd)); - return_code = search_command(cmd, &sc, TRUE); + return_code = WCMD_search_command(cmd, &sc, TRUE); if (return_code != NO_ERROR && sc.cmd_index == WCMD_EXIT + 1) { /* Not found anywhere - give up */ @@ -2459,7 +2450,7 @@ RETURN_CODE WCMD_call_command(WCHAR *command) struct search_command sc; RETURN_CODE return_code; - return_code = search_command(command, &sc, FALSE); + return_code = WCMD_search_command(command, &sc, FALSE); if (return_code == NO_ERROR) { if (!*sc.path) return NO_ERROR; @@ -4519,7 +4510,7 @@ static RETURN_CODE spawn_pipe_sub_command(CMD_NODE *node, HANDLE *child) struct search_command sc; /* command isn't delayed expanded... */ - return_code = search_command(node->command, &sc, TRUE); + return_code = WCMD_search_command(node->command, &sc, TRUE); if (return_code != NO_ERROR && sc.cmd_index == WCMD_EXIT + 1) return RETURN_CODE_CANT_LAUNCH; if ((sc.cmd_index <= WCMD_EXIT && (return_code != NO_ERROR || (!sc.has_path && !sc.has_extension))) || @@ -4902,7 +4893,7 @@ static void parse_command_line_parameters(struct cmd_parameters *parameters) { struct search_command sc; - if (search_command(parameters->initial_command, &sc, TRUE) != NO_ERROR) /* no command found */ + if (WCMD_search_command(parameters->initial_command, &sc, TRUE) != NO_ERROR) /* no command found */ { WINE_TRACE("Binary not found, dropping back to old behaviour\n"); opt_s = TRUE; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11608
From: Santino Mazza <smazza@codeweavers.com> --- programs/cmd/builtins.c | 333 ++++++++++++++++------- programs/cmd/cmd.rc | 1 + programs/cmd/tests/test_builtins.bat.exp | 4 +- programs/cmd/tests/test_builtins.cmd.exp | 4 +- programs/cmd/wcmd.h | 1 + 5 files changed, 237 insertions(+), 106 deletions(-) diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index b706feb39c7..d8cc545d00f 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -3292,129 +3292,258 @@ RETURN_CODE WCMD_shift(const WCHAR *args) /**************************************************************************** * WCMD_start + * + * Start a program with ShellExecute. + * + * Big part of the code is just copied from programs/start/start.c + * This implementation doesn't contain Wine-specific extensions. */ RETURN_CODE WCMD_start(WCHAR *args) { RETURN_CODE return_code = NO_ERROR; - int argno; - int have_title; - WCHAR file[MAX_PATH]; - WCHAR *cmdline, *cmdline_params; - STARTUPINFOW st; - PROCESS_INFORMATION pi; - - GetSystemDirectoryW( file, MAX_PATH ); - lstrcatW(file, L"\\start.exe"); - cmdline = xalloc( (wcslen(file) + wcslen(args) + 8) * sizeof(WCHAR) ); - lstrcpyW( cmdline, file ); - lstrcatW(cmdline, L" "); - cmdline_params = cmdline + lstrlenW(cmdline); - - /* The start built-in has some special command-line parsing properties - * which will be outlined here. - * - * both '\t' and ' ' are argument separators - * '/' has a special double role as both separator and switch prefix, e.g. - * - * > start /low/i - * or - * > start "title"/i - * - * are valid ways to pass multiple options to start. In the latter case - * '/i' is not a part of the title but parsed as a switch. - * - * However, '=', ';' and ',' are not separators: - * > start "deus"=ex,machina - * - * will in fact open a console titled 'deus=ex,machina' - * - * The title argument parsing code is only interested in quotes themselves, - * it does not respect escaping of any kind and all quotes are dropped - * from the resulting title, therefore: - * - * > start "\"" hello"/low - * - * actually opens a console titled '\ hello' with low priorities. - * - * To not break compatibility with wine programs relying on - * wine's separate 'start.exe', this program's peculiar console - * title parsing is actually implemented in 'cmd.exe' which is the - * application native Windows programs will use to invoke 'start'. - * - * WCMD_parameter_with_delims will take care of everything for us. - */ - /* FIXME: using an external start.exe has several caveats: - * - cannot discriminate syntax error in arguments from child's return code - * - need to access start.exe's child to get its running state - * (not start.exe itself) - */ - have_title = FALSE; - for (argno=0; ; argno++) { - WCHAR *thisArg, *argN; + DWORD binary_type, creation_flags; + int argn = 0; + SHELLEXECUTEINFOW sei = { 0 }; + USHORT machine = 0; + WCHAR *thisparam, *rawarg, *qual; + WCHAR path_argument[MAXSTRING] = L"cmd.exe"; /* the path parameter can also be a URL which can be larger than MAX_PATH. */ + WCHAR lpDirectory[MAX_PATH] = L""; + WCHAR *title = NULL; + struct search_command sc; + + sei.cbSize = sizeof(sei); + sei.lpVerb = L"open"; + sei.nShow = SW_SHOWNORMAL; + /* Dunno what these mean, but it looks like winMe's start uses them */ + sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI; + creation_flags = CREATE_NEW_CONSOLE; + + while (!!(thisparam = WCMD_parameter(args, argn, &rawarg, FALSE, FALSE)) && !!rawarg) + { + if (!title && rawarg[0] == '"') + { + title = wcsdup(thisparam); + argn++; + continue; + } - argN = NULL; - thisArg = WCMD_parameter_with_delims(args, argno, &argN, FALSE, FALSE, L" \t/"); + if (rawarg[0] != '/') break; - /* No more parameters */ - if (!argN) - break; + qual = wcstok(thisparam, L"/", NULL); + while (qual) + { + /* Qualifiers with values just break the loop. */ + if (towupper(*qual) == 'D') + { + WCHAR *dir = ++qual; - /* Found the title */ - if (argN[0] == '"') { - TRACE("detected console title: %s\n", wine_dbgstr_w(thisArg)); - have_title = TRUE; + if (!*dir && !*(dir = WCMD_parameter(args, ++argn, &rawarg, FALSE, FALSE))) + WINE_ERR("you must specify a directory path for the /d option\n"); - /* Copy all of the cmdline processed */ - memcpy(cmdline_params, args, sizeof(WCHAR) * (argN - args)); - cmdline_params[argN - args] = '\0'; + if (!WCMD_get_fullpath(dir, ARRAY_SIZE(lpDirectory), lpDirectory, NULL)) + goto error; - /* Add quoted title */ - lstrcatW(cmdline_params, L"\"\\\""); - lstrcatW(cmdline_params, thisArg); - lstrcatW(cmdline_params, L"\\\"\""); + TRACE("%s\n", wine_dbgstr_w(lpDirectory)); - /* Concatenate remaining command-line */ - thisArg = WCMD_parameter_with_delims(args, argno, &argN, TRUE, FALSE, L" \t/"); - lstrcatW(cmdline_params, argN + lstrlenW(thisArg)); + sei.lpDirectory = lpDirectory; + break; + } + else if (towupper(*qual) == 'B') + creation_flags &= ~CREATE_NEW_CONSOLE; + else if (towupper(*qual) == 'I') + FIXME("/i is ignored\n"); /* FIXME */ + else if (!_wcsicmp(qual, L"MIN")) + sei.nShow = SW_SHOWMINIMIZED; + else if (!_wcsicmp(qual, L"MAX")) + sei.nShow = SW_SHOWMAXIMIZED; + else if (!_wcsicmp(qual, L"LOW")) + creation_flags |= IDLE_PRIORITY_CLASS; + else if (!_wcsicmp(qual, L"NORMAL")) + creation_flags |= NORMAL_PRIORITY_CLASS; + else if (!_wcsicmp(qual, L"HIGH")) + creation_flags |= HIGH_PRIORITY_CLASS; + else if (!_wcsicmp(qual, L"REALTIME")) + creation_flags |= REALTIME_PRIORITY_CLASS; + else if (!_wcsicmp(qual, L"ABOVENORMAL")) + creation_flags |= ABOVE_NORMAL_PRIORITY_CLASS; + else if (!_wcsicmp(qual, L"BELOWNORMAL")) + creation_flags |= BELOW_NORMAL_PRIORITY_CLASS; + else if (!_wcsicmp(qual, L"SEPARATE")) + creation_flags |= CREATE_SEPARATE_WOW_VDM; + else if (!_wcsicmp(qual, L"SHARED")) + creation_flags |= CREATE_SHARED_WOW_VDM; + else if (towupper(*qual) == 'W' || !_wcsicmp(qual, L"WAIT")) + sei.fMask |= SEE_MASK_NOCLOSEPROCESS; + else if (!_wcsicmp(qual, L"NODE")) + FIXME("start /node is ignored\n"); /* FIXME */ + else if (!_wcsicmp(qual, L"AFFINITY")) + { + if (!*(thisparam = WCMD_parameter(args, ++argn, &rawarg, FALSE, FALSE))) + { + SetLastError(return_code = ERROR_INVALID_PARAMETER); + WCMD_print_error(); + goto error; + } + FIXME("start /affinity is ignored\n"); /* FIXME */ + break; + } + else if (!_wcsicmp(qual, L"MACHINE")) + { + if (!*(thisparam = WCMD_parameter(args, ++argn, &rawarg, FALSE, FALSE))) + { + SetLastError(return_code = ERROR_INVALID_PARAMETER); + WCMD_print_error(); + goto error; + } - break; - } + if (!_wcsicmp( thisparam, L"x86" )) machine = IMAGE_FILE_MACHINE_I386; + else if (!_wcsicmp( thisparam, L"amd64" )) machine = IMAGE_FILE_MACHINE_AMD64; + else if (!_wcsicmp( thisparam, L"arm" )) machine = IMAGE_FILE_MACHINE_ARMNT; + else if (!_wcsicmp( thisparam, L"arm64" )) machine = IMAGE_FILE_MACHINE_ARM64; + else + { + SetLastError(return_code = ERROR_INVALID_PARAMETER); + WCMD_print_error(); + goto error; + } + break; + } + else + { + TRACE("Error %s\n", wine_dbgstr_w(thisparam)); + SetLastError(return_code = ERROR_INVALID_PARAMETER); + WCMD_print_error(); + goto error; + } - /* Skipping a regular argument? */ - else if (argN != args && argN[-1] == '/') { - continue; + qual = wcstok(NULL, L"/", NULL); + } - /* Not an argument nor the title, start of program arguments, - * stop looking for title. - */ - } else - break; + argn++; } - /* build command-line if not built yet */ - if (!have_title) { - lstrcatW( cmdline, args ); - } + thisparam = WCMD_parameter(args, argn, &rawarg, FALSE, FALSE); + if (*(thisparam)) + wcscpy(path_argument, thisparam); + + if (*(thisparam = WCMD_parameter(args, ++argn, &rawarg, FALSE, FALSE))) + sei.lpParameters = rawarg; + else + sei.lpParameters = L""; - memset( &st, 0, sizeof(STARTUPINFOW) ); - st.cb = sizeof(STARTUPINFOW); + if (WCMD_search_command(path_argument, &sc, FALSE) == NO_ERROR) + sei.lpFile = sc.path; + else sei.lpFile = path_argument; - if (CreateProcessW( file, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &st, &pi )) + if (GetBinaryTypeW(sei.lpFile, &binary_type)) { - DWORD exit_code; - WaitForSingleObject( pi.hProcess, INFINITE ); - GetExitCodeProcess( pi.hProcess, &exit_code ); - errorlevel = (exit_code == STILL_ACTIVE) ? NO_ERROR : exit_code; - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); + WCHAR *commandline; + PROCESS_INFORMATION process_information; + BOOL ret; + STARTUPINFOEXW si = {{ sizeof(si.StartupInfo) }}; + struct _PROC_THREAD_ATTRIBUTE_LIST *attribute_list = NULL; + int len = lstrlenW(sei.lpFile) + 4 + lstrlenW(sei.lpParameters); + + /* explorer on windows always quotes the filename when running a binary on windows (see bug 5224) so we have to use CreateProcessW in this case */ + + if (machine) + { + SIZE_T size = 1024; + attribute_list = malloc( size ); + InitializeProcThreadAttributeList( attribute_list, 1, 0, &size ); + UpdateProcThreadAttribute( attribute_list, 0, PROC_THREAD_ATTRIBUTE_MACHINE_TYPE, &machine, sizeof(machine), NULL, NULL ); + si.StartupInfo.cb = sizeof(si); + si.lpAttributeList = attribute_list; + creation_flags |= EXTENDED_STARTUPINFO_PRESENT; + } + + commandline = malloc(len * sizeof(WCHAR)); + swprintf(commandline, len, L"\"%s\" %s", path_argument, sei.lpParameters); + + si.StartupInfo.wShowWindow = sei.nShow; + si.StartupInfo.dwFlags |= STARTF_USESHOWWINDOW; + si.StartupInfo.lpTitle = title; + + ret = CreateProcessW( sei.lpFile, commandline, NULL, NULL, FALSE, + creation_flags, NULL, sei.lpDirectory, + &si.StartupInfo, &process_information ); + free(attribute_list); + free(commandline); + if (!ret) + { + ERR("failed to create process %ld\n", GetLastError()); + return_code = GetLastError(); + goto error; + } + sei.hProcess = process_information.hProcess; } - else + else if (!ShellExecuteExW(&sei)) { - SetLastError(ERROR_FILE_NOT_FOUND); - WCMD_print_error (); - return_code = errorlevel = ERROR_INVALID_FUNCTION; + const WCHAR *filename = sei.lpFile; + DWORD size, filename_len; + WCHAR pathext[MAX_PATH]; + WCHAR *name; + + size = GetEnvironmentVariableW(L"PATHEXT", pathext, ARRAY_SIZE(pathext)); + if (size) + { + WCHAR *start, *ptr; + + filename_len = lstrlenW(filename); + name = malloc((filename_len + size) * sizeof(WCHAR)); + if (!name) + { + return_code = ERROR_OUTOFMEMORY; + goto error; + } + + sei.lpFile = name; + start = pathext; + return_code = ERROR_FILE_NOT_FOUND; + while ((ptr = wcschr(start, ';'))) + { + if (start == ptr) + { + start = ptr + 1; + continue; + } + + lstrcpyW(name, filename); + memcpy(&name[filename_len], start, (ptr - start) * sizeof(WCHAR)); + name[filename_len + (ptr - start)] = 0; + + if (ShellExecuteExW(&sei)) { + return_code = NO_ERROR; + break; + } + start = ptr + 1; + } + + free(name); + + if (return_code != NO_ERROR) + goto error; + } } - free(cmdline); + + if (sei.fMask & SEE_MASK_NOCLOSEPROCESS) + { + DWORD exitcode; + + SetConsoleCtrlHandler(NULL, TRUE); + WaitForSingleObject(sei.hProcess, INFINITE); + GetExitCodeProcess(sei.hProcess, &exitcode); + SetConsoleCtrlHandler(NULL, FALSE); + + errorlevel = exitcode; + } + + error: + free(title); + + if (return_code != NO_ERROR) + return_code = ERROR_INVALID_FUNCTION; + return return_code; } diff --git a/programs/cmd/cmd.rc b/programs/cmd/cmd.rc index bc738faa5e9..ead40fc8296 100644 --- a/programs/cmd/cmd.rc +++ b/programs/cmd/cmd.rc @@ -408,4 +408,5 @@ Enter HELP <command> for further information on any of the above commands.\n" WCMD_ENDOFFILE, "End of file" WCMD_NUMCOPIED, "%t%1!u! file(s) copied\n" WCMD_NOCOPYTOSELF, "File cannot be copied onto itself.\n" + WCMD_STRING_UNIXFAIL, "Could not translate the specified Unix filename to a DOS filename.\n" } diff --git a/programs/cmd/tests/test_builtins.bat.exp b/programs/cmd/tests/test_builtins.bat.exp index 4952fe4dda3..6ecc7e49c19 100644 --- a/programs/cmd/tests/test_builtins.bat.exp +++ b/programs/cmd/tests/test_builtins.bat.exp @@ -58,10 +58,10 @@ SUCCESS 0 FAILURE 255 FAILURE 255 --- success/failure for START command -@todo_wine@FAILURE 1 +FAILURE 1 foo@space@ SUCCESS 1024 -@todo_wine@SUCCESS 666 +SUCCESS 666 0 @todo_wine@FAILURE 1 --- success/failure for TYPE command diff --git a/programs/cmd/tests/test_builtins.cmd.exp b/programs/cmd/tests/test_builtins.cmd.exp index d2f076a2dc7..d3f561d6b9f 100644 --- a/programs/cmd/tests/test_builtins.cmd.exp +++ b/programs/cmd/tests/test_builtins.cmd.exp @@ -577,10 +577,10 @@ SUCCESS 0 FAILURE 255 FAILURE 255 --- success/failure for START command -@todo_wine@FAILURE 1 +FAILURE 1 foo@space@ SUCCESS 1024 -@todo_wine@SUCCESS 666 +SUCCESS 666 0 @todo_wine@FAILURE 1 --- success/failure for TYPE command diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index dd912ea33c7..dc461ccc786 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -495,3 +495,4 @@ extern WCHAR version_string[]; #define WCMD_ENDOFFILE 1049 #define WCMD_NUMCOPIED 1050 #define WCMD_NOCOPYTOSELF 1051 +#define WCMD_STRING_UNIXFAIL 1052 -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11608
eric pouech (@epo) commented about programs/cmd/builtins.c:
+ if (*(thisparam)) + wcscpy(path_argument, thisparam); + + if (*(thisparam = WCMD_parameter(args, ++argn, &rawarg, FALSE, FALSE))) + sei.lpParameters = rawarg; + else + sei.lpParameters = L"";
- memset( &st, 0, sizeof(STARTUPINFOW) ); - st.cb = sizeof(STARTUPINFOW); + if (WCMD_search_command(path_argument, &sc, FALSE) == NO_ERROR) + sei.lpFile = sc.path; + else sei.lpFile = path_argument;
- if (CreateProcessW( file, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &st, &pi )) + if (GetBinaryTypeW(sei.lpFile, &binary_type)) for this part, I think you need also to share with the existing helpers for spwaning external process
* likely spawn_external_full path has to be reworked (as you need here to pass process_flags and STARTUPINFO to CreateProcess), and split in several helpers, * the console mode changes in spawn_external_full path are needed * search_command shall give you the kind of action needed: * external executable for CreateProcess * internal builtin command ('start /b dir' which I'm not sure it's supported in this MR) * ShellExecute * no match * execute_single_command shall give an example of how the manage the output of search_command (yes that's cumbersome) -- https://gitlab.winehq.org/wine/wine/-/merge_requests/11608#note_149344
participants (3)
-
eric pouech (@epo) -
Santino Mazza -
Santino Mazza (@tati)