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
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.