The new kbmMW v. 5.06.20 a new unit, kbmMWProcess, was added.
This unit make it easy to group, start and stop external processes on Windows, via various class methods.
In the upcoming minor fix released, it has been extended with a couple of ExecureProcess methods too:
TkbmMWProcess = class public class function TerminateProcess(const AHandle:THandle; const AExitCode:integer; const AWaitUntilTerminated:boolean = false):boolean; class function CreateProcess(const AProcessFile:string; const AArgs:string; const AStartupDirectory:string = ''):THandle; overload; class function CreateProcess(const AJob:THandle; const AProcessFile:string; const AArgs:string; const AStartupDirectory:string = ''):THandle; overload; class function CreateProcess(const AJob:THandle; const AInput:THandle; const AOutput:THandle; const AErr:THandle; const AProcessFile:string; const AArgs:string; const AStartupDirectory:string = ''; const AShowWindow:boolean=false):THandle; overload; class function CreateJob:THandle; class function TerminateJob(const AHandle:THandle; const AExitCode:integer; const AWaitUntilTerminated:boolean = false):boolean; class function ExecuteProcess(const AProcessFile:string; const AArgs:string; const ATimeoutMS:integer=4000; const AStartupDirectory:string = ''; const AShowWindow:boolean = false):string; overload; class function ExecuteProcess(const AJob:THandle; const AProcessFile:string; const AArgs:string; const ATimeoutMS:integer=4000; const AStartupDirectory:string = ''; const AShowWindow:boolean = false):string; overload; end;
To simply start an external process, one can do:
The executable some.exe will be started and run “forever” until it decides itself to stop, or you stop it via the task manager. If the executable is a console type application, you will not see any visual window.
However if you like to easily be able to shut down the started process at your will, you can do like this:
var h:THandle; begin h:=TkbmMWProcess.CreateProcess('\somepath\some.exe',''); .... TkbmMWProcess.TerminateProcess(h); end;
TerminateProcess will force close of the external executable, but will not wait for it stopping. If you want to block until it has stopped, add a true argument to the TerminateProcess call.
But what if you want to guarantee that the external process is terminated if your main executable dies of any reason, or you want to start a number of external processes that all should be terminated together? Then you should define a job.
var j:THandle; begin j:=TkbmMWProcess.CreateJob; try TkbmMWProcess.CreateProcess(j,'\somepath\some1.exe',''); TkbmMWProcess.CreateProcess(j,'\somepath\some2.exe',''); .... finally TkbmMWProcess.TerminateJob(j,1); end; end;
The job is automatically defined in such way that if your main executable (containing the CreateJob call) dies, all processes that has been started using CreateProcess(AJob…) will be automatically terminated.
What if you want to start an external console app, but want to see its console view? Then we use the more complex version of CreateProcess and provides 0 values for the first 4 arguments:
Perhaps you want to receive the output of a console app. For example we may want a directory listing of a specific directory (it can be done in lots of more native ways, so its just shown as an example):
var s:string; begin s:=TkbmMWProcess.ExecuteProcess('c:\windows\system32\cmd.exe','/C DIR'); end;
What will happen is that it will run cmd.exe with the argumente /C DIR which will make a directory listing of the current directory (c:\windows\system32). ExecuteProcess will read all output (stdout and stderr) for until 4 seconds and return that as a string. After the 4 seconds (4000 msecs) the started external executable will be automatically terminated if it has already not terminated itself. You can change the max time to wait by adding a different ATimeoutMS value. If you set the value to 0, it will wait indefinitely until the external process terminates. The resolution of ATimeoutMS is 100 msecs.
ExecuteProcess can also participate in a job the same as shown above, to guarantee termination at time of main executable termination.
Finally, by user suggestion, an additional advanced variant of ExecuteProcess is being made available, that provides real time access to received data.
var s:string; begin s:=TkbmMWProcess.ExecuteProcess(0,'C:\Windows\System32\cmd.exe','/C dir', function(var ABuf:PByte; const ABufSize:cardinal; var ASize:cardinal):boolean begin OutputDebugString(PChar('Received '+inttostr(ASize)+' bytes')); Result:=true; end, 0,'',false); end;
This variant calls the provided anonymous function, with 3 arguments:
- ABuf which is a pointer to an internal buffer containing data
- ABufSize which is a constant that contains the capacity of the buffer
- ASize which is a value that tells the actually used size of the buffer (the real amount of data scraped for you).
If your anonymous function returns false, you will force a termination of the external process.
If ABuf is nil, the external process has terminated or been terminated.
You can modify the data contents directly in the buffer pointer to by ABuf and return a new ASize. But remember doing so, you must never exceed the ABufSize size. If you want to skip the data completely from the string, you can set ABuf:=nil, or if you want to return more data than can be stored in ABufSize, you can return a pointer to your own buffer in ABuf and the returned size in ASize.
Any altered/returned data will be part of the final string returned as result of ExecuteProcess.
Currently the features of TkbmMWProcess are only available on the Windows platform.
If you like kbmMW and want to support our work, please click like and share this and other of our blog posts with your network.