1-sec googling: https://wiki.delphi-jedi.org/wiki/JVCL_Help:TJvCreateProcess that claims to have CDir setting. I could suggest my implementation but it's somewhat tied to other util units. Anyway there's nothing hard in launching (code is NOT standalone - some additional utils required)
// Launch a process with I/O redirect.
// @param ExecProps - requisites for launch
// @param [OUT] Handles - in / out pipe handles, process handle
// @raises Exception on error
procedure ExecProcess(const ExecProps: TExecProps; out Handles: THandleArr);
var
si: TStartupInfo;
pi: TProcessInformation;
sa: TSecurityAttributes;
hStdOut, hStdIn, hStdErr: THandle;
IntCmdLine, IntCurrDir, Env: string;
begin
Handles := Default(THandleArr);
hStdOut := 0; hStdIn := 0; hStdErr := 0;
si := Default(TStartupInfo);
pi := Default(TProcessInformation);
try try
// TSecurityAttributes для процесса и труб
sa := Default(TSecurityAttributes);
sa.nLength := SizeOf(sa);
sa.lpSecurityDescriptor := nil;
sa.bInheritHandle := True;
// create pipes if needed
// ! We can't simply override only some of handles - https://stackoverflow.com/questions/30494945
// But assigning standard values with GetStdHandle results in weird behavior
// (I/O error on ReadLn specifying standard STDIN, weird hangs etc).
// As the situation when STDIN is required in executed process but not redirected
// will unlikely happen, just set the handle to NULL.
// As for output pipes, create and redirect them always to avoid bugs.
// STDIN
if pStdIn in ExecProps.RedirectPipes then
begin
if not CreatePipe(hStdIn, Handles[ehStdIn], @sa, PipeBufSize) then
raise LastOSErr('CreatePipe');
// Ensure the write handle to the pipe for STDIN is not inherited (from MSDN example)
SetHandleInformation(Handles[ehStdIn], HANDLE_FLAG_INHERIT, 0);
end;
// STDOUT
// if pStdOut in ExecProps.RedirectPipes then
begin
if not CreatePipe(Handles[ehStdOut], hStdOut, @sa, PipeBufSize) then
raise LastOSErr('CreatePipe');
// Ensure the read handle to the pipe for STDOUT is not inherited (from MSDN example)
SetHandleInformation(Handles[ehStdOut], HANDLE_FLAG_INHERIT, 0);
end;
// STDERR
// if pStdErr in ExecProps.RedirectPipes then
begin
if not CreatePipe(Handles[ehStdErr], hStdErr, @sa, PipeBufSize) then
raise LastOSErr('CreatePipe');
// Ensure the read handle to the pipe for STDERR is not inherited (from MSDN example)
SetHandleInformation(Handles[ehStdErr], HANDLE_FLAG_INHERIT, 0);
end;
si.cb := SizeOf(si);
si.dwFlags := STARTF_USESHOWWINDOW;
if ExecProps.RedirectPipes <> [] then
si.dwFlags := si.dwFlags or STARTF_USESTDHANDLES;
si.wShowWindow := SW_HIDE;
si.hStdInput := hStdIn;
si.hStdOutput := hStdOut;
si.hStdError := hStdErr;
if ExecProps.CurrDir = '' then IntCurrDir := GetCurrentDir else IntCurrDir := ExecProps.CurrDir;
// Construct a new env from an old one with addition of that given in parameters and
// error signature.
Env := StrArrToEnv(ExecProps.EnvVars) +
GetEnv + #0;
IntCmdLine := ExecProps.CmdLine; // command line MUST be modifyable - CreateProcessW requirement
UniqueString(IntCmdLine);
if not CreateProcess(nil, PChar(IntCmdLine), @sa, nil, True,
{} // show window
CREATE_NEW_CONSOLE{$IFDEF UNICODE} or CREATE_UNICODE_ENVIRONMENT{$ENDIF},
PChar(Env), PChar(IntCurrDir), si, pi) then
raise LastOSErr('CreateProcess', GetLastError, '"'+IntCmdLine+'"');
Handles[ehProcess] := pi.hProcess;
// Set priority if not default
if ExecProps.Priority <> NORMAL_PRIORITY_CLASS then
SetPriorityClass(Handles[ehProcess], ExecProps.Priority);
except
CloseHandles(Handles);
raise;
end;
finally
// Free thread handles and unneeded pipe ends
CloseAndZeroHandle(hStdIn);
CloseAndZeroHandle(hStdOut);
CloseAndZeroHandle(hStdErr);
CloseAndZeroHandle(pi.hThread);
end;
end;