Solved

Running DOS programs from a Delphi app

Posted on 1998-12-28
15
225 Views
Last Modified: 2010-04-04
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)?
0
Comment
Question by:sandman_br
  • 6
  • 4
  • 2
  • +2
15 Comments
 
LVL 17

Accepted Solution

by:
inthe earned 30 total points
ID: 1353418
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
 
LVL 1

Expert Comment

by:martin_g
ID: 1353419
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
 
LVL 17

Expert Comment

by:inthe
ID: 1353420
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
 
LVL 20

Expert Comment

by:Madshi
ID: 1353421
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
 

Author Comment

by:sandman_br
ID: 1353422
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
 
LVL 20

Expert Comment

by:Madshi
ID: 1353423
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
 

Author Comment

by:sandman_br
ID: 1353424
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 20

Expert Comment

by:Madshi
ID: 1353425
No problem...   :-)
0
 
LVL 17

Expert Comment

by:inthe
ID: 1353426
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
 
LVL 20

Expert Comment

by:Madshi
ID: 1353427
:-)  perfection... Yeah!!   :-)
0
 
LVL 2

Expert Comment

by:SupWang
ID: 1353428
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
 
LVL 20

Expert Comment

by:Madshi
ID: 1353429
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
 
LVL 17

Expert Comment

by:inthe
ID: 1353430
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
 
LVL 2

Expert Comment

by:SupWang
ID: 1353431
Hi, Madshi
Thanks :-)
Regards,SupWang

0
 
LVL 20

Expert Comment

by:Madshi
ID: 1353432
No prob...  :-)

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

Regards, Madshi.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Video by: Mark
This lesson goes over how to construct ordered and unordered lists and how to create hyperlinks.
Both in life and business – not all partnerships are created equal. As the demand for cloud services increases, so do the number of self-proclaimed cloud partners. Asking the right questions up front in the partnership, will enable both parties …

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now