Skip to Content
Technical Articles
Author's profile photo Stefan Schnell

How to Execute SAP GUI Scripting Parallel

To be able to process a higher amount of data in the same time, parallelization is a valid approach. The SAP GUI scripting, as an automation interface to the SAP GUI for Windows, is a basis for many RPA platforms. In this context it is worth to taking a look at the parallelization capabilities of the SAP GUI Scripting. In this blog post one possible approach is shown.

For easier understanding I have created the example in VBScript. VBScript is actually no longer recommended, but for the presentation of the basics here quite suitable.

The following code has three routines:

  1. Main
    Connects the open session, just like the standard does. Then two additional sessions are opened with different transaction codes, in our example the SE16 and SE37. After that the session object via GetSession is detected, based on the transaction code, and an external script is started via Action.
  2. GetSession
    Loops over all the sessions of the connection to detect the session with the transaction code and delivers the session object.
  3. Action
    Starts an external script with the connection and session number as parameters.
'-Begin-----------------------------------------------------------------

'-Directives------------------------------------------------------------
Option Explicit

'-Sub Action------------------------------------------------------------
'-
'- Starts external script with the connection and session number
'- as parameters
'-
'-----------------------------------------------------------------------
Sub Action(con, ses, TAC)

  Dim objShell, RegEx, Matches, con_no, ses_no

  '-Extracts connection and session number------------------------------
  Set RegEx = New RegExp
  RegEx.Pattern = "[\d]+"
  Set Matches = RegEx.Execute(con)
  con_no = Matches(0).Value
  Set Matches = RegEx.Execute(ses)
  ses_no = Matches(0).Value

  '-Executes the external script----------------------------------------
  Set objShell = Wscript.CreateObject("WScript.Shell")
  objShell.Run "YourScript." + TAC + ".vbs " + con_no + " " + ses_no

End Sub

'-Function GetSession---------------------------------------------------
'-
'- Detects a session by transaction code (TAC)
'-
'-----------------------------------------------------------------------
Function GetSession(connection, TAC)

  Dim sessions, session, sessionInfo, j, i

  Set sessions = connection.Sessions()
  '-Loop over sessions--------------------------------------------------
  For Each session In sessions
    If session.Busy() = vbFalse Then
      Set sessionInfo = session.Info()
      If sessionInfo.Transaction() = TAC Then
        Set GetSession = session
      End If
    End If
  Next

End Function

'-Sub Main--------------------------------------------------------------
Sub Main()

  Dim SapGuiAuto, app, connection, session
  Dim session_SE16, session_SE37
  Dim arr

  Set SapGuiAuto = GetObject("SAPGUI")
  If Not IsObject(SapGuiAuto) Then
    Exit Sub
  End If

  Set app = SapGuiAuto.GetScriptingEngine
  If Not IsObject(app) Then
    Exit Sub
  End If

  Set connection = app.Children(0)
  If Not IsObject(connection) Then
    Exit Sub
  End If

  If connection.DisabledByServer = True Then
    Exit Sub
  End If

  Set session = connection.Children(0)
  If Not IsObject(session) Then
    Exit Sub
  End If

  If session.Info.IsLowSpeedConnection = True Then
    Exit Sub
  End If

  '-Open different sessions with different TACs-------------------------
  session.findById("wnd[0]/tbar[0]/okcd").text = "/oSE16"
  session.findById("wnd[0]").sendVKey 0
  session.findById("wnd[0]/tbar[0]/okcd").text = "/oSE37"
  session.findById("wnd[0]").sendVKey 0
  WScript.Sleep 500

  '-Detects the session with TAC SE16 and calls an external script------
  Set session_SE16 = GetSession(connection, "SE16")
  arr = Split(session_SE16.ID, "/")
  Action arr(2), arr(3), "SE16"
  
  '-Detects the session with TAC SE37 and calls an external script------
  Set session_SE37 = GetSession(connection, "SE37")
  arr = Split(session_SE37.ID, "/")
  Action arr(2), arr(3), "SE37"

