Application Life Cycle Management - excel

We connect ALM using OTA connection library but our company added "2FA" two factor authentication as a security using Symantic VIP access for every outside employee who will access our ALM so what I need now is to add this 2FA authentication in the following previous code to work well as previous.
Private Function TDConnect_ServerConnect(ByVal strServer As String)
On Error GoTo ErrCatch
If (g_objTDC Is Nothing) Then Set g_objTDC = New TDConnection
If (g_objTDC Is Nothing) Then
TDConnect_ServerConnect = TDCONNECT_STATUS_FAIL
Else
g_objTDC.InitConnectionEx strServer
TDConnect_ServerConnect = TDCONNECT_STATUS_PASS
End If
Exit Function
ErrCatch:
TDConnect_Log Err.description, LOG_ERROR
TDConnect_ServerConnect = TDCONNECT_STATUS_FAIL
End Function

Related

Find SAP GUI session opened for given SAP system

First I want to check via VBA, before I do some transactions in SAP GUI, if a connection is already open. I am not able to login a second time, so I need to stay in the same connection.
Secondly I want to open another session. The second problem has been solved, if I assume SAP GUI is already open. But I don't know it for sure. So I need to find a way to access the current SAPGUI and Application and Connection, if they exist. If not, the standard code of If Not IsObject(SAPGUI) Then… is fine. But how do I define these variables correctly to check, if they are „filled“ Objects or not?
Thanks for help!
Based on a script by S. Schnell you can use the follwing function to find a free session
Function findGuiSession(ByVal sapSID As String, Optional tCode As String) As SAPFEWSELib.GuiSession
' this will find a free session using the systemnam resp. SID
' and optional one can also supply a transaction to
Dim CollCon As SAPFEWSELib.GuiComponentCollection
Dim CollSes As SAPFEWSELib.GuiComponentCollection
Dim guiCon As SAPFEWSELib.GuiConnection
Dim guiSes As SAPFEWSELib.GuiSession
Dim guiSesInfo As SAPFEWSELib.GuiSessionInfo
Dim i As Long, j As Long
Dim SID As String, transaction As String
'On Error GoTo EH
Dim guiApplication As SAPFEWSELib.guiApplication
Set guiApplication = getGuiApplication
If guiApplication Is Nothing Then
Exit Function
End If
Set CollCon = guiApplication.Connections
If Not IsObject(CollCon) Then
Exit Function
End If
' Loop through all existing connections
For i = 0 To CollCon.Count() - 1
Set guiCon = guiApplication.Children(CLng(i))
If Not IsObject(guiCon) Then
Exit Function
End If
Set CollSes = guiCon.Sessions
If Not IsObject(CollSes) Then
Exit Function
End If
' Now loop through all existing sessions
For j = 0 To CollSes.Count() - 1
Set guiSes = guiCon.Children(CLng(j))
If Not IsObject(guiSes) Then
Exit Function
End If
If guiSes.Busy = vbFalse Then
Set guiSesInfo = guiSes.Info
If guiSesInfo.user = "" Or guiSesInfo.user = "SAPSYS" Then
' Logon Screen - cannot be used
Else
If IsObject(guiSesInfo) Then
SID = guiSesInfo.SystemName()
transaction = guiSesInfo.transaction()
' Take the first one - In case one could also use the transactionaction addtionally
If Len(tCode) = 0 Then
If SID = sapSID Then
Set findGuiSession = guiSes
'FindSession = True
Exit Function
End If
Else
If SID = sapSID And transaction = tCode Then
Set findGuiSession = guiSes
'FindSession = True
Exit Function
End If
End If
End If
End If
End If
Next
Next
Exit Function
'EH:
End Function
Function getGuiApplication() As SAPFEWSELib.guiApplication
On Error GoTo EH
Set getGuiApplication = GetObject("SAPGUI").GetScriptingEngine
EH:
End Function
For this code to run you need to add a reference to the SAP library, described here
The following piece of code uses the above function to connect to a system with the name P11, starts the transaction MB52 and downloads the result in a Excel file
Option Explicit
Sub getMB52_data()
Dim guiSes As SAPFEWSELib.GuiSession
Set guiSes = getGuiSession("P11")
If Not guiSes Is Nothing Then
With guiSes
.StartTransaction "MB52"
.FindById("wnd[0]/usr/ctxtMATNR-LOW").Text = "<MATNR_LOW<" ' replace with a material nr
.FindById("wnd[0]/usr/ctxtMATNR-HIGH").Text = "<MATNR_HIGH<" ' replace with a material nr
.FindById("wnd[0]/usr/ctxtWERKS-LOW").Text = "<WERKS>" ' replace wiht a plant
.FindById("wnd[0]/tbar[1]/btn[8]").Press
.FindById("wnd[0]/tbar[0]/okcd").Text = "&XXL"
.FindById("wnd[0]/tbar[0]/btn[0]").Press
.FindById("wnd[1]/tbar[0]/btn[0]").Press
.FindById("wnd[1]/usr/ctxtDY_PATH").Text = "<xlPath>" ' Pathname
.FindById("wnd[1]/usr/ctxtDY_FILENAME").Text = "<xlFile>" ' filename
.FindById("wnd[1]/tbar[0]/btn[11]").Press
End With
Else
MsgBox "No free SAP Session", vbOKOnly + vbInformation, "SAP Verbindung"
End If
End Sub
Function getGuiSession(sapSID As String, Optional tCode As String) As SAPFEWSELib.GuiSession
Dim guiApp As SAPFEWSELib.guiApplication
Set guiApp = getGuiApplication
If Not guiApp Is Nothing Then
Set getGuiSession = findGuiSession(sapSID, tCode)
End If
End Function
Additonal remarks: (hopefully answering some questions in the comments)
Gui Connection: A GuiConnection represents the connection between SAP GUI and an application server. Connections can be opened from SAP Logon or from GuiApplication’s openConnection and openConnectionByConnectionString
methods
So, in other words a gui connection is a kind of login to an SAP system. And usually you have more than one SAP system in your organization. If you follow the guidelines you have a DEV, QUAL and PROD for a given system environment. Each of this system is identifid by a SID
What is SID?
SID is a unique identification code for every R/3 installation (SAP system) consisting of a database server & several application servers. SID stands for SAP System Identification. SAPSID — a three-character code such as C11, PRD, E56, etc.)
An SID is unique within the organization. Usually SAP licence only allows a user to login to a productive system only once, i.e. you cannot use the same user on different computers and you cannot even login to a SAP system with the same user on the same computer twice.
Having said that: One might be tempted to use guiApplication.Children(0) instead of looping through all connections as done in findGuiSession. And this will work as long as you can make sure that you are only logged on to one SAP system and it is the right one. But in my experience this is often not the case.
The parameter SID in findGuiSession tells the function which system to look for. As written above SID is unique and therefore identfies the system you want to use.
Using tCode in findGuiSession is optional and just forces the user to have a session in place with a given tCode already started. I use this very seldom.
OpenConnection: If you open a connection with the function OpenConnection("<SYSTEM>") you can, of course, use the returned object in order to work with it. But this only does a logon to the system if you have a kind of single sign on in your organization in place. Otherwise you have to provide logon credentials. I do not use this because I do not want to take care of this. And it also can happen that a password change is requested during the logon and I sure do not want to script this.
Example code
Rem Open a connection in synchronous mode
Set Connection = Application.OpenConnection( "U9C [PUBLIC]", True)
Set Session = Connection.Children(0)
Rem Do something: Either fill out the login screen
Rem or in case of Single-Sign-On start a transaction.
Session.SendCommand( "/nbibs")

