Solved

Cancel Created Process

Posted on 2007-11-26
11
317 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
 
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
This is used to tweak the memory usage for your computer, it is used for servers more so than workstations but just be careful editing registry settings as it may cause irreversible results. I hold no responsibility for anything you do to the regist…

911 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

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now