Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Execute command line command in Delphi 2

Status
Not open for further replies.

Jenda

Programmer
Feb 27, 2001
14
CZ
Hello

I need to know how to execute command line command in Delphi. I want to run external applications (DOS commands - copy,cd,delete,.. and some compilers and linker) in my project. I found one possible way by windows API functions, but I don't understand the lots of parameters and I hope there is some easy way to solve the problem.

Thanks
 
Hi Jenda,

I searched an old The Delphi Magazin CD, found something from 1996, author Jaroslav Blaha - it executes a command (DOS, batch) and waits until that completed. This is done by reading all running tasks first, then executing your command and waiting until that new handle/task is not running anymore:

Code:
uses WinTypes, WinProcs, ToolHelp;

procedure ExecuteAndWait(Command : string);
  var
    ModuleID  : THandle;
    TaskEntry : TTaskEntry;
    TaskCount : integer;
    TaskList  : array [1..100] of THandle;  { More than 100 tasks ??? }
    i         : integer;
begin
  TaskEntry.dwSize := SizeOf(TTaskEntry);    { Has to be initalized }
  TaskCount := 0;
  if TaskFirst(@TaskEntry) then              { Save list of active tasks }
    repeat
      Inc(TaskCount);
      TaskList[TaskCount] := TaskEntry.hTask;
    until (not TaskNext(@TaskEntry));
  Command := Command + #0;
  ModuleID := WinExec(@Command[1], SW_SHOWNOACTIVATE);         { Execute }
  if (ModuleID <= hInstance_Error) then
                  { Error, Report the error }
  else
    if TaskFirst(@TaskEntry) then    { Search for new task }
      repeat
        if (TaskEntry.hModule = ModuleID) then    { Task uses same module }
          for i := 1 to TaskCount do
            { Search through list }
            if (TaskList[i] <> TaskEntry.hTask) then begin
              { Found }
              repeat
                { Wait for termination }
                Application.ProcessMessages;
              until (not IsTask(TaskEntry.hTask)) or Application.Terminated;
              exit;
            end;
      until (not TaskNext(@TaskEntry));
end;

I assume still valid, haven't tested.

Cheers,
Matthias
 
Hi Jenda,

somehow the connection crashed while I sent my initial reply, so it didn't increase the post-reply counter. Just in case you haven't noticed the reply yet - is it what you need?

Cheers,
Matthias
 
Mattias's code uses WinExecute these days you should use Createproccess or Shellexecute.
But if all you want to do is launch a DOS program you can do it with the suppied library 'fmxutils' located in demos/doc/filemanex. this has an easy to use function

ExecuteFile(const FileName, Params, DefaultDir: string;
ShowCmd: Integer): THandle;

simple as:-
ExecuteFile(FileName, Params or '', DefaultDir or '',0);

You only need the CreateProccess type of solution if your Delphi code needs to wait until the DOS code has finished
for example if the DOS code writes a file and you then want to check that it has been created.
There have been several posts recently with CreateProcess type solutions if that is what you need.

Be careful though some of the example won't always work as they are.

DOS programs differ a lot in their behavour.
Some require that you set the 'Working Directory' parameter of 'CreateProccess' not all the handlers I have seen do this.
Some dont like it if you try to pass the executable as P1 and parameters as P2 but will work if you pass the filename and parameters together as the second parameter of waitproccess.

A word on 'Close on exit'
If you look at the PIF dialog for a DOS progam you will see a close on exit checkbox I tried without sucess to find a way to set this from a Delphi Program. However if you call the DOS executable from batch file and make the last line of that file 'CLS' that will force a close on exit.
A possible problem here is that sometime you might want to write the Batchfile on the fly for example if you are dynamiclly setting parameters.
if you use a Stringlist to do this (saves overhead) it dosent work.
I found that using a Memo component to store the text and setting that last line to 'CLS' does work, so write your batchfile in a memo!

This is my own version of the CreateProcess Handler
apologies to whoever wrote the original.

function WaitProcess(Filename: TFilename; Params: string; Working: string;
Timeout: integer; Visibility: integer): string;
var StartupInfo: TStartupInfo;
ProcessInfo: TProcessInformation;
WaitResult: integer;
begin
Result := 'OK';
ZeroMemory(@StartupInfo, SizeOf(TStartupInfo));
with StartupInfo do
begin
cb := SizeOf(TStartupInfo);
dwFlags := STARTF_USESHOWWINDOW or STARTF_FORCEONFEEDBACK;
wShowWindow := Visibility;
end;
if fileexists(filename) or fileexists(params) then
begin
if (CreateProcess(nil, Pchar(Filename +' '+ Params), Nil, Nil,
False, NORMAL_PRIORITY_CLASS,
Nil, pchar(working), StartupInfo, ProcessInfo))
then
begin
WaitResult := WaitForSingleObject(ProcessInfo.hProcess, Timeout);
if WaitResult = WAIT_TIMEOUT then
begin
result := 'Timeout has occured';
TerminateProcess(ProcessInfo.hprocess, 1);
end;
CloseHandle(ProcessInfo.hProcess);
CloseHandle(ProcessInfo.hThread);
end
else
result := 'Createproccess failed ' + filename + ' '+ Params+ ' '+inttostr(getlasterror);
end
else
result := 'Process file does not exist';
end;


Steve..




 
Hello Matthias, hello Steve, many thanks for your replies!!
(now I am maximally angry, because when I wanted Submit Post, the electrical power went down! So Iam writting this at the second time and I will be more brief :)

Mathias's code:
- WinExec function goes perfectly
- ExecuteAndWait doesn't go because I dont have library ToolHelp

Steve's code:
- ShellExecute (=ExecuteCommand) goes perfectly too, it needs library ShellAPI
- WaitProcess reporting error -> CreateProcess error number is 161, I didn't find why

That's all (I am writing fastly because I suppose that next power shutdown can come every moment :)), I found your answers are very helpfull!
Many thanks again, Jenda
 
I think 161 is 'file not found'? Someone could correct me on that.

In any case I should check that you are passing the correct file paths, setting the working folder etc.
Steve.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top