使用VBA停止SAP中的交易

时间:2018-07-04 11:29:38

标签: vba excel-vba sap excel

我有一个正常工作的VBA宏,该宏进入SAP,开始事务,然后从电子表格中提取数据。但是有时计算运行时间过长,或者我只是想阻止它进行干预。左上角的工具栏上有一个功能,用户可以在其中手动“停止交易”。 “停止交易”按钮是否有任何SAP脚本代码,因此我可以避免手动操作?

SAP工具栏:

SAP toolbar

谢谢您的帮助!

3 个答案:

答案 0 :(得分:1)

假定VBA宏在第一个会话中运行。如果在启动宏之前打开了第二个会话,则可以用来关闭第一个会话。

例如:

Set SapGuiAuto  = GetObject("SAPGUI")
Set SAPapp = SapGuiAuto.GetScriptingEngine
Set SAPconnection = SAPapp.Children(0)
Set session    = SAPconnection.Children(1)

session.findById("wnd[0]/tbar[0]/okcd").text = "/i1"
session.findById("wnd[0]").sendVKey 0
session.createSession

Application.Wait (Now + TimeValue("0:00:05"))

session.findById("wnd[0]/tbar[0]/okcd").text = "/i3"
session.findById("wnd[0]").sendVKey 0
session.createSession

Application.Wait (Now + TimeValue("0:00:05"))

是否执行“回滚”将用于测试。

关于, 脚本人

答案 1 :(得分:0)

我想您最好在这种情况下记录脚本,然后您可以随时重用它。 否则,我此刻正在努力处理相同的情况,但是如果运行时间太长,则运行时计数器部分会留下tcode。 这也是一个很难破解的话题,但主题不同。

更新:意识到没有办法记录“停止交易”步骤,因此我采用了上面的方法-谢谢Script Man,这不是您第一次节省这一天。 对于阅读此线程的任何人-了解如何从VBA脚本运行时拆分SAP运行时可能很有用。 我介绍了一个对象,即“ Execute”命令本身。这样,SAP将接受命令并开始执行,而宏将逐步执行,因为它不是实际命令,而是仅应用新对象。如果运行时间太长,此技巧可以帮助用户编写一个计时器并删除会话。 作为参考,请在此处查看我的代码-我引用了包含相关方法的代码部分。

'check whether you already have an extra session open to close the long running session
'open one if needed
On Error Resume Next
Set session1 = Connection.Children(1)
If Err.Number <> 0 Then
   session.CreateSession
    Application.Wait (Now + TimeValue("0:00:05"))
    're-set the sessions, ensuring you use the first session for actual work and keep session1 in background
    Set session = Connection.Children(0)
    Set session1 = Connection.Children(1)
    SesCount = Connection.Sessions.Count()
    Err.Clear
On Error GoTo 0
End If

'get the ID of first session, so you can enter the correct terminating transaction code when needed
sessionID = Mid(session.ID, (InStrRev(session.ID, "[") + 1), 1)
Terminator = "/i" & sessionID + 1
session.FindById("wnd[0]").Maximize

'some code comes here

'here I use an object to apply the execute button - this way parallel with the SAP runtime, the VBA script can proceed.
perec = session.FindById("wnd[0]/tbar[1]/btn[8]").press

'here we set a loop to check whether system is busy over a certain time then we may interrupt:
Do
Application.Wait (Now + TimeValue("0:00:05"))
SecondsElapsed = SecondsElapsed + 5
fityirc = session.Busy()
if fityirc = False then
exit Do
end if
Loop Until SecondsElapsed >= 100


If fityirc = True Then
session1.FindById("wnd[0]/tbar[0]/okcd").Text = Terminator
session1.FindById("wnd[0]").sendVKey 0
End If

'...and so on. This solution is applied in a loop to extract datasets massively without human interaction.

答案 2 :(得分:0)

