Topic TerminateProcess introduced the equivalent to the Unix "kill -9" command.
The following 4GL procedure KillProcess(pid) also terminates a process, but tries to avoid the use of TerminateProcess.
Procedure CloseProcessWindows is based on API-function EnumWindows. This API-function can not be called from within P4GL because it needs a callback, so I wrote procedure CloseProcessWindows in Pascal and added it to proextra.dll (see page ProExtra.dll). Of course I might as well have included all the rest in Pascal too, but then I would not allow myself to post it on this Progress site :-)
By the way, the topic on CreateProcess shows how to create a process and return a PID.
{windows.i}
{proextra.i} /* version August 21, 1999 */
&GLOBAL-DEFINE PROCESS_QUERY_INFORMATION 1024
&GLOBAL-DEFINE PROCESS_TERMINATE 1
&GLOBAL-DEFINE STILL_ACTIVE 259
/* =======================================================
IsProcessRunning
Returns TRUE if the process is not terminated.
(also returns TRUE if the process is hanging)
------------------------------------------------------- */
FUNCTION IsProcessRunning RETURNS LOGICAL (PID AS INTEGER) :
DEFINE VARIABLE IsRunning AS LOGICAL NO-UNDO INITIAL NO.
DEFINE VARIABLE hProcess AS INTEGER NO-UNDO.
DEFINE VARIABLE ExitCode AS INTEGER NO-UNDO.
DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO.
RUN Sleep IN hpApi (0).
/* Sleep(0) just gives the remainder of this
thread's time quantum back to the task switcher so the other
process gets the opportunity to finish and release itself. */
RUN OpenProcess IN hpApi
( {&PROCESS_QUERY_INFORMATION},
0,
PID,
OUTPUT hProcess).
IF hProcess NE 0 THEN DO:
RUN GetExitcodeProcess IN hpApi
( hProcess,
OUTPUT ExitCode,
OUTPUT ReturnValue).
IsRunning = (ExitCode={&STILL_ACTIVE}) AND (ReturnValue NE 0).
RUN CloseHandle IN hpApi(hProcess, OUTPUT ReturnValue).
END.
RETURN IsRunning.
END FUNCTION.
/* =======================================================
KillProcess
terminates a process as gently as possible.
pHow tells you how it is done, for debugging purposes
------------------------------------------------------- */
PROCEDURE KillProcess :
DEFINE INPUT PARAMETER PID AS INTEGER NO-UNDO.
DEFINE OUTPUT PARAMETER pHow AS CHARACTER NO-UNDO.
DEFINE VARIABLE cName AS CHARACTER NO-UNDO.
DEFINE VARIABLE ReturnValue AS INTEGER NO-UNDO.
DEFINE VARIABLE ProcessHandle AS INTEGER NO-UNDO.
/* first step: */
/* ------------ */
/* verify if the process is really running */
pHow='not running'.
IF NOT IsProcessRunning(PID) THEN RETURN.
/* second step: */
/* ------------ */
/* does the process have windows?
If it does, the nicest way to stop the process is
send a WM_CLOSE message to each window, as if a human operator
pressed the [x]-titlebar button. */
/* If the process is very young it might not have created a window yet.
Use WaitForInputIdle to wait until the process has a window and is
ready to receive messages. */
pHow='close'.
RUN OpenProcess IN hpApi({&PROCESS_QUERY_INFORMATION},
0,
PID,
OUTPUT ProcessHandle).
IF ProcessHandle NE 0 THEN
RUN WaitForInputIdle IN hpApi(ProcessHandle,
1000, /* one second maximum */
OUTPUT ReturnValue).
RUN CloseProcessWindows IN hpExtra (PID, OUTPUT ReturnValue).
/* ReturnValue=0 if the PID didn't own any windows.
The windows may be too busy to close immediately.
Give them 5 seconds to respond.
That's what the Windows Task Manager would also do. */
IF ReturnValue NE 0 THEN
RUN WaitForSingleObject IN hpApi (ProcessHandle,
5000, /* five seconds maximum */
OUTPUT ReturnValue).
RUN CloseHandle IN hpApi(ProcessHandle, OUTPUT ReturnValue).
/* third step: */
/* ----------- */
/* If PID is a Progress session it would be nice to execute PROSHUT.
You would first have to find the user number
via the VST _Connect table. And you would have
to repeat this for every database the process is connected to. */
/* I am not going to do this, but it would have been nice... */
/* last step: */
/* ---------- */
/* because everything else failed: TerminateProcess.
This is similar to "kill -9" in Unix so should be avoided */
/* Must assume we have sufficient rights for terminating this process. */
IF NOT IsProcessRunning(PID) THEN RETURN.
pHow='kill'.
RUN OpenProcess IN hpApi({&PROCESS_TERMINATE}, 0, PID, OUTPUT ProcessHandle).
IF ProcessHandle NE 0 THEN DO:
RUN TerminateProcess IN hpApi(ProcessHandle, 0, OUTPUT ReturnValue).
RUN CloseHandle IN hpApi(ProcessHandle, OUTPUT ReturnValue).
END.
/* if everything failed the process will keep running. How could this happen? */
IF IsProcessRunning(PID) THEN pHow='failed'.
END PROCEDURE.