Link to home
Start Free TrialLog in
Avatar of pr_wainwright
pr_wainwright

asked on

Terminate Running Process

How do I terminate a running process using delphi (same as using windows task manager - End Task). Program is not a windows program so I can't use...

var
  h: HWND;
begin
  h := FindWindow(nil, 'The Application Caption');
  if h <> 0 then PostMessage(h, WM_QUIT, 0, 0);
end;

I need to terminate using the applications name.

Thanks
Paul.
Avatar of pr_wainwright
pr_wainwright

ASKER

esoftbg,
           function KillTask(FileName:String):integer;

does not work on Windows NT (The process entry point Process32Next could not be located in the DLL kernel32.dll).

I don't know how to find the PID to use the following.

procedure CloseAProcess(PID: DWORD;);
var
 h: THandle;
begin
 try
   h := OpenProcess(PROCESS_TERMINATE, false, PID);
   try
     if h <> 0 then TerminateProcess(h, 0);
   finally
     CloseHandle(h);
   end;
 except
   ShowMessage('Error');
 end;
end;

The others use FindWindow & the program is not a windows program.

Regards
Paul.
 
you have to get the handle of the window so you can get the process id. use GetWindowThreadProcessID() to find the process id.

this works:

procedure TForm1.Button1Click(Sender: TObject);
var pid: Cardinal;
    ProcessHandle, wnd: THandle;
begin
 wnd := FindWindow(nil, 'Audacity');
 GetWindowThreadProcessID(wnd, @pid);
 ProcessHandle := OpenProcess(PROCESS_TERMINATE, FALSE, pid);
 TerminateProcess(ProcessHandle,4);
 CloseHandle(ProcessHandle);
end;
Hi,

Here it is:

Drop a Button and Edit controls on a form. Add the code below. Write 'Project1.exe' in the Edit and press the button.

uses
 TLHelp32, PsApi;

procedure CloseAProcess(PID: DWORD);
var
 h: THandle;
begin
 try
   h := OpenProcess(PROCESS_TERMINATE, false, PID);
   try
     if h <> 0 then TerminateProcess(h, 0);
   finally
     CloseHandle(h);
   end;
 except
   ShowMessage('Error');
 end;
end;

function RunningProcessesList(List: TStrings): Boolean;

 function BuildListTH: Boolean;
 var
   SnapProcHandle: THandle;
   ProcEntry: TProcessEntry32;
   NextProc: Boolean;
 begin
   SnapProcHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
   if SnapProcHandle <> THandle(-1) then
   begin
     Result := True;
     ProcEntry.dwSize := Sizeof(ProcEntry);
     NextProc := Process32First(SnapProcHandle, ProcEntry);
     while NextProc do
     begin
       List.AddObject(ProcEntry.szExeFile, Pointer(ProcEntry.th32ProcessID));
       NextProc := Process32Next(SnapProcHandle, ProcEntry);
     end;
     CloseHandle(SnapProcHandle);
   end else
     Result := False;
 end;

 function BuildListPS: Boolean;
 var
   PIDs: array[0..1024] of DWORD;
   Handle: THandle;
   Needed: DWORD;
   I: Integer;
   ModuleFileName: array[0..MAX_PATH] of Char;
 begin
   Result := EnumProcesses(@PIDs, Sizeof(PIDs), Needed);
   if not Result then Exit;
   for I := 0 to (Needed div Sizeof(DWORD)) - 1 do
     if PIDs[I] <> 0 then
     begin
       Handle := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, PIDs[I]);
       if Handle <> 0 then
       begin
         if GetModuleFileNameEx(Handle, 0, ModuleFileName, Sizeof(ModuleFileName)) = 0 then
           List.AddObject('[System]', Pointer(INVALID_HANDLE_VALUE))
         else
           List.AddObject(ModuleFileName, Pointer(PIDs[I]));
         CloseHandle(Handle);
       end;
     end;
 end;

begin
 Assert(Assigned(List));
 List.BeginUpdate;
 try
   List.Clear;
   if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion = 4) then
     Result := BuildListPS
   else
     Result := BuildListTH;
 finally
   List.EndUpdate;
 end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i: integer;
  PID: Cardinal;
  sl: TStringList;
