1

First I want to check via VBA, before I do some transactions in SAP GUI, if a connection is already open. I am not able to login a second time, so I need to stay in the same connection.

Secondly I want to open another session. The second problem has been solved, if I assume SAP GUI is already open. But I don't know it for sure. So I need to find a way to access the current SAPGUI and Application and Connection, if they exist. If not, the standard code of If Not IsObject(SAPGUI) Then… is fine. But how do I define these variables correctly to check, if they are „filled“ Objects or not?

Thanks for help!

Sandra Rossi
  • 11,934
  • 5
  • 22
  • 48
iAmMiee
  • 27
  • 1
  • 8

1 Answers1

1

Based on a script by S. Schnell you can use the follwing function to find a free session

Function findGuiSession(ByVal sapSID As String, Optional tCode As String) As SAPFEWSELib.GuiSession
    ' this will find a free session using the systemnam resp. SID
    ' and optional one can also supply a transaction to

    Dim CollCon As SAPFEWSELib.GuiComponentCollection
    Dim CollSes As SAPFEWSELib.GuiComponentCollection
    Dim guiCon As SAPFEWSELib.GuiConnection
    Dim guiSes As SAPFEWSELib.GuiSession
    
    Dim guiSesInfo As SAPFEWSELib.GuiSessionInfo
    
    Dim i As Long, j As Long
    Dim SID As String, transaction As String


    'On Error GoTo EH
    
    Dim guiApplication As SAPFEWSELib.guiApplication
    Set guiApplication = getGuiApplication
    
    If guiApplication Is Nothing Then
        Exit Function
    End If
    
    Set CollCon = guiApplication.Connections
    
    If Not IsObject(CollCon) Then
        Exit Function
    End If

    ' Loop through all existing connections
    For i = 0 To CollCon.Count() - 1

        Set guiCon = guiApplication.Children(CLng(i))

        If Not IsObject(guiCon) Then
            Exit Function
        End If

        Set CollSes = guiCon.Sessions
        If Not IsObject(CollSes) Then
            Exit Function
        End If

        ' Now loop through all existing sessions
        For j = 0 To CollSes.Count() - 1

            Set guiSes = guiCon.Children(CLng(j))
            If Not IsObject(guiSes) Then
                Exit Function
            End If

            If guiSes.Busy = vbFalse Then

                Set guiSesInfo = guiSes.Info

                If guiSesInfo.user = "" Or guiSesInfo.user = "SAPSYS" Then
                    ' Logon Screen - cannot be used
                Else
                    If IsObject(guiSesInfo) Then
                        SID = guiSesInfo.SystemName()
                        transaction = guiSesInfo.transaction()
                        ' Take the first one  - In case one could also use the transactionaction addtionally
                        If Len(tCode) = 0 Then
                            If SID = sapSID Then
                                Set findGuiSession = guiSes
                                'FindSession = True
                                Exit Function
                            End If
                        Else
                            If SID = sapSID And transaction = tCode Then
                                Set findGuiSession = guiSes
                                'FindSession = True
                                Exit Function
                            End If
                        End If
                    End If
                End If
            End If
        Next
    Next

    Exit Function

'EH:

End Function

Function getGuiApplication() As SAPFEWSELib.guiApplication
    
    On Error GoTo EH
    Set getGuiApplication = GetObject("SAPGUI").GetScriptingEngine

EH:

End Function

For this code to run you need to add a reference to the SAP library, described here

The following piece of code uses the above function to connect to a system with the name P11, starts the transaction MB52 and downloads the result in a Excel file

Option Explicit

    Sub getMB52_data()
    
        Dim guiSes As SAPFEWSELib.GuiSession
        Set guiSes = getGuiSession("P11")
        
        If Not guiSes Is Nothing Then
            
            With guiSes
                .StartTransaction "MB52"
                .FindById("wnd[0]/usr/ctxtMATNR-LOW").Text = "<MATNR_LOW<"  ' replace with a material nr
                .FindById("wnd[0]/usr/ctxtMATNR-HIGH").Text = "<MATNR_HIGH<"  ' replace with a material nr
                .FindById("wnd[0]/usr/ctxtWERKS-LOW").Text = "<WERKS>"  ' replace wiht a plant  
                .FindById("wnd[0]/tbar[1]/btn[8]").Press
                .FindById("wnd[0]/tbar[0]/okcd").Text = "&XXL"
                .FindById("wnd[0]/tbar[0]/btn[0]").Press
                .FindById("wnd[1]/tbar[0]/btn[0]").Press
                .FindById("wnd[1]/usr/ctxtDY_PATH").Text = "<xlPath>" ' Pathname   
                .FindById("wnd[1]/usr/ctxtDY_FILENAME").Text = "<xlFile>"  ' filename
                .FindById("wnd[1]/tbar[0]/btn[11]").Press
            End With
            
        Else
            MsgBox "No free SAP Session", vbOKOnly + vbInformation, "SAP Verbindung"
        End If
    
    End Sub
