VBA SAP createsession - vba

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))

Related

SAP GUI Scripting: new session from VBA

I am searching for macro script that opens new session when current session is running.
Problem is that macro opens new session when it's only opened, but not makes new session when current session is running example transaction after pressing execute button.
My macro below:
Private Sub nextSession()
Dim nSessions As Integer
Set SapGuiAuto = GetObject("SAPGUI")
Set SAPApp = SapGuiAuto.GetScriptingEngine
Set sapCon = SAPApp.Children(0)
Set session = sapCon.Children(0)
nSessions = sapCon.Sessions.Count
session.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))
End Sub

Find component in SAP GUI using VBA

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!

Get SAP System Date

Using SAP scripting, I'm trying to figure out a way of obtaining SAP's current system date.
If I following System > Status..., there is a field displaying the SAP system's current time, but unfortunately there is no field for the current date. Code below.
Set SapGuiAuto = GetObject("SAPGUI")
Set SAPApp = SapGuiAuto.GetScriptingEngine
Set SAPConnection = SAPApp.Children(0)
Set session = SAPConnection.Children(0)
Dim systemDate, systemTime As String
session.findById("wnd[0]/mbar/menu[4]/menu[11]").Select
systemTime = session.findById("wnd[1]/usr/ctxtSYST-UZEIT").Text
'systemDate = .....
I feel like there must be a simple way of getting the system date, but after hours of searching the web I have come up with nothing. Any help would be appreciated, thanks.
EDIT:
I have found one solution, sort of. It's not the simplest way, but I can save a variant in one of SAP's transaction (IW37N) so that it auto populates a date and a time field with a dynamic value of now upon entry. Once the variant is saved, I can use SAP scripting to access the transaction > access the variant > access the two dynamic fields (code below). Again, not really the simplest option, so I'm open to hearing better ideas.
'Connect to SAP
Set SapGuiAuto = GetObject("SAPGUI")
Set SAPApp = SapGuiAuto.GetScriptingEngine
Set SAPConnection = SAPApp.Children(0)
Set session = SAPConnection.Children(0)
'Enter Transaction
session.findById("wnd[0]/tbar[0]/okcd").Text = "/NIW37N"
session.findById("wnd[0]").sendVKey 0
'Select Variant
session.findById("wnd[0]/tbar[1]/btn[17]").press
session.findById("wnd[1]/usr/txtV-LOW").Text = "TEST001"
session.findById("wnd[1]/usr/ctxtENVIR-LOW").Text = ""
session.findById("wnd[1]/usr/txtENAME-LOW").Text = ""
session.findById("wnd[1]/usr/txtAENAME-LOW").Text = ""
session.findById("wnd[1]/usr/txtMLANGU-LOW").Text = ""
session.findById("wnd[1]/tbar[0]/btn[8]").press
'Select Dates Tab
session.findById("wnd[0]/usr/tabsTABSTRIP_TABBLOCK1/tabpS_TAB5").Select
'Get Field Values
Dim systemDate, systemTime As String
systemDate = session.findById("wnd[0]/usr/tabsTABSTRIP_TABBLOCK1/tabpS_TAB5/ssub%_SUBSCREEN_TABBLOCK1:RI_ORDER_OPERATION_LIST:1500/ctxtS_ISDD-LOW").Text
systemTime = session.findById("wnd[0]/usr/tabsTABSTRIP_TABBLOCK1/tabpS_TAB5/ssub%_SUBSCREEN_TABBLOCK1:RI_ORDER_OPERATION_LIST:1500/ctxtS_ISDZ-LOW").Text
Sergii was right. The problem is that the same dates are hidden. Thus, the variables are not available. I wanted to know, so I signed in to SAP shortly before midnight. It will look like that:
The script could look like this:
'...
session.findById("wnd[0]/mbar/menu[1]/menu[11]").select
on error resume next
LAST_LOGON_DATE = session.findById("wnd[1]/usr/ctxtLAST_LOGON_DATE").text
SESSION_START_DATE = session.findById("wnd[1]/usr/ctxtSESSION_START_DATE").text
SYST_DATE = session.findById("wnd[1]/usr/ctxtSYST-DATUM").setFocus
on error goto 0
session.findById("wnd[1]").close
if SESSION_START_DATE = "" then SESSION_START_DATE = LAST_LOGON_DATE
if SYST_DATE = "" then SYST_DATE = SESSION_START_DATE
msgbox LAST_LOGON_DATE & " / " & SESSION_START_DATE & " / " & SYST_DATE
'...
Regards,
ScriptMan
Let you try this:
systemDate = session.findById("wnd[1]/usr/ctxtSYST-DATUM").Text
You can see for details there:
https://archive.sap.com/discussions/thread/1095191
Regards
Sergii

Converting VBA to VBScript - Not working but no error