VBA program executing SAP RFCs works in Excel 2016 on-prem, but not in Office 365 (Run-time error 20080008...Bad Variant Type)

Let me first say that I saw the other two threads that mentioned this issue here and here, but they didn't help me solve my problem.
I've been testing a program for several weeks in the on-prem Excel 2016 environment (32-bit) with no problems. My company is making the move to Office 365 soon, so I decided to test it over there as well. On that system, I'm getting a run-time error on the line Functions.Connection = objConnection
Option Explicit
Public Functions As SAPFunctionsOCX.SAPFunctions
Private LogonControl As SAPLogonCtrl.SAPLogonControl
Private objConnection As SAPLogonCtrl.Connection
Public Func As SAPFunctionsOCX.Function
Public Commit As SAPFunctionsOCX.Function
Public TableFactory As SAPTableFactory
Public silentLogon As Boolean
Public tblReadTableOptions, tblReadTableFields, tblReadTableData As SAPTableFactoryCtrl.Table
Sub ExtractProjectData()
If objConnection Is Nothing Then LogonToSAP
InitiateSAPVariables
Set Func = Functions.Add("BBP_RFC_READ_TABLE")
Set tblReadTableOptions = Func.Tables("OPTIONS")
Set tblReadTableFields = Func.Tables("FIELDS")
Set tblReadTableData = Func.Tables("DATA")
'extract/transform data from SAP tables
End Sub
Function InitiateSAPVariables()
Set Functions = Nothing
Set TableFactory = Nothing
Set Func = Nothing
Set Functions = CreateObject("SAP.Functions")
Set TableFactory = CreateObject("SAP.TableFactory.1")
Functions.Connection = objConnection 'run-time error here in Office 365 but not in on-prem
End Function
Function LogonToSAP()
Dim establishConnection As Boolean
silentLogon = false
Set LogonControl = CreateObject("SAP.LogonControl.1")
Set objConnection = LogonControl.NewConnection
objConnection.Client = "###"
objConnection.Language = "EN"
objConnection.SystemNumber = "##"
objConnection.User = ""
objConnection.Password = ""
objConnection.HostName = "###############"
objConnection.System = "###"
objConnection.ApplicationServer = "###.###.#.##"
establishConnection = objConnection.Logon(0, silentLogon)
End Function
A quick check of objConnection tells me that logon was successful...so I know that part is working on 365. For some reason though, it doesn't like assigning the Connection property of the Functions SAPFunctionsOCX.SAPFunctions object in the 365 environment (please feel free to correct my verbiage on that...I know it's not quite right).
Note that I'm not seeing any reference issues nor am I getting any compile errors in either environment. The first sign of trouble is on execution of Functions.Connection = objConnection
There's one more twist here and that is that I have another older VBA program that logs into SAP and runs remote function calls that doesn't use SAPFunctionsOCX.SAPFunctions, but rather declares variable R3 as Public R3 As Object and then sets R3 later in the logon code as Set R3 = CreateObject("SAP.Functions")...it does not use OCX. In other words, the old routine uses late binding. When the Functions object (R3 in this case) is set this way, I am able to run RFCs in both on prem and Office 365 environments.
Function LogonProdSAP(Optional SuppressLoginScreen As Boolean)
Application.ScreenUpdating = False
'**********************************************
'Create Server object and Setup the connection for DEV
'**********************************************
Set R3 = CreateObject("SAP.Functions")
If SuppressLoginScreen Then
R3.Connection.System = "###"
R3.Connection.HostName = "###################"
R3.Connection.SystemNumber = "##"
R3.Connection.Client = "###"
R3.Connection.User = "##########"
R3.Connection.Password = "#########"
R3.Connection.Language = "EN"
' Call Logger("LogonProdSAP> " & GetUserName)
End If
LogonProdSAP = R3.Connection.logon(0, SuppressLoginScreen)
If LogonProdSAP <> True Then MsgBox ("Logon error"): Exit Function
End Function
I could just go back to doing it this way, but I'd rather not have to reconfigure all of the code I just set up. In addition, I prefer binding early so Intellitype works to show all properties/methods available to that object. I'm sure there are other benefits as well.
What do I have to do to get the early-binding technique to work on Office 365?
It's due to the fact that your Office is in 64 bits version, and SAP GUI for Windows up to version 7.60 is in 32 bits (next SAP GUI version 7.70 should be in 64 bits, so it should work again).
You have a workaround to make VBA work with SAP GUI 32-bits DLL, by using DLL Surrogate, i.e. by editing the Windows Registry of all incompatible SAP GUI DLL. The original solution was proposed here at SAP Community.
To simplify the task, you may create my .REG file, execute it to update automatically the Windows Registry, and your VBA macro should then work.
I duplicate here my .REG file:
; ====================================================================================
; SAP Logon Unicode Control %ProgramFiles(x86)%\SAP\FrontEnd\SAPgui\wdtlogU.ocx {0AAF5A11-8C04-4385-A925-0B62F6632BEC}
; ====================================================================================
[HKEY_CLASSES_ROOT\WOW6432Node\AppID\{0AAF5A11-8C04-4385-A925-0B62F6632BEC}]
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{0AAF5A11-8C04-4385-A925-0B62F6632BEC}]
"AppID"="{0AAF5A11-8C04-4385-A925-0B62F6632BEC}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{0AAF5A11-8C04-4385-A925-0B62F6632BEC}]
; ====================================================================================
; SAP Remote Function Call Unicode Control %ProgramFiles(x86)%\SAP\FrontEnd\SAPgui\wdtfuncu.ocx {0AF427E7-03B9-4673-8F21-F33A683BCE28}
; ====================================================================================
[HKEY_CLASSES_ROOT\WOW6432Node\AppID\{0AF427E7-03B9-4673-8F21-F33A683BCE28}]
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{0AF427E7-03B9-4673-8F21-F33A683BCE28}]
"AppID"="{0AF427E7-03B9-4673-8F21-F33A683BCE28}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{0AF427E7-03B9-4673-8F21-F33A683BCE28}]
; ====================================================================================
; SAP Logon Control (not Unicode) %ProgramFiles(x86)%\SAP\FrontEnd\SAPgui\wdtlog.ocx {B24944D6-1501-11CF-8981-0000E8A49FA0}
; ====================================================================================
[HKEY_CLASSES_ROOT\WOW6432Node\AppID\{B24944D6-1501-11CF-8981-0000E8A49FA0}]
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{B24944D6-1501-11CF-8981-0000E8A49FA0}]
"AppID"="{B24944D6-1501-11CF-8981-0000E8A49FA0}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{B24944D6-1501-11CF-8981-0000E8A49FA0}]
; ====================================================================================
; SAP Remote Function Call Control (not Unicode) %ProgramFiles(x86)%\SAP\FrontEnd\SAPgui\wdtfuncs.ocx {5B076C03-2F26-11CF-9AE5-0800096E19F4}
; ====================================================================================
[HKEY_CLASSES_ROOT\WOW6432Node\AppID\{5B076C03-2F26-11CF-9AE5-0800096E19F4}]
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\WOW6432Node\CLSID\{5B076C03-2F26-11CF-9AE5-0800096E19F4}]
"AppID"="{5B076C03-2F26-11CF-9AE5-0800096E19F4}"
[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{5B076C03-2F26-11CF-9AE5-0800096E19F4}]

