SAP GUI for Windows Execution Unit for UiPath

The last days I developed an approach to execute SAP GUI for Windows activities direct from UiPath. In my post here I showed the possibility to execute SAP GUI Scripting via PowerShell. But I think it would be better to do that via a custom activity.

Let us start with a special SAP GUI Scripting recorder. It is nothing more than an easy VBScript which records user activities from the SAP GUI for Windows in a special format and copies it to the clipboard.

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

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

'-Variables-------------------------------------------------------------
Dim clpText

'-Sub ses_Change--------------------------------------------------------
Sub ses_Change(Sess, Comp, CmdArray)

  '-Variables-----------------------------------------------------------
  Dim Cmd, TypeElement, NameElement, ParamElement, i
        
  Cmd = CmdArray(0)
  For i = 0 To UBound(Cmd)
    Select Case i
	  Case 0
        TypeElement = CStr(Cmd(i))
	  Case 1
	    NameElement = CStr(Cmd(i))
	  Case Else
	    If ParamElement = vbEmpty Then
  	      ParamElement = CStr(Cmd(i))  
		Else
  	      ParamElement = ParamElement & "," & CStr(Cmd(i))  
		End If
	End Select
  Next  

  If ParamElement = vbEmpty Then
    If clpText = vbEmpty Then
      clpText = """" & TypeElement & ";" & Comp.Id() & ";" & _
        NameElement & """"
	Else
      clpText = clpText & " & vbNewLine & """ & TypeElement & ";" & _
	    Comp.Id() & ";" & NameElement & """"
	End If
  Else
    If clpText = vbEmpty Then
      clpText = """" & TypeElement & ";" & Comp.Id() & ";" & _
        NameElement & ";" & ParamElement & """"
	Else
      clpText = clpText & " & vbNewLine & """ & TypeElement & ";" & _
	    Comp.Id() & ";" & NameElement & ";" & ParamElement & """"
	End If
  End If

End Sub

'-Sub Main--------------------------------------------------------------
Sub Main()
  
  '-Variables-----------------------------------------------------------
  Dim SapGuiAuto, application, connection, session, oIE

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

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

  If Not IsObject(WScript) Then
    Exit Sub
  End If

  WScript.ConnectObject session, "ses_"

  session.Record() = vbTrue
  MsgBox "Beenden?", vbOkOnly
  session.Record() = vbFalse

  Set oIE = CreateObject("InternetExplorer.Application")
  oIE.Navigate ("about:blank")
  oIE.Document.ParentWindow.ClipboardData.SetData "Text", clpText
  oIE.Quit
  Set oIE = Nothing
  
End Sub

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

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

This script registers on the change event of an SAP GUI the sub routine ses_Change. It records all activities and if you press the ok button on the “Beenden?” dialog all activties will be copied to the clipboard. From here you can directly import it at UiPath. One line stores the type element (M = Method, SP = SetProperty or GP = GetProperty), the id of the element, the name of the method or property and the parameters. For this recorder I developed a custom activity. This custom activity contains a function, which allows to replay the SAP GUI Scripting activities from the recorder. It contains a set of COM functions and in the execute function it runs the recorded script line by line.

//-Begin----------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Activities;
using System.ComponentModel;
using Microsoft.VisualBasic;
using System.Reflection;

[assembly: AssemblyVersion("1.0.0.0")]

namespace SAP {
  public class GUIScript : CodeActivity {

    [Category("Input")]
    [RequiredArgument]
    public InArgument<int> ConnectionNumber { get; set; }

    [Category("Input")]
    [RequiredArgument]
    public InArgument<int> SessionNumber { get; set; }

    [Category("Input")]
    [RequiredArgument]
    public InArgument<string> Commands { get; set; }

    private object GetObject(string objectName) {
      return Microsoft.VisualBasic.Interaction.GetObject(objectName);
    }
  
    private dynamic InvokeMethod(object obj, string methodName, object[] methodParams = null) {
      return obj.GetType().InvokeMember(methodName, System.Reflection.BindingFlags.InvokeMethod, null, obj, methodParams);
    }
  
    private dynamic GetProperty(object obj, string propertyName, object[] propertyParams = null) {
      return obj.GetType().InvokeMember(propertyName, System.Reflection.BindingFlags.GetProperty, null, obj, propertyParams); 
    }
  
    private dynamic SetProperty(object obj, string propertyName, object[] propertyParams = null) {
      return obj.GetType().InvokeMember(propertyName, System.Reflection.BindingFlags.SetProperty, null, obj, propertyParams);
    }

    private void FreeObject(object obj) {
      System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
    }

    protected override void Execute(CodeActivityContext context) {

      int ConnNumber = ConnectionNumber.Get(context);
      int SessNumber = SessionNumber.Get(context);
      string cmds = Commands.Get(context);

      object SapGuiAuto = GetObject("SAPGUI");
      object Application = InvokeMethod(SapGuiAuto, "GetScriptingEngine");
      object Connection = GetProperty(Application, "Children", new Object[1]{ConnNumber});
      object Session = GetProperty(Connection, "Children", new Object[1]{SessNumber});

      object ID = null;
      string[] Elements = null;
      object[] Params = null;
      int cnt = 0;

      string[] lines = cmds.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
      foreach(string line in lines) {
        Elements = line.Split(new[] {";"}, StringSplitOptions.None);
        ID = InvokeMethod(Session, "FindById", new Object[1]{Elements[1]});
        if(Elements.Length == 4) {
          cnt = Elements[3].Split(new[] {","}, StringSplitOptions.None).Length;
          Params = new Object[cnt];
          for(int i = 0; i < cnt; i++) {
            Params[i] = Elements[3].Split(new[] {","}, StringSplitOptions.None)[i];
          }
        } else {
          Params = null;
        }
        switch(Elements[0]) {
          case "M":
            InvokeMethod(ID, Elements[2], Params);
            break;
          case "GP":
            GetProperty(ID, Elements[2], Params);    
            break;
          case "SP":
            SetProperty(ID, Elements[2], Params);
            break;
        }
      }

      FreeObject(SapGuiAuto);

    }

  }
}

//-End------------------------------------------------------------------

My first UiPath custom activity works so far, great :slightly_smiling_face:

As you can see is the execution time very fast, as fast as in my comparison between UiPath and PowerShell in the link above.

My idea is an additional recorder in UiPath for SAP GUI for Windows activities. If you want to record SAP GUI for Windows activities you should have the choice to record and execute your activities via SAP GUI Scripting directly. On this way you can execute your SAP GUI for Windows activities five times faster. This gives you the possibility to reduce the execution time for repetitive processes in large amounts dramatically. With the recorder and the custom activity here we have a first approach, not perfect but good enough to see the possibilities.

Hi @StefanSchnell

Would you say that the recently added Invoke VBScript activity helps here?
image

It should reduce the design process to two steps - recording with SAP built-in recorder and then executing the scripts with the activity.

1 Like

@loginerror

Hello Maciej,
yes, absolutely.

I tried it with this recorded SAP GUI script:

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

Option Explicit

Dim SapGuiAuto, application, connection, Conn, session, Sess

If Not IsObject(application) Then
  Set SapGuiAuto = GetObject("SAPGUI")
  Set application = SapGuiAuto.GetScriptingEngine
End If

If Not IsObject(connection) Then
  Set connection = application.Children(CInt(Conn))
End If

If Not IsObject(session) Then
  Set session = connection.Children(CInt(Sess))
End If

session.findById("wnd[0]/tbar[0]/okcd").text = "/nse16"
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/ctxtDATABROWSE-TABLENAME").text = "tadir"
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/tbar[1]/btn[31]").press
WScript.Echo session.findById("wnd[1]/usr/txtG_DBCOUNT").text
session.findById("wnd[1]/tbar[0]/btn[0]").press
session.findById("wnd[0]/tbar[0]/btn[3]").press
session.findById("wnd[0]/tbar[0]/btn[3]").press

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

This script uses transaction code (TAC) SE16 to view a table, in this case TADIR table. It opens an additional window with the number of records in the table, reads and returns the number from field txtG_DBCOUNT and sets the session back to entry screen.


Here you see the UiPath Studio and the additional SAP window from TAC SE16

That was very easy and works very well.

Best regards
Stefan

2 Likes