Contributor: SWAG SUPPORT TEAM


{Here's an implementation (based on Pat's WinExecAndWait32) that uses a thread, so that your application can continue to process windows messages (and do something else) while it waits for the launched application to finish.}

unit WinExec;
interface
uses
  Classes, SysUtils, Windows;
type
  TWinExec = class(TThread)
  private
    FFileName, FArguments: String;
    FProcessActive: boolean;
    FOnProcessIdle: TNotifyEvent;
  public
    constructor Create(AppName, Args : String; OnExit, OnIdle : TNotifyEvent);
  protected
    procedure Execute; override;
    function StartApp(AppName, ArgStr :String; Visibility : integer):integer;
  end;
type
  FileSpec = array [0..MAX_PATH] of char;
implementation
{ TWinExec }
constructor TWinExec.Create(AppName, Args: String; OnExit, OnIdle: TNotifyEvent);
begin
  inherited Create(False);
  FOnProcessIdle := OnIdle;
  FFileName := AppName;
  FArguments := Args;
  FProcessActive := False;
  FreeOnTerminate := False;  // Note that this implementation requires you 
  OnTerminate := OnExit;     // to explicitly Free the TWinExec object.    
end;
procedure TWinExec.Execute;
begin
  FProcessActive := True;
  StartApp(FFileName, FArguments, SW_NORMAL);
  FProcessActive := False;
end;
function TWinExec.StartApp(AppName, ArgStr :String; Visibility : integer):integer;
var
  zAppName : FileSpec;
  zCurDir : FileSpec;
  WorkDir : String;
  StartupInfo : TStartupInfo;
  ProcessInfo : TProcessInformation;
begin
  if ArgStr <> '' then
     AppName := AppName + ' ' + ArgStr;
  StrPCopy(zAppName, AppName);
  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,                           { pointer to executable}
    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 }
    zCurDir,                       { pointer to current directory name }
    StartupInfo,                   { pointer to STARTUPINFO }
    ProcessInfo) then Result := -1 { pointer to PROCESS_INF }
  else
  begin
    if Assigned(FOnProcessIdle) then
    begin
      WaitForInputIdle(ProcessInfo.dwProcessId, INFINITE);
      FOnProcessIdle(Self);
    end;
    WaitforSingleObject(ProcessInfo.hProcess,INFINITE);
    GetExitCodeProcess(ProcessInfo.hProcess,Result);
    CloseHandle(ProcessInfo.hProcess );
    CloseHandle(ProcessInfo.hThread );
  end;
end;
end. // Winexec.pas

Here's a simple example that uses TWinExec.

unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, WinExec;
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    Button1: TButton;
    Label3: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
  private
    Process : TWinExec;
    procedure ProcessDone(Sender: TObject);
    procedure ProcessReady(Sender: TObject);
  public
  end;
var
  Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
   Process := TWinExec.Create(Edit1.Text, Edit2.Text, ProcessDone, ProcessReady);
   Button1.Enabled := False;
   Button1.Caption := 'Waiting for Launched Application to Finish';
   Label3.Caption := 'Waiting for Idle Message';
end;
procedure TForm1.ProcessDone(Sender: TObject);
begin
  Process.Free;
  Button1.Enabled := True;
  Button1.Caption := 'Click to Start the Application';
end;
procedure TForm1.ProcessReady(Sender: TObject);
begin
  Label3.Caption := 'Application OnIdle received.';
end;
procedure TForm1.Edit1Change(Sender: TObject);
begin
  Button1.Enabled := FileExists(Edit1.Text);
end;
end.
// =============  UNIT1.TXT ======================
object Form1: TForm1
  Left = 200
  Top = 200
  Width = 435
  Height = 177
  Caption = 'Form1'
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 24
    Top = 16
    Width = 53
    Height = 13
    Caption = 'Executable'
  end
  object Label2: TLabel
    Left = 24
    Top = 44
    Width = 53
    Height = 13
    Caption = 'Arguments:'
  end
  object Label3: TLabel
    Left = 26
    Top = 76
    Width = 17
    Height = 13
    Caption = 'Idle'
  end
  object Edit1: TEdit
    Left = 83
    Top = 12
    Width = 309
    Height = 21
    TabOrder = 0
    OnChange = Edit1Change
  end
  object Button1: TButton
    Left = 20
    Top = 104
    Width = 373
    Height = 25
    Caption = 'Click to Start Application'
    Enabled = False
    TabOrder = 1
    OnClick = Button1Click
  end
  object Edit2: TEdit
    Left = 83
    Top = 44
    Width = 309
    Height = 21
    TabOrder = 2
  end
end