How can I wait for a command-line program to finish?
Asked Answered
A

6

8

I have run program with command-line parameters. How can i wait for it to finish running?

Alexio answered 28/11, 2010 at 4:1 Comment(4)
cant say what question is very clear for me... for CLI input comes from stdin and output goes to stdout (or stderr in some cases). parameters acting as modifiers for program behaviourArmourer
Please rephrase your question, as the current form is very unclear. What are you waiting for? Console output of the executed program? Windows messages sent by that program?Septilateral
Sorry for my bad English ! i found the answer . you can see that in bottom of the page !Alexio
It that's the answer, then you didn't ask your question very clearly. I've edited it for you so that it matches what you apparently intended to ask.Astrid
A
14

This is my answer : (Thank you all)

uses ShellAPI;

function TForm1.ShellExecute_AndWait(FileName: string; Params: string): bool;
var
  exInfo: TShellExecuteInfo;
  Ph: DWORD;
begin

  FillChar(exInfo, SizeOf(exInfo), 0);
  with exInfo do
  begin
    cbSize := SizeOf(exInfo);
    fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT;
    Wnd := GetActiveWindow();
    exInfo.lpVerb := 'open';
    exInfo.lpParameters := PChar(Params);
    lpFile := PChar(FileName);
    nShow := SW_SHOWNORMAL;
  end;
  if ShellExecuteEx(@exInfo) then
    Ph := exInfo.hProcess
  else
  begin
    ShowMessage(SysErrorMessage(GetLastError));
    Result := true;
    exit;
  end;
  while WaitForSingleObject(exInfo.hProcess, 50) <> WAIT_OBJECT_0 do
    Application.ProcessMessages;
  CloseHandle(Ph);

  Result := true;

end;
Alexio answered 28/11, 2010 at 7:18 Comment(4)
You should use MsgWaitForMultipleObjects() instead of WaitForSingleObject() so you do not call Application.ProcessMessages() unnecessarily. Doing so too often can degrade your app's performance while your loop is running.Myall
I'll use it in a thread ! so Application.ProcessMessages; will remove !Alexio
MsgWaitForMultipleObjects really is likely to be the better solution - you'll only have to wait for the thread if you did it that way!Dragrope
Working fine in XE3 with Params = ''. But just curious what kind of Params can I pass to that function?Denny
B
7

If I understand your question correctly, you want to execute program in command-line and capture its output in your application rather than in console window. To do so, you can read the output using pipes. Here is an example source code:

Capture the output from a DOS (command/console) Window

Blanketing answered 28/11, 2010 at 6:55 Comment(0)
S
4

Using DSiWin32:

sl := TStringList.Create;
if DSiExecuteAndCapture('cmd.exe /c dir', sl, 'c:\test', exitCode) = 0 then
  // exec error
else
  // use sl
sl.Free;
Schwerin answered 28/11, 2010 at 10:23 Comment(2)
@gabr-Hi! I got DSIWin32 v1.70b - Is this a beta version?Conchitaconchobar
@gabr-And another question. The application freezes while it captures the output. There is a way to show dynamically the captured output.Conchitaconchobar
F
2

Ok, getting the command-line parameters, you use

ParamCount : returns the number of parameters passed to the program on the command-line.

ParamStr : returns a specific parameter, requested by index. Running Dephi Applications With Parameters

Now, if what you meant is reading and writing to the console, you use

WriteLn : writes a line of text to the console.

ReadLn : reads a line of text from the console as a string. Delphi Basics

Forbidding answered 28/11, 2010 at 4:9 Comment(0)
G
2

If what you want is to execute a command-line executable, and get the response that this exe writes to the console, the easiest way could be to call the exe from a batch file and redirect the output to another file using >, and then read that file.

For example, if you need to execute the "dir" command and get its output you could have a batch file called getdir.bat that contains the following:

@echo off
dir c:\users\myuser\*.* > output.txt

you could exec that batch file using the API function ShellExecute. You can read about it http://delphi.about.com/od/windowsshellapi/a/executeprogram.htm

Then you can read output file, even using something like a TStringList:

var
  output: TStringList;
begin
  output := TStringList.Create();
  output.LoadFromFile('output.txt');
  ...
Grallatorial answered 28/11, 2010 at 4:50 Comment(0)
O
0

Thanks from this - Changed & Tested:

function ExecAndWait(ExeFileName, CommandLine: string): Boolean;
var
  ExitCode: DWORD;
  ProcessInformation: TProcessInformation;
  StartupInfo: TStartupInfo;
begin
  Result := False;
  FillChar(StartupInfo, SizeOf(TStartupInfo), 0);
  StartupInfo.cb := SizeOf(TStartupInfo);
  // Hide process
  // https://mcmap.net/q/1321827/-hide-process-window-with-39-createprocess-39
  StartupInfo.wShowWindow := SW_HIDE;
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  if CreateProcess(PChar(ExeFileName), PChar(CommandLine), nil, nil, False, 0, nil, nil, StartupInfo, ProcessInformation) then
  begin
    if WAIT_OBJECT_0 = WaitForSingleObject(ProcessInformation.hProcess, INFINITE) then
      if GetExitCodeProcess(ProcessInformation.hProcess, ExitCode) then
        if ExitCode = 0 then
          Result := True
        else
          SetLastError(ExitCode + $2000);

    ExitCode := GetLastError;
    CloseHandle(ProcessInformation.hProcess);
    CloseHandle(ProcessInformation.hThread);
    SetLastError(ExitCode);
  end;
end;
Otiliaotina answered 25/2 at 8:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.