&GLOB PROCESS_QUERY_INFORMATION 1024
&GLOB PROCESS_VM_READ 16
&GLOB MAX_PATH 260
&GLOB TH32CS_SNAPPROCESS 2
&GLOB PROCESS_TERMINATE 1
 
DEFINE VARIABLE viPID AS INTEGER    NO-UNDO.
DEFINE VARIABLE ProcessHandle AS INTEGER    NO-UNDO.
DEFINE VARIABLE lpId          AS MEMPTR  NO-UNDO.
DEFINE VARIABLE PID           AS INTEGER NO-UNDO.
DEFINE VARIABLE cbNeeded      AS INTEGER NO-UNDO.
DEFINE VARIABLE i             AS INTEGER NO-UNDO.
DEFINE VARIABLE ReturnValue   AS INTEGER NO-UNDO.
 
PROCEDURE EnumProcesses EXTERNAL "psapi.dll" :
  DEFINE INPUT  PARAMETER lpIdProcess AS LONG.
  DEFINE INPUT  PARAMETER cb          AS LONG.
  DEFINE OUTPUT PARAMETER cbNeeded    AS LONG.
  DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.
 
PROCEDURE EnumProcessModules EXTERNAL "psapi.dll" :
  DEFINE INPUT  PARAMETER hProcess    AS LONG.
  DEFINE INPUT  PARAMETER lphModule   AS LONG.  /* lp to array of module handles */
  DEFINE INPUT  PARAMETER cb          AS LONG.
  DEFINE OUTPUT PARAMETER cbNeeded    AS LONG.
  DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.
 
PROCEDURE GetModuleBaseNameA EXTERNAL "psapi.dll" :
  DEFINE INPUT  PARAMETER hProcess      AS LONG.
  DEFINE INPUT  PARAMETER hModule       AS LONG.
  DEFINE OUTPUT PARAMETER lpBaseName    AS CHAR.
  DEFINE INPUT  PARAMETER nSize         AS LONG.
  DEFINE RETURN PARAMETER nReturnedSize AS LONG.
END PROCEDURE.
 
PROCEDURE OpenProcess EXTERNAL "kernel32.dll" :
  DEFINE INPUT  PARAMETER dwDesiredAccess AS LONG.
  DEFINE INPUT  PARAMETER bInheritHandle  AS LONG.
  DEFINE INPUT  PARAMETER dwProcessId     AS LONG.
  DEFINE RETURN PARAMETER hProcess        AS LONG.
END PROCEDURE.
 
PROCEDURE CloseHandle EXTERNAL "kernel32.dll" :
  DEFINE INPUT  PARAMETER hObject     AS LONG.
  DEFINE RETURN PARAMETER ReturnValue AS LONG.
END PROCEDURE.

FUNCTION GetProcessName RETURNS CHAR (INPUT PID AS INTEGER) :
 
  DEFINE VARIABLE hProcess      AS INTEGER NO-UNDO.
  DEFINE VARIABLE cbNeeded      AS INTEGER NO-UNDO.
  DEFINE VARIABLE lphMod        AS MEMPTR  NO-UNDO.
  DEFINE VARIABLE szProcessName AS CHAR    NO-UNDO.
  DEFINE VARIABLE ReturnValue   AS INTEGER NO-UNDO.
 
  /* OpenProcess returns a handle (hProcess),
     needed for querying info about the process */
  RUN OpenProcess ( {&PROCESS_QUERY_INFORMATION} + {&PROCESS_VM_READ},
                    0,
                    PID,
                    OUTPUT hProcess).
 
  /* some system processes can not be queried, 
     like "System" and "System Idle Process" and "csrss.exe".
     ProcessName will be initialized to [unknown] for these processes: */
  szProcessName = "[unknown]" + FILL(" ", {&MAX_PATH}).
  IF hProcess NE 0 THEN DO:
 
     /* EnumProcessModules fills an array of module handles */
     /* The first module handle is a handle to the main module, and that's the 
        only handle you need  */
     SET-SIZE (lphMod) = 4. /* need only one hMod  */
     RUN EnumProcessModules ( hProcess,
                              GET-POINTER-VALUE(lphMod),
                              GET-SIZE(lphMod),
                              OUTPUT cbNeeded,
                              OUTPUT ReturnValue).
     IF ReturnValue NE 0 THEN DO:
        /* GetModuleBaseNameA returns the name of a module.
           Because this module is the main module, it's also considered to 
           be the name of the process */
        RUN GetModuleBaseNameA (hProcess,
                                GET-LONG(lphMod,1),
                                OUTPUT szProcessName,
                                LENGTH(szProcessName),
                                OUTPUT ReturnValue).
        /* ReturnValue is the number of returned bytes (chars): */
        szProcessName = SUBSTRING(szProcessName,1,ReturnValue).
        SET-SIZE (lphMod) = 0.
     END.
     RUN CloseHandle ( hProcess, OUTPUT ReturnValue).
  END.
  RETURN TRIM(szProcessName).
 
