?
Solved

Kill process

Posted on 2004-11-18
15
Medium Priority
?
20,968 Views
Last Modified: 2012-08-13
Main question : how to kill a process (Delphi 5 or 7(as U want)  , XP )
Origin :
   I use Firebird Classic  as DB. For each connection, a new firebird process is created on the server. this would not be a problem, except when the Client lose the connection for any resaon (hard reboot, network problem...) : In such case, the process stay launched on the server, and its attached ressources stay reserved (ie Memory).

I am abble to retreive with instance is no more connected with a client, and get this PID.

I tried this, but it does not works:


procedure TForm1.KillProcess(PID: Cardinal);
var
  exitcode:UINT;
  x:THandle;
begin
  x:=Openprocess(PROCESS_ALL_ACCESS,false,PID);
  GetExitCodeProcess(x,ExitCode);
  TerminateProcess(x,Exitcode);
end;

 --> X always receive 0 from OpenProcess (why?)

I also tried this :

procedure TForm1.KillProcess(PID: Cardinal);
begin
  SendMessage(PID,wm_close,0,0);
end;

but it also does not seems to works...

Thanks for any help.

Ekim
0
Comment
Question by:EKIM
  • 5
  • 4
  • 2
  • +3
15 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12613545
Terminating the process won't be very useful since it might still lead to resources being used. In general, with using client-server techniques, the best thing to do is connect upon request and disconnect before returning a reply. Maybe maintain a pool of connections somewhere to speed up the connection speed. But you will always have this problem if you keep connections open between requests.
I knwo, it is a lot easier to keep it open. Performs a little better too. But you have to be aware that connections can be broken anytime. This is why most client-server solutions are stateless solutions. (The server closes and frees anything it doesn't need as soon as it has the reply ready.)
I think it's better to redesign your server-side code instead.

To forcefully close a process, you might want to call some kernel function to do this. I have forgotten which one, though. And it only works on NT systems. You also need appropiate privileges too. Killing processes are a real pain...
You might consider including a separate thread in your server-side code that just kills the process if a time-out occurs. Then again, instead of killing the process, the thread could just kill the connection and free the resources...
0
 

Author Comment

by:EKIM
ID: 12613687
Are you serious ?
 - If I open/close the connection on each request It will take really too much time !
 - I cannot modify the Database Server source code !
0
 
LVL 17

Expert Comment

by:geobul
ID: 12613774
Try this:

procedure TForm1.KillProcess(PID: Cardinal);
var
  exitcode:UINT;
  x:THandle;
begin
  x:=Openprocess(PROCESS_TERMINATE,false,PID);
  if x <> 0 then begin
    try
      GetExitCodeProcess(x,ExitCode);
      TerminateProcess(x,Exitcode);
    finally
      CloseHandle(x);
    end;
  end;
end;

Regards, Geo
0
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 

Author Comment

by:EKIM
ID: 12613807
geobul : hu...  what is the difference with my code ?
0
 
LVL 17

Accepted Solution

by:
geobul earned 2000 total points
ID: 12613835
It should be
h := OpenProcess(PROCESS_TERMINATE or PROCESS_QUERY_INFORMATION, false, PID);

but are you really need the exit code? If not try:

procedure TForm1.KillProcess(PID: Cardinal);
var
  exitcode:UINT;
  x:THandle;
begin
  x:=Openprocess(PROCESS_TERMINATE,false,PID);
  if x <> 0 then begin
    try
      TerminateProcess(x, 0);
    finally
      CloseHandle(x);
    end;
  end;
end;

Possible reasons are:
- you don't have any access to that process and can't open it;
- PID is wrong;
- something else.

Check GetLastError to see why:

var
  lpMsgBuf: THandle;
  exitcode:UINT;
  x:THandle;
begin
  x:=Openprocess(PROCESS_TERMINATE,false,PID);
  if x <> 0 then begin
    try
      TerminateProcess(x, 0);
    finally
      CloseHandle(x);
    end;
  end else begin
    FormatMessage(
      FORMAT_MESSAGE_ALLOCATE_BUFFER or FORMAT_MESSAGE_FROM_SYSTEM,
      nil,
      GetLastError(),
      0,
      PChar(@lpMsgBuf),
      0,
      nil);
    ShowMessage(PChar(lpMsgBuf));
    LocalFree(lpMsgBuf);
  end;
end;

Regards, Geo
0
 
LVL 17

Expert Comment

by:geobul
ID: 12613872
If you get 'Parameter is incorrect' it means that there is no such process (PID is wrong).
0
 

Author Comment

by:EKIM
ID: 12614133
GeoBul : while I was trying your code, I understood something : I was trying to kill the service rather than the applications this service launch on each connection.
I changed this, but it does not works if the service is logged on with 'Local System Account'...
0
 
LVL 17

Expert Comment

by:geobul
ID: 12614286
And you're receiving 'Access is denied', right?
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 12614589
> Are you serious ?
Yes, I am...
Which is why I suggested the option of connection pooling. Microsoft is doing something like that in their ADO components and ODBC also has support for the pooling of connections. Basically, it just means that after you're done with a connection, you send it to some pool (array of connection) and keep it there until you can use it again. Because all the connections are stored in a global array, you could free those connections if they're in the pool for more than 5 minutes. But if a user requests new data, you take an open connection from this pool instead of opening a new one. If there are no connections in the pool, then you'll have to create a new connection. And once the user is done with the connection, you put it back into the pool.

>  - If I open/close the connection on each request It will take really too much time !
Have you even tried it? I know it will slow things down but are we talking about milliseconds, seconds or even minutes? Maybe if you need to retrieve a lot of data at once, you should use a different approach instead. In general, when you do client-server applications you should close resources on the server as soon as possible, because there could be 5000 other clients who also want to do stuff... And if you could re-use something for another user, then that would be perfect. Thus, connection-pooling...

> - I cannot modify the Database Server source code !
Well, that is a good excuse! ;-)
Okay, See http://help.madshi.net/Processes.htm for some process handling examples. You would need the Madshi components for this, though.
But there's a chance that the process that you're trying to kill is set up as something extremely secure and thus you might need proper access rights to kill it. If you don't have proper access rights, terminating the process will fail. This is especially true for services.
0
 
