Skip to content

Building an RFC interface with MBS Xojo Plugin to SAP R/3 or SAP S/4 HANA

If you work with large companies, you’ve most likely heard of SAP, a widely used enterprise software solution. With the RFC classes of the MBS Xojo Plugin you can build RFC (Remote Function Call) interfaces so that Xojo apps can communicate with SAP systems. I’ve done this to SAP R/3 and SAP S/4 HANA. The MBS plugin covers the libraries of the SAP NetWeaver RFC SDK 7.50.

The SAP interface has four steps:

  1. Determine the path to the SAP library 
  2. Build a connection to the SAP system
  3. Transfer data to the SAP system
  4. Receive data from the SAP system

Connect the SAP System

Your SAP user must have the authority for RFC connections. If so, you must know some data of your SAP logon to connect to an SAP system, such as:

  • host name – a name or an IP address (ashost)
  • router string 
  • system number (sysnr)
  • client (client)
  • language (lang)
  • user (user)
  • password (passwd)

At first you must set the path to the SAP libraries. In Windows you have some DLL’s around SAPNWRFC.DLL and on macOS you have some DYLIB’s around LIBSAPNWRFC.DYLIB.

If TargetWin32
  var LibFile as string = "sapnwrfc.dll"
Else
  // get the actual folder and handle the exception
  var MacOsFolder as folderitem = app.ExecutableFile.Parent
  System.EnvironmentVariable("DYLD_LIBRARY_PATH") = MacOsFolder.NativePath
  If System.EnvironmentVariable("DYLD_LIBRARY_PATH") = "" Then
    MessageBox("DYLD_LIBRARY_PATH variable not set")
    return
  end if
  var LibFile as FolderItem = MacOsFolder.Child("libsapnwrfc.dylib")
  var LibPath As String = LibFile.parent.NativePath
  Call RFCModuleMBS.SetCurrentWorkingDirectory(libPath)
EndIf

I’ve copied the SAP libraries with the Xojo build settings into the application resource folders. 

If the setting of the LibPath fails then send the error message:

If not RFCModuleMBS.LoadLibrary(LibFile) Then
  // Failed to load library
  Messagebox RFCModuleMBS.LibraryLoadErrorMessage
  return
End If 

And if the LibPath is set you can do the logon as second step:

var loginParams As New Dictionary
loginParams.Value("ashost") = "12.345.67.89"
loginParams.Value("sysnr")  = "10"
loginParams.Value("client") = "100"
loginParams.Value("user")   = "MYUSERNAME”
loginParams.Value("passwd") = "MyPassword"
loginParams.Value("lang")   = "EN"
var ConnectionToSAP As New RFCConnectionMBS(loginParams) 

Please note if you have a router string you must build the host name (ashost) with a concatenation of router string and host name like this:

loginParams.Value("ashost") = <router string> + "/H/" + <host name>

If the connection fails you will get the reason with:

Exception r As RFCErrorExceptionMBS
 MessageBox r.message 

Calling an SAP Function Module

If you are calling a SAP Function Module you will export key values to SAP and you will receive data or i.e. error messages. To understand the import and export parameters you must look out of the SAP function module in the surrounding world.

This example calls the SAP function module RFC_READ_TABLE. With this standard RFC module you can get the content of a database table and/or the SAP data dictionary description of this table.

Exporting key values to SAP

For exporting the key values to the SAP function module you must load a functions description and create a data container for executing the function module.

var fd as RFCFunctionDescriptionMBS = app.ConnectionToSAP.FunctionDescription("RFC_READ_TABLE")
var f as RFCFunctionMBS = fd.CreateFunction 

The function module RFC_READ_TABLE has two parameters:

  • the name of the table as import parameter: QUERY_TABLE
  • the select options of the where clause as tables parameter: OPTIONS
f.StringValue("QUERY_TABLE") = "<name of the table>"

var it_OPTIONS as RFCTableMBS = f.TableValue("OPTIONS")
var is_OPTIONS as RFCStructureMBS

is_OPTIONS = it_OPTIONS.AppendNewRow
is_OPTIONS.StringValue("TEXT") = "(MATNR = '4711')" // WHERE clause

You must consider that the maximum length of a where clause for the table OPTIONS is 72 digits. If the where clause length is greater than 72 you must split the clause to several lines. The clause must look like this “(MATNR = ‘1234’ AND WERKS = ‘1000’) OR (MATNR = ‘3456’ AND WERKS = ‘1000’)”. 

And now you can execute the function module into the backend system:

f.invoke

Receiving data from SAP

The function module RFC_READ_TABLE returns now to tables parameters:

  • FIELDS – contains the SAP data dictionary description of the returned table
  • DATA – contains the data found for the transferred where clauses
TableFields as RFCTableMBS = f.TableValue("FIELDS")
TableData as RFCTableMBS = f.TableValue("DATA") 

If the TableFields.RowCount = 0 then the returned table contains no data. To get the content of a returned table you must loop like this:

If TableData.RowCount > 0 then
  TableData.MoveToFirstRow
End if
For iRow as integer = 1 to TableData.RowCount
  // get a field value
  Var FieldValue as string = TableData.StringValue("<Fieldname in the table record>")
  If iRow < TableData.RowCount then
    TabeData.MoveToNextRow
  End if
next

Error Handling

To catch an exception, you should code into your method something like this:

 Exception r As RFCErrorExceptionMBS
  MessageBox r.message 

Interpretation of Returned Data

If you want to get after the INVOKE the returned data you will have 

  • a table or
  • a structure or
  • a field

If you have a table you will get a certain field with:

Var TableContent as RFCTableMBS
TableContent = f.TableValue("<Name of the returned table parameters>")
If TableContent.RowCount > 0 then
  TableContent.MoveToFirstRow
End if
For iRow as integer = 1 to TableContent.RowCount
  ListBox1.AddRow(TableContent.StringValue("FieldOne"), TableContent.StringValue("FieldTwo"))
  If iRow < TableContent.RowCount then
    TableContent.MoveToNextRow
  End if
Next

If you have a structure you will get a certain field with:

var s As RFCStructureMBS = f.StructureValue("ES_MESSAGE")
TextField1.Value = s.StringValue("FieldOne")

If you have a field you will get the data with:

TextField1.Value = f.StringValue("FieldName")

Using the above techniques with the MBS plugin, your Xojo apps can now access information contained in SAP.

Michael Eckert studied economics from 1982-1986 and has been employed at T-Systems as a software architect since 1989. Michael has worked with ERP systems for 34 years, until 1998 with PL/1, since 1998 with ABAP in SAP R/3 and SAP S/4 HANA. He’s been developing with Xojo for about 9 years.