silent logon to sap bw server via excel vba script and bexanalyzer

we are running SAP BW with BExAnalyzer 7.5. I've been trying for days to establish a connection to the SAP - Server, but unfortunately I am not even receiving an error message. So it seems the logon has succeeded, but no data from BW is fetched, so I am assuming there is a problem in the logon. Please help!
Function LogonToServer() As Boolean
LogonToServer = False
Dim myConnection As Object
Set myConnection = Run("'C:\Program Files (x86)\Common Files\SAP Shared\BW\BExAnalyzer.xla'!SAPBEXgetConnection")
With myConnection
.client = "xxx"
.user = "xxx"
.Password = "xxxx"
.Language = "DE"
.systemnumber = "xxx"
.system = "xxx"
.ApplicationServer = "xxx"
.SAProuter = ""
.Logon 0, True
End With
If myConnection.IsConnected <> 1 Then
'launch the Logon Dialog for manual connection
myConnection.Logon 0, False
If myConnection.IsConnected <> 1 Then
MsgBox "something went wrong ..."
Exit Function
End If
End If
If myConnection.IsConnected = 1 Then
LogonToServer = True
End If
Run "BExAnalyzer.xla!SAPBEXinitConnection"
End Function
SAP Note 2541995 says that the cause is that the Password property is not available in 7.5. It suggests that you can reconnect if you are using Single Sign On (SSO). It also points to note 2635165 that is a front end patch that may fix the issue with the password property. The code you attached does work with version 7.4 and I experienced similar issues with 7.5 but do not have access to download the patch. I'll try and get the front end patch and test again and update my answer with the results.