begin
  sl := TStringList.Create;
  try
    RunningProcessesList(sl);
    repeat
      i := sl.IndexOf(Edit1.Text);
      if i > -1 then begin
        PID := Integer(Pointer(sl.Objects[i]));
        CloseAProcess(PID);
        sl.Delete(i);
      end;
    until i = -1;
  finally
    sl.Free;
  end;
end;

Regards, Geo
Geo,
      Still get this error using your code while running Windows NT4 (The process entry point Process32Next could not be located in the DLL kernel32.dll).

Any idea's

Thanks
Paul.

When are you getting that error - on startup of the app or when you are pressing the button?
The function BuildListTH should not be called if you're running NT4. The line:
if (Win32Platform = VER_PLATFORM_WIN32_NT) and (Win32MajorVersion = 4) then
should do that.

Could you tell me what Win32Platform and Win32MajorVersion your computer reports back?

Regards, Geo
Try:

function KillTask(ExeFileName: string): integer; //used to kill a process
const
PROCESS_TERMINATE=$0001;
var
ContinueLoop: BOOL;
FSnapshotHandle: THandle;
FProcessEntry32: TProcessEntry32;
begin
result := 0;
FSnapshotHandle := CreateToolhelp32Snapshot
(TH32CS_SNAPPROCESS, 0);
FProcessEntry32.dwSize := Sizeof(FProcessEntry32);
ContinueLoop := Process32First(FSnapshotHandle,
FProcessEntry32);
while integer(ContinueLoop) <> 0 do
begin
if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
UpperCase(ExeFileName))
or (UpperCase(FProcessEntry32.szExeFile) =
UpperCase(ExeFileName))) then
Result := Integer(TerminateProcess(OpenProcess(
PROCESS_TERMINATE, BOOL(0),
FProcessEntry32.th32ProcessID), 0));
ContinueLoop := Process32Next(FSnapshotHandle,
FProcessEntry32);
end;
CloseHandle(FSnapshotHandle);
end;

This will kill a process by it's exe name e.g.

killtask('notepad.exe');

Regards,

Hypoviax
U don't need to loop through all processes to kill a specific applications if u know the window caption

var pid: Cardinal;
    Process, h: THandle;
begin
 wnd := FindWindow(nil, 'The Application Caption'); //get the window handle
 GetWindowThreadProcessID(wnd, @pid); //then get it's pid
 ProcessHandle := OpenProcess(PROCESS_TERMINATE, FALSE, pid); //open the process with termination rights using the PID
 TerminateProcess(ProcessHandle,0); // terminate the process (in this case, 0 is the exit code)
 CloseHandle(ProcessHandle); //close the process handle beacuse we don't use the process ahndle anymore
end;

This only works if you know the window caption, but not the .exe filename

StTwister
Geo,
       1) The error is reported at startup
       2) Windows NT 4.0 Service Pack 5 Build 1381

Regards
Paul.
Sorry for the late reply. I was in another city for one week.

Can you open a new project, drop one TEdit and one TButton components on a form and apply my code above? Perhaps there is something else in your current test project which causes that error.

I cannot test it here because I have no NT4 at hand anymore but I used that code on NT 4 before (Delphi 5).

Regards, Geo
Geobul,
           Did not call 'BuildListTH', no error when program started but pressing the button did nothing.

Reagrds
Paul.
My fault, sorry. Modify the following lines as shown below:

in BuildListTH:
   List.AddObject(UpperCase(ProcEntry.szExeFile), Pointer(ProcEntry.th32ProcessID));

in BuildListPS:
  List.AddObject(UpperCase(ExtractFileName(ModuleFileName)), Pointer(PIDs[I]));

in ButtonClick:
  i := sl.IndexOf(UpperCase(Edit1.Text));

and try again.

Regards, Geo
Geo,
      Get this error using your new code while running Windows NT4 (The process entry point Process32First could not be located in the DLL kernel32.dll).

Thanks
Paul.


Process32First and the others seem not to work in NT4. You will need to find another way to enumerate processes before you can terminate them.
ASKER CERTIFIED SOLUTION
Avatar of geobul
geobul

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Geo,
       The company where I work are rolling out XP soon & I know your initial code works ok so I will award you the points.

Thanks
Paul.
Paul, thanks for the points. I'm so sorry I wasn't able to help you more.

Regards, Geo