Skip to Content
Author's profile photo Former Member

BEx 7.x: Another way to set variable values with VBA – A way without using BExApi -.

As in the very good article posted by François Gyöngyösi, I had developed a Visual Basic code to set the values of BEx variables for queries embedded in Excel workbooks under BW 3.x, too. I also had the problem that my solution doesn’t work with BW 7.x.

I could not find an adequate documentation regarding the new BexApi. So after a lot of trial and error I took another way. Now I’m using the Send Keys Method. I know that it isn’t the best way, but it works. Maybe the following code will help someone. Here are some instructions how to use the code.

1.    1. Launch the BEx Analyzer and open a BEx query with variables.

2.    2. Start the Visual Basic editor.

3.    3. Insert a new module

4.    4. Copy the code below into the module

5.    5. Adjust the code for the function “FokusAndKey”. You will find an example with comments in the code below.

6.    6. Run the procedure “RefQueryStepA”.

Option Explicit
Private Declare Function GetDesktopWindow Lib “user32” () As Long

Private Declare Function GetWindow Lib “user32” ( _
    ByVal hwnd As Long, ByVal wCmd As Long) As Long

Private Declare Function GetWindowText Lib “user32” Alias “GetWindowTextA” ( _
    ByVal hwnd As Long, _
    ByVal lpString As String, _
    ByVal cch As Long) As Long

Private Declare Function GetWindowTextLength Lib “user32” Alias “GetWindowTextLengthA” ( _
    ByVal hwnd As Long) As Long

Private Declare Function GetWindowLong Lib “user32” Alias “GetWindowLongA” ( _
    ByVal hwnd As Long, _
    ByVal wIndx As Long) As Long

Private Declare Function GetParent Lib “user32” ( _
    ByVal hwnd As Long) As Long

Private Declare Function SetForegroundWindow Lib “user32” ( _
    ByVal hwnd As Long) As Long

Private Declare Function SetTimer Lib “user32.dll” ( _
    ByVal hwnd As Long, _
    ByVal nIDEvent As Long, _
    ByVal uElapse As Long, _
    ByVal lpTimerFunc As Long) As Long

Private Declare Function KillTimer Lib “user32.dll” ( _
    ByVal hwnd As Long, _
    ByVal nIDEvent As Long) As Long

Private Declare Function FindWindow Lib “user32.dll” Alias “FindWindowA” ( _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String) As Long

Private Const GC_CLASSNAMEMSEXCEL = “XLMAIN”
     
Const GW_HWNDFIRST = 0
Const GW_HWNDLAST = 1
Const GW_HWNDNEXT = 2
Const GW_HWNDPREV = 3
Const GW_OWNER = 4
Const GW_CHILD = 5
Const GW_MAX = 5

Const GWL_STYLE = (-16)

Const WS_VISIBLE = &H10000000
Const WS_BORDER = &H800000

Private ArrHandeles() As Long

Private TimerHwnd As Long

Sub RefQueryStepA()
   
    ‘I need to start a timer for the second step, because the Bex-Refresh-Variable-Window will interrupt the VB-Code.
    Call StartTimer
   
    ‘Before starting the Bex-Refresh-Variable-Window, write all windows into an array.
    If SucheHandles = True Then
        ‘Run Bex-Refresh-Variable-Window
        If RunRefVarWin = True Then
       
        End If
    End If
   
End Sub

Sub RefQueryStepB()
   
    Dim ArrHandelesA() As Long
    Dim i, j As Integer
    Dim hwnd As Long
       
    ‘Copy array into an second array, before Bex-Refresh-Variable-Window starts.
    ArrHandelesA = ArrHandeles
   
    ‘After the Bex-Refresh-Variable-Window started, write all windows into an array.
    If SucheHandles = True Then
       
        ‘Compare both arrays. If the value is similar set 0
        For i = LBound(ArrHandeles) To UBound(ArrHandeles)
            For j = LBound(ArrHandelesA) To UBound(ArrHandelesA)
                If ArrHandeles(i) = ArrHandelesA(j) Then
                    ArrHandeles(i) = 0
                End If
            Next j
        Next i
       
        ‘Only one window should be left in the array – the Bex-Refresh-Variable-Window -.
        j = 0
        For i = LBound(ArrHandeles) To UBound(ArrHandeles)
            If ArrHandeles(i) <> 0 Then
                j = j + 1
                hwnd = ArrHandeles(i)
            End If
        Next i
       
        If j = 1 Then
            ‘If only one window is left in the array, the EnterKey-Function will starts
            If FokusAndKey(hwnd) = True Then
                ‘stop timer
                Call StopTimer
            End If
        End If
       
    End If
   
End Sub

Function SucheHandles() As Boolean

    Dim hwnd, par, sty, lentit As Long
   
    Dim i As Integer
   
    ‘get desktop handle number.
    hwnd = GetDesktopWindow()
   
    ‘get aktive child window from desktop
    hwnd = GetWindow(hwnd, GW_CHILD)
   
    i = 0
    Do While hwnd <> 0
        ‘select next window
        hwnd = GetWindow(hwnd, GW_HWNDNEXT)
       
        ‘get parent from selected window
        par = GetParent(hwnd)
       
        ‘get style from selected window
        sty = GetWindowLong(hwnd, GWL_STYLE)
       
        ‘get length of title from selected window
        lentit = GetWindowTextLength(hwnd) + 1
       
        ‘If the window has no parent, it could be the Bex-Refresh-Variable-Window
        If par = 0 Then
            ‘If the window has a title, it could be the Bex-Refresh-Variable-Window
            If lentit > 0 Then
                ‘If the window is visible and has a border, it could be the Bex-Refresh-Variable-Window
                If (CBool(sty And WS_VISIBLE) = True And CBool(sty And WS_BORDER) = True) Then
                   
                    ‘write handle number from window into an array
                    ReDim Preserve ArrHandeles(i)
                    ArrHandeles(i) = hwnd
                   
                    i = i + 1
                   
                End If
            End If
        End If
       
    Loop
   
    SucheHandles = True