Implementing Single Sign-On from .NET Application to SAP System, using SAP.NET Connector 3.0

We are trying to use SAP.NET NCo 3.0 to implement single sign on from .net application to SAP System. In the configuration set up method we are fetching user name and password along with other configuration information from configuration file.
E.g.
RfcConfigParameters rfcConfig = new RfcConfigParameters();
rfcConfig.Add(RfcConfigParameters.User, ConfigurationSettings.AppSettings["SAP_USRNAME"]);
rfcConfig.Add(RfcConfigParameters.Password, ConfigurationSettings.AppSettings["SAP_PWD"]);
rfcConfig.Add(RfcConfigParameters.Client, ConfigurationSettings.AppSettings["SAP_CLIENT"]);
We are looking for a way that we can implement SSO with windows authentication where will ne NO need to pass user id and password explicitly. We also have SNC configuration and other required file available with us.
Any relevant code snippet or pointer addressing this will be of great help.
Thanks in advance
You need to make a http request to the SAP portal from the client. This will give you the SAPSSO2 token (parse it out of the http headers you receive, sample in VB):
Public Function GetSAPSSOTicket(sPortalURL As String, ByRef Ticket As String, ByRef ErrorMsg As String) As Boolean
Dim offset As Long
GetSSOTicket = False
ErrorMsg = ""
Ticket = ""
Const MYSAPSSO2 As String = "MYSAPSSO2="
On Error GoTo Err1
'contact the sap portal
Dim req As New WinHttp.WinHttpRequest
req.Open "GET", sPortalURL, False
req.SetAutoLogonPolicy AutoLogonPolicy_Always
req.Send
Dim S As String
S = req.GetAllResponseHeaders()
'parse the ticket out of the response
offset = InStr(1, S, MYSAPSSO2, vbTextCompare)
If offset <= 0 Then
ErrorMsg = "The Portal Server returned an empty ticket. Authentication failed."
GoSub Cleanup
Exit Function
End If
S = Mid(S, offset + Len(MYSAPSSO2))
offset = InStr(1, S, ";")
S = Left(S, offset - 1)
Ticket = S
'complete
On Error GoTo 0
'success
GoSub Cleanup
GetSSOTicket = True
Exit Function
Cleanup:
Set req = Nothing
Return
Err1:
'some error
GoSub Cleanup
ErrorMsg = Err.Description
End Function
Next, transport this token to your SAP.NET connector code where you make your destination and connection, and assign the value you obtained to the destination's SAPSSO2 property (sample in c#):
var destX = new SAP.Connector.Destination();
destX.Type = "3"; /* meaning R/3 */
destX.AppServerHost = "hostname";
destX.Client = (short)99; /* your client number here */
destX.SystemNumber = (short)42; /* your system number here */
/* single sign-on token passed in from SAPSSO2 header value in sapCookie parameter */
destX.MySAP_SSO2 = System.Web.HttpUtility.UrlDecode(sapCookie, Encoding.UTF8);
destX.Language = "DE";
destX.MsgServerHost = "message server (if needed, otherwise blank)";
destX.LogonGroup = "group name (or blank)";
destX.AbapDebug = false;
destX.Trace = true;
sap.Connection = new SAP.Connector.SAPConnection(destX);
sap.Connection.Open();
We have this code in production since 2004 and it survived many releases, up to and including SAP HANA with Unicode.