End Sub

'-Main------------------------------------------------------------------
Main()

'-End-------------------------------------------------------------------

Here the script which automates the TAC SE16. First the connection and session number of the arguments are read. Then we have the standard sequence for establishing the connection to the session, with use of the passed arguments. Last but not least a for loop that does the same thing over and over again, totally senseless.

'-Begin------------------------------------------------------------------

Set Args = WScript.Arguments
con = Args(0)
ses = Args(1)

Set SapGuiAuto = GetObject("SAPGUI")
If Not IsObject(SapGuiAuto) Then
  WScript.Quit
End If

Set app = SapGuiAuto.GetScriptingEngine
If Not IsObject(app) Then
  WScript.Quit
End If

Set connection = app.Children(CLng(con))
If Not IsObject(connection) Then
  WScript.Quit
End If

Set session = connection.Children(CLng(ses))
If Not IsObject(session) Then
  WScript.Quit
End If

For i = 1 To 50
  session.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").text = "TADIR"
  session.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").caretPosition = 5
  session.findById("wnd[0]").sendVKey 0
  session.findById("wnd[0]").sendVKey 31
  session.findById("wnd[1]/tbar[0]/btn[0]").press
  session.findById("wnd[0]/tbar[0]/btn[3]").press
Next

'-End--------------------------------------------------------------------

Here the script which automates the TAC SE37. Here exactly the same as above.

'-Begin------------------------------------------------------------------

Set Args = WScript.Arguments
con = Args(0)
ses = Args(1)

Set SapGuiAuto = GetObject("SAPGUI")
If Not IsObject(SapGuiAuto) Then
  WScript.Quit
End If

Set app = SapGuiAuto.GetScriptingEngine
If Not IsObject(app) Then
  WScript.Quit
End If

Set connection = app.Children(CLng(con))
If Not IsObject(connection) Then
  WScript.Quit
End If

Set session = connection.Children(CLng(ses))
If Not IsObject(session) Then
  WScript.Quit
End If

For i = 1 To 25
  session.findById("wnd[0]/usr/ctxtRS38L-NAME").text = "RFC_READ_TABLE"
  session.findById("wnd[0]/usr/ctxtRS38L-NAME").caretPosition = 14
  session.findById("wnd[0]/usr/btnBUT3").press
  session.findById("wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpHEADER").select
  session.findById("wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpIMPORT").select
  session.findById("wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpEXPORT").select
  session.findById("wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpCHANGE").select
  session.findById("wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpTABLES").select
  session.findById("wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpEXCEPT").select
  session.findById("wnd[0]/tbar[0]/btn[3]").press
Next

'-End--------------------------------------------------------------------

Now when the script is started, the sessions are opened with the transaction codes. Then other Windows Scripting Hosts are opened parallel and the scripts for SE16 and SE37 are executed parallel.

And in the taskbar we see the different sessions with their activities.

To execute SAP GUI Scripting in different sessions is possible in principle. This is one approach, surely better approaches can be realized with other programming languages that support parallelization. Here it was important to check the basic operability.

Hint: I have tested this approach with the SAP GUI for Windows 7.60 PL11 and 7.70 PL03. With version 7.60 everything ran excellent, with version 7.70 I noticed that after the script execution the whole SAP Logon crashed.

