ClientExecute function

The purpose of REXX function ClientExecute is to allow advanced client integration with locally installed programs in a locally secured and controlled environment, without having to worry about security issues. Thus the NetPhantom Client can perform tasks that are otherwise limited by security restrictions imposed by Java. This integration is controlled from the NetPhantom Server and the currently running application, directing the client environment and execution delicately.

This function allows execution of client code directly from server-based REXX code in two ways: as a direct program call with parameters, or by creating a client-local temporary batch file (typically .BAT). This batch file is then executed on the client and will typically contain a set of batch file commands provided by the server (in the ClientExecute function). In the case of batch file execution, the temporary file will be removed immediately after execution (successful or not).

The execution of the program or the batch file on the NetPhantom Client requires the highest level of Java Permissions (security level).


The program or batch file can be executed on the client either synchronously or asynchronously. If the execution is done synchronously, the server will wait until the client has finished the task completely, returning both the return code of the execution along with possible process output (in "Standard Output - stdout" and "Standard Error - stderr", e.g. from the output of the "dir" DOS command). If the execution is done asynchronously (this should be used with care), the time the server waits for the command will be very short, requiring only the successful start of the process on the client side in case of a single program call or the successful creation of the client-local batch file followed by the successful start of execution. This type of execution is intended for lengthy processing in the client, letting the server go about working with "other things".

In the case of synchronous client execution, the "Client GUI" will be "locked" from user input until the completion of the task. In all cases it is recommended you use the REXX functions rc=PanLock(1) and rc=PanLock(0) to inhibit user input while the command is executing. Possibly a PanHostInhibit call may be required to guarantee that a host-based application does not suddenly switch screens in the middle of the processing.

As mentioned above, there are two methods of invoking the client execution:

  1. Synchronously: the call to ClientExecute in the server will wait until the client has completed execution, also returning the real return code for the client process back to the server.
  2. Asynchronously: the call to ClientExecute in the server will wait only until the client has successfully managed to start the execution of the command in a separate process, then return control to the server. The actual return code of the client process will never reach the server because it is executing as a background process in the client!

The ClientExecute function can execute programs on the client as either:

  1. A direct program call with parameters, or
  2. Using a batch file created temporarily on the client.

Function Syntax

   rc = ClientExecute(AsyncFlag, ProgramExecutionAndParameters [, BatchFileContent])

The AsyncFlag is either 0 = synchronous execution, or 1 = asynchronous execution.

If a batch file is not required, the BatchFileContent parameter should not be specified. The ProgramExecutionAndParameters should contain what should be executed on the client, for example

   rc = ClientExecute(0, "explorer")
would cause a Windows platform to launch the display of the Microsoft Internet Explorer with the web page "".

The following example illustrates a scenario where a user is logged on to a "special" network, copying a "task-oriented" file to the client, followed by starting the "task-oriented" software in order to display the tasks to the user (in the example below, it is assumed that the client runs a Windows platform):

   crlf = '0D'X || '0A'X
   ex = '@echo off' || crlf
   ex = ex || 'logon ' || userid || ' password=' || password || crlf
   ex = ex || 'if errorlevel 1 exit 1' || crlf
   ex = ex || 'net use X: \\server\common' || crlf
   ex = ex || 'if errorlevel 1 exit 2' || crlf
   ex = ex || 'copy X:\' || userid || '.uid  %TEMP%\localfile.tmp' || crlf
   ex = ex || 'if errorlevel 1 exit 3' || crlf
   ex = ex || 'callSpecialUserSoftwareWithParams %TEMP%\localfile.tmp' || crlf
   ex = ex || 'if errorlevel 1 exit 4' || crlf
   ex = ex || 'exit 0'
   rc = ClientExecute(0, "cmd.exe /c logontmp.bat logontmp.bat", ex)

The client in the sample above would execute its command line processor (e.g. for batch programs CMD.EXE).

The arguments to ClientExecute when using a batch file are:

   rc = ClientExecute(AsyncFlag, ProgramExecutionAndParameters, BatchFileContent)
where the ProgramExecutionAndParameters should be e.g. for Windows:

   CMD /C thetempfileweuse.bat thetempfileweuse.bat
In the example above the Command Processor of Windows (CMD) is started running the batch file "thetempfileweuse.bat". The file name is repeated once again after the command: this is used by ClientExecute as the argument for the temporary file name, and is removed from the execution parameters, e.g. the CMD program receives the parameters "/C thetempfileweuse.bat".

Note: if execution is done asynchronously, the batch file created from the file name will only be deleted when the batch file has completed execution (successfully or not). This means that if several calls to ClientExecute are made with the asynchronous option, different file batch file names must be specified!

It is also important to call the appropriate Command Processor for the operation system in question. The Global Variable "NETPHANTOM_CLIENT_OS_NAME" would e.g. be used to identify if either "CMD.EXE" or "COMMAND.COM" should be used.

The return code of ClientExecute consists of three strings concatenated with the character '01'X. The first string is the actual return code of the process or "-1" for failure. The second string is the "stdout" and the third "stderr". The easiest way to separate these strings in REXX is as follows:

   ret = ClientExecute(0, "CMD /c temp.bat temp.bat", ex)
   parse var ret rc '01'X stdout '01'X stderr
In the sample above, the "complex" return code of ClientExecute is first stored in "ret", then separated into "rc", "stdout" and "stderr".