或者,查看我刚刚编写并测试的代码,以使用 Windows API 运行“停止事务”菜单项。我在 SAP 论坛上提出了一个关于它的问题,但同时我自己弄明白了 (SAP Forum)

Private Declare PtrSafe Function FindWindowA Lib "user32.dll" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
Private Declare PtrSafe Function GetSystemMenu Lib "user32" (ByVal hWnd As LongPtr, ByVal bRevert As Long) As LongPtr
Private Declare PtrSafe Function GetMenuItemCount Lib "user32" (ByVal hMenu As LongPtr) As Long
Private Declare PtrSafe Function GetMenuItemInfoA Lib "user32" (ByVal hMenu As LongPtr, ByVal un As Long, ByVal b As Long, lpMenuItemInfo As MENUITEMINFO) As Long
Private Declare PtrSafe Function SendMessageA Lib "user32" (ByVal hWnd As LongPtr, ByVal wMsg As Long, ByVal wParam As LongPtr, lParam As Any) As LongPtr

Public Const MIIM_STRING As Integer = &H40
Public Const MIIM_ID = &H2
Public Const WM_COMMAND = &H111
Public Const WM_SYSCOMMAND = &H112

Public Type MENUITEMINFO
    cbSize As Long
    fMask As Long
    fType As Long
    fState As Long
    wID As LongPtr
    hSubMenu As Long
    hbmpChecked As Long
    hbmpUnchecked As Long
    dwItemData As Long
    dwTypeData As String
    cch As Long
End Type

Public Function RunMenuItemByString(ByVal sMenuItem As String, _
                                    ByVal sWindowClass As String, _
                                    ByVal sWindowText As String, _
                                    ByVal iCommandType As Integer) As Boolean

    Dim hWnd As LongPtr, hMenu As LongPtr, lpMenuItemID As LongPtr

    Dim lngMenuItemCount As Long, lngMenuItem As Long, lngResultMenuItemInfo As Long

    Dim typMI As MENUITEMINFO

    Dim s As String

    Dim blnRet As Boolean

    hWnd = FindWindowA(sWindowClass, sWindowText)

    hMenu = GetSystemMenu(hWnd, 0&)

    lngMenuItemCount = GetMenuItemCount(hMenu)

    For lngMenuItem = 0 To lngMenuItemCount - 1

        typMI.cbSize = Len(typMI)
        typMI.dwTypeData = String$(255, " ")
        typMI.cch = Len(typMI.dwTypeData)
        typMI.fMask = MIIM_STRING Or MIIM_ID
        lngResultMenuItemInfo = GetMenuItemInfoA(hMenu, lngMenuItem, 1, typMI)
        s = Trim$(typMI.dwTypeData)
        lpMenuItemID = typMI.wID
        If InStr(1, s, sMenuItem, vbTextCompare) > 0 Then
            blnRet = SendMessageA(hWnd, iCommandType, lpMenuItemID, 0&) = 0
            Exit For
        End If

    Next lngMenuItem

    RunMenuItemByString = blnRet

End Function

Public Function TestRunMenuItemByString()

    lpHwndSAPSession = oSAPSession.FindById("wnd[0]").Handle

    sWindowText = GetWindowText(lpHwndSAPSession)

    TestRunMenuItemByString = RunMenuItemByString("Stop Transaction", "SAP_FRONTEND_SESSION", sWindowText, WM_SYSCOMMAND)

End Function

TestRunMenuItemByString 函数只能在会话启动后使用,并且只有在实际有事务执行时才会起作用。您需要弄清楚如何引用您的 sap 会话对象 (oSAPSession) 以便使用它的 Handle 值。

声明应该适用于 32 位和 64 位版本的 VBA,并且 LongPtr 已用于句柄 (h) 和指针 (lp) 变量以反映这一点。

这已在 Microsoft Access 中进行了测试,但我认为没有理由它不能在其他 Office 应用程序的 VBA 中工作。我不能保证它适用于 VBScript。