System Delphi

Title: Class to Execute and Manage External EXE in your App
Question: This class allows you to Execute and Manage
External Applications from within your Application.
Features
--------
* Execute with or without 'Wait for Completion'
* Get the Windows Handle of the running App.
* Determine if the Executed App is still running.
* Close the running App (Like a user would)
* Terminate the running App (Like 'End Task' in Task Manager)
* Autoclose the App if running when class Freed or your App terminates.
* SetFocus and Restore a running App.
Usage Examples :
...
var WApp : TWinApp;
...
WApp := TWinApp.Create;
WApp.ApplcationName := 'c:\winnt\notepad.exe';
WApp.parameters := 'c:\mytest.txt';
[or]
WApp := TWinApp.Create('c:\winnt\notepad.exe','c:\mytest.txt');
...
WApp.Execute;
...
PostMessage(WApp.Handle,WM_XXXX, .....
...
WApp.Close
...
if WApp.IsRunning then WApp.SetFocus .....
...
if .... then WApp.Terminate
...
WApp.Free; (WApp will close if CloseOnExit = true)
This is a brand new beta class from my side, so any bugs,
fixes or enhancements will be appreciated.
Answer:
unit MahWinExec;
interface
uses Windows, Messages, SysUtils, Forms;
// ==========================================================================
// Class to Manage External Windows Application in your Application
// Mike Heydon April 2004
//
// PROPERTIES
// ----------
// WaitForHandle - Denotes whether to wait for windows to create and
// allocate a Handle to the Main Window of the Executed
// Application. Default is false. (Only neede to be true
// if you really required the window handle IMMEDIATELY
// after calling execute). If false the Handle will
// eventually become available once the app has loaded
// and created the main window.
//
// Handle - Returns the Handle of the Executed App's main window.
// See property WaitForHandle. This can be used for API
// calls such as SendMessage() and ShowWindow() or any
// call that requires a valid Windows Handle (HWND).
//
// CloseOnExit - Denotes whether to close the Executed App (if running)
// when YOUR applications end. Default is true.
//
// IsRunning - Read Only. Denotes whether the Executed App is still
// running or not. It may have been closed by the User,
// Close Method, Terminate Method etc.
//
// ApplicationName - Name of the App to Execute. Can also be specified at
// Create time using an overloaded Create() method.
// eg. 'c:\winnt\notepad.exe'
//
// StartDirectory - Name of the Directory to start the Application in.
// Default is '' (Current Directory).
// eg. 'c:\mydir'
//
// Parameters - Any parameters (Command Line Argument) to the App.
// eg. 'c:\mydata\problems.txt'
//
// METHODS
// -------
// Execute - Execute the Application specified by properties
// ApplicationName,Parameters and StartDirectory.
// If optional parameter AWaitForTerminate is set to
// true then Execute will NOT return until the Executed
// Application has been shut down or terminated. Default
// for this parameter is false (Executes returns
// immediately and execution of main thread continues)
// You can also direct Execute to wait for the main
// window handle to be created, see property
// WaitForHandle for details.
//
// Close - If the App is Running then a windows message is sent
// to it instruction it to close and exit. This is the
// same as if the User had selected EXIT in the App.
//
// Terminate - If the App is Running then TerminateProcess() is
// executed on the App's process ID. This is the same as
// selected "End Task" in the task manager. Use it only in
// extreme circumstances. The state of global data
// maintained by dynamic-link libraries (DLLs) may be
// compromised if Terminate is used rather than Close
//
// SetFocus - If Running then the Executed App is given focus.
//
// ==========================================================================
type
// TWinApp - Windows Executable App manager
TWinApp = class(TObject)
private
FApplicationName,
FStartDirectory,
FParameters : string;
FCloseOnExit,
FWaitForHandle : boolean;
FProcHandle : THandle;
FStartupInfo : TStartupInfo;
FProcessInfo : TProcessInformation;
function GetWindowHandle : THandle;
function GetAppRunning : boolean;
public
// Methods
constructor Create; overload;
constructor Create(const AApplicationName : string;
AParameters : string = '';
AStartDirectory : string = ''); overload;
destructor Destroy; override;
function Execute(AWaitForTerminate : boolean = false) : boolean;
procedure Terminate;
procedure Close;
procedure SetFocus;
// Properties
property Handle : THandle read GetWindowHandle;
property WaitForHandle : boolean read FWaitForHandle
write FWaitForHandle;
property IsRunning : boolean read GetAppRunning;
property CloseOnExit : boolean read FCloseOnExit write FCloseOnExit;
property ApplicationName : string read FApplicationName
write FApplicationName;
property Parameters : string read FParameters write FParameters;
property StartDirectory : string read FStartDirectory
write FStartDirectory;
end;
// --------------------------------------------------------------------------
implementation
// ====================================
// Constructor Methods - Overloaded
// ====================================
constructor TWinApp.Create;
begin
FProcHandle := 0;
FCloseOnExit := true;
FApplicationName := '';
FStartDirectory := '';
FParameters := '';
FWaitForHandle := false;
end;
constructor TWinApp.Create(const AApplicationName : string;
AParameters : string = '';
AStartDirectory : string = '');
begin
Create; // Call Standard Constructor
FApplicationName := AApplicationName;
FParameters := AParameters;
FStartDirectory := AStartDirectory;
end;
// =====================================================================
// Get Handle of Main Window of Executed Application
// Returns 0 if App not running or No main Window Handle.
//
// NOTE : If WaitForHanlde is false this function may return 0 if called
// to soon after Execute(), as the Main Window may not yet have
// been created and a Windows Handle allocated. If you require
// the handle immediately after calling Execute then set
// property WaitForHandle to true. Execute will then not return
// until the Windows Handle is present.
// Default for WaitForHandle is false.
// =====================================================================
function TWinApp.GetWindowHandle : THandle;
type PTEnumCodeData = ^TEnumCodeData; // Data struture used
TEnumCodeData = record // for API CallBack Proc
WindowsHandle, // EnumWindowsCode()
ProcessHandle : THandle;
end;
var rEnumCodeData : TEnumCodeData;
Retvar : THandle;
// Win API Callback Function
function EnumWindowsCode(Wnd : hWnd;
PInfo : PTEnumCodeData) : boolean;
export; stdcall;
var hProcess : THandle;
begin
GetWindowThreadProcessId(Wnd,hProcess);
if PInfo^.ProcessHandle = hProcess then begin
PInfo^.WindowsHandle := Wnd;
Result := false;
end
else
Result := true;
end;
// Start GetWindowHandle()
begin
if FProcHandle 0 then begin
rEnumCodeData.ProcessHandle := FProcessInfo.dwProcessId;
rEnumCodeData.WindowsHandle := 0;
EnumWindows(@EnumWindowsCode,integer(@rEnumCodeData));
Retvar := rEnumCodeData.WindowsHandle;
end
else
Retvar := 0;
Result := Retvar;
end;
// ===============================================
// Destructor Method
// If property CloseOnExit is true then the
// Executed Application is closed if running
// ===============================================
destructor TWinApp.Destroy;
begin
if FCloseOnExit and GetAppRunning then Close;
if FProcHandle 0 then CloseHandle(FProcHandle);
inherited Destroy;
end;
// =====================================
// Check if the app is running or not
// =====================================
function TWinApp.GetAppRunning : boolean;
var Retvar : boolean;
iExitCode : DWORD;
begin
if FProcHandle 0 then begin
if GetExitCodeProcess(FProcHandle,iExitCode) then
Retvar := iExitCode = STILL_ACTIVE
else
Retvar := false;
end
else
Retvar := false;
Result := Retvar;
end;
// ==============================
// Execute the application
// ==============================
function TWinApp.Execute(AWaitForTerminate : boolean = false) : boolean;
var Retvar : boolean;
sCurrDir,
sCommand : string;
Wnd : THandle;
begin
Retvar := false; // Assume we can't execute
if not GetAppRunning then begin
if FProcHandle 0 then CloseHandle(FProcHandle);
sCurrDir := GetCurrentDir;
if trim(FStartDirectory) '' then
SetCurrentDir(FStartDirectory);
FParameters := trim(FParameters);
FProcHandle := 0;
FillChar(FStartupInfo,SizeOf(FStartupInfo),0);
FStartupInfo.wShowWindow := SW_SHOWNORMAL;
FStartupInfo.cb := SizeOf(FStartupInfo);
if FParameters '' then
sCommand := trim(FApplicationName) + ' "' +FParameters + '"'
else
sCommand := trim(FApplicationName);
if CreateProcess(nil,PChar(sCommand),nil,nil,false,0,nil,nil,
FStartupInfo,FProcessInfo) then begin
// Must we wait for App to finish ?
// If so then all handles are n/a
if AWaitForTerminate then begin
WaitForSingleObject(FProcessInfo.hProcess,INFINITE);
FProcHandle := 0;
end
else begin
// Get Main Window Process Handle
// FProcessInfo.dwProcessID is NOT the handle we are
// looking for. (think it is an Explorer Process
FProcHandle := OpenProcess(PROCESS_ALL_ACCESS,false,
FProcessInfo.dwProcessId);
// Must we wait until App is loaded and has a windows handle ?
// If so then stay in loop until Main Windows of App is created
// and a Windows Handle has been allocated.
// Default for this action is false
if FWaitForHandle then
while GetWindowHandle = 0 do Application.ProcessMessages;
end;
// Close unused handles
CloseHandle(FProcessInfo.hProcess);
CloseHandle(FProcessInfo.hThread);
Retvar := true;
end
else
FProcHandle := 0;
SetCurrentDir(sCurrDir);
end
else begin
if FProcHandle 0 then begin
Wnd := GetWindowHandle;
if Wnd 0 then begin
// Focus and DeMinize App
SetForegroundWindow(Wnd);
ShowWindow(Wnd,SW_RESTORE);
Retvar := true;
end;
end;
end;
Result := RetVar;
end;
// =============================================
// Ask the Application to close down normally
// =============================================
procedure TWinApp.Close;
var Wnd : THandle;
begin
if FProcHandle 0 then begin
Wnd := GetWindowHandle;
if Wnd 0 then PostMessage(Wnd,WM_QUIT,0,0);
end;
end;
// ===================================================================
// The Terminate method is used to unconditionally cause a
// TWinApp to exit. Use it only in extreme circumstances. The state of
// global data maintained by dynamic-link libraries (DLLs) may be
// compromised if Terminate is used rather than Close
// ===================================================================
procedure TWinApp.Terminate;
begin
if FProcHandle 0 then TerminateProcess(FProcHandle,0);
end;
// ========================================
// Bring to the front and give focus
// ========================================
procedure TWinApp.SetFocus;
var Wnd : THandle;
begin
if FProcHandle 0 then begin
Wnd := GetWindowHandle;
if (Wnd 0) and GetAppRunning then begin
SetForegroundWindow(Wnd);
ShowWindow(Wnd,SW_RESTORE);
end;
end;
end;
end.