I've been following articles and questions about converting VBA to VBScript but I'm now stuck. The following code still works in VBA (if I remove the Sub routine call) but it won't run as a script.
The code opens a connection to SQL Server to check a table to see if the process has already run today and loads the result into a Recordset. If the field is set to No then it opens up an Excel workbook and runs a macro. It works in VBA but when I run the same code as a script nothing happens (no errors either).
Can you see what the problem is? Thanks very much.
NB. There are two lines for cmd.CommandText. The commented out line is designed to always return No for testing purposes only.
' Author Steve Wolstencroft
' Inititates the Automated Excel Refresh Procedure
Option Explicit
Pivot_Refresh
Public Function ConnectToSQLDwarfP()
On Error Resume Next
ConnectToSQLDwarfP = "Driver={SQL Server Native Client 10.0};Server=DwarfP;Database=DwarfPortable;Trusted_Connection=yes;"
End Function
Public Sub Pivot_Refresh()
On Error Resume Next
Dim cnx
Dim Rst
Set cnx = New ADODB.Connection
cnx.ConnectionString = ConnectToSQLDwarfP
cnx.Open
Dim cmd
Set cmd = New ADODB.Command
cmd.ActiveConnection = cnx
cmd.CommandType = adCmdText
cmd.CommandText = "Select Case When max(DwarfPortable.dbo.fn_GetJustDate(pl.StartDateTime)) = DwarfPortable.dbo.fn_GetJustDate(getDate()) Then 'Y' Else 'N' End as RunToday From ProcessControl.dbo.ProcessLog pl Where pl.ProcessName = 'Excel_Auto_Refresh'"
'cmd.CommandText = "Select Case When max(pl.StartDateTime) = DwarfPortable.dbo.fn_GetJustDate(getDate()) Then 'Y' Else 'N' End as RunToday From ProcessControl.dbo.ProcessLog pl Where pl.ProcessName = 'Excel_Auto_Refresh'"
Set Rst = cmd.Execute
Dim objXL, objBook
Set objXL = CreateObject("Excel.Application")
If Rst.Fields("RunToday") = "N" Then
Set objBook = objXL.Workbooks.Open("\\nch\dfs\SharedArea\HI\Clinical-Informatics\InfoRequestOutputs\Regular-Jobs\Pivot-Refresh\Pivot-Refresh-Control.xls", 0, True)
objXL.Application.Visible = True
objXL.Application.Run "'Pivot-Refresh-Control.xls'!Auto_Refresh"
objXL.ActiveWindow.Close
objXL.Quit
Set objBook = Nothing
Set objXL = Nothing
End If
End Sub
You can't instantiate external objects in VBScript with e.g. New ADODB.Connection because there are no references to external libraries.
You can't use constants like adCmdText either. They will be treated as undefined empty variables.
You don't get any errors because you shut them up with On Error Resume Next. Remove that and you will get your errors.
Make sure all external object instantiation is done with CreateObject like you are doing for Excel, and replace all external constants with their literal values.

Finding imported data in a cell to stop importing it VBA

Im making a macro on excel that import data from MySQL (with querytables.add and using OBCD) and every time i run the macro it creates a new connection and its a waste of time and space. Is there a function to know if a cell/sheet has a connection on it so i dont have to import the data again and create a new connection or a code to know when was the last time the connection was refreshed.
i looked up for something but it seems there is nothing like it, so maybe and alternative way to do it will be useful, thanks!
Code:
Worksheets("Hoja1").Activate
Dim sqlstring As String
Const connstring As String = "ODBC;DSN=blabla;UID=blabla;PWD=blabla"
if "***Range("A1") has a connection***" then
ActiveWorkbook.Connections("Conexión").Refresh 'actualize the connection previously made
Else 'import the table from sql server
sqlstring = vbNullString
sqlstring = "SELECT * FROM ExTable WHERE year > '2012'"
With ActiveSheet.QueryTables.Add(Connection:=connstring, Destination:=Range("A1"), Sql:=sqlstring)
.RefreshStyle = xlOverwriteCells
.Refresh BackgroundQuery:=False
End With
I just built and tested this nifty little procedure that checks if a connection exists for a specific worksheet range and if so, refreshes it. I also left a spot to add the part where it creates a new one if it's not found.
Warning - as written, this will potentially fail if there is another connection listed on the worksheet outside the desired range and it checks that connection first while there is also an existing connection within the desired range. You'll need to adjust for that.
Sub RefreshMakeConnection()
Dim cnT As Connections
Set cnT = ThisWorkbook.Connections
Dim sWS As String
sWS = "Hoja1"
Dim cn As WorkbookConnection
For Each cn In cnT
If cn.Ranges(1).Parent.Name = sWS Then
With Worksheets(sWS)
If Not Intersect(.Range("A1"), cn.Ranges(1)) Is Nothing Then
cn.Refresh
Else
'code to create new connection
End If
End With
End If
Next
End Sub
Perhaps you may find the connections name?
Sub test()
Dim ItemConnection As Variant
Dim TotalConnections As Connections: Set TotalConnections = ThisWorkbook.Connections
For Each ItemConnection In TotalConnections
MsgBox ItemConnection.Name
Next ItemConnection
End Sub
PS: Variant is because I didn't find a way to declare connection as a single item of connection