LVL 5

Expert Comment

by:Hypoviax
ID: 12621589
function KillTask(ExeFileName: string): integer;
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 is good code for killing by exename.

For killing by PID (done off top of head but should work):

procedure TForm1.KillProcess(PID: Cardinal);
const
PROCESS_TERMINATE=$0001;
begin
    TerminateProcess(OpenProcess(PROCESS_TERMINATE, BOOL(0),PID), 0);
end;


Regards,

Hypoviax
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12621796
Well, a bit off-topic, but is your db server running on multiprocessor machine? Because otherwise, there is not much sense in using the Classic Server. With the SuperServer, only one instance of the db server runs, but each connection will open up a new thread, but sharing the same cache. Which means, if there is a number of simultaneous connections requesting the same data, apart from the first request, everyone will be reading from the cache, making it much faster!

http://firebird.sourceforge.net/manual/qsg15-classic-or-super.html
0
 
LVL 17

Expert Comment

by:geobul
ID: 12622960
I have no experience using Firebird but if you make the service logging under your account instead of Local System then you'll be able to kill its processes using your first code. Not sure if changing the Logon account is allowed, though.
0
 
LVL 1

Expert Comment

by:winexec
ID: 12623104
you have to set the privileges before killing, like that:

procedure KillPrivilege;
var
   DebugValue : TLargeInteger;
   tkp : TTokenPrivileges ;
   PreviousState: TTokenPrivileges;
   dw:DWORD;
   h:THandle;
begin
   OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,h);
   lookupPrivilegeValue(nil,'SeDebugPrivilege', DebugValue);
   dw:=0;
   tkp.PrivilegeCount:=1;
   tkp.Privileges[0].Luid:=DebugValue;
   tkp.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;
   AdjustTokenPrivileges(h,false,tkp, SizeOf(TTokenPrivileges),PreviousState ,dw);
end;


0
 

Author Comment

by:EKIM
ID: 12623125
Dragon Slayer : sys used : Windows Server2003.
We were using the super server but we frequently get a Firebird system crash... After looking deeper, it seems that the max memory allocated by W2003 to an application is 4Go (the system has 8Go). This 4Go was splitted (according W2003 params) to 2Go for Application and 2Go for System. It seems that when the transaction manager need more than 2Go, the whole system crsashes...  (instead of using swap)
Question is : 1) Why Super sever need so much memory ?? (DB is +/- 6Go, 40 Users)
                   2) Does W2003 or SuperServer frees memory properly
                   4) Does W2003 or SuperServer have problem tu re-use recently freed memory

Because we are a company, we cannot leave our customers in such situation, So we decided to install them the classic server witch does not have this problem, waiting for another solution. BUT, Classic server is not without any problem, specially when the TCP/IP connection is lost. This is why I'am trying to hook the fbirg task create process( as U can see I have a question on this subject in Programming/Delphi topic)   to link it with a User ID, and when thê same user ID tries to re-connect: I can know that there was already a connection(lost) to this user and then shoot it.

Geobul : yep, it works fine with my loggin, I think I will do like this... for the moment.

EKIM
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 12623258
Here is a bugtracker report from sourceforge that you might want to track... I don't know if it is relevant, but it might be... http://sourceforge.net/tracker/?group_id=9028&atid=109028&func=detail&aid=1021143
0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying 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

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…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
This lesson discusses how to use a Mainform + Subforms in Microsoft Access to find and enter data for payments on orders. The sample data comes from a custom shop that builds and sells movable storage structures that are delivered to your property. …
Whether it be Exchange Server Crash Issues, Dirty Shutdown Errors or Failed to mount error, Stellar Phoenix Mailbox Exchange Recovery has always got your back. With the help of its easy to understand user interface and 3 simple steps recovery proced…
Suggested Courses

864 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