Skip to Content
Author's profile photo Stefan Schnell

SAP GUI Scripting: Collection vs. Children, the Busy Difference

In some cases it is necessary with SAP GUI Scripting to loop over all existing connections and sessions. If a session is busy, which means the SAP GUI is waiting for data from the server, it is necessary to detect this situation, to avoid blocking the execution thread. For this case offers SAP GUI Scripting the property Busy of the GuiSession class. But in some cases blocks the property Children of the GuiConnection class, before it is possible to use Busy property.

The following code blocks the execution at line

$session = Get-Property $connection "Children" @($j)

The execution of the script is blocked until the session is available again.

#-Begin-----------------------------------------------------------------

  #-Includes------------------------------------------------------------
  ."$PSScriptRoot\COM.ps1"

  #-Sub Main------------------------------------------------------------
  Function Main() {

    $SapGuiAuto = Get-Object( , "SAPGUI")
    If ($SapGuiAuto -isnot [__ComObject]) {
      Exit
    }

    $application = Invoke-Method $SapGuiAuto "GetScriptingEngine"
    If ($application -isnot [__ComObject]) {
      Free-Object $SapGuiAuto
      Exit
    }

    For($i = 0; $i -lt $application.Children().Count(); $i++) {
      $connection = Get-Property $application "Children" @($i)
      For($j = 0; $j -lt $connection.Children().Count(); $j++) {
        $session = Get-Property $connection "Children" @($j)
        If ($session.Busy() -eq 1) {
          Continue
        }

      }
    }

    Free-Object $SapGuiAuto

  }

  #-Main----------------------------------------------------------------
  Main

#-End-------------------------------------------------------------------

 

Here another approach to bypass this situation:

#-Begin-----------------------------------------------------------------

  #-Includes------------------------------------------------------------
  ."$PSScriptRoot\COM.ps1"

  #-Sub Main------------------------------------------------------------
  Function Main() {

    $SapGuiAuto = Get-Object( , "SAPGUI")
    If ($SapGuiAuto -isnot [__ComObject]) {
      Exit
    }

    $application = Invoke-Method $SapGuiAuto "GetScriptingEngine"
    If ($application -isnot [__ComObject]) {
      Free-Object $SapGuiAuto
      Exit
    }

    $connections = Get-Property $application "Connections"
    ForEach ($connection In $connections) {
      $sessions = Get-Property $connection "Sessions"
      ForEach ($session In $sessions) {
        If ($session.Busy() -eq 1) {
          Continue
        }

      }
    }

    Free-Object $SapGuiAuto

  }

  #-Main----------------------------------------------------------------
  Main

#-End-------------------------------------------------------------------

Both sources do exactly the same, they loop over all connections and sessions. But in the secound source I use another method. I get all connections and sessions and loop over this. And with this approach works the Busy property as expected.

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Márcio Vieira
      Márcio Vieira

      Hello Stefan,

      I have been trying to do a script to run multiple transactions in different windows, I found this article https://archive.sap.com/discussions/thread/3388231 which is already archived since it is the year 2013 now reading this topic on the property “Busy”, would it be possible to run multiple sessions simultaneously?

       

      Note: My scripts are in VBA or Autoit.

       

      Thank you very much

       

      Márcio.

       

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Márcio,

      sure it that possible. Here an example in PowerShell.

      #-Begin-----------------------------------------------------------------
      
      $ScriptBlock = {
        Param($sessionNumber);
      
        ."C:\Script\COM.ps1"
      
        $SapGuiAuto = Get-Object( , "SAPGUI")
        If ($SapGuiAuto -isnot [__ComObject]) {
          Exit
        }
      
        $application = Invoke-Method $SapGuiAuto "GetScriptingEngine"
        If ($application -isnot [__ComObject]) {
          Free-Object $SapGuiAuto
          Exit
        }
      
        $connection = Get-Property $application "Children"@(0)
        If ($connection -eq $Null) {
          Free-Object $SapGuiAuto
          Exit
        }
      
        $session = Get-Property $connection "Children"@($sessionNumber)
        If ($session -eq $Null) {
          Free-Object $SapGuiAuto
          Exit
        }
      
        for ($i = 1; $i -le 10; $i++) {
          $ID = Invoke-Method $session "findById" @("wnd[0]/tbar[0]/okcd")
          Set-Property $ID "text" @("/nse16")
          $ID = Invoke-Method $session "findById" @("wnd[0]")
          Invoke-Method $ID "sendVKey" @(0)
          $ID = Invoke-Method $session "findById" @("wnd[0]/usr/ctxtDATABROWSE-TABLENAME")
          Set-Property $ID "text" @("tfdir")
          $ID = Invoke-Method $session "findById" @("wnd[0]/usr/ctxtDATABROWSE-TABLENAME")
          Set-Property $ID "caretPosition" @(5)
          $ID = Invoke-Method $session "findById" @("wnd[0]")
          Invoke-Method $ID "sendVKey" @(0)
          $ID = Invoke-Method $session "findById" @("wnd[0]/tbar[1]/btn[31]")
          Invoke-Method $ID "press"
          $ID = Invoke-Method $session "findById" @("wnd[1]/tbar[0]/btn[0]")
          Invoke-Method $ID "press"
          $ID = Invoke-Method $session "findById" @("wnd[0]/tbar[0]/btn[3]")
          Invoke-Method $ID "press"
          $ID = Invoke-Method $session "findById" @("wnd[0]/tbar[0]/btn[3]")
          Invoke-Method $ID "press"
          Start-Sleep -Milliseconds 500
        }
      
        Free-Object $session
        Free-Object $connection
        Free-Object $application
        Free-Object $SapGuiAuto
      
      }
      
      Start-Job -ScriptBlock $ScriptBlock -ArgumentList 0;
      Start-Job -ScriptBlock $ScriptBlock -ArgumentList 1;
      
      #-End-------------------------------------------------------------------

      The ScriptBlock contains the script and with the commands Start-Job two scripts are running parallel. PowerShell offers fantastic possibilities to use background jobs. In my eyes it is not up to date anymore to realize those kinds of solutions in VBA. So you must realize solutions which have nothing to do with your business problem. To use this solution also in VBA you can use SAPIENS ActiveXPoSHV3, PowerShell access for VBScript/JScript developers - but you can use it also in VBA or AutoIt. You can find more information here. Here an example how to use it in VBA:

      Option Explicit
      
      Const OUTPUT_CONSOLE = 0
      Const OUTPUT_WINDOW = 1
      Const OUTPUT_BUFFER = 2
      
      Sub ParallelTest()
      
        Dim ActiveXPosh As ActiveXPoshV3.IActiveXPoSH
        Dim success As Boolean
        Dim PSScript As String
        Dim iFile As Integer: iFile = FreeFile
      
        Open "C:\Script\Test.ps1" For Input As #iFile
        PSScript = Input(LOF(iFile), iFile)
        Close #iFile
        
        Set ActiveXPosh = CreateObject("SAPIEN.ActiveXPoSHV3")
        success = ActiveXPosh.Init(vbFalse)
        If success <> 0 Then
          Debug.Print "Init failed"
          Exit Sub
        End If
          
        If ActiveXPosh.IsPowerShellInstalled Then
          ActiveXPosh.OutputMode = OUTPUT_BUFFER
          ActiveXPosh.Execute (PSScript)
          Debug.Print ActiveXPosh.OutputString
        Else
          Debug.Print "PowerShell not installed"
          Exit Sub
        End If
      
      End Sub

      Cheers
      Stefan