Kill process

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
EKIMAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Wim ten BrinkSelf-employed developerCommented:
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
EKIMAuthor Commented:
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
geobulCommented:
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
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

EKIMAuthor Commented:
geobul : hu...  what is the difference with my code ?
0
geobulCommented:
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

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
geobulCommented:
If you get 'Parameter is incorrect' it means that there is no such process (PID is wrong).
0
EKIMAuthor Commented:
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
geobulCommented:
And you're receiving 'Access is denied', right?
0
Wim ten BrinkSelf-employed developerCommented:
> 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
HypoviaxCommented:
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
DragonSlayerCommented:
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
geobulCommented:
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
winexecCommented:
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
EKIMAuthor Commented:
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
DragonSlayerCommented:
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
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.