Tip: How to Detect SAP Connection and Session Number in the Context of Project

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

7 Likes

Thank you @StefanSchnell. Appreciate it.

1 Like

Nice work. Its truly a great help with sap gui scripting where you need work with multiple SAP session to make your automation much faster then what we have now.

I am agree with the Disadvantage part: so in my case i had 12 SAP window bot is opening and working on them in parallel also its making sure it open by checking sap session and SAP session ID like
Sap easy acess(0), Session (0), Sap easy acess(1), Session (1), I was storing all session in Var and pass accordingly through the work flow and VB scripting.

It was working all good with a awesome speed, but sometime i crashed and can’t find session or skip to open season. i couldn’t not find a specific fix for this issue except keep changing VB scripting until it start working :star_struck:.

1 Like