END FUNCTION.
 
{inc/windows.i}

FUNCTION WINGetVersion RETURNS CHARACTER () :
/*-----------------------------------------------------------------------------
  Purpose: Calls the WINAPI function GetVersionExA to determine the version
           of the Windows operating system that is running on the machine.
    Notes: Returns "95" for Windows 95, "98" for Windows 98, "NT" for Windows NT
           Returns "undef" if unable to determine platform.
------------------------------------------------------------------------------*/
 
    DEF VAR v_version-buf AS MEMPTR.
    DEF VAR v_platform-id AS INTEGER NO-UNDO.
    DEF VAR v_platform-desc AS CHAR NO-UNDO.
    DEF VAR v_major-version AS INTEGER NO-UNDO.
    DEF VAR v_minor-version AS INTEGER NO-UNDO.
    DEF VAR v_return-value  AS INTEGER NO-UNDO.
 
    SET-SIZE(v_version-buf)   = 148.
    PUT-LONG(v_version-buf,1) = 148.
 
    RUN GetVersionExA (INPUT GET-POINTER-VALUE(v_version-buf),
                       OUTPUT v_return-value).
 
    v_platform-id = GET-LONG(v_version-buf,17).
 
    CASE v_platform-id:
        WHEN 1 THEN DO:
            v_minor-version = GET-BYTE(v_version-buf,15).
            v_major-version = GET-BYTE(v_version-buf,16).
        END.
        OTHERWISE DO:
            v_major-version = GET-LONG(v_version-buf,5).
            v_minor-version = GET-LONG(v_version-buf,9).
        END.
    END.
 
    CASE v_platform-id:
        WHEN 0 THEN v_platform-desc = "3.1".
        WHEN 1 THEN
        DO:
            IF v_minor-version EQ 0 THEN v_platform-desc = "95".
            ELSE IF v_minor-version GT 0 THEN v_platform-desc = "98".
            ELSE v_platform-desc = "undef".
        END.
        WHEN 2 THEN
            v_platform-desc = "NT".
        OTHERWISE
            v_platform-desc = "undef".
    END.
 
    SET-SIZE(v_version-buf) = 0.
 
    RETURN v_platform-desc.
 
END FUNCTION.

PROCEDURE GetVersionExA EXTERNAL {&KERNEL} :
  DEFINE INPUT  PARAMETER lpVersionInfo AS LONG.
  DEFINE RETURN PARAMETER ReturnValue   AS {&BOOL}.
END PROCEDURE.

