Running DOS programs from a Delphi app

Can I run a DOS program from inside my Delphi app in such a way that my program waits for the DOS program to end (something like a "modal" DOS program)?
sandman_brAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
intheConnect With a Mentor Commented:
hi
stick one button on a form (name is button3)
then paste this code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button3: TButton;
    procedure Button3Click(Sender: TObject);
  private
    { Private declarations }
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

function WinExecAndWait32(FileName:String; Visibility :integer):integer;
  var
    zAppName:array[0..512] of char;
     zCurDir:array[0..255] of char;
     WorkDir:String;
     StartupInfo:TStartupInfo;
     ProcessInfo:TProcessInformation;
 begin
     StrPCopy(zAppName,FileName);
     GetDir(0,WorkDir);
     StrPCopy(zCurDir,WorkDir);
     FillChar(StartupInfo,Sizeof(StartupInfo),#0);
     StartupInfo.cb := Sizeof(StartupInfo);
     StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
     StartupInfo.wShowWindow := Visibility;
 if not CreateProcess(nil,zAppName,  { 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 Result := -1 { pointer to PROCESS_INF }
     else
        begin
        WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
        GetExitCodeProcess(ProcessInfo.hProcess,Result);
        CloseHandle( ProcessInfo.hProcess );
        CloseHandle( ProcessInfo.hThread );
        end;
   end;
procedure TForm1.Button3Click(Sender: TObject);
begin
WinExecAndWait32('c:\edit.com',1);
Close;
end;
end.
hope it shows you what you need
Regards Barry
0
 
martin_gCommented:
I've used a simple approach with success.  Use FileExecute() found in the FMXUtils.pas that ships with Delphi.
Here's an example:
ExecuteFile ('gencri.exe',,SW_SHOWMINIMIZED);

You can put command line parameters for your DOS app between the two commas.

REFERENCE: From Delphi 3 Help under FileExecute -
"Many times an application needs to execute another application, either to perform a specific task or just to have that application run concurrently. The Windows API provides a function, ShellExecute, that executes an application, but it requires a number of parameters superfluous to Delphi applications. The FMXUtils unit provides a more useful alternative, called ExecuteFile.
ExecuteFile operates in two different ways. If passed the name of an executable file, ExecuteFile runs that application. If passed the name of a document with an associated application, ExecuteFile runs the application, automatically opening that document at startup."

Hope this helps.

0
 
intheCommented:
martin_q
 the whole point was to execute and wait. try running your way and putting close statement after execute file,sure it opens the file but it dont wait.(or at least i cant get it to)
executefile is calling shellexecute as you say but shellexecute is calling createprocess so why not go straight to createprocess
and tweak a bit to get dos prog to wait like in code above.
please correct me if im wrong  :-)
Regards Barry
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
MadshiCommented:
Hi Barry,

your sources look nice, but not enough (I'm a perfectionist). The problem with your sources is that your application doesn't process messages while waiting on the dos program. That means that the main form isn't repainted anymore and all that stuff.
So here comes my solution (thread based) that solves this problem, too.

sandman_br, my sources copies the "autoexec.bat" file, and waits until this is ready. Then you'll find the output text in 'c:\output.txt'. Furthermore the dos window is hidden. If you don't like that, just remove the line:
  si.dwFlags:=STARTF_USESHOWWINDOW; si.wShowWindow:=SW_HIDE;

Regards, Madshi.

unit runThread_;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, tools, ddraw;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen}
  public
    { Public-Deklarationen}
  end;

var Form1 : TForm1 = nil;

implementation

{$R *.DFM}

const unitName = 'runThread_.';

type TRunThread = class(TThread)
  private
    processHandle : cardinal;
    processReady  : boolean;
    waitingThread : cardinal;
    procedure Execute; override;
  end;

procedure TRunThread.Execute;
begin
  WaitForSingleObject(processHandle,INFINITE);   // This call does not return, unless copy is stopped
  processReady:=true;                            // Set "processReady" flag for main thread
  PostThreadMessage(waitingThread,WM_NULL,0,0);  // Wake up main thread
                                                 // If you call Application.HandleMessage (see below) in the
                                                 // main thread, the main thread is sleeping the most time in
                                                 // winAPI "waitMessage". So we send a "dummy" message in order
                                                 // to let the main thread return from Application.HandleMessage
end;

procedure TForm1.Button1Click(Sender: TObject);
var si : TStartupInfo;
    pi : TProcessInformation;
begin
  caption:='start copy...';
  ZeroMemory(@si,sizeOf(si)); si.cb:=sizeOf(si);
  si.dwFlags:=STARTF_USESHOWWINDOW; si.wShowWindow:=SW_HIDE;
  if CreateProcess(nil,'c:\command.com /c copy c:\autoexec.bat c:\test.bat >c:\output.txt',nil,nil,false,0,nil,nil,si,pi) then begin
    caption:='copy started...';
    with TRunThread.Create(true) do         // create the thread object, but do not start it now...
      try
        processHandle:=pi.hProcess;         // tell the thread what process it has to watch
        processReady:=false;                // flag for the loop (see below)
        waitingThread:=GetCurrentThreadID;  // the current threadID for the wakeup message (see above)
        caption:='wait for copy...';
        Resume;                             // now all information is prepared; so let's start the thread
        repeat
          Application.HandleMessage;        // message loop
        until Application.Terminated or processReady;  // continue with normal program when either the
                                                       // started process has stopped or our program is closed
        caption:='copy stopped...';
      finally Free end;
    CloseHandle(pi.hThread); CloseHandle(pi.hProcess); // Never forget to close handles...
    caption:='ready...';
  end else caption:='could not start copy...';
end;

end.
0
 
sandman_brAuthor Commented:
Hi guys,
Barry's code worked great. My app's main window won't get repainted until the DOS program ends, as Madshi pointed, but I can live with that :) Madshi, I tried your code too, but the app was still accessible to the user while the DOS prog was running... but thanks for your efforts.
Thanks everyone!

Best regards,
Roger
0
 
MadshiCommented:
Hmmm. If you want your main window to be disabled, you just need to call "form1.enabled:=false" before starting the dos program and "form1.enabled:=true" after coming back...
0
 
sandman_brAuthor Commented:
Hi Madshi,
Thanks for the last comment, that finishing touch makes your solution perfect. I'm just a beginner in Delphi and had not realized I could use that... thanks a lot!
0
 
MadshiCommented:
No problem...   :-)
0
 
intheCommented:
yes thanks for your input madshi the more ways to know how to do something the better then we can use all the best bits and have perfection eh :-)
Regards Barry
0
 
MadshiCommented:
:-)  perfection... Yeah!!   :-)
0
 
SupWangCommented:
hi, inthe
I used your code in Delphi 3, it work Ok. But In Delphi 4, "GetExitCodeProcess(ProcessInfo.hProcess,Result)" could not be compiled. The Error Messsage: Types of actual and formal var parameters must be identical My Delphi version is Version 4.0(Build 5.104) Update Pack 2. why? :-(

Regards,
SupWang
0
 
MadshiCommented:
SupWang,

change the result type of the function "WinExecAndWait32" to cardinal.
In D3, integer and cardinal were almost identical. In D4, they are incompatible.

Regards, Madshi.
0
 
intheCommented:
hi all
thanks madshi ,just got in and seen comment
we have to be more careful now with all different versions of delphi being slightly different eh.
Regards Barry
0
 
SupWangCommented:
Hi, Madshi
Thanks :-)
Regards,SupWang

0
 
MadshiCommented:
No prob...  :-)

I really like it that D4 has no a "real" cardinal type, but unfortunately that makes some problems, too...

Regards, Madshi.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.