excel VBA web service give error METHOD OR DATAOBJECT NOT FOUND

I have a weird problem with an excel VBA application.
It uses a web service to connect to a mysql database.
it all runs well in most computers....however in some computers it throws an error:
ERROR WHEN COMPILING "METHOD OR DATAOBJECT NOT FOUND"
All computers are running Windows 7 and Office 2007.
Here is an example of the web service code (where the error happens)
Public Function wsm_get_portscountries(ByVal str_SQLQuery As String) As MSXML2.IXMLDOMNodeList
On Error GoTo wsm_get_portscountriesTrap
Set wsm_get_portscountries = sc_WebService1.wsm_get_portscountries(str_SQLQuery)
Exit Function
wsm_get_portscountriesTrap:
WebService1ErrorHandler "wsm_get_portscountries"
End Function
The error highlights the bolded part here:
sc_WebService1.wsm_get_portscountries(str_SQLQuery)
Has anyone encountered the same problem ?? Any ideas ??
As I said, on most computers it runs well, no problems, it only happens with some.
Thanks in advance.
additional information:
class module
Private Sub Class_Initialize()
On Error GoTo Class_Initialize_error
Dim str_WSML As String
str_WSML = ""
Set sc_WebService1 = New SoapClient30
sc_WebService1.MSSoapInit2 c_WSDL_URL, str_WSML, c_SERVICE, c_PORT, c_SERVICE_NAMESPACE
sc_WebService1.ConnectorProperty("ProxyServer") = "<CURRENT_USER>"
sc_WebService1.ConnectorProperty("EnableAutoProxy") = True
Exit Sub
Class_Initialize_error:
End Sub

Resources