User Tools

Site Tools


k21:k21.3:k21.3.3:start

21.3.3 Project - Process Control and Process Data

In the following chapters 21.3.3 to 21.3.6 you will be presented with projects in which you will learn how to successfully use the SHELL and EXEC instructions primarily in interactive console programmes.

You will have noticed that up to now no other possibilities have been presented for reading process data or permanently transferring inputs to an active process:

Events exist to signal you that data is available, but you can neither read this data directly nor send data to the process.These tasks are taken over by a Stream object, which was already presented in Chapter 15.2, since the Process class inherits from the Stream class.Therefore, you can treat a Process object like a Stream and use its input and output functions, such as Write, Print or Read.

The use of the event handler

  • ProcessEventName_Read(),
  • ProcessEventName_Kill() and
  • ProcessEventName_Error(sError as String)

are described and procedures are presented with which you pass input to a process and write input (data or commands) to the standard input of a process, respectively. The core of the procedures presented will be these statements:

Print   #ProzessVariable   Eingabe_String   or
Write   #ProzessVariable   Eingabe_String.

21.3.3.1 Process Data Project - 'Basic Calculator'

This project is about developing the basis for a graphical user interface (GUI) for the interactive console programme 'bc'.

BC

Figure 21.3.3.1.1: Draft GUI for the programme 'bc' - Basic Calculator

There is at least one good reason to take a closer look at the programme 'bc':

hans@linux:~$ echo $(( 22/(7+4) ))
2
hans@linux:~$ echo $(( 22/(7+3) ))
2
hans@linux:~$ echo "scale=15; 0.77*2+e(3.44)" | bc -il
scale=15; 0.77*2+e(3.44)
32.726958168309462
hans@linux:~$

In contrast to the integer arithmetic of a console, with the programme 'bc' you can, among other things, calculate with floating point numbers, use selected mathematical functions and also store and use self-defined constants and functions.

The programme Basic Calculator is a suitable candidate for demonstrating the use of the instructions SHELL and EXEC, because it can be shown how to

  • ( A ) start a process,
  • ( B ) read and display data from the started process,
  • ( C ) reads, evaluates and displays error messages,
  • ( D ) writes data into the standard input of the process,
  • ( E ) terminates the programme 'bc' regularly with the command quit and thus also the process,
  • ( F ) terminates the started process with the method hProcess.Kill, if the external programme 'bc' was not terminated regularly, because the Gambas programme is terminated and evaluates and displays the effect of the method hProcess.Kill..

The source text is displayed in full and commented on in selected sections (A) to (F):

' Gambas class file
 
Private $hProcess As Process
Private sProgrammName As String = "bc"
Private sStartParameter As String = "-i -l"
 
Public Sub Form_Open()
  FMain.Center()
  FMain.Resizable = False
  txaOutput.Clear()
  btnProcessKill.Enabled = False
  txbEingabe.ReadOnly = True
  SetLEDColor("orange")
End

(A)

The external programme is started by the instruction SHELL …. The process thus started is assigned to the process variable $hProcess and the event name is freely defined on myBCProcess.

Public Sub BCProcessStart()
  Dim sCommand As String
 
  txaOutput.SetFocus()
  txaOutput.Clear()
  txaOutput.Foreground = Color.Black
  $hProcess = Null
 
  sCommand = sProgrammName & " " & sStartParameter
  $hProcess = Shell sCommand For Read Write As "myBCProcess"
 
  FMain.Text = "BC - Basic Calculator : PID = " & $hProcess.Id
  btnBCProcessStart.Enabled = False
  btnProcessKill.Enabled = True
  txbEingabe.ReadOnly = False
  SetLEDColor("green")
 
End

(B)

Data can be read from the process in the event handler myBCProcess_Read():

Public Sub myBCProcess_Read()
  Dim sPuffer As String
 
  txaOutput.Insert(gb.NewLine)
  sPuffer = ""
  Read #$hProcess, sPuffer, Lof($hProcess)
  txaOutput.Insert(sPuffer)
End

The following alternatives are possible for 'Read #$hProcess, sPuffer, Lof($hProcess)':

Alternative 1:

Read #$hProcess, sPuffer, -256 

Alternative 2:

While Not Eof($hProcess)
  Read #$hProcess, sPuffer, Lof($hProcess)
Wend

Alternative 3:

Read #Last, sPuffer, Lof(Last) 

The following instruction is not an alternative, although it is often quoted, because it does not fully read all incoming data on the standard output of the process:

Line Input #Last, sPuffer
Line Input #$hProcess, sPuffer

The instruction LINE INPUT should only be used with caution in processes. LINE INPUT returns output of the process in units of “lines”, i.e. received data remains invisible to the Gambas programme until the line is terminated. But not every programme terminates important data with a NewLine character and therefore this information cannot be read out in the Gambas programme. For example, the shell sends a command prompt to signal that it is ready to receive a new command. This prompt is usually not terminated by a NewLine, which is why the programme - if it uses LINE INPUT - cannot read this prompt. The implied readiness of the shell to continue is lost.