End Function

Function RunRefVarWin() As Boolean
    ‘Run Bex-Refresh-Variable-Window
   
    Dim SAPpAddin As Object
    Dim lCMD As String
   
    Set SAPpAddin = CreateObject(“com.sap.bi.et.analyzer.addin.BExConnect”)
   
    lCMD = SAPpAddin.ExcelInterface.cCMDRefreshVariables
   
    Call SAPpAddin.ExcelInterface.ProcessBExMenuCommand(lCMD)
   
    RunRefVarWin = True

End Function

Public Sub StartTimer()
    ‘Run timer in an intervall of 500 milliseconds.
    ‘The timer will start the second step, because the Bex-Refresh-Variable-Window interrupts the VB-Code
       
    TimerHwnd = FindWindow(GC_CLASSNAMEMSEXCEL, Application.Caption)
    SetTimer TimerHwnd, 0&, 500&, AddressOf RefQueryStepB
End Sub

Public Sub StopTimer()
    ‘Stop timer
   
    KillTimer TimerHwnd, 0&
End Sub

Function FokusAndKey(hwnd As Long) As Boolean
   
    ‘This function will set the focus to the Bex-Refresh-Variable-Window and send keys to the window.
   
    Dim i As Integer
   
    ‘Now you have to count how much tab-key’s you have to enter to reach the variable-field.
   
    ‘XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    ‘XXXXXXX from here you have to adjust the code to your Bex-Refresh-Variable-Window XXXXXXXXX
    ‘XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   
    ‘In my case I need 5 tab-key’s to reach the first variable.
    For i = 1 To 5
        SetForegroundWindow hwnd
        SendKeys “{TAB}”
    Next i
       
    ‘enter the value of the first valiable
    SetForegroundWindow hwnd
    SendKeys “001.2012 – 012.2012”
   
    ‘To reach the second variable I need 2 tab-key’s
    For i = 1 To 2
        SetForegroundWindow hwnd
        SendKeys “{TAB}”
    Next i
   
    ‘enter the value of the second valiable
    SetForegroundWindow hwnd
    SendKeys “001.2013 – 008.2013”
   
   
    ‘Enter again tab-key’s to reach the OK-Button from the Bex-Refresh-Variable-Window
    For i = 1 To 2
        SetForegroundWindow hwnd
        SendKeys “{TAB}”
    Next i
   
    ‘XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    ‘XXXXXXX till here you have to adjust the code to your Bex-Refresh-Variable-Window XXXXXXXXX
    ‘XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
       
    ‘Send Enter-key to start the Refresh
    SetForegroundWindow hwnd
    SendKeys “{ENTER}”
   
   
    FokusAndKey =True
   
End Function

This code has been tested in Excel 2010 and BEx 7.2. Please note that I will not take the responsibility for issues which arise resulting from its use.

Assigned Tags

      4 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hi Dominik

      Using: BEx 7.x

      As part of my BEx / VBA automation project I been using a Filter Object linked to a Grid to update my query by overwriting the Cell Value using VBA, but this is limited to single Variable inputs ie. you cannot use a Range like 39.2015 - 40.2015 as the Filter does not process this like the Variables Screen.  So once the Report is setup I have only been able to change the Calendar Week to a single Week when automating.

      I have recently tried the Button linking and the Range with SAPBEXsetVariables with limited / no success (not sure if this is due to a recent HANNAH upgrade). 


      Anyhow, your Code worked fine once the SendKeys routine was adapted for my Variables Screen - a great little workaround.  No developer ever likes using SendKeys, but for my project where the entire process is silent, login, refresh, email, close, the example Code posted is a useful workaround.


      Thanks, Mark Kubiszyn

      Author's profile photo Former Member
      Former Member

      By the way I found that I needed to pass semi-colon delimited lists of Materials that exceeded the maximum String Length that you can pass using SendKeys, therefore as a workaround I have added in an enhancement to Paste data directly from the Clipboard after Copying it from a Named Range (or Defined Name) in Excel using VBA

      1. Add a reference to: Microsoft Forms 2.0 Object Library (Important!)

      Add these variables to the top of your Code Module

      Private objData As DataObject

      Private strClipboard As String

      2. Add the following Code at the beginning of the FocusAndEnterVariables() Function to pick up a Named Range called Materials (which has 3,500 Material Codes formatted like this 56510;56615 etc...)

      strClipboard = Range("Materials").Value

      Set objData = New DataObject

      objData.SetText strClipboard

      objData.PutInClipboard

      3. Add the following Code in place of the normal SendKeys to Paste the Clipboard contents into the Variable Screen Input Box

      SetForegroundWindow hwnd

      SendKeys ("^v")

      Now you can Paste as many characters as is possible in the Variables Screen Input Box...

      Author's profile photo Thorsten Niehues
      Thorsten Niehues

      Very good explanation of how to changes variables of an existing query. Very intuitive, plenty of comments. Thanks

      Author's profile photo Former Member
      Former Member

      Thanks for the helpful post.

       

      Is there any way to put delays between sendkeys?

      CPU isn't following the speed of the command it seems..

       

      Thanks,