PROCEDURE ListProcesses:
 
    DEFINE OUTPUT PARAMETER pAdobePID AS CHARACTER  NO-UNDO.

    DEF VAR hSnapShot   AS INTEGER   NO-UNDO.
    DEF VAR lpPE        AS MEMPTR    NO-UNDO. /* PROCESSENTRY32 structure */
    DEF VAR ReturnValue AS INTEGER   NO-UNDO.
    DEF VAR list        AS CHARACTER NO-UNDO INITIAL "Process-List:".
 
 
    /* Create and open SnapShot-list */
    RUN CreateToolhelp32Snapshot({&TH32CS_SNAPPROCESS}, 
                                 0, 
                                 OUTPUT hSnapShot).
    IF hSnapShot = -1 THEN RETURN.
 
    /* init buffer for lpPE */
    SET-SIZE(lpPE)    = 336.
    PUT-LONG(lpPE, 1) = GET-SIZE(lpPE).
 
    /* Cycle thru process-records */
    RUN Process32First(hSnapShot, 
                       lpPE,
                       OUTPUT ReturnValue).

    DO WHILE ReturnValue NE 0:

       IF GET-STRING(lpPE, 37) = "Acrobat.exe"
       OR GET-STRING(lpPE, 37) = "Acrord32.exe" THEN DO:
           list = list + "~n".
     
           /* show process identifier (pid): */
           pAdobePID = STRING(GET-LONG(lpPE, 9)) + " ".
     
           /* show path and filename of executable: */
           list = list + GET-STRING(lpPE, 37).
       END.

       RUN Process32Next(hSnapShot, 
                         lpPE,
                         OUTPUT ReturnValue).
    END.
 
    /* Close SnapShot-list */
    RUN CloseHandle(hSnapShot, OUTPUT ReturnValue).
END PROCEDURE.

PROCEDURE CreateToolhelp32Snapshot EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER dwFlags           AS LONG.
  DEFINE INPUT  PARAMETER th32ProcessId     AS LONG.
  DEFINE RETURN PARAMETER hSnapShot         AS LONG.
END PROCEDURE.
 
PROCEDURE Process32First EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER hSnapShot         AS LONG.
  DEFINE INPUT  PARAMETER lpProcessEntry32  AS MEMPTR.
  DEFINE RETURN PARAMETER ReturnValue       AS LONG.
END PROCEDURE.
 
PROCEDURE Process32Next EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER hSnapShot         AS LONG.
  DEFINE INPUT  PARAMETER lpProcessEntry32  AS MEMPTR.
  DEFINE RETURN PARAMETER ReturnValue       AS LONG.
END PROCEDURE.

PROCEDURE TerminateProcess EXTERNAL "kernel32" :
  DEFINE INPUT  PARAMETER hProcess  AS LONG.
  DEFINE INPUT  PARAMETER uExitCode AS LONG.
  DEFINE RETURN PARAMETER retval    AS LONG.
END PROCEDURE.

/* =============== TEST ================ */
 
 
/* lpID is an array of PID's (Process Identifiers) */
SET-SIZE(lpId) = 1000. /* assume room for 250 pid's */
 
IF WINGetVersion() <> '98' THEN DO:

    /* EnumProcesses fills an array of PID's */
    RUN EnumProcesses (INPUT GET-POINTER-VALUE(lpId),
                       INPUT GET-SIZE(lpID),
                       OUTPUT cbNeeded,
                       OUTPUT ReturnValue).
     
    DO i = 1 TO cbNeeded / 4 :
      PID = GET-LONG(lpID, 4 * (i - 1) + 1).
     
      /* display what you have found (for testing purposes) */
      IF GetProcessName(PID) = 'Acrobat.exe'
      OR GetProcessName(PID) = 'Acrord32.exe' THEN
          ASSIGN viPID = INTEGER(PID).
    END.
     
    SET-SIZE(lpId) = 0.
END.
ELSE DO:
    RUN ListProcesses (OUTPUT viPID).
END.

IF viPID <> 0 THEN DO:
    RUN OpenProcess ({&PROCESS_TERMINATE}, 0, viPID, OUTPUT ProcessHandle).
    
    IF ProcessHandle NE 0 THEN DO:
        RUN TerminateProcess (ProcessHandle, 0, OUTPUT ReturnValue).
        RUN CloseHandle(ProcessHandle, OUTPUT ReturnValue).
    END.

END.
