I'm trying to solve a relatively straight forward problem. I would like to be able to use excel VBA to find a component in the SAP GUI window.
The Script can be found below:
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/tbar[1]/btn[42]").press
session.findById("wnd[1]/usr/txtSEARCH_BY-MATNR").text = "53211"
session.findById("wnd[1]/usr/txtSEARCH_BY-MATNR").caretPosition = 5
session.findById("wnd[1]/tbar[0]/btn[0]").press
The Code can be found below:
More Scripting here
-----------------------------------------------
For Each row In [Multi_Lvl_BOM].Rows
If (Cells(Row_Num, 1).Value = "") Then
Exit For
End If
If (row.Columns(9).Value = "N/A") Then GoTo NextIteration2b
session.findById("wnd[0]/tbar[1]/btn[42]").press
-----------------------------------------------------------
Everything works fine until here
session.findById("wnd[1]/usr/txtSEARCH_BY-MATNR").text = "53211"
-----------------------------------------------------------
On that line Excel Throws an Error
session.findById("wnd[1]/usr/txtSEARCH_BY-MATNR").caretPosition = 5
session.findById("wnd[1]/tbar[0]/btn[0]").press
NextIteration2b:
Row_Num = Row_Num + 1
Next
I recorded a script in SAP, and when I run it there, it works fine. However, when I try to use it in VBA it works until the line where I try to insert the search text. So any interaction with the new open search window would throw an error.
Could it be just a matter of a reference that I am not using? See my references below:
Any help is highly appreciated!
Related
I'm currently trying to fix some issues in a SAP procedure using VBA.
By now I have a piece of code that can correctly handle the error pop-up that sometimes appears:
If session.findById("wnd[2]/usr/txtMESSTXT1").Text = "Material já atualizado para esta operação" Then
'Saves error text
ThisWoorkbook.Worksheets("ExpandirMateriais").Cells(i, "d") = "error"
ThisWoorkbook.Worksheets("ExpandirMateriais").Cells(i, "e") = Now
ThisWoorkbook.Worksheets("ExpandirMateriais").Cells(i, "f") = session.findById("wnd[2]/usr/txtMESSTXT1").Text
'Goes to the inicial SAP window
session.findById("wnd[0]/tbar[0]/okcd").Text = "/nBPMDG/UTL_BROWSER"
session.findById("wnd[0]/tbar[0]/btn[0]").Press
'Goes to the last line of the while loop
GoTo end_while
End If
The issue is this: this error is triggered by just some of the lines of my database. If I leave the code this way, it will cause an error in the lines that don't need the error handling. I need to verify if the active session is the error pop-up and then proceed to handle the error, ie, I need something like this:
If ActiveSession.Name = "wnd[2]/usr/txtMESSTXT1" Then
If session.findById("wnd[2]/usr/txtMESSTXT1").Text = "Material já atualizado para esta operação" Then
'Saves error text
ThisWoorkbook.Worksheets("ExpandirMateriais").Cells(i, "d") = "error"
ThisWoorkbook.Worksheets("ExpandirMateriais").Cells(i, "e") = Now
ThisWoorkbook.Worksheets("ExpandirMateriais").Cells(i, "f") = session.findById("wnd[2]/usr/txtMESSTXT1").Text
'Goes to the inicial SAP window
session.findById("wnd[0]/tbar[0]/okcd").Text = "/nBPMDG/UTL_BROWSER"
session.findById("wnd[0]/tbar[0]/btn[0]").Press
'Goes to the last line of the while loop
GoTo end_while
End If
End If
but I don't know how to properly verify if the active windows is THE error window I'm working with.
I appreciate any help with this syntax.
You could use the following 2 methods to find the relevant SAP session:
the easy way
Set SapGuiAuto = GetObject("SAPGUI")
Set SapApplication = SapGuiAuto.GetScriptingEngine
Set connection = SapApplication.Children(0)
set session = SapApplication.activeSession
...
If session.Name = "wnd[2]/usr/txtMESSTXT1" Then
...
the complicated method
Set SapGuiAuto = GetObject("SAPGUI")
Set SapApplication = SapGuiAuto.GetScriptingEngine
Set connection = SapApplication.Children(0)
for mySession = 0 to connection.children.count - 1
Set ActiveSession = connection.Children(int(mySession))
If ActiveSession.Name = "wnd[2]/usr/txtMESSTXT1" Then
set session = ActiveSession
exit for
end if
next
If session.Name = "wnd[2]/usr/txtMESSTXT1" Then
...
You will have to find out for yourself which of the two methods is applicable to you.
Regards, ScriptMan
Deleting Orders on SAP is one of my Daily Tasks, I Have about 300 Orders to be Deleted everyday so each time i Go to the Transaction (VAO2) then Paste the order number from the excel then Choose options and Delete it, i wanted to script the whole process but each time to paste the new number i Copy from excel, so i created the below script but it goes with the same exact order "2268979048", I need to write the part of the code that let the script paste the number in the clipboard the time i run the Script (Note that i am not authorized to Use MASS deletion transaction)
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/tbar[0]/okcd").text = "va02"
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/ctxtVBAK-VBELN").text = "2268979048"
session.findById("wnd[0]/usr/ctxtVBAK-VBELN").caretPosition = 10
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[1]/tbar[0]/btn[0]").press
Here's what may be helpful half-way lets say:
session.findById("wnd[0]/usr/ctxtVBAK-VBELN").text = InputBox("Pass in order to delete:", "Order deleting script")
This way you could provide each order at a time. But that does not solve your problem, I know. Your problem is more complex as you are trying to use a VBS. It's not easy to use a clipboard in vbs, but its possible.
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").maximize
IterateThroughOrders()
Sub IterateThroughOrders()
Dim userClippboard
userClippboard = CreateObject("HtmlFile").ParentWindow.ClipboardData.GetData("text")
For Each item In Split(userClippboard, Chr(13))
If item <> "" Then
'open new transaction no matter what
session.findById("wnd[0]/tbar[0]/okcd").text = "/nVA02"
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/ctxtVBAK-VBELN").text = item
session.findById("wnd[0]/usr/ctxtVBAK-VBELN").caretPosition = 10
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[1]/tbar[0]/btn[0]").press
'the rest of the code goes here, supposedly there's more to that
End If
Next
End Sub
Explanation:
What happens here is that your clippboard is being loaded using a HtmlFile object, which is a way to get pass a wall that VBS have - it does not support clipboard handling easy way - but it works.
Data copied from excel sheet from a column containing proper orders is being split by Chr(13) character, that is, is being splitted by breakline - new cell in this case.
This split will make it possible to create a loop over every each value you just copied.
I am having trouble with Windows 10 and my connection code in VBA to automatically open SAP, login for me, and begin the macro, Is there a standard piece of code for Windows 10?
I have the code for the older version of Windows , but I keep getting a run time error because it doesn't exactly know what/where the new version of SAP that installed is.
If Sheets("Start").Range("E9") = "Yes" Then
On Error Resume Next
Set SapGuiAuto = CreateObject("Sapgui.ScriptingCtrl.1")
On Error GoTo 0
If SapGuiAuto Is Nothing Then
MsgBox "Please start SAPlogon"
Exit Sub
End If
On Error Resume Next
Set SAP_Applic = SapGuiAuto.GetScriptingEngine
On Error GoTo 0
If SAP_Applic Is Nothing Then
MsgBox "Scripting disabled"
Exit Sub
End If
Set Connection = SAP_Applic.OpenConnection("", True) 'Enter your system here
Set session = Connection.Children(0)
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject SAP_Applic, "on"
End If
I want to edit and launch SAP macros from either the VBA editor in Excel or from a Windows Form Application.
I cannot get my code to "connect" to the current SAP session when the script is used in a compiler. The only time it works is when I open the original VBScript that the macro recorder creates.
The way SAP is set up on my system we are automatically logged in to SAP Logon and launch a new sap GUI window via a web portal saplogon.com/irj/portal, I don't need to physically log on before I interact with the GUI.
When I copy the macro script verbatim I get runtime errors:
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(connection) Then
Set connection = application.Children(0)
End If
If Not IsObject(session) Then
Set session = connection.Children(0)
End If
If IsObject(WScript) Then
WScript.ConnectObject session, "on"
WScript.ConnectObject application, "on"
End If
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/subSA_0100_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2410/subSA_2410_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2510/ctxtKUWEV-KUNNR").text = "I033"
session.findById("wnd[0]/usr/subSA_0100_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2410/subSA_2410_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2510/ctxtKUWEV-KUNNR").caretPosition = 4
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[1]/usr/lbl[12,3]").setFocus
session.findById("wnd[1]/usr/lbl[12,3]").caretPosition = 16
session.findById("wnd[1]").sendVKey 2
session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell").setCurrentCell 1,"MAKTX2"
session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell").doubleClickCurrentCell
session.findById("wnd[1]/tbar[0]/btn[0]").press`
The way I have been trying to go about this is to add the sapfewselib reference into the project and then declare the SAP GUI object.
All the examples I can find are on how to log on to a new SAP session. I can't understand why the code will execute when a notepad is saved as a VBScript file but not when attached to a button in a Windows Form Application or an Excel Spreadsheet even though I have added the reference.
So I still can't find an example in c# which doesn't include log in but for the VBA editor in Excel the following works, but note in Visual Studio 'set' and 'let' keywords have been retired. Just in case anyone else has the same issue, this is what you need to assign to a button:
Sub Button1_Click()
Dim SapGuiAuto
Dim SetApp
Dim Connection
Dim Session
Set SapGuiAuto = GetObject("SAPGUI")
Set SetApp = SapGuiAuto.GetScriptingEngine
Set Connection = SetApp.Children(0)
Set Session = Connection.Children(0)
Session.findById("wnd[0]").maximize
//Then your script to control gui below this://
Session.findById("wnd[0]/usr/subSA_0100_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2410/subSA_2410_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2510/ctxtKUWEV-KUNNR").Text = "I033"
Session.findById("wnd[0]/usr/subSA_0100_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2410/subSA_2410_1:SAPMZCX_CSDSLSBM5001_OFS_OTS:2510/ctxtKUWEV-KUNNR").caretPosition = 4
Session.findById("wnd[0]").sendVKey 0
Session.findById("wnd[1]/usr/lbl[12,3]").SetFocus
Session.findById("wnd[1]/usr/lbl[12,3]").caretPosition = 16
Session.findById("wnd[1]").sendVKey 2
Session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell").setCurrentCell 1, "MAKTX2"
Session.findById("wnd[0]/shellcont/shell/shellcont[1]/shell").doubleClickCurrentCell
Session.findById("wnd[1]/tbar[0]/btn[0]").press
End Sub
Maybe someone can help me with creating new SAP session using VBA Excel
Some code to understand the problem
If Not IsObject(sap) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set sap = SapGuiAuto.GetScriptingEngine
End If
If Not IsObject(Connection) Then
Set Connection = sap.Connections.Item(0)
End If
If Not IsObject(session) Then
Set session = Connection.Children(0)
End If
Most cases this one work fine. But sometimes this part doesn't work
Set session = Connection.Children(0)
it happens for example when SAP timeout occur (auto logoff after some idle time).
In that case I have
sap.Connections.Count
= 2
but
Connection.Sessions.Count
= 0
Looks like the timeouted connection still hangs somewhere in SAP. So when I try to connect to first session of first connection I got an error couse there is no session in first connection.
What I want to do is to create new session.
I can do this by
Dim sapSession As SAPFEWSELib.GuiSession
Dim sapCon As SAPFEWSELib.GuiConnection
Set sapCon = sap.Connections.Item(0)
Set sapSession = Connection.sessions.Item(0)
sapsession.createsession
This one works ok but it doesn't help couse I still need to set the session first
Is there a way to create session after setting the connection?
Something like sapCon.createsession
And does anyone know how can I use specific session using variable?
Set sapSession = Connection.sessions.Item(0)
This works ok but when I try
Dim SessionNumber as integer
....
SessionNumber = 0
Set sapSession = Connection.sessions.Item(SessionNumber)
it throws an error "Bad index type for collection access"
Excel requires that the session number is an integer, so you can use the type conversion from Cint(). Strange that this is advised/required even when SessionNumber is defined as an integer.
Dim SessionNumber
....
SessionNumber = 0
Set sapSession = Connection.sessions.Item(Cint(SessionNumber))
The CreateSession command executes quickly and returns to Excel, but SAP takes a while to finish opening the new session. Thus, you'll need to make your Excel code wait.
Here's an example:
Const ms as Double = 1.15740741E-08 ' one millisecond, in days = 1/(1000*24*60*60)
Dim sapCon As SAPFEWSELib.GuiConnection
Dim sapSession As SAPFEWSELib.GuiSession
Dim nSessions As Integer
Set sapCon = sap.Connections(0)
Set sapSession = sapCon.Sessions(0)
nSessions = sapCon.Sessions.Count
sapSession.createsession
Do
Application.Wait (Now() + 500*ms)
If sapCon.Sessions.Count > nSessions Then Exit Do
Loop
Set sapSession = sapCon.Sessions.Item(CInt(sapCon.Sessions.Count - 1))