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.