(C)

The event Process_Error(…) has a special feature: You do not read directly from the standard error output of the process, but get the data already in the parameter of the event handler with Process_Error(sErrorMessage As String), if data are present at the standard error output of the process. Whether you output the error message unfiltered or still provide an error handling routine to influence the programme flow depending on the displayed error is certainly determined by the task to be solved:

Public Sub myBCProcess_Error(sFehler As String)
  txaOutput.Clear
  txaOutput.Insert(gb.NewLine)
  txaOutput.Insert("PROCESS FAILURE!" & gb.NewLine)
  txaOutput.Insert(gb.NewLine)
  txaOutput.Insert(sFehler)
End

(D)

If user inputs are to be passed to the process, then you must realise this in a separate procedure. The programme 'bc' as a console programme expects arithmetic expressions and special commands in a line on the standard input of the started process. These inputs are provided in the main programme via an input box:

Public Sub txbEingabe_Activate()
  If txbEingabe.Text = "" Then Return
  txbEingabe.Text = Trim(txbEingabe.Text)
  WriteToMyBCProcess(txbEingabe.Text)
  txbEingabe.Clear
End

You must take care in a separate procedure to write the inputs for the external program 'bc' into the standard input of the started process. Since you can treat a Process object like a stream, use its output functions Print or Write after checking whether a Process object exists and whether the process is active:

Public Sub WriteToMyBCProcess(sInput As String)
   If $hProcess Then
      If $hProcess.State = $hProcess.Running Then
         Print #$hProcess, sInput
      Endif
   Endif
End

(E)

If you enter the command 'quit', then the external programme Basic Calculator is terminated in a regular manner and the process object is destroyed after the process was previously terminated. The triggered event Kill activates the event handler myBCProcess_Kill(), which gives you the opportunity to react to it appropriately:

Public Sub myBCProcess_Kill()
  txaOutput.Insert(gb.NewLine)
  txaOutput.Foreground = Color.Red
  txaOutput.Insert("Rückgabewert von '" & sProgrammName & "' = " & $hProcess.Value & Chr(10)
 
  Select Case $hProcess.State
  Case 0
    txaOutput.Insert("Prozess (PID= " & $hProcess.Id & ") normal beendet." & gb.NewLine)
  Case 1
    txaOutput.Insert("Prozess (PID= " & $hProcess.Id & ") gestoppt!" & gb.NewLine)
  Case 2
    txaOutput.Insert("Prozess (PID= " & $hProcess.Id & ") beendet! (SIGKILL)" & gb.NewLine)
  End Select
 
  SetLEDColor("red")
  btnProcessKill.Enabled = False
  btnBCProcessStart.Enabled = True
End

You get the following output in the presented project:

Return value from programme 'bc' = 0
The process with the PID = 7411 was terminated normally.

(F)

If you close the main programme, then you should first kill the started process with the method ProcessVariableName.Kill:

Public Sub btnProcessKill_Click()
  txaOutput.Clear()
  If $hProcess Then $hProcess.Kill()
  FMain.Text = "BC - Basic Calculator"
End

Also in this case you will get an output generated in the event handler myBCProcess_Kill():

Return value from programme 'bc' = 9
The process with the PID = 7458 was terminated! (SIGKILL]

The rest of the source code does not contain any special features:

Public Sub btnClose_Click()
  FMain.Close
End ' btnClose_Click()
 
Public Sub btnTextAreaClear_Click()
  txaOutput.Clear
End
 
Public Sub btnBCProcessStart_Click()
  BCProcessStart()
End
 
Public Sub txaOutput_Change()
  txaOutput.Pos = Len(txaOutput.Text) ' ---> Sprung in die letzte Zeile
End
 
Public Sub SetLEDColor(sLEDColor As String)
   PictureBox1.Picture = Picture["LED/led_" & sLEDColor & ".svg"]
End
 
Public Sub Form_Close()
  If $hProcess Then
     txaOutput.SetFocus
     txaOutput.Clear
     $hProcess.Kill
  Endif ' $hProcess ?
End

Hint:

It does not necessarily mean an error if data is output on the standard error output, i.e. the Error() event of a process is called. The programme “strace”, for example, takes all its output on stderr so that it can be distinguished from the output of the called programme by redirecting the streams. If one is only interested in the output of strace, then one can ignore everything else (>/dev/null or 2>strace.log).

21.3.3.2 Digression - Basic Calculator

Before you set off to develop your version from the presented approach to a GUI for the console program 'bc', a look at the BC help files with 'man bc' or 'info bc' will help.

This lists interesting sources to learn about the features and use of the Basic Calculator program:

download

Project

Download

The website uses a temporary session cookie. This technically necessary cookie is deleted when the browser is closed. You can find information on cookies in our privacy policy.
k21/k21.3/k21.3.3/start.txt · Last modified: 23.10.2023 by emma

Page Tools