Mega Code Archive

 
Categories / Delphi / System
 

Class to Execute and Manage External EXE in your App

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.