In the area of SAP GUI for Windows automation plays the identifier (ID) of the UI elements an important role. It looks e.g. like this:
/app/con[0]/ses[0]/wnd[0]/usr/cntlIMAGE_CONTAINER/shellcont/shell
The ID starts always with /app, the GuiApplication. Then follows /con[0], which is the connection with its number, the GuiConnection. Then follows /ses[0], which is the session with its number, the GuiSession. When you log on to an SAP system, you establish a connection. Each open main window has a session. You can find more information about the SAP GUI Scripting object model here on slide 21.
In the context of UiPath are the application, connection and session without significance. UiPath detects the window and an UI element with a selector e.g. like this:
<wnd app='saplogon.exe' cls='SAP_FRONTEND_SESSION' title='SAP Easy Access*' />
<sap id='usr/cntlIMAGE_CONTAINER/shellcont/shell' />
As we can see the window is identified with other selectors and below the window the SAP GUI Scripting ID is used, beginning with the user screen /usr. This approach makes it difficult to implement external SAP GUI scripts, so some time ago I made a proposal to compensate this.
Now the question arises why this approach is necessary at all. This can be the case if consolidated complex scripts already exist that are to be transferred to a project. You can find different SAP GUI Scripting development scenarios of integration here. On this base I have developed an approach with which this can be easily realized.
The handle of the SAP GUI window, that is to be automated, is transmitted to an external script. This handle is then used to determine the connection and session number, with the simplification that it is always the main window, /wnd[0]. Here the code in VBScript:
'-Function FindSAPWindowsByHandle---------------------------------------
Function FindSAPWindowByHandle(hSAPWnd)
Dim SapGuiAuto, app, CollCon, oCon, CollSes, oSes, hWnd, i, j
Set SapGuiAuto = GetObject("SAPGUI")
If Not IsObject(SapGuiAuto) Then
Exit Function
End If
Set app = SapGuiAuto.GetScriptingEngine
If Not IsObject(app) Then
Exit Function
End If
'-Get all connections-------------------------------------------------
Set CollCon = app.Connections()
If Not IsObject(CollCon) Then
Exit Function
End If
'-Loop over connections-----------------------------------------------
For i = 0 To CollCon.Count() - 1
Set oCon = app.Children(CLng(i))
If Not IsObject(oCon) Then
Exit Function
End If
'-Get all sessions of a connection----------------------------------
Set CollSes = oCon.Sessions()
If Not IsObject(CollSes) Then
Exit Function
End If
'-Loop over sessions------------------------------------------------
For j = 0 To CollSes.Count() - 1
Set oSes = oCon.Children(CLng(j))
If Not IsObject(oSes) Then
Exit Function
End If
If oSes.Busy() = vbFalse Then
hWnd = oSes.findById("wnd[0]").Handle
If hSAPWnd = hWnd Then
FindSAPWindowByHandle = oSes.ID
End If
End If
Next
Next
End Function
The function gets all connections and loops over it. It gets for each connection all sessions and loops over it too. If the determined handle matches the passed one, the session ID is returned. And this session ID contains the information we need.
Here my test sequence …
… and here my complete script.
'-Begin-----------------------------------------------------------------
'-Directives------------------------------------------------------------
Option Explicit
'-Function FindSAPWindowsByHandle---------------------------------------
Function FindSAPWindowByHandle(hSAPWnd)
Dim SapGuiAuto, app, CollCon, oCon, CollSes, oSes, hWnd, i, j
Set SapGuiAuto = GetObject("SAPGUI")
If Not IsObject(SapGuiAuto) Then
Exit Function
End If
Set app = SapGuiAuto.GetScriptingEngine
If Not IsObject(app) Then
Exit Function
End If
'-Get all connections-------------------------------------------------
Set CollCon = app.Connections()
If Not IsObject(CollCon) Then
Exit Function
End If
'-Loop over connections-----------------------------------------------
For i = 0 To CollCon.Count() - 1
Set oCon = app.Children(CLng(i))
If Not IsObject(oCon) Then
Exit Function
End If
'-Get all sessions of a connection----------------------------------
Set CollSes = oCon.Sessions()
If Not IsObject(CollSes) Then
Exit Function
End If
'-Loop over sessions------------------------------------------------
For j = 0 To CollSes.Count() - 1
Set oSes = oCon.Children(CLng(j))
If Not IsObject(oSes) Then
Exit Function
End If
If oSes.Busy() = vbFalse Then
hWnd = oSes.findById("wnd[0]").Handle
If hSAPWnd = hWnd Then
FindSAPWindowByHandle = oSes.ID
End If
End If
Next
Next
End Function
'-Sub Main--------------------------------------------------------------
Sub Main()
Dim HandleSAPWindow
Dim sessionId, connectionNumber, sessionNumber
Dim pos, Len
HandleSAPWindow = CLng(WScript.Arguments.Item(0))
sessionId = CStr(FindSAPWindowByHandle(HandleSAPWindow))
pos = InStr(sessionId, "con[") + 4
Len = InStr(pos, sessionId, "]") - pos
connectionNumber = CLng(Mid(sessionId, pos, Len))
pos = InStr(sessionId, "ses[") + 4
Len = InStr(pos, sessionId, "]") - pos
sessionNumber = CLng(Mid(sessionId, pos, Len))
WScript.Echo(sessionId & ";" & connectionNumber & ";" & sessionNumber)
End Sub
'-Main------------------------------------------------------------------
Main
'-End-------------------------------------------------------------------
The trick is here to use the Get Attribute activity with the handle of the window, hwnd. The handle is transfered to the script and the script delivers the session ID, the connection and session number back to the project. But this is not necessary at all. A recorded SAP GUI script can also be inserted in the main routine instead.
Here the full example:
'-Begin-----------------------------------------------------------------
'-Directives------------------------------------------------------------
Option Explicit
'-Function FindSAPWindowsByHandle---------------------------------------
Function FindSAPWindowByHandle(hSAPWnd)
Dim SapGuiAuto, app, CollCon, oCon, CollSes, oSes, hWnd, i, j
Set SapGuiAuto = GetObject("SAPGUI")
If Not IsObject(SapGuiAuto) Then
Exit Function
End If
Set app = SapGuiAuto.GetScriptingEngine
If Not IsObject(app) Then
Exit Function
End If
'-Get all connections-------------------------------------------------
Set CollCon = app.Connections()
If Not IsObject(CollCon) Then
Exit Function
End If
'-Loop over connections-----------------------------------------------
For i = 0 To CollCon.Count() - 1
Set oCon = app.Children(CLng(i))
If Not IsObject(oCon) Then
Exit Function
End If
'-Get all sessions of a connection----------------------------------
Set CollSes = oCon.Sessions()
If Not IsObject(CollSes) Then
Exit Function
End If
'-Loop over sessions------------------------------------------------
For j = 0 To CollSes.Count() - 1
Set oSes = oCon.Children(CLng(j))
If Not IsObject(oSes) Then
Exit Function
End If
If oSes.Busy() = vbFalse Then
hWnd = oSes.findById("wnd[0]").Handle
If hSAPWnd = hWnd Then
FindSAPWindowByHandle = oSes.ID
End If
End If
Next
Next
End Function
'-Sub Main--------------------------------------------------------------
Sub Main()
Dim HandleSAPWindow
Dim sessionId, connectionNumber, sessionNumber
Dim pos, Len
HandleSAPWindow = CLng(WScript.Arguments.Item(0))
sessionId = CStr(FindSAPWindowByHandle(HandleSAPWindow))
pos = InStr(sessionId, "con[") + 4
Len = InStr(pos, sessionId, "]") - pos
connectionNumber = CLng(Mid(sessionId, pos, Len))
pos = InStr(sessionId, "ses[") + 4
Len = InStr(pos, sessionId, "]") - pos
sessionNumber = CLng(Mid(sessionId, pos, Len))
'-SAP GUI Script - Begin------------------------------------------------
Dim SapGuiAuto, application, connection, session, dbCount
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(ConnectionNumber))
End If
If Not IsObject(session) Then
Set session = connection.Children(CInt(SessionNumber))
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]/usr/ctxtDATABROWSE-TABLENAME").caretPosition = 5
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]").sendVKey 31
dbCount = session.findById("wnd[1]/usr/txtG_DBCOUNT").Text
session.findById("wnd[1]/tbar[0]/btn[0]").press
session.findById("wnd[0]").sendVKey 3
session.findById("wnd[0]").sendVKey 3
MsgBox CStr(dbCount)
'-SAP GUI Script - End--------------------------------------------------
End Sub
'-Main------------------------------------------------------------------
Main
'-End-------------------------------------------------------------------
Conclusion
With the approach presented here we have the possibility to use existing SAP GUI scripts seamlessly in UiPath. All we have to do is change the recorded connection and session number with variables. The advantages of this approach are, that we can use all the possibilities of the SAP GUI Scripting API and that we can use existing consolidated scripts furthermore. The disadvantage of this approach is, that we pass the control of the automation to another engine, so the complexity increases. It depends on the use case.
However, it is good to know that we have this approach.