Function getGuiSession(sapSID As String, Optional tCode As String) As SAPFEWSELib.GuiSession

    Dim guiApp As SAPFEWSELib.guiApplication
    Set guiApp = getGuiApplication

    If Not guiApp Is Nothing Then
        Set getGuiSession = findGuiSession(sapSID, tCode)
    End If

End Function

Additonal remarks: (hopefully answering some questions in the comments)

Gui Connection: A GuiConnection represents the connection between SAP GUI and an application server. Connections can be opened from SAP Logon or from GuiApplication’s openConnection and openConnectionByConnectionString methods

So, in other words a gui connection is a kind of login to an SAP system. And usually you have more than one SAP system in your organization. If you follow the guidelines you have a DEV, QUAL and PROD for a given system environment. Each of this system is identifid by a SID

What is SID? SID is a unique identification code for every R/3 installation (SAP system) consisting of a database server & several application servers. SID stands for SAP System Identification. SAPSID — a three-character code such as C11, PRD, E56, etc.)

An SID is unique within the organization. Usually SAP licence only allows a user to login to a productive system only once, i.e. you cannot use the same user on different computers and you cannot even login to a SAP system with the same user on the same computer twice.

Having said that: One might be tempted to use guiApplication.Children(0) instead of looping through all connections as done in findGuiSession. And this will work as long as you can make sure that you are only logged on to one SAP system and it is the right one. But in my experience this is often not the case.

The parameter SID in findGuiSession tells the function which system to look for. As written above SID is unique and therefore identfies the system you want to use.

Using tCode in findGuiSession is optional and just forces the user to have a session in place with a given tCode already started. I use this very seldom.

OpenConnection: If you open a connection with the function OpenConnection("<SYSTEM>") you can, of course, use the returned object in order to work with it. But this only does a logon to the system if you have a kind of single sign on in your organization in place. Otherwise you have to provide logon credentials. I do not use this because I do not want to take care of this. And it also can happen that a password change is requested during the logon and I sure do not want to script this.

Example code

Rem Open a connection in synchronous mode
Set Connection = Application.OpenConnection( "U9C [PUBLIC]", True)
Set Session = Connection.Children(0)
Rem Do something: Either fill out the login screen 
Rem or in case of Single-Sign-On start a transaction.
Session.SendCommand( "/nbibs")
Storax
  • 11,158
  • 3
  • 16
  • 33
  • Hello, thank you very much. But does every user, who wants to run this VBA-Code, have to add a reference to the SAP library? I can‘t tell 100+ people, who will be using this, to change their settings in Visual Basic References. Is there a way to „automatically“ activate this via VBA code? And does everyone with SAP installed has the SAP library? Thanks. – iAmMiee Mar 26 '22 at 09:33
  • No, you do it once for the file and that's it. The reference will travel with the file. But, of course, SAPGUI should be installed on the target computers. Then the library is also installed. One disadvantage, but not in this case, could be version conflicts. But the versioning of the SAPGUI library has not changed for a long time. It has been _sapfewse.ocx_ for ages. – Storax Mar 26 '22 at 10:11
  • Thank you! That makes it much easier! But do I have to add the reference to the SAP library for each Excel-File separately if I want to use SAP GUI Scripting, because it is file based? – iAmMiee Mar 26 '22 at 10:19
  • Yes, you have to add it for each file where you want to use the library unless you want to use [late binding](https://learn.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/early-late-binding/) which I do not prefer in this case as versions conflicts should not occur. PS Link is not excatly for VBA but in general also true for VBA. This [artilce](https://learn.microsoft.com/en-us/previous-versions/office/troubleshoot/office-developer/binding-type-available-to-automation-clients) is more approriate for VBA – Storax Mar 26 '22 at 10:25
  • Thank you so much! But I have some questions to the Function `FindGuiSession`: 1. Do I really need the variables tCode, SID and transaction and why? They don't seem necessary. 2. "Connection" means how many logins are active, right? So if I am only able to login with one account at a time, I don't need the `For i = 0 To CollCon.Count() - 1`-Loop, I can use `guiCon = guiApplication.Children(0)` instead? 3. Is `sapSID = "P11"` the ConnectionName for `Connection = Application.OpenConnection(ConnectionName, True)`? – iAmMiee Mar 26 '22 at 17:33
  • @iAmMiee: I edited the answer. Maybe this answers some of the question. But attention, you have to use the `set` keyword. – Storax Mar 26 '22 at 18:18