We help IT Professionals succeed at work.

Check out our new AWS podcast with Certified Expert, Phil Phillips! Listen to "How to Execute a Seamless AWS Migration" on EE or on your favorite podcast platform. Listen Now

x

Returning DOS command output : Delphi 3

sxh
sxh asked
on
Medium Priority
1,680 Views
Last Modified: 2008-02-01
I would like to know how to run a DOS command and return it's output to a memo control on a form without spawning the DOS window.

example:

form contains; edit box, button and memo control.

when I click the button the 'DIR' command is run for the directory given in the edit box. The result (file list or any error) is returned in the memo control.

the DOS window must not be shown.

should work for delphi 3 under Win 95/98.

regards

sxh

Comment
Watch Question

Commented:
how about ...

      begin
         exec('DIR >mydata')
         memo1.lines.readFromFile('mydata')
      end;

exec is procedure to execute shell app.  need details ? .. :)

Commented:
Try to use anonymous pipes to redirect the child process's standard input and output.



sxh

Author

Commented:
hi hrizal

thanks for the response.

Your solution is one that would possibly work for the example I gave. However, as this was an example it would not be practical to issue commands like DIR /p.

I will rephrase the question a little, as I am probably after a little more than what I asked for originaly.

regards

sxh


sxh

Author

Commented:
hi vladika

thanks for your response.

I do not know the meaning of anonymous pipes, I know what a pipe is ??

regards

sxh
sxh

Author

Commented:
:additional requirements:

I would like the program to allow me to issue commands which require interactive responses from the user like DIR /p or DIR | more.

Also the program should display interactively, ie if the commamd DIR /o/s *.exe was issued, the memo control would display each line as it was found.

regards

sxh

Commented:
This is code I use often. It's not very sophisticated but it works very well and is easy
enough to understand:

// Generic execute routine...
function ExecuteAndWait( sExeFileName, sCommandLine: string; bHidden: Boolean ): Integer;
 { returns -1 if the Exec failed, otherwise returns the process' exit
   code when the process terminates }
var
  sCommand    : string;
  StartupInfo: TStartupInfo;
  ProcessInfo: TProcessInformation;