Assigned Tags

      1 Comment
      You must be Logged on to comment or reply to a post.
      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      As a tiny addendum here a variant of parallel SAP GUI Scripting executing with C# and multi threading.

      //-Begin----------------------------------------------------------------
      
      using System;
      using System.Reflection;
      using System.Runtime.InteropServices;
      using System.Threading;
      using Microsoft.VisualBasic;
      
      namespace ThreadingDemo {
      
        class Program {
      
          static dynamic InvokeMethod(object obj, string methodName, object[] methodParams = null) {
            return obj.GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, methodParams);
          }
      
          static dynamic GetProperty(object obj, string propertyName, object[] propertyParams = null) {
            return obj.GetType().InvokeMember(propertyName, BindingFlags.GetProperty, null, obj, propertyParams);
          }
      
          static dynamic SetProperty(object obj, string propertyName, object[] propertyParams = null) {
            return obj.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, obj, propertyParams);
          }
      
          static void FreeObject(object obj) {
            Marshal.ReleaseComObject(obj);
          }
      
          static void Main(string[] args) {
      
            Console.WriteLine("Main Thread Started");
      
            Thread SE37 = new Thread(MethodSE37) {
                Name = "ThreadSE37"
            };
            Thread SE16 = new Thread(MethodSE16) {
                Name = "ThreadSE16"
            };
      
            SE37.Start();
            SE16.Start();
            Console.WriteLine("Main Thread Ended");
      
          }
      
          static void MethodSE37() {
      
            object SapGuiAuto = null;
            object app = null;
            object connection = null;
            object session = null;
      
            try {
              SapGuiAuto = Interaction.GetObject("SAPGUI");
              app = InvokeMethod(SapGuiAuto, "GetScriptingEngine");
              SetProperty(app, "HistoryEnabled", new object[1]{false});
              connection = GetProperty(app, "Children", new object[1]{0});
              session = GetProperty(connection, "Children", new object[1]{1});
            } catch {
              return;
            }
      
            dynamic ID = null;
      
            for (int i = 1; i <= 5; i++) {
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/tbar[0]/okcd"});
              SetProperty(ID, "text", new object[1]{"/nse37"});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{0});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/ctxtRS38L-NAME"});
              SetProperty(ID, "text", new object[1]{"RFC_READ_TABLE"});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{7});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpHEADER"});
              InvokeMethod(ID, "select");
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpIMPORT"});
              InvokeMethod(ID, "select");
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpEXPORT"});
              InvokeMethod(ID, "select");
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpCHANGE"});
              InvokeMethod(ID, "select");
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpTABLES"});
              InvokeMethod(ID, "select");
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpEXCEPT"});
              InvokeMethod(ID, "select");
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/tabsFUNC_TAB_STRIP/tabpSOURCE"});
              InvokeMethod(ID, "select");
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{3});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{3});
            }
      
            SetProperty(app, "HistoryEnabled", new object[1]{true});
      
            FreeObject(session);
            FreeObject(connection);
            FreeObject(app);
            FreeObject(SapGuiAuto);
      
          }
      
          static void MethodSE16() {
      
            object SapGuiAuto = null;
            object app = null;
            object connection = null;
            object session = null;
      
            try {
              SapGuiAuto = Interaction.GetObject("SAPGUI");
              app = InvokeMethod(SapGuiAuto, "GetScriptingEngine");
              SetProperty(app, "HistoryEnabled", new object[1]{false});
              connection = GetProperty(app, "Children", new object[1]{0});
              session = GetProperty(connection, "Children", new object[1]{2});
            } catch {
              return;
            }
      
            dynamic ID = null;
      
            for (int i = 1; i <= 10; i++) {
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/tbar[0]/okcd"});
              SetProperty(ID, "text", new object[1]{"/nse16"});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{0});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/ctxtDATABROWSE-TABLENAME"});
              SetProperty(ID, "text", new object[1]{"TADIR"});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]/usr/ctxtDATABROWSE-TABLENAME"});
              SetProperty(ID, "caretPosition", new object[1]{5});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{7});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{31});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[1]"});
              InvokeMethod(ID, "sendVKey", new object[1]{0});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{3});
              ID = InvokeMethod(session, "findById", new object[1]{"wnd[0]"});
              InvokeMethod(ID, "sendVKey", new object[1]{3});
            }
      
            SetProperty(app, "HistoryEnabled", new object[1]{true});
      
            FreeObject(session);
            FreeObject(connection);
            FreeObject(app);
            FreeObject(SapGuiAuto);
      
          }
      
        }
      
      }
      
      //-End------------------------------------------------------------------