Delphi - gracefully closing a created process in a service. (using tprocess / createProcess)

I have a Windows Service written in Delphi that runs several programs.

When the service stops, I want to close these programs as well. When the service was originally written it worked well, but I think I updated the tProcess component and now - subordinate programs are not closed.

in tProcess - here is the code that starts new processes.

  if CreateProcess( nil , PChar( FProcess.Command ) , nil , nil , False ,
    NORMAL_PRIORITY_CLASS , nil , Directory ,
    StartupInfo , ProcessInfo ) then
    begin
      if FProcess.Wait then
        begin
          WaitForSingleObject( ProcessInfo.hProcess , Infinite );
          GetExitCodeProcess( ProcessInfo.hProcess , ExitCode );
          if Assigned( FProcess.FOnFinished ) then
            FProcess.FOnFinished( FProcess , ExitCode );
        end;
      CloseHandle( ProcessInfo.hProcess );
      CloseHandle( ProcessInfo.hThread );
    end;

      

Each of the executables called by this are Windows GUI programs (with a close button at the top).

When I stop the service, I also want to stop (not kill) the programs that I started using the createProcess procedure.

How do you do it?

+1


source to share


3 answers


You want to list the open windows corresponding to your running process and tell those windows to close. Here's some sample code for that:

uses Windows;

interface   

function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean; stdcall;

implementation

function MyTerminateAppEnum(hHwnd:HWND; dwData:LPARAM):Boolean; 
var   
  vID:DWORD; 
begin   
  GetWindowThreadProcessID(hHwnd, @vID);   
  if vID = dwData then   
  begin
    PostMessage(hHwnd, WM_CLOSE, 0, 0); //tell window to close gracefully
    Result := False;  //can stop enumerating    
  end   
  else   
  begin
    Result := TRUE;  //keep enumerating until you find your id   
  end; 
end;

      



Then you will want to use this in your code if you want to close running applications:

Procedure TerminateMe(YourSavedProcessInfo:TProcessInformation);
var
  vExitCode:UINT;
begin
  GetExitCodeProcess(YourSavedProcessInfo.hProcess, vExitCode);
  if (vExitCode = STILL_ACTIVE) then  //launched app still running..
  begin
    //tell it to close
    EnumWindows(@MyTerminateAppEnum, YourSavedProcessInfo.dwProcessId);

    if WaitForSingleObject(YourSavedProcessInfo.hProcess, TIMEOUT_VAL) <> WAIT_OBJECT_0 then
    begin
      if not TerminateProcess(YourSavedProcessInfo.hProcess, 0) then  //didn't close, try to terminate
      begin
         //uh-oh   Didn't close, didn't terminate..
      end;
    end;
  end;
  CloseHandle(YourSavedProcessInfo.hProcess);
  CloseHandle(YourSavedProcessInfo.hThread);
end;

      

+1


source


I would use the TJvCreateProcess JVCL component , which wraps any win32 process related functionality in an elegant way. This answer comes from the Dont-touch-winapi-if-really-required department :-)



+4


source


The only common way to stop a process is using TerminateProcess . But it's not as graceful as you can get. To gracefully close a process, you need to tell the process that you want to stop and then hope that it obeys. But in general, this cannot be done.

For a GUI program, the usual way to say that you want to stop it is to close the main window. However, there is no formal idea of ​​a "main window". A program can have zero or more windows, and there is no way of knowing from the outside which one you have to close for the program to stop working.

You can use EnumWindows to view all windows and select those that belong to your process. (These were the ones for which GetWindowThreadProcessId gives the same process ID that CreateProcess provided.)

Closing the window may not be enough. The program may display a dialog box (confirmation request or a request to save changes, etc.). You need to know in advance how to dismiss this dialog.

Non-GUI programs can have similar problems. This might be enough to simulate Ctrl + C key press. However, it does boast and handle this pressing. It may have a menu system that expects you to type "Q" to exit the program.

In short, you cannot gracefully close a program unless you know ahead of time how that program expects to close.

+1


source







All Articles