Solved

Cancel Created Process

Posted on 2007-11-26
11
321 Views
Last Modified: 2010-04-21
I'm using Delphi to start another process, and that's working well (see code below). Now I want to add a button that cancels the started process if it runs too long.

What's the easiest/safest way to kill this process?

Thanks!
if not CreateProcess(nil,
                        pchar(sBatch + ' ' + sParams),
                        nil,
                        nil,
                        FALSE,
                        CREATE_DEFAULT_ERROR_MODE,
                        nil,
                        nil,
                        StartUpInfo,
                        ProcessInfo) then
    begin
      Form1.StatusBar1.Panels[0].Text :=
       ' Could not run program.';
      Form1.StatusBar1.Refresh;
      Exit;
    end
   else
    begin
      repeat
         iResult := WaitForSingleObject(ProcessInfo.hProcess, 100);
         Application.ProcessMessages;
      until (iResult <> WAIT_TIMEOUT);
      CloseHandle(ProcessInfo.hProcess);
      CloseHandle(ProcessInfo.hThread);
   end;

Open in new window

0
Comment
Question by:surfbored
  • 5
  • 3
  • 2
  • +1
11 Comments
 
LVL 18

Expert Comment

by:Johnjces
ID: 20352226
If you know what is in the other application's caption name,  you can use:

function CloseApp(const sCapt: PChar) : boolean;
  var AppHandle:THandle;
begin
  AppHandle:=FindWindow(Nil, sCapt) ;
  Result:=PostMessage(AppHandle, WM_QUIT, 0, 0) ;
end;

John
0
 
LVL 1

Author Comment

by:surfbored
ID: 20352327
Johnjces,

I'm not sure this would work since the started process is a CONSOLE app. I don't think CONSOLE apps have caption names? I was kinda hoping to use something a little more unique (I won't know if more than one app of the same name will be running).

Thanks!
0
 
LVL 18

Expert Comment

by:Johnjces
ID: 20352365
I did not realize that it was a console application. The window then would have the same caption, i.e. c:\Windows\system32\cmd.exe or command.com.

I do not know!

John

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 18

Expert Comment

by:Johnjces
ID: 20352451
It looks like you can get the ProcessID from the PROCESS_INFORMATION structure.

You might try this from Delphi3000.com:

http://www.delphi3000.com/articles/article_857.asp?SK=

John

0
 
LVL 1

Author Comment

by:surfbored
ID: 20352513
Johnjces,

Thanks again for the idea, but this link gives instructions specifically for Windows NT. I should have specified that I need it for Windows XP (and Vista too, preferably).

Sorry for the confusion.

I've bumped up the point value as well!
0
 
LVL 18

Expert Comment

by:Johnjces
ID: 20352552
Win2K, XP and even Vista are built on NT technology.

"Generally", what works for NT works for 2K, and XP.

Vista is whole different animal.

You should try it in any event! Might just work!

John

0
 
LVL 25

Accepted Solution

by:
imitchie earned 225 total points
ID: 20353030
This is a modification of what I use. NT and above (yes, Vista)
var
  Sei: TShellExecuteInfo;
  WaitHandles: array[0..1] of THandle;
 
// PUT THIS SOMEWHERE, MAYBE IN FORM CREATE
  WaitHandles[0] := CreateEvent(nil,TRUE,False,nil); // Signal Event;
 
// PUT THIS SOMEWHERE, MAYBE IN FORM DESTROY
  CloseHandle(WaitHandles[0]);
 
function TForm1.BtnAbortClick(Sender: TObject);
begin
  SetEvent(WaitHandles[0]); // signal abort
end;
 
function ShellExec(const FileName, Parameters, Directory: string;
  iWaitTime: integer;
  const Verb: string = 'OPEN';
  CmdShow: Integer = SW_SHOWNORMAL): integer;
var
  SeiResult: integer;
begin
  FillChar(Sei, SizeOf(Sei), #0);
  Sei.cbSize := SizeOf(Sei);
  Sei.fMask := SEE_MASK_DOENVSUBST  or SEE_MASK_FLAG_NO_UI  or
      SEE_MASK_NOCLOSEPROCESS or SEE_MASK_FLAG_DDEWAIT;
  Sei.lpFile := PChar(FileName);
  Sei.lpParameters := PCharOrNil(Parameters);
  Sei.lpDirectory := PCharOrNil(Directory);
  Sei.lpVerb := PCharOrNil(Verb);
  Sei.nShow := CmdShow;
  // try to execute
 
  if ShellExecuteEx(@Sei) then
  begin
    // now wait for it to finish
    WaitHandles[1] := Sei.hProcess;
    ResetEvent(WaitHandles[0]);
    SeiResult := WaitForMultipleObjects(2, @WaitHandles, False, iWaitTime);
    if (SeiResult = WAIT_TIMEOUT) or // timeout-kill
       (SeiResult = WAIT_OBJECT_0) then begin // user abort-kill
      TerminateProcess(Sei.hProcess, 0);
      CloseHandle(Sei.hProcess);
    end;
    Result := 0;
  end
  else
    Result := GetLastError;
end;

Open in new window

0
 
LVL 10

Expert Comment

by:dinilud
ID: 20355845
0
 
LVL 10

Expert Comment

by:dinilud
ID: 20355873
private
     ProcessInfo: TProcessInformation;


function ExecuteProcess(FileName: string; Visibility: Integer; BitMask: Integer; Synch: Boolean): Longword;
var
  zAppName: array[0..512] of Char;
  zCurDir: array[0..255] of Char;
  WorkDir: string;
  StartupInfo: TStartupInfo;
  Closed: Boolean;
begin
  Closed := True;
  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) // pointer to PROCESS_INF
    then Result := WAIT_FAILED
  else
  begin
    //running the process on the set of CPUs specified by BitMask
    SetProcessAffinityMask(ProcessInfo.hProcess, BitMask);
    /////
    if (Synch = True) then //if I want a Synchronous execution (I cannot close my
    // application before this process is terminated)
      begin
        Closed:= False;
        repeat
          case WaitForSingleObject(
            ProcessInfo.hProcess, 100) of
              WAIT_OBJECT_0 : Closed:= True;
              WAIT_FAILED : RaiseLastWin32Error;
          end;
          Application.ProcessMessages;
        until (Closed);
        GetExitCodeProcess(ProcessInfo.hProcess, Result);
        //exit code of the launched process (0 if the process returned no error  )
        CloseHandle(ProcessInfo.hProcess);
        CloseHandle(ProcessInfo.hThread);
      end
    else
      begin
        Result := 0;
      end;
  end;
end;

procedure KillProcess;
begin
   CloseHandle(ProcessInfo.hProcess);
   CloseHandle(ProcessInfo.hThread);
end;

    ......
    ......


   ExecuteProcess(FileName,1,0,False);

   procedure Button1Click(Sender:TObject);
   begin
      KillProcess;
   end;
0
 
LVL 18

Expert Comment

by:Johnjces
ID: 20362012
I ran across this which may help. Kill an application by name, i.e. mytask.exe.

Might help...

http://www.torry.net/samples/samples/soft/KillEXE.zip

John
0
 
LVL 1

Author Closing Comment

by:surfbored
ID: 31411052
None of the solutions offered were exactly what I asked for, but imitchie gave the most direct and simple response. With a little tweaking, it's what I ended up using. Thanks to everyone for taking the time and effort.
0

Featured Post

Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…
In an interesting question (https://www.experts-exchange.com/questions/29008360/) here at Experts Exchange, a member asked how to split a single image into multiple images. The primary usage for this is to place many photographs on a flatbed scanner…

733 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