begin
  sCommand := sExeFilename+' '+sCommandLine;
  FillChar( StartupInfo, SizeOf( StartupInfo ), #0);
  StartupInfo.cb := SizeOf( StartupInfo );
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
  if bHidden
  then StartupInfo.wShowWindow := SW_HIDE
  else StartupInfo.wShowWindow := SW_SHOWNORMAL;
  if not CreateProcess( nil,
      PChar( sCommand ),                { pointer to command line string }
      nil,                           { pointer to process security attributes }
      nil,                           { pointer to thread security attributes }
      False,                         { handle inheritance flag }
      CREATE_NEW_CONSOLE or          { creation flags }
      NORMAL_PRIORITY_CLASS,
      nil,                           { pointer to new environment block }
      nil,                           { pointer to current directory name }
      StartupInfo,                   { pointer to STARTUPINFO }
      ProcessInfo ) then              { pointer to PROCESS_INF }
    Result := -1
  else begin
    WaitforSingleObject( ProcessInfo.hProcess, INFINITE );
    GetExitCodeProcess( ProcessInfo.hProcess, Result );
  end;
end;

function ExecuteAndRedirect( sCommand, sCommandLine: string; List: TStrings ): Boolean;
var
  sTempFilename: string;
  iIndex: Integer;
begin
  // first validate parameters...
  if ( sCommand = '' ) or ( sCommandLine = '' ) or ( not Assigned( List ) ) then begin
    Result := False;
    Exit;
  end;
  iIndex := 0;
  repeat // repeat until unique filename ( not really needed? )
    sTempFilename := Format( 'redir%s.$$$', [ IntToHex( iIndex, 3 ) ] );
  until ( not FileExists( sTempFilename ) );
  Result := ( -1 <> ExecuteAndWait(
    'command.exe /c ' + sCommand, // "command.exe /c" needed for 95/98 & NT "cmd.exe /c" is not enough for 95/98
    sCommandLine + ' >' + sTempFilename, // redirection included
    True // hidden
  ) );
  List.LoadFromFile( sTempFilename ); // load to any TStrings-decendant like TMemo
  DeleteFile( sTempFilename ); // remove tempfile
end;

Usage:
  bResult := ExecuteAndRedirect( 'dir', '/o/s', MyMemo );

Probably typos everywhere, but it's supposed to work fine.
Study "CreateProcess", "WaitForSingleObject", "GetExitCodeProcess", "TStrings", "command.exe"-parameters!
There are a lot of goodies...

/// John

Commented:
Erajoj,
I think it will not work for 'DIR /p'


Commented:
Sorry, can't help you there...

/// John
sxh

Author

Commented:
hi erajoj

Great answer.

I have seen the execute and wait code before, but a different version.

Your answer does not give me the interactivity specified. The controlling procedure ExecuteAndRedirect calls the
ExecuteAndWait procedure, it's not until the command has finished executing that the call to load the redirected output into the memo is processed, therefor the user would have to wait until the command had finished processing before any results were made available.

regards

sxh
sxh

Author

Commented:
hi erajoj

Great answer.

I have seen the execute and wait code before, but a different version.

Your answer does not give me the interactivity specified. The controlling procedure ExecuteAndRedirect calls the
ExecuteAndWait procedure, it's not until the command has finished executing that the call to load the redirected output into the memo is processed, therefor the user would have to wait until the command had finished processing before any results were made available.

regards

sxh
sxh

Author

Commented:
hi erajoj

Great answer.

I have seen the execute and wait code before, but a different version.

Your answer does not give me the interactivity specified. The controlling procedure ExecuteAndRedirect calls the
ExecuteAndWait procedure, it's not until the command has finished executing that the call to load the redirected output into the memo is processed, therefor the user would have to wait until the command had finished processing before any results were made available.

regards

sxh
sxh

Author

Commented:
hi all

Maybe I should be using some kind of console in place of the memo control ????.

How would I do that on the same form ????

regards

sxh
I would be very interested to see if you get this working.  I have tried plenty of times to try and get some interactivity happening between some of my apps and the command prompt, however, on every occassion, I have not really been successful in getting what was returned by the command prompt.

For instance, if you type DIR *.EXE /S /P or DIR *.EXE /S | MORE, the command processor waits for keyboard input before proceeding with the next screenful of text.  As you are piping this to a file (this is the only method I can think of), you have no way of knowing when the "press any key to continue..." prompt appears.  A problem with the text file is that you will not be able to open it until DOS has finished writing too it anyway.  The file will be locked.

A few years ago, I wrote a program which would capture a text screen and could then work out what was typed.  However, this doesnt work in Windows properly for some reason (and I dont think it would work in Delphi anyway).  

What you need to try and achieve is a way of reading line by line what is shown on the DOS screen and scanning it for recognisable items.  Then, using a send key function, type back to the DOS window.  

I dont know if that is useful for you or not, but I seriously cant think of any way of doing this at all - sort of writing your own command interpreter which just supports the very basic DOS functions.

Best of luck!

Stuart.
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
sxh

Author

Commented:
hi vladika

I'm sure that all of the people who follow this thread would definately learn something from your innovative solution.

I can see where you are coming from now, and with a little work I could tweak your solution to my needs.

There is one question I have regarding your solution:

After running a standard 'DIR' command, I can't exit from the form unless I do a Program Reset in the IDE. This also leaves the 'winoldap' and 'redir32' processes running and can be seen in the task manager..... How do I cancel these after the command has been executed and finished???

many thanks for your input, I have raised the points to 500.

well done

sxh
sxh

Author

Commented:
hi stuart johnson

I have accepted the answer from vladika, as you can see from this, there are ways of doing a task other than the obvious.

I would recommend you debug vladika's code and pleasure at it's operation. This may be what you've been looking for too....

regards

sxh
sxh

Author

Commented:
hi vladika

I've found a safe way to destroy the processes, no need to reply.

regards

sxh

Commented:
Hi, Sxh

I think if you run process by typing in CommandEdit 'command.com /c dir'
then command.com run 'DIR' command and exit.

If you run 'command.com' and then type into InputEdit 'DIR'
then command.com run 'DIR' command but not exit after it.
You have to type 'EXIT' into InputEdit to shutdown command.com

And what is your way to destroy the processes?

Vladika

sxh

Author

Commented:
hi vladika

I shut down the processes by typing exit into the inputedit box.

When I move onto the project in which this will be used, I will incorporate these commands into a command class and then just simply create and destroy through the class.